chromium/gpu/ipc/service/gpu_channel.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#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  // BUILDFLAG(IS_ANDROID)

#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  // BUILDFLAG(IS_OZONE)

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  // BUILDFLAG(IS_ANDROID)

#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  // BUILDFLAG(IS_WIN)

bool WillGetGmbConfigFromGpu() {}

}  // namespace

// This filter does the following:
// - handles the Nop message used for verifying sync tokens on the IO thread
// - forwards messages to child message filters
// - posts control and out of order messages to the main thread
// - forwards other messages to the scheduler
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  // BUILDFLAG(IS_ANDROID)

#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  // BUILDFLAG(IS_WIN)

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  // BUILDFLAG(IS_WIN)

// Helper to ensure CreateCommandBuffer below always invokes its response
// callback.
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  // BUILDFLAG(IS_WIN)

#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  // BUILDFLAG(IS_FUCHSIA)

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 {}

}  // namespace gpu