blob: 893f4d19b6f02ef2e9eb5d3b98bcf50dde06f622 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gpu/command_buffer/service/shared_image_backing_d3d.h"
#include "base/trace_event/memory_dump_manager.h"
#include "components/viz/common/resources/resource_format_utils.h"
#include "components/viz/common/resources/resource_sizes.h"
#include "gpu/command_buffer/common/shared_image_trace_utils.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/command_buffer/service/shared_image_representation_d3d.h"
#include "gpu/command_buffer/service/shared_image_representation_skia_gl.h"
#include "ui/gl/trace_util.h"
namespace gpu {
namespace {
class ScopedRestoreTexture2D {
public:
explicit ScopedRestoreTexture2D(gl::GLApi* api) : api_(api) {
GLint binding = 0;
api->glGetIntegervFn(GL_TEXTURE_BINDING_2D, &binding);
prev_binding_ = binding;
}
~ScopedRestoreTexture2D() {
api_->glBindTextureFn(GL_TEXTURE_2D, prev_binding_);
}
private:
gl::GLApi* const api_;
GLuint prev_binding_ = 0;
DISALLOW_COPY_AND_ASSIGN(ScopedRestoreTexture2D);
};
} // anonymous namespace
SharedImageBackingD3D::SharedImageBackingD3D(
const Mailbox& mailbox,
viz::ResourceFormat format,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
GrSurfaceOrigin surface_origin,
SkAlphaType alpha_type,
uint32_t usage,
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain,
scoped_refptr<gles2::TexturePassthrough> texture,
scoped_refptr<gl::GLImage> image,
size_t buffer_index,
Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11_texture,
base::win::ScopedHandle shared_handle,
Microsoft::WRL::ComPtr<IDXGIKeyedMutex> dxgi_keyed_mutex)
: ClearTrackingSharedImageBacking(mailbox,
format,
size,
color_space,
surface_origin,
alpha_type,
usage,
texture->estimated_size(),
false /* is_thread_safe */),
swap_chain_(std::move(swap_chain)),
texture_(std::move(texture)),
image_(std::move(image)),
buffer_index_(buffer_index),
d3d11_texture_(std::move(d3d11_texture)),
shared_handle_(std::move(shared_handle)),
dxgi_keyed_mutex_(std::move(dxgi_keyed_mutex)) {
DCHECK(texture_);
}
SharedImageBackingD3D::~SharedImageBackingD3D() {
if (!have_context())
texture_->MarkContextLost();
texture_ = nullptr;
swap_chain_ = nullptr;
d3d11_texture_.Reset();
dxgi_keyed_mutex_.Reset();
keyed_mutex_acquire_key_ = 0;
keyed_mutex_acquired_ = false;
shared_handle_.Close();
#if BUILDFLAG(USE_DAWN)
external_image_ = nullptr;
#endif // BUILDFLAG(USE_DAWN)
}
void SharedImageBackingD3D::Update(std::unique_ptr<gfx::GpuFence> in_fence) {
DLOG(ERROR) << "SharedImageBackingD3D::Update : Trying to update "
"Shared Images associated with swap chain.";
}
bool SharedImageBackingD3D::ProduceLegacyMailbox(
MailboxManager* mailbox_manager) {
mailbox_manager->ProduceTexture(mailbox(), texture_.get());
return true;
}
uint32_t SharedImageBackingD3D::GetAllowedDawnUsages() const {
// TODO(crbug.com/2709243): Figure out other SI flags, if any.
DCHECK(usage() & gpu::SHARED_IMAGE_USAGE_WEBGPU);
return static_cast<uint32_t>(
WGPUTextureUsage_CopySrc | WGPUTextureUsage_CopyDst |
WGPUTextureUsage_Sampled | WGPUTextureUsage_OutputAttachment);
}
std::unique_ptr<SharedImageRepresentationDawn>
SharedImageBackingD3D::ProduceDawn(SharedImageManager* manager,
MemoryTypeTracker* tracker,
WGPUDevice device) {
#if BUILDFLAG(USE_DAWN)
// Persistently open the shared handle by caching it on this backing.
if (!external_image_) {
DCHECK(shared_handle_.IsValid());
const viz::ResourceFormat viz_resource_format = format();
const WGPUTextureFormat wgpu_format =
viz::ToWGPUFormat(viz_resource_format);
if (wgpu_format == WGPUTextureFormat_Undefined) {
DLOG(ERROR) << "Unsupported viz format found: " << viz_resource_format;
return nullptr;
}
WGPUTextureDescriptor texture_descriptor = {};
texture_descriptor.nextInChain = nullptr;
texture_descriptor.format = wgpu_format;
texture_descriptor.usage = GetAllowedDawnUsages();
texture_descriptor.dimension = WGPUTextureDimension_2D;
texture_descriptor.size = {size().width(), size().height(), 1};
texture_descriptor.mipLevelCount = 1;
texture_descriptor.sampleCount = 1;
dawn_native::d3d12::ExternalImageDescriptorDXGISharedHandle
externalImageDesc;
externalImageDesc.cTextureDescriptor = &texture_descriptor;
externalImageDesc.sharedHandle = shared_handle_.Get();
external_image_ = dawn_native::d3d12::ExternalImageDXGI::Create(
device, &externalImageDesc);
if (!external_image_) {
DLOG(ERROR) << "Failed to create external image";
return nullptr;
}
}
return std::make_unique<SharedImageRepresentationDawnD3D>(
manager, this, tracker, device, external_image_.get());
#else
return nullptr;
#endif // BUILDFLAG(USE_DAWN)
}
void SharedImageBackingD3D::OnMemoryDump(
const std::string& dump_name,
base::trace_event::MemoryAllocatorDump* dump,
base::trace_event::ProcessMemoryDump* pmd,
uint64_t client_tracing_id) {
// Add a |service_guid| which expresses shared ownership between the
// various GPU dumps.
auto client_guid = GetSharedImageGUIDForTracing(mailbox());
base::trace_event::MemoryAllocatorDumpGuid service_guid =
gl::GetGLTextureServiceGUIDForTracing(texture_->service_id());
pmd->CreateSharedGlobalAllocatorDump(service_guid);
int importance = 2; // This client always owns the ref.
pmd->AddOwnershipEdge(client_guid, service_guid, importance);
// Swap chain textures only have one level backed by an image.
image_->OnMemoryDump(pmd, client_tracing_id, dump_name);
}
bool SharedImageBackingD3D::BeginAccessD3D12(uint64_t* acquire_key) {
if (keyed_mutex_acquired_) {
DLOG(ERROR) << "Recursive BeginAccess not supported";
return false;
}
*acquire_key = keyed_mutex_acquire_key_;
keyed_mutex_acquire_key_++;
keyed_mutex_acquired_ = true;
return true;
}
void SharedImageBackingD3D::EndAccessD3D12() {
keyed_mutex_acquired_ = false;
}
bool SharedImageBackingD3D::BeginAccessD3D11() {
if (dxgi_keyed_mutex_) {
if (keyed_mutex_acquired_) {
DLOG(ERROR) << "Recursive BeginAccess not supported";
return false;
}
const HRESULT hr =
dxgi_keyed_mutex_->AcquireSync(keyed_mutex_acquire_key_, INFINITE);
if (FAILED(hr)) {
DLOG(ERROR) << "Unable to acquire the keyed mutex " << std::hex << hr;
return false;
}
keyed_mutex_acquire_key_++;
keyed_mutex_acquired_ = true;
}
return true;
}
void SharedImageBackingD3D::EndAccessD3D11() {
if (dxgi_keyed_mutex_) {
const HRESULT hr = dxgi_keyed_mutex_->ReleaseSync(keyed_mutex_acquire_key_);
if (FAILED(hr)) {
DLOG(ERROR) << "Unable to release the keyed mutex " << std::hex << hr;
return;
}
keyed_mutex_acquired_ = false;
}
}
HANDLE SharedImageBackingD3D::GetSharedHandle() const {
return shared_handle_.Get();
}
gl::GLImage* SharedImageBackingD3D::GetGLImage() const {
return image_.get();
}
bool SharedImageBackingD3D::PresentSwapChain() {
TRACE_EVENT0("gpu", "SharedImageBackingD3D::PresentSwapChain");
if (buffer_index_ != 0) {
DLOG(ERROR) << "Swap chain backing does not correspond to back buffer";
return false;
}
DXGI_PRESENT_PARAMETERS params = {};
params.DirtyRectsCount = 0;
params.pDirtyRects = nullptr;
UINT flags = DXGI_PRESENT_ALLOW_TEARING;
HRESULT hr = swap_chain_->Present1(0 /* interval */, flags, &params);
if (FAILED(hr)) {
DLOG(ERROR) << "Present1 failed with error " << std::hex << hr;
return false;
}
gl::GLApi* const api = gl::g_current_gl_context;
ScopedRestoreTexture2D scoped_restore(api);
api->glBindTextureFn(GL_TEXTURE_2D, texture_->service_id());
if (!image_->BindTexImage(GL_TEXTURE_2D)) {
DLOG(ERROR) << "GLImage::BindTexImage failed";
return false;
}
TRACE_EVENT0("gpu", "SharedImageBackingD3D::PresentSwapChain::Flush");
// Flush device context through ANGLE otherwise present could be deferred.
api->glFlushFn();
return true;
}
std::unique_ptr<SharedImageRepresentationGLTexturePassthrough>
SharedImageBackingD3D::ProduceGLTexturePassthrough(SharedImageManager* manager,
MemoryTypeTracker* tracker) {
TRACE_EVENT0("gpu", "SharedImageBackingD3D::ProduceGLTexturePassthrough");
return std::make_unique<SharedImageRepresentationGLTexturePassthroughD3D>(
manager, this, tracker, texture_);
}
std::unique_ptr<SharedImageRepresentationSkia>
SharedImageBackingD3D::ProduceSkia(
SharedImageManager* manager,
MemoryTypeTracker* tracker,
scoped_refptr<SharedContextState> context_state) {
return SharedImageRepresentationSkiaGL::Create(
ProduceGLTexturePassthrough(manager, tracker), std::move(context_state),
manager, this, tracker);
}
std::unique_ptr<SharedImageRepresentationOverlay>
SharedImageBackingD3D::ProduceOverlay(SharedImageManager* manager,
MemoryTypeTracker* tracker) {
TRACE_EVENT0("gpu", "SharedImageBackingD3D::ProduceOverlay");
return std::make_unique<SharedImageRepresentationOverlayD3D>(manager, this,
tracker);
}
} // namespace gpu