Skip to content

Commit

Permalink
Fix no gl context issue in D3DImageBacking::Create*()
Browse files Browse the repository at this point in the history
With Graphite, D3DImageBacking can be created and destroyed
without any GL context current. It will cause no gl context issue,
because we create GL texture during creating and cache textures
in the backing. Fix the problem by deferring gl texture creation
and just cache weak pointers to the gl textures. So the GL textures
will be destroyed if they are not used by any GL representations.

Bug: 1499650,1499739
Change-Id: Id22c556ba24da5848c87cf2ce528aa38d061c057
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5006653
Reviewed-by: Saifuddin Hitawala <hitawala@chromium.org>
Auto-Submit: Peng Huang <penghuang@chromium.org>
Commit-Queue: Peng Huang <penghuang@chromium.org>
Reviewed-by: Frank Liberato <liberato@chromium.org>
Reviewed-by: Sunny Sachanandani <sunnyps@chromium.org>
Commit-Queue: Sunny Sachanandani <sunnyps@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1222368}
  • Loading branch information
phuang authored and Chromium LUCI CQ committed Nov 9, 2023
1 parent 5044948 commit a2826d3
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 129 deletions.
205 changes: 86 additions & 119 deletions gpu/command_buffer/service/shared_image/d3d_image_backing.cc
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,6 @@ bool BindEGLImageToTexture(GLenum texture_target, void* egl_image) {
return true;
}

bool CanTextureBeUsedByANGLE(
const Microsoft::WRL::ComPtr<ID3D11Texture2D>& d3d11_texture) {
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device;
d3d11_texture->GetDevice(&d3d11_device);
return gl::QueryD3D11DeviceObjectFromANGLE() == d3d11_device;
}

} // namespace

D3DImageBacking::GLTextureHolder::GLTextureHolder(
Expand All @@ -154,6 +147,26 @@ D3DImageBacking::GLTextureHolder::GLTextureHolder(
: texture_passthrough_(std::move(texture_passthrough)),
egl_image_(std::move(egl_image)) {}

bool D3DImageBacking::GLTextureHolder::BindEGLImageToTexture() {
if (!needs_rebind_) {
return true;
}

gl::GLApi* const api = gl::g_current_gl_context;
gl::ScopedRestoreTexture scoped_restore(api, GL_TEXTURE_2D);

DCHECK_EQ(texture_passthrough_->target(),
static_cast<unsigned>(GL_TEXTURE_2D));
api->glBindTextureFn(GL_TEXTURE_2D, texture_passthrough_->service_id());

if (!::gpu::BindEGLImageToTexture(GL_TEXTURE_2D, egl_image_.get())) {
return false;
}

needs_rebind_ = false;
return true;
}

void D3DImageBacking::GLTextureHolder::MarkContextLost() {
if (texture_passthrough_) {
texture_passthrough_->MarkContextLost();
Expand Down Expand Up @@ -251,18 +264,11 @@ std::unique_ptr<D3DImageBacking> D3DImageBacking::CreateFromSwapChainBuffer(
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain,
bool is_back_buffer) {
DCHECK(format.is_single_plane());
auto gl_texture_holder =
CreateGLTexture(format, size, color_space, d3d11_texture, GL_TEXTURE_2D,
/*array_slice=*/0u, /*plane_index=*/0u, swap_chain);
if (!gl_texture_holder) {
LOG(ERROR) << "Failed to create GL texture.";
return nullptr;
}
return base::WrapUnique(new D3DImageBacking(
mailbox, format, size, color_space, surface_origin, alpha_type, usage,
std::move(d3d11_texture), {std::move(gl_texture_holder)},
/*dxgi_shared_handle_state=*/nullptr, GL_TEXTURE_2D, /*array_slice=*/0u,
/*plane_index=*/0u, std::move(swap_chain), is_back_buffer));
std::move(d3d11_texture), /*dxgi_shared_handle_state=*/nullptr,
GL_TEXTURE_2D, /*array_slice=*/0u, /*plane_index=*/0u,
std::move(swap_chain), is_back_buffer));
}

// static
Expand All @@ -282,38 +288,10 @@ std::unique_ptr<D3DImageBacking> D3DImageBacking::Create(
const bool has_webgpu_usage = !!(usage & SHARED_IMAGE_USAGE_WEBGPU);
// DXGI shared handle is required for WebGPU/Dawn/D3D12 interop.
CHECK(!has_webgpu_usage || dxgi_shared_handle_state);
// SHARED_IMAGE_USAGE_VIDEO_DECODE means that this is for D3D11VideoDecoder.
const bool has_video_decode_usage =
!!(usage & SHARED_IMAGE_USAGE_VIDEO_DECODE);
std::vector<scoped_refptr<GLTextureHolder>> gl_texture_holders;
// Do not cache GL textures in the backing if it could be owned by Dawn, or
// the video decoder, since there could be no GL context to MakeCurrent in the
// destructor. And the d3d11_texture is created with d3d11 device in ANGLE.
if (!dxgi_shared_handle_state && !has_video_decode_usage &&
CanTextureBeUsedByANGLE(d3d11_texture)) {
for (int plane = 0; plane < format.NumberOfPlanes(); plane++) {
gfx::Size plane_size = format.GetPlaneSize(plane, size);
// For legacy multiplanar formats, format() is plane format (eg. RED, RG)
// which is_single_plane(), but the real plane is in plane_index so we
// pass that.
unsigned plane_id = format.is_single_plane() ? plane_index : plane;
// Creating the GL texture doesn't require exclusive access to the
// underlying D3D11 texture.
scoped_refptr<GLTextureHolder> gl_texture_holder =
CreateGLTexture(format, plane_size, color_space, d3d11_texture,
texture_target, array_slice, plane_id);
if (!gl_texture_holder) {
LOG(ERROR) << "Failed to create GL texture.";
return nullptr;
}
gl_texture_holders.push_back(std::move(gl_texture_holder));
}
}
auto backing = base::WrapUnique(new D3DImageBacking(
mailbox, format, size, color_space, surface_origin, alpha_type, usage,
std::move(d3d11_texture), std::move(gl_texture_holders),
std::move(dxgi_shared_handle_state), texture_target, array_slice,
plane_index));
std::move(d3d11_texture), std::move(dxgi_shared_handle_state),
texture_target, array_slice, plane_index));
return backing;
}

Expand Down Expand Up @@ -361,10 +339,10 @@ D3DImageBacking::CreateFromVideoTexture(
shared_images[plane_index] = base::WrapUnique(new D3DImageBacking(
mailbox, plane_format, plane_size, kInvalidColorSpace,
kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, usage, d3d11_texture,
/*gl_texture_holders=*/{}, dxgi_shared_handle_state, kTextureTarget,
array_slice, plane_index));
dxgi_shared_handle_state, kTextureTarget, array_slice, plane_index));
if (!shared_images[plane_index])
return {};

shared_images[plane_index]->SetCleared();
}

Expand All @@ -380,7 +358,6 @@ D3DImageBacking::D3DImageBacking(
SkAlphaType alpha_type,
uint32_t usage,
Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11_texture,
std::vector<scoped_refptr<GLTextureHolder>> gl_texture_holders,
scoped_refptr<DXGISharedHandleState> dxgi_shared_handle_state,
GLenum texture_target,
size_t array_slice,
Expand All @@ -397,7 +374,6 @@ D3DImageBacking::D3DImageBacking(
format.EstimatedSizeInBytes(size),
/*is_thread_safe=*/false),
d3d11_texture_(std::move(d3d11_texture)),
gl_texture_holders_(std::move(gl_texture_holders)),
dxgi_shared_handle_state_(std::move(dxgi_shared_handle_state)),
texture_target_(texture_target),
array_slice_(array_slice),
Expand All @@ -409,18 +385,14 @@ D3DImageBacking::D3DImageBacking(
d3d11_texture_->GetDevice(&texture_d3d11_device_);
d3d11_texture_->GetDesc(&d3d11_texture_desc_);
}

const bool has_video_decode_usage =
!!(usage & SHARED_IMAGE_USAGE_VIDEO_DECODE);
CHECK(has_video_decode_usage || dxgi_shared_handle_state_ ||
angle_d3d11_device_ != texture_d3d11_device_ ||
!gl_texture_holders_.empty());
}

D3DImageBacking::~D3DImageBacking() {
if (!have_context()) {
for (auto& texture_holder : gl_texture_holders_) {
texture_holder->MarkContextLost();
if (texture_holder) {
texture_holder->MarkContextLost();
}
}
}
}
Expand Down Expand Up @@ -599,13 +571,13 @@ bool D3DImageBacking::ReadbackToMemory(const std::vector<SkPixmap>& pixmaps) {
return true;
}

#if BUILDFLAG(USE_DAWN)
std::unique_ptr<DawnImageRepresentation> D3DImageBacking::ProduceDawn(
SharedImageManager* manager,
MemoryTypeTracker* tracker,
const wgpu::Device& device,
wgpu::BackendType backend_type,
std::vector<wgpu::TextureFormat> view_formats) {
#if BUILDFLAG(USE_DAWN)
#if BUILDFLAG(DAWN_ENABLE_BACKEND_OPENGLES)
if (backend_type == wgpu::BackendType::OpenGLES) {
std::unique_ptr<GLTextureImageRepresentationBase> gl_representation =
Expand Down Expand Up @@ -656,10 +628,8 @@ std::unique_ptr<DawnImageRepresentation> D3DImageBacking::ProduceDawn(

return std::make_unique<DawnD3DImageRepresentation>(manager, this, tracker,
device, backend_type);
#else
return nullptr;
#endif // BUILDFLAG(USE_DAWN)
}
#endif // BUILDFLAG(USE_DAWN)

void D3DImageBacking::UpdateExternalFence(
scoped_refptr<gfx::D3DSharedFence> external_fence) {
Expand Down Expand Up @@ -954,8 +924,7 @@ void D3DImageBacking::EndAccessCommon(

void* D3DImageBacking::GetEGLImage() const {
DCHECK(format().is_single_plane());
return !gl_texture_holders_.empty() ? gl_texture_holders_[0]->egl_image()
: nullptr;
return gl_texture_holders_[0] ? gl_texture_holders_[0]->egl_image() : nullptr;
}

bool D3DImageBacking::PresentSwapChain() {
Expand All @@ -965,80 +934,80 @@ bool D3DImageBacking::PresentSwapChain() {
return false;
}

DXGI_PRESENT_PARAMETERS params = {};
params.DirtyRectsCount = 0;
params.pDirtyRects = nullptr;

UINT flags = DXGI_PRESENT_ALLOW_TEARING;
constexpr UINT kFlags = DXGI_PRESENT_ALLOW_TEARING;
constexpr DXGI_PRESENT_PARAMETERS kParams = {};

HRESULT hr = swap_chain_->Present1(/*interval=*/0, flags, &params);
HRESULT hr = swap_chain_->Present1(/*interval=*/0, kFlags, &kParams);
if (FAILED(hr)) {
LOG(ERROR) << "Present1 failed with error " << std::hex << hr;
return false;
}

gl::GLApi* const api = gl::g_current_gl_context;
gl::ScopedRestoreTexture scoped_restore(api, GL_TEXTURE_2D);

DCHECK(format().is_single_plane());
DCHECK_EQ(gl_texture_holders_[0]->texture_passthrough()->target(),
static_cast<unsigned>(GL_TEXTURE_2D));
api->glBindTextureFn(
GL_TEXTURE_2D,
gl_texture_holders_[0]->texture_passthrough()->service_id());

// we're rebinding to ensure that underlying D3D11 resource views are
// recreated in ANGLE.
void* egl_image = GetEGLImage();
if (!BindEGLImageToTexture(GL_TEXTURE_2D, egl_image)) {
return false;
if (gl_texture_holders_[0]) {
gl_texture_holders_[0]->set_needs_rebind(true);
}

TRACE_EVENT0("gpu", "D3DImageBacking::PresentSwapChain::Flush");
// Flush device context otherwise present could be deferred.
Microsoft::WRL::ComPtr<ID3D11DeviceContext> d3d11_device_context;
texture_d3d11_device_->GetImmediateContext(&d3d11_device_context);
d3d11_device_context->Flush();

// Flush device context through ANGLE otherwise present could be deferred.
api->glFlushFn();
return true;
}

std::unique_ptr<GLTexturePassthroughImageRepresentation>
D3DImageBacking::ProduceGLTexturePassthrough(SharedImageManager* manager,
MemoryTypeTracker* tracker) {
TRACE_EVENT0("gpu", "D3DImageBacking::ProduceGLTexturePassthrough");
// Lazily create a GL texture if it wasn't provided on initialization.
auto gl_texture_holders = gl_texture_holders_;
if (gl_texture_holders.empty()) {
// If DXGI shared handle is present, the |d3d11_texture_| might belong to a
// different device with Graphite so retrieve the ANGLE specific D3D11
// texture from the |dxgi_shared_handle_state_|.
const bool is_angle_texture = texture_d3d11_device_ == angle_d3d11_device_;
CHECK(is_angle_texture || dxgi_shared_handle_state_);
auto d3d11_texture =
is_angle_texture ? d3d11_texture_
: dxgi_shared_handle_state_->GetOrCreateD3D11Texture(
angle_d3d11_device_);
if (!d3d11_texture) {
LOG(ERROR) << "Failed to open DXGI shared handle";
return nullptr;

const auto number_of_planes = static_cast<size_t>(format().NumberOfPlanes());
std::vector<scoped_refptr<GLTextureHolder>> gl_texture_holders(
number_of_planes);
DCHECK_GE(gl_texture_holders_.size(), number_of_planes);

// If DXGI shared handle is present, the |d3d11_texture_| might belong to a
// different device with Graphite so retrieve the ANGLE specific D3D11
// texture from the |dxgi_shared_handle_state_|.
const bool is_angle_texture = texture_d3d11_device_ == angle_d3d11_device_;
CHECK(is_angle_texture || dxgi_shared_handle_state_);
auto d3d11_texture = is_angle_texture
? d3d11_texture_
: dxgi_shared_handle_state_->GetOrCreateD3D11Texture(
angle_d3d11_device_);
if (!d3d11_texture) {
LOG(ERROR) << "Failed to open DXGI shared handle";
return nullptr;
}

for (int plane = 0; plane < format().NumberOfPlanes(); ++plane) {
auto& holder = gl_texture_holders[plane];
if (gl_texture_holders_[plane]) {
holder = gl_texture_holders_[plane].get();
continue;
}
for (int plane = 0; plane < format().NumberOfPlanes(); plane++) {
gfx::Size plane_size = format().GetPlaneSize(plane, size());
// For legacy multiplanar formats, format() is plane format (eg. RED, RG)
// which is_single_plane(), but the real plane is in plane_index_ so we
// pass that.
unsigned plane_id = format().is_single_plane() ? plane_index_ : plane;
// Creating the GL texture doesn't require exclusive access to the
// underlying D3D11 texture.
scoped_refptr<GLTextureHolder> gl_texture_holder =
CreateGLTexture(format(), plane_size, color_space(), d3d11_texture,
texture_target_, array_slice_, plane_id, swap_chain_);
if (!gl_texture_holder) {
LOG(ERROR) << "Failed to create GL texture.";
return nullptr;
}
gl_texture_holders.push_back(std::move(gl_texture_holder));

gfx::Size plane_size = format().GetPlaneSize(plane, size());
// For legacy multiplanar formats, format() is plane format (eg. RED, RG)
// which is_single_plane(), but the real plane is in plane_index_ so we
// pass that.
unsigned plane_id = format().is_single_plane() ? plane_index_ : plane;
// Creating the GL texture doesn't require exclusive access to the
// underlying D3D11 texture.
holder =
CreateGLTexture(format(), plane_size, color_space(), d3d11_texture,
texture_target_, array_slice_, plane_id, swap_chain_);
if (!holder) {
LOG(ERROR) << "Failed to create GL texture for plane: " << plane;
return nullptr;
}
// Cache the gl textures using weak pointers.
gl_texture_holders_[plane] = holder->GetWeakPtr();
}

return std::make_unique<GLTexturePassthroughD3DImageRepresentation>(
manager, this, tracker, angle_d3d11_device_,
std::move(gl_texture_holders));
Expand All @@ -1058,12 +1027,12 @@ D3DImageBacking::ProduceSkiaGanesh(
this, tracker);
}

#if BUILDFLAG(SKIA_USE_DAWN)
std::unique_ptr<SkiaGraphiteImageRepresentation>
D3DImageBacking::ProduceSkiaGraphite(
SharedImageManager* manager,
MemoryTypeTracker* tracker,
scoped_refptr<SharedContextState> context_state) {
#if BUILDFLAG(SKIA_USE_DAWN)
auto device = context_state->dawn_context_provider()->GetDevice();
wgpu::AdapterProperties adapter_properties;
device.GetAdapter().GetProperties(&adapter_properties);
Expand All @@ -1074,10 +1043,8 @@ D3DImageBacking::ProduceSkiaGraphite(
std::move(dawn_representation), context_state,
context_state->gpu_main_graphite_recorder(), manager, this, tracker,
is_yuv_plane);
#else
NOTREACHED_NORETURN();
#endif
}
#endif // BUILDFLAG(SKIA_USE_DAWN)

std::unique_ptr<OverlayImageRepresentation> D3DImageBacking::ProduceOverlay(
SharedImageManager* manager,
Expand Down
Loading

0 comments on commit a2826d3

Please sign in to comment.