#include "gpu/ipc/service/gpu_channel.h"
#include <cstdint>
#include <utility>
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/task/single_thread_task_runner.h"
#include "build/build_config.h"
#if BUILDFLAG(IS_WIN)
#include <windows.h>
#endif
#include <algorithm>
#include <set>
#include <vector>
#include "base/atomicops.h"
#include "base/command_line.h"
#include "base/containers/circular_deque.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
#include "base/process/process.h"
#include "base/strings/string_util.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/bind_post_task.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
#include "base/timer/timer.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/trace_event.h"
#include "base/unguessable_token.h"
#include "components/viz/common/resources/shared_image_format_utils.h"
#include "gpu/command_buffer/common/context_creation_attribs.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "gpu/command_buffer/service/memory_tracking.h"
#include "gpu/command_buffer/service/scheduler.h"
#include "gpu/command_buffer/service/service_utils.h"
#include "gpu/command_buffer/service/task_graph.h"
#include "gpu/config/gpu_finch_features.h"
#include "gpu/ipc/common/command_buffer_id.h"
#include "gpu/ipc/common/gpu_channel.mojom.h"
#include "gpu/ipc/common/gpu_memory_buffer_impl_shared_memory.h"
#include "gpu/ipc/common/gpu_memory_buffer_support.h"
#include "gpu/ipc/service/gles2_command_buffer_stub.h"
#include "gpu/ipc/service/gpu_channel_manager.h"
#include "gpu/ipc/service/gpu_channel_manager_delegate.h"
#include "gpu/ipc/service/gpu_memory_buffer_factory.h"
#include "gpu/ipc/service/image_decode_accelerator_stub.h"
#include "gpu/ipc/service/raster_command_buffer_stub.h"
#include "gpu/ipc/service/webgpu_command_buffer_stub.h"
#include "ipc/ipc_channel.h"
#include "mojo/public/cpp/base/shared_memory_version.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "ui/base/ozone_buildflags.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gl_utils.h"
#if BUILDFLAG(IS_ANDROID)
#include "gpu/ipc/service/stream_texture_android.h"
#endif
#if BUILDFLAG(IS_WIN)
#include "components/viz/common/overlay_state/win/overlay_state_service.h"
#include "gpu/ipc/service/dcomp_texture_win.h"
#endif
#if BUILDFLAG(IS_OZONE)
#include "ui/ozone/public/ozone_platform.h"
#endif
namespace gpu {
namespace {
#if BUILDFLAG(IS_ANDROID)
bool TryCreateStreamTexture(
base::WeakPtr<GpuChannel> channel,
int32_t stream_id,
mojo::PendingAssociatedReceiver<mojom::StreamTexture> receiver) {
if (!channel)
return false;
return channel->CreateStreamTexture(stream_id, std::move(receiver));
}
#endif
#if BUILDFLAG(IS_WIN)
bool TryCreateDCOMPTexture(
base::WeakPtr<GpuChannel> channel,
int32_t route_id,
mojo::PendingAssociatedReceiver<mojom::DCOMPTexture> receiver) {
if (!channel)
return false;
return channel->CreateDCOMPTexture(route_id, std::move(receiver));
}
bool TryRegisterOverlayStateObserver(
base::WeakPtr<GpuChannel> channel,
mojo::PendingRemote<gpu::mojom::OverlayStateObserver>
promotion_hint_observer,
const gpu::Mailbox& mailbox) {
if (!channel)
return false;
return channel->RegisterOverlayStateObserver(
std::move(promotion_hint_observer), std::move(mailbox));
}
#endif
bool WillGetGmbConfigFromGpu() { … }
}
class GPU_IPC_SERVICE_EXPORT GpuChannelMessageFilter
: public base::RefCountedThreadSafe<GpuChannelMessageFilter>,
public mojom::GpuChannel { … };
GpuChannelMessageFilter::GpuChannelMessageFilter(
gpu::GpuChannel* gpu_channel,
const base::UnguessableToken& channel_token,
Scheduler* scheduler,
ImageDecodeAcceleratorWorker* image_decode_accelerator_worker,
const gfx::GpuExtraInfo& gpu_extra_info,
gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)
: … { … }
GpuChannelMessageFilter::~GpuChannelMessageFilter() { … }
void GpuChannelMessageFilter::Destroy() { … }
void GpuChannelMessageFilter::AddRoute(int32_t route_id,
SequenceId sequence_id) { … }
void GpuChannelMessageFilter::RemoveRoute(int32_t route_id) { … }
SequenceId GpuChannelMessageFilter::GetSequenceId(int32_t route_id) const { … }
void GpuChannelMessageFilter::FlushDeferredRequests(
std::vector<mojom::DeferredRequestPtr> requests,
uint32_t flushed_deferred_message_id) { … }
bool GpuChannelMessageFilter::IsNativeBufferSupported(
gfx::BufferFormat buffer_format,
gfx::BufferUsage buffer_usage) { … }
void GpuChannelMessageFilter::CreateGpuMemoryBuffer(
const gfx::Size& size,
const viz::SharedImageFormat& format,
gfx::BufferUsage buffer_usage,
CreateGpuMemoryBufferCallback callback) { … }
void GpuChannelMessageFilter::GetGpuMemoryBufferHandleInfo(
const gpu::Mailbox& mailbox,
GetGpuMemoryBufferHandleInfoCallback callback) { … }
void GpuChannelMessageFilter::CrashForTesting() { … }
void GpuChannelMessageFilter::TerminateForTesting() { … }
void GpuChannelMessageFilter::GetChannelToken(
GetChannelTokenCallback callback) { … }
void GpuChannelMessageFilter::GetSharedMemoryForFlushId(
GetSharedMemoryForFlushIdCallback callback) { … }
void GpuChannelMessageFilter::Flush(FlushCallback callback) { … }
void GpuChannelMessageFilter::CreateCommandBuffer(
mojom::CreateCommandBufferParamsPtr params,
int32_t routing_id,
base::UnsafeSharedMemoryRegion shared_state,
mojo::PendingAssociatedReceiver<mojom::CommandBuffer> receiver,
mojo::PendingAssociatedRemote<mojom::CommandBufferClient> client,
CreateCommandBufferCallback callback) { … }
void GpuChannelMessageFilter::DestroyCommandBuffer(
int32_t routing_id,
DestroyCommandBufferCallback callback) { … }
void GpuChannelMessageFilter::ScheduleImageDecode(
mojom::ScheduleImageDecodeParamsPtr params,
uint64_t decode_release_count) { … }
#if BUILDFLAG(IS_ANDROID)
void GpuChannelMessageFilter::CreateStreamTexture(
int32_t stream_id,
mojo::PendingAssociatedReceiver<mojom::StreamTexture> receiver,
CreateStreamTextureCallback callback) {
base::AutoLock auto_lock(gpu_channel_lock_);
if (!gpu_channel_) {
receiver_.reset();
return;
}
main_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&TryCreateStreamTexture, gpu_channel_->AsWeakPtr(),
stream_id, std::move(receiver)),
std::move(callback));
}
#endif
#if BUILDFLAG(IS_WIN)
void GpuChannelMessageFilter::CreateDCOMPTexture(
int32_t route_id,
mojo::PendingAssociatedReceiver<mojom::DCOMPTexture> receiver,
CreateDCOMPTextureCallback callback) {
base::AutoLock auto_lock(gpu_channel_lock_);
if (!gpu_channel_) {
receiver_.reset();
return;
}
main_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&TryCreateDCOMPTexture, gpu_channel_->AsWeakPtr(),
route_id, std::move(receiver)),
std::move(callback));
}
void GpuChannelMessageFilter::RegisterOverlayStateObserver(
mojo::PendingRemote<gpu::mojom::OverlayStateObserver>
promotion_hint_observer,
const gpu::Mailbox& mailbox,
RegisterOverlayStateObserverCallback callback) {
base::AutoLock auto_lock(gpu_channel_lock_);
if (!gpu_channel_) {
receiver_.reset();
return;
}
main_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&TryRegisterOverlayStateObserver,
gpu_channel_->AsWeakPtr(),
std::move(promotion_hint_observer), mailbox),
std::move(callback));
}
void GpuChannelMessageFilter::CopyToGpuMemoryBufferAsync(
const gpu::Mailbox& mailbox,
const std::vector<gpu::SyncToken>& sync_token_dependencies,
uint64_t release_count,
CopyToGpuMemoryBufferAsyncCallback callback) {
TRACE_EVENT0("gpu", "GpuChannelMessageFilter::CopyToGpuMemoryBufferAsync");
base::AutoLock auto_lock(gpu_channel_lock_);
if (!gpu_channel_) {
std::move(callback).Run(false);
receiver_.reset();
return;
}
int32_t routing_id =
static_cast<int32_t>(GpuChannelReservedRoutes::kSharedImageInterface);
auto it = route_sequences_.find(routing_id);
if (it == route_sequences_.end()) {
LOG(ERROR) << "Could not find SharedImageInterface route id!";
std::move(callback).Run(false);
return;
}
SyncToken release;
if (release_count != 0) {
release = SyncToken(CommandBufferNamespace::GPU_IO,
CommandBufferIdFromChannelAndRoute(
gpu_channel_->client_id(), routing_id),
release_count);
}
auto run_on_main = base::BindOnce(
[](base::WeakPtr<gpu::GpuChannel> channel, const gpu::Mailbox& mailbox,
CopyToGpuMemoryBufferAsyncCallback callback) {
if (!channel) {
std::move(callback).Run(false);
}
channel->shared_image_stub()->CopyToGpuMemoryBufferAsync(
mailbox, std::move(callback));
},
gpu_channel_->AsWeakPtr(), mailbox,
base::BindPostTask(base::SequencedTaskRunner::GetCurrentDefault(),
std::move(callback)));
scheduler_->ScheduleTask(Scheduler::Task(it->second, std::move(run_on_main),
sync_token_dependencies, release));
}
#endif
void GpuChannelMessageFilter::WaitForTokenInRange(
int32_t routing_id,
int32_t start,
int32_t end,
WaitForTokenInRangeCallback callback) { … }
void GpuChannelMessageFilter::WaitForGetOffsetInRange(
int32_t routing_id,
uint32_t set_get_buffer_count,
int32_t start,
int32_t end,
WaitForGetOffsetInRangeCallback callback) { … }
GpuChannel::GpuChannel(
GpuChannelManager* gpu_channel_manager,
const base::UnguessableToken& channel_token,
Scheduler* scheduler,
SyncPointManager* sync_point_manager,
scoped_refptr<gl::GLShareGroup> share_group,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
int32_t client_id,
uint64_t client_tracing_id,
bool is_gpu_host,
ImageDecodeAcceleratorWorker* image_decode_accelerator_worker,
const gfx::GpuExtraInfo& gpu_extra_info,
gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory)
: … { … }
GpuChannel::~GpuChannel() { … }
std::unique_ptr<GpuChannel> GpuChannel::Create(
GpuChannelManager* gpu_channel_manager,
const base::UnguessableToken& channel_token,
Scheduler* scheduler,
SyncPointManager* sync_point_manager,
scoped_refptr<gl::GLShareGroup> share_group,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
int32_t client_id,
uint64_t client_tracing_id,
bool is_gpu_host,
ImageDecodeAcceleratorWorker* image_decode_accelerator_worker,
const gfx::GpuExtraInfo& gpu_extra_info,
gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory) { … }
void GpuChannel::Init(IPC::ChannelHandle channel_handle,
base::WaitableEvent* shutdown_event) { … }
base::WeakPtr<GpuChannel> GpuChannel::AsWeakPtr() { … }
bool GpuChannel::OnMessageReceived(const IPC::Message& msg) { … }
void GpuChannel::OnChannelError() { … }
void GpuChannel::GetIsolationKey(
const blink::WebGPUExecutionContextToken& token,
GetIsolationKeyCallback cb) { … }
void GpuChannel::OnCommandBufferScheduled(CommandBufferStub* stub) { … }
void GpuChannel::OnCommandBufferDescheduled(CommandBufferStub* stub) { … }
CommandBufferStub* GpuChannel::LookupCommandBuffer(int32_t route_id) { … }
bool GpuChannel::HasActiveStatefulContext() const { … }
void GpuChannel::MarkAllContextsLost() { … }
bool GpuChannel::AddRoute(int32_t route_id, SequenceId sequence_id) { … }
void GpuChannel::RemoveRoute(int32_t route_id) { … }
void GpuChannel::ExecuteDeferredRequest(
mojom::DeferredRequestParamsPtr params,
FenceSyncReleaseDelegate* release_delegate) { … }
void GpuChannel::GetGpuMemoryBufferHandleInfo(
const gpu::Mailbox& mailbox,
mojom::GpuChannel::GetGpuMemoryBufferHandleInfoCallback callback) { … }
void GpuChannel::PerformImmediateCleanup() { … }
void GpuChannel::WaitForTokenInRange(
int32_t routing_id,
int32_t start,
int32_t end,
mojom::GpuChannel::WaitForTokenInRangeCallback callback) { … }
void GpuChannel::WaitForGetOffsetInRange(
int32_t routing_id,
uint32_t set_get_buffer_count,
int32_t start,
int32_t end,
mojom::GpuChannel::WaitForGetOffsetInRangeCallback callback) { … }
mojom::GpuChannel& GpuChannel::GetGpuChannelForTesting() { … }
bool GpuChannel::CreateSharedImageStub(
const gfx::GpuExtraInfo& gpu_extra_info) { … }
#if BUILDFLAG(IS_ANDROID)
const CommandBufferStub* GpuChannel::GetOneStub() const {
for (const auto& kv : stubs_) {
const CommandBufferStub* stub = kv.second.get();
if (stub->decoder_context() && !stub->decoder_context()->WasContextLost())
return stub;
}
return nullptr;
}
void GpuChannel::DestroyStreamTexture(int32_t stream_id) {
auto found = stream_textures_.find(stream_id);
if (found == stream_textures_.end()) {
LOG(ERROR) << "Trying to destroy a non-existent stream texture.";
return;
}
found->second->ReleaseChannel();
stream_textures_.erase(stream_id);
}
#endif
#if BUILDFLAG(IS_WIN)
void GpuChannel::DestroyDCOMPTexture(int32_t route_id) {
auto found = dcomp_textures_.find(route_id);
if (found == dcomp_textures_.end()) {
LOG(ERROR) << "Trying to destroy a non-existent dcomp texture.";
return;
}
found->second->ReleaseChannel();
dcomp_textures_.erase(route_id);
}
#endif
class ScopedCreateCommandBufferResponder { … };
void GpuChannel::CreateCommandBuffer(
mojom::CreateCommandBufferParamsPtr init_params,
int32_t route_id,
base::UnsafeSharedMemoryRegion shared_state_shm,
mojo::PendingAssociatedReceiver<mojom::CommandBuffer> receiver,
mojo::PendingAssociatedRemote<mojom::CommandBufferClient> client,
mojom::GpuChannel::CreateCommandBufferCallback callback) { … }
void GpuChannel::DestroyCommandBuffer(int32_t route_id) { … }
#if BUILDFLAG(IS_ANDROID)
bool GpuChannel::CreateStreamTexture(
int32_t stream_id,
mojo::PendingAssociatedReceiver<mojom::StreamTexture> receiver) {
auto found = stream_textures_.find(stream_id);
if (found != stream_textures_.end()) {
LOG(ERROR)
<< "Trying to create a StreamTexture with an existing stream_id.";
return false;
}
scoped_refptr<StreamTexture> stream_texture =
StreamTexture::Create(this, stream_id, std::move(receiver));
if (!stream_texture) {
return false;
}
stream_textures_.emplace(stream_id, std::move(stream_texture));
return true;
}
#endif
#if BUILDFLAG(IS_WIN)
bool GpuChannel::CreateDCOMPTexture(
int32_t route_id,
mojo::PendingAssociatedReceiver<mojom::DCOMPTexture> receiver) {
auto found = dcomp_textures_.find(route_id);
if (found != dcomp_textures_.end()) {
LOG(ERROR) << "Trying to create a DCOMPTexture with an existing route_id.";
return false;
}
scoped_refptr<DCOMPTexture> dcomp_texture =
DCOMPTexture::Create(this, route_id, std::move(receiver));
if (!dcomp_texture) {
return false;
}
dcomp_textures_.emplace(route_id, std::move(dcomp_texture));
return true;
}
bool GpuChannel::RegisterOverlayStateObserver(
mojo::PendingRemote<gpu::mojom::OverlayStateObserver>
promotion_hint_observer,
const gpu::Mailbox& mailbox) {
viz::OverlayStateService* overlay_state_service =
viz::OverlayStateService::GetInstance();
if (!overlay_state_service)
return false;
overlay_state_service->RegisterObserver(std::move(promotion_hint_observer),
std::move(mailbox));
return true;
}
#endif
#if BUILDFLAG(IS_FUCHSIA)
void GpuChannel::RegisterSysmemBufferCollection(
mojo::PlatformHandle service_handle,
mojo::PlatformHandle sysmem_token,
const viz::SharedImageFormat& format,
gfx::BufferUsage usage,
bool register_with_image_pipe) {
shared_image_stub_->RegisterSysmemBufferCollection(
zx::eventpair(service_handle.TakeHandle()),
zx::channel(sysmem_token.TakeHandle()), format, usage,
register_with_image_pipe);
}
#endif
std::optional<gpu::GpuDiskCacheHandle> GpuChannel::GetCacheHandleForType(
gpu::GpuDiskCacheType type) { … }
void GpuChannel::RegisterCacheHandle(const gpu::GpuDiskCacheHandle& handle) { … }
void GpuChannel::CacheBlob(gpu::GpuDiskCacheType type,
const std::string& key,
const std::string& shader) { … }
uint64_t GpuChannel::GetMemoryUsage() const { … }
}