| // 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/memory/ptr_util.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 { |
| |
| bool SupportsVideoFormat(DXGI_FORMAT dxgi_format) { |
| switch (dxgi_format) { |
| case DXGI_FORMAT_NV12: |
| case DXGI_FORMAT_P010: |
| case DXGI_FORMAT_B8G8R8A8_UNORM: |
| case DXGI_FORMAT_R10G10B10A2_UNORM: |
| case DXGI_FORMAT_R16G16B16A16_FLOAT: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| size_t NumPlanes(DXGI_FORMAT dxgi_format) { |
| switch (dxgi_format) { |
| case DXGI_FORMAT_NV12: |
| case DXGI_FORMAT_P010: |
| return 2; |
| case DXGI_FORMAT_B8G8R8A8_UNORM: |
| case DXGI_FORMAT_R10G10B10A2_UNORM: |
| case DXGI_FORMAT_R16G16B16A16_FLOAT: |
| return 1; |
| default: |
| NOTREACHED(); |
| return 0; |
| } |
| } |
| |
| viz::ResourceFormat PlaneFormat(DXGI_FORMAT dxgi_format, size_t plane) { |
| DCHECK_LT(plane, NumPlanes(dxgi_format)); |
| switch (dxgi_format) { |
| // TODO(crbug.com/1011555): P010 formats are not fully supported by Skia. |
| // Treat them the same as NV12 for the time being. |
| case DXGI_FORMAT_NV12: |
| case DXGI_FORMAT_P010: |
| // Y plane is accessed as R8 and UV plane is accessed as RG88 in D3D. |
| return plane == 0 ? viz::RED_8 : viz::RG_88; |
| case DXGI_FORMAT_B8G8R8A8_UNORM: |
| return viz::BGRA_8888; |
| case DXGI_FORMAT_R10G10B10A2_UNORM: |
| return viz::RGBA_1010102; |
| case DXGI_FORMAT_R16G16B16A16_FLOAT: |
| return viz::RGBA_F16; |
| default: |
| NOTREACHED(); |
| return viz::BGRA_8888; |
| } |
| } |
| |
| gfx::Size PlaneSize(DXGI_FORMAT dxgi_format, |
| const gfx::Size& size, |
| size_t plane) { |
| DCHECK_LT(plane, NumPlanes(dxgi_format)); |
| switch (dxgi_format) { |
| case DXGI_FORMAT_NV12: |
| case DXGI_FORMAT_P010: |
| // Y plane is full size and UV plane is accessed as half size in D3D. |
| return plane == 0 ? size : gfx::Size(size.width() / 2, size.height() / 2); |
| case DXGI_FORMAT_B8G8R8A8_UNORM: |
| case DXGI_FORMAT_R10G10B10A2_UNORM: |
| case DXGI_FORMAT_R16G16B16A16_FLOAT: |
| return size; |
| default: |
| NOTREACHED(); |
| return gfx::Size(); |
| } |
| } |
| |
| class ScopedRestoreTexture { |
| public: |
| ScopedRestoreTexture(gl::GLApi* api, GLenum target) |
| : api_(api), target_(target) { |
| DCHECK(target == GL_TEXTURE_2D || target == GL_TEXTURE_EXTERNAL_OES); |
| GLint binding = 0; |
| api->glGetIntegervFn(target == GL_TEXTURE_2D |
| ? GL_TEXTURE_BINDING_2D |
| : GL_TEXTURE_BINDING_EXTERNAL_OES, |
| &binding); |
| prev_binding_ = binding; |
| } |
| |
| ~ScopedRestoreTexture() { api_->glBindTextureFn(target_, prev_binding_); } |
| |
| private: |
| gl::GLApi* const api_; |
| const GLenum target_; |
| GLuint prev_binding_ = 0; |
| DISALLOW_COPY_AND_ASSIGN(ScopedRestoreTexture); |
| }; |
| |
| scoped_refptr<gles2::TexturePassthrough> CreateGLTexture( |
| viz::ResourceFormat format, |
| const gfx::Size& size, |
| const gfx::ColorSpace& color_space, |
| Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11_texture, |
| Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain = nullptr, |
| GLenum texture_target = GL_TEXTURE_2D, |
| unsigned array_slice = 0u, |
| unsigned plane_index = 0u) { |
| gl::GLApi* const api = gl::g_current_gl_context; |
| ScopedRestoreTexture scoped_restore(api, texture_target); |
| |
| GLuint service_id = 0; |
| api->glGenTexturesFn(1, &service_id); |
| api->glBindTextureFn(texture_target, service_id); |
| |
| // The GL internal format can differ from the underlying swap chain or texture |
| // format e.g. RGBA or RGB instead of BGRA or RED/RG for NV12 texture planes. |
| // See EGL_ANGLE_d3d_texture_client_buffer spec for format restrictions. |
| const auto internal_format = viz::GLInternalFormat(format); |
| const auto data_type = viz::GLDataType(format); |
| auto image = base::MakeRefCounted<gl::GLImageD3D>( |
| size, internal_format, data_type, color_space, d3d11_texture, array_slice, |
| plane_index, swap_chain); |
| DCHECK_EQ(image->GetDataFormat(), viz::GLDataFormat(format)); |
| if (!image->Initialize()) { |
| DLOG(ERROR) << "GLImageD3D::Initialize failed"; |
| api->glDeleteTexturesFn(1, &service_id); |
| return nullptr; |
| } |
| if (!image->BindTexImage(texture_target)) { |
| DLOG(ERROR) << "GLImageD3D::BindTexImage failed"; |
| api->glDeleteTexturesFn(1, &service_id); |
| return nullptr; |
| } |
| |
| auto texture = base::MakeRefCounted<gles2::TexturePassthrough>( |
| service_id, texture_target); |
| texture->SetLevelImage(texture_target, 0, image.get()); |
| GLint texture_memory_size = 0; |
| api->glGetTexParameterivFn(texture_target, GL_MEMORY_SIZE_ANGLE, |
| &texture_memory_size); |
| texture->SetEstimatedSize(texture_memory_size); |
| |
| return texture; |
| } |
| |
| } // anonymous namespace |
| |
| SharedImageBackingD3D::SharedState::SharedState( |
| base::win::ScopedHandle shared_handle, |
| Microsoft::WRL::ComPtr<IDXGIKeyedMutex> dxgi_keyed_mutex) |
| : shared_handle_(std::move(shared_handle)), |
| dxgi_keyed_mutex_(std::move(dxgi_keyed_mutex)) {} |
| |
| SharedImageBackingD3D::SharedState::~SharedState() { |
| DCHECK(!acquired_for_d3d12_); |
| DCHECK_EQ(acquired_for_d3d11_count_, 0); |
| shared_handle_.Close(); |
| } |
| |
| bool SharedImageBackingD3D::SharedState::BeginAccessD3D12( |
| uint64_t* acquire_key) { |
| if (!dxgi_keyed_mutex_) { |
| DLOG(ERROR) << "D3D12 access not supported without keyed mutex"; |
| return false; |
| } |
| if (acquired_for_d3d12_ || acquired_for_d3d11_count_ > 0) { |
| DLOG(ERROR) << "Recursive BeginAccess not supported"; |
| return false; |
| } |
| *acquire_key = acquire_key_; |
| acquire_key_++; |
| acquired_for_d3d12_ = true; |
| return true; |
| } |
| |
| void SharedImageBackingD3D::SharedState::EndAccessD3D12() { |
| acquired_for_d3d12_ = false; |
| } |
| |
| bool SharedImageBackingD3D::SharedState::BeginAccessD3D11() { |
| // Nop for shared images that are created without keyed mutex (D3D11 only). |
| if (!dxgi_keyed_mutex_) |
| return true; |
| |
| if (acquired_for_d3d12_) { |
| DLOG(ERROR) << "Recursive BeginAccess not supported"; |
| return false; |
| } |
| if (acquired_for_d3d11_count_ > 0) { |
| acquired_for_d3d11_count_++; |
| return true; |
| } |
| const HRESULT hr = dxgi_keyed_mutex_->AcquireSync(acquire_key_, INFINITE); |
| if (FAILED(hr)) { |
| DLOG(ERROR) << "Unable to acquire the keyed mutex " << std::hex << hr; |
| return false; |
| } |
| acquire_key_++; |
| acquired_for_d3d11_count_++; |
| return true; |
| } |
| |
| void SharedImageBackingD3D::SharedState::EndAccessD3D11() { |
| // Nop for shared images that are created without keyed mutex (D3D11 only). |
| if (!dxgi_keyed_mutex_) |
| return; |
| |
| DCHECK_GT(acquired_for_d3d11_count_, 0); |
| acquired_for_d3d11_count_--; |
| if (acquired_for_d3d11_count_ == 0) { |
| const HRESULT hr = dxgi_keyed_mutex_->ReleaseSync(acquire_key_); |
| if (FAILED(hr)) |
| DLOG(ERROR) << "Unable to release the keyed mutex " << std::hex << hr; |
| } |
| } |
| |
| HANDLE SharedImageBackingD3D::SharedState::GetSharedHandle() const { |
| return shared_handle_.Get(); |
| } |
| |
| // static |
| std::unique_ptr<SharedImageBackingD3D> |
| SharedImageBackingD3D::CreateFromSwapChainBuffer( |
| 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<ID3D11Texture2D> d3d11_texture, |
| Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain, |
| size_t buffer_index) { |
| auto gl_texture = |
| CreateGLTexture(format, size, color_space, d3d11_texture, swap_chain); |
| if (!gl_texture) { |
| DLOG(ERROR) << "Failed to create GL texture"; |
| return nullptr; |
| } |
| return base::WrapUnique(new SharedImageBackingD3D( |
| mailbox, format, size, color_space, surface_origin, alpha_type, usage, |
| std::move(d3d11_texture), std::move(gl_texture), std::move(swap_chain), |
| buffer_index)); |
| } |
| |
| // static |
| std::unique_ptr<SharedImageBackingD3D> |
| SharedImageBackingD3D::CreateFromSharedHandle( |
| 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<ID3D11Texture2D> d3d11_texture, |
| base::win::ScopedHandle shared_handle) { |
| DCHECK(shared_handle.IsValid()); |
| // Keyed mutexes are required for Dawn interop but are not used for XR |
| // composition where fences are used instead. |
| Microsoft::WRL::ComPtr<IDXGIKeyedMutex> dxgi_keyed_mutex; |
| d3d11_texture.As(&dxgi_keyed_mutex); |
| DCHECK(!(usage & SHARED_IMAGE_USAGE_WEBGPU) || dxgi_keyed_mutex); |
| |
| auto shared_state = base::MakeRefCounted<SharedState>( |
| std::move(shared_handle), std::move(dxgi_keyed_mutex)); |
| |
| // Creating the GL texture doesn't require exclusive access to the underlying |
| // D3D11 texture. |
| auto gl_texture = CreateGLTexture(format, size, color_space, d3d11_texture); |
| if (!gl_texture) { |
| DLOG(ERROR) << "Failed to create GL texture"; |
| return nullptr; |
| } |
| |
| return base::WrapUnique(new SharedImageBackingD3D( |
| mailbox, format, size, color_space, surface_origin, alpha_type, usage, |
| std::move(d3d11_texture), std::move(gl_texture), /*swap_chain=*/nullptr, |
| /*buffer_index=*/0, std::move(shared_state))); |
| } |
| |
| std::unique_ptr<SharedImageBackingD3D> |
| SharedImageBackingD3D::CreateFromGLTexture( |
| 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<ID3D11Texture2D> d3d11_texture, |
| scoped_refptr<gles2::TexturePassthrough> gl_texture) { |
| return base::WrapUnique(new SharedImageBackingD3D( |
| mailbox, format, size, color_space, surface_origin, alpha_type, usage, |
| std::move(d3d11_texture), std::move(gl_texture))); |
| } |
| |
| // static |
| std::vector<std::unique_ptr<SharedImageBackingD3D>> |
| SharedImageBackingD3D::CreateFromVideoTexture( |
| base::span<const Mailbox> mailboxes, |
| DXGI_FORMAT dxgi_format, |
| const gfx::Size& size, |
| uint32_t usage, |
| Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11_texture, |
| unsigned array_slice, |
| base::win::ScopedHandle shared_handle) { |
| DCHECK(SupportsVideoFormat(dxgi_format)); |
| DCHECK_EQ(mailboxes.size(), NumPlanes(dxgi_format)); |
| |
| // Shared handle and keyed mutex are required for Dawn interop. |
| Microsoft::WRL::ComPtr<IDXGIKeyedMutex> dxgi_keyed_mutex; |
| d3d11_texture.As(&dxgi_keyed_mutex); |
| DCHECK(!(usage & gpu::SHARED_IMAGE_USAGE_WEBGPU) || |
| (shared_handle.IsValid() && dxgi_keyed_mutex)); |
| |
| // Share the same keyed mutex state for all the plane backings. |
| auto shared_state = base::MakeRefCounted<SharedState>( |
| std::move(shared_handle), std::move(dxgi_keyed_mutex)); |
| |
| std::vector<std::unique_ptr<SharedImageBackingD3D>> shared_images( |
| NumPlanes(dxgi_format)); |
| for (size_t plane_index = 0; plane_index < shared_images.size(); |
| plane_index++) { |
| const auto& mailbox = mailboxes[plane_index]; |
| |
| const auto plane_format = PlaneFormat(dxgi_format, plane_index); |
| const auto plane_size = PlaneSize(dxgi_format, size, plane_index); |
| |
| // Shared image does not need to store the colorspace since it is already |
| // stored on the VideoFrame which is provided upon presenting the overlay. |
| // To prevent the developer from mistakenly using it, provide the invalid |
| // value from default-construction. |
| constexpr gfx::ColorSpace kInvalidColorSpace; |
| |
| auto gl_texture = CreateGLTexture( |
| plane_format, plane_size, kInvalidColorSpace, d3d11_texture, |
| /*swap_chain=*/nullptr, GL_TEXTURE_EXTERNAL_OES, array_slice, |
| plane_index); |
| if (!gl_texture) { |
| DLOG(ERROR) << "Failed to create GL texture"; |
| return {}; |
| } |
| |
| shared_images[plane_index] = base::WrapUnique(new SharedImageBackingD3D( |
| mailbox, plane_format, plane_size, kInvalidColorSpace, |
| kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, usage, d3d11_texture, |
| std::move(gl_texture), /*swap_chain=*/nullptr, /*buffer_index=*/0, |
| shared_state)); |
| shared_images[plane_index]->SetCleared(); |
| } |
| |
| return shared_images; |
| } |
| |
| 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<ID3D11Texture2D> d3d11_texture, |
| scoped_refptr<gles2::TexturePassthrough> gl_texture, |
| Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain, |
| size_t buffer_index, |
| scoped_refptr<SharedState> shared_state) |
| : ClearTrackingSharedImageBacking(mailbox, |
| format, |
| size, |
| color_space, |
| surface_origin, |
| alpha_type, |
| usage, |
| gl_texture->estimated_size(), |
| false /* is_thread_safe */), |
| d3d11_texture_(std::move(d3d11_texture)), |
| gl_texture_(std::move(gl_texture)), |
| swap_chain_(std::move(swap_chain)), |
| buffer_index_(buffer_index), |
| shared_state_(std::move(shared_state)) { |
| DCHECK(gl_texture_); |
| } |
| |
| SharedImageBackingD3D::~SharedImageBackingD3D() { |
| if (!have_context()) |
| gl_texture_->MarkContextLost(); |
| gl_texture_ = nullptr; |
| shared_state_ = nullptr; |
| swap_chain_.Reset(); |
| d3d11_texture_.Reset(); |
| |
| #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(), gl_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(base::win::HandleTraits::IsHandleValid(GetSharedHandle())); |
| |
| 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 = GetSharedHandle(); |
| |
| 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(gl_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. |
| GetGLImage()->OnMemoryDump(pmd, client_tracing_id, dump_name); |
| } |
| |
| bool SharedImageBackingD3D::BeginAccessD3D12(uint64_t* acquire_key) { |
| return shared_state_->BeginAccessD3D12(acquire_key); |
| } |
| |
| void SharedImageBackingD3D::EndAccessD3D12() { |
| shared_state_->EndAccessD3D12(); |
| } |
| |
| bool SharedImageBackingD3D::BeginAccessD3D11() { |
| return shared_state_->BeginAccessD3D11(); |
| } |
| |
| void SharedImageBackingD3D::EndAccessD3D11() { |
| shared_state_->EndAccessD3D11(); |
| } |
| |
| HANDLE SharedImageBackingD3D::GetSharedHandle() const { |
| return shared_state_->GetSharedHandle(); |
| } |
| |
| gl::GLImage* SharedImageBackingD3D::GetGLImage() const { |
| return gl_texture_->GetLevelImage(gl_texture_->target(), 0u); |
| } |
| |
| 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, ¶ms); |
| if (FAILED(hr)) { |
| DLOG(ERROR) << "Present1 failed with error " << std::hex << hr; |
| return false; |
| } |
| |
| gl::GLApi* const api = gl::g_current_gl_context; |
| |
| DCHECK_EQ(gl_texture_->target(), static_cast<unsigned>(GL_TEXTURE_2D)); |
| ScopedRestoreTexture scoped_restore(api, GL_TEXTURE_2D); |
| |
| api->glBindTextureFn(GL_TEXTURE_2D, gl_texture_->service_id()); |
| if (!GetGLImage()->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, gl_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 |