blob: 3a4334ae45e709ff09769406513a50d8dfd21401 [file] [log] [blame]
// Copyright 2024 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_shared_image_interface.h"
#include "base/synchronization/waitable_event.h"
#include "build/build_config.h"
#include "components/viz/common/resources/shared_image_format_utils.h"
#include "gpu/command_buffer/client/client_shared_image.h"
#include "gpu/command_buffer/common/shared_image_capabilities.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "gpu/command_buffer/service/scheduler.h"
#include "gpu/command_buffer/service/shared_image/shared_image_factory.h"
#include "gpu/command_buffer/service/shared_image_interface_in_process_base.h"
#include "gpu/ipc/service/gpu_channel.h"
#include "gpu/ipc/service/gpu_channel_manager.h"
#if BUILDFLAG(IS_ANDROID)
#include "gpu/command_buffer/service/ref_counted_lock.h"
#include "gpu/command_buffer/service/shared_image/android_video_image_backing.h"
#include "gpu/command_buffer/service/stream_texture_shared_image_interface.h"
#endif
namespace gpu {
namespace {
// Generates unique IDs for GpuChannelSharedImageInterface.
base::AtomicSequenceNumber g_next_id;
} // namespace
GpuChannelSharedImageInterface::GpuChannelSharedImageInterface(
base::WeakPtr<SharedImageStub> shared_image_stub)
: SharedImageInterfaceInProcessBase(
CommandBufferNamespace::GPU_CHANNEL_SHARED_IMAGE_INTERFACE,
CommandBufferIdFromChannelAndRoute(
shared_image_stub->channel()->client_id(),
g_next_id.GetNext() + 1),
/*verify_creation_sync_token=*/true,
shared_image_stub->factory()->MakeCapabilities()),
shared_image_stub_(shared_image_stub),
scheduler_(shared_image_stub->channel()->scheduler()),
sequence_(scheduler_->CreateSequence(
SchedulingPriority::kLow,
shared_image_stub->channel()->task_runner(),
CommandBufferNamespace::GPU_CHANNEL_SHARED_IMAGE_INTERFACE,
command_buffer_id())) {}
GpuChannelSharedImageInterface::~GpuChannelSharedImageInterface() {
scheduler_->DestroySequence(sequence_);
}
// Public functions specific to GpuChannelSharedImageInterface:
#if BUILDFLAG(IS_ANDROID)
scoped_refptr<ClientSharedImage>
GpuChannelSharedImageInterface::CreateSharedImageForAndroidVideo(
const gfx::Size& size,
const gfx::ColorSpace& color_space,
scoped_refptr<StreamTextureSharedImageInterface> image,
scoped_refptr<RefCountedLock> drdc_lock) {
DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
if (!shared_image_stub_) {
return nullptr;
}
auto mailbox = Mailbox::Generate();
scoped_refptr<SharedContextState> shared_context =
shared_image_stub_->shared_context_state();
if (shared_context->context_lost()) {
return nullptr;
}
auto shared_image_backing = AndroidVideoImageBacking::Create(
mailbox, size, color_space, kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
/*debug_label=*/"SIForAndroidVideo", std::move(image),
std::move(shared_context), std::move(drdc_lock));
SharedImageMetadata metadata{shared_image_backing->format(),
shared_image_backing->size(),
shared_image_backing->color_space(),
shared_image_backing->surface_origin(),
shared_image_backing->alpha_type(),
shared_image_backing->usage()};
// Register it with shared image mailbox. This keeps |shared_image_backing|
// around until its destruction cb is called.
DCHECK(shared_image_stub_->channel()
->gpu_channel_manager()
->shared_image_manager());
shared_image_stub_->factory()->RegisterBacking(
std::move(shared_image_backing));
SharedImageInfo info(metadata, /*debug_label=*/"SIForAndroidVideo");
return base::WrapRefCounted<ClientSharedImage>(new ClientSharedImage(
mailbox, info, GenVerifiedSyncToken(), holder_, GL_TEXTURE_EXTERNAL_OES));
}
#endif
#if BUILDFLAG(IS_WIN)
scoped_refptr<ClientSharedImage>
GpuChannelSharedImageInterface::CreateSharedImageForD3D11Video(
const SharedImageInfo& si_info,
Microsoft::WRL::ComPtr<ID3D11Texture2D> texture,
scoped_refptr<gpu::DXGISharedHandleState> dxgi_shared_handle_state,
size_t array_slice,
const bool is_thread_safe) {
DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
if (!shared_image_stub_) {
return nullptr;
}
auto mailbox = Mailbox::Generate();
auto metadata = si_info.meta;
auto caps = shared_image_stub_->shared_context_state()->GetGLFormatCaps();
// The target must be GL_TEXTURE_EXTERNAL_OES as the texture is not created
// with D3D11_BIND_RENDER_TARGET bind flag and so it cannot be bound to the
// framebuffer. To prevent Skia trying to bind it for read pixels, we need
// it to be GL_TEXTURE_EXTERNAL_OES.
std::unique_ptr<gpu::SharedImageBacking> backing =
gpu::D3DImageBacking::Create(
mailbox, metadata.format, metadata.size, metadata.color_space,
metadata.surface_origin, metadata.alpha_type, metadata.usage,
si_info.debug_label, texture, std::move(dxgi_shared_handle_state),
caps, GL_TEXTURE_EXTERNAL_OES, array_slice,
/*use_update_subresource1=*/false,
/*want_dcomp_texture=*/false, is_thread_safe);
if (!backing) {
return nullptr;
}
// Need to clear the backing since the D3D11 Video Decoder will initialize
// the textures.
backing->SetCleared();
DCHECK(shared_image_stub_->channel()
->gpu_channel_manager()
->shared_image_manager());
shared_image_stub_->factory()->RegisterBacking(std::move(backing));
return base::WrapRefCounted<ClientSharedImage>(
new ClientSharedImage(mailbox, si_info, GenVerifiedSyncToken(), holder_,
GL_TEXTURE_EXTERNAL_OES));
}
#endif
SharedImageFactory*
GpuChannelSharedImageInterface::GetSharedImageFactoryOnGpuThread() {
DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
if (!shared_image_stub_) {
return nullptr;
}
return shared_image_stub_->factory();
}
bool GpuChannelSharedImageInterface::MakeContextCurrentOnGpuThread(
bool needs_gl) {
DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
if (!shared_image_stub_) {
return false;
}
return shared_image_stub_->MakeContextCurrent(needs_gl);
}
void GpuChannelSharedImageInterface::MarkContextLostOnGpuThread() {
DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
shared_image_stub_->shared_context_state()->MarkContextLost();
}
void GpuChannelSharedImageInterface::ScheduleGpuTask(
base::OnceClosure task,
std::vector<SyncToken> sync_token_fences,
const SyncToken& release) {
scheduler_->ScheduleTask(gpu::Scheduler::Task(
sequence_, std::move(task), std::move(sync_token_fences), release));
}
} // namespace gpu