Commit 4ce13b5e authored by Rafael Cintron's avatar Rafael Cintron Committed by Commit Bot

Implement CreateSharedImage from GpuMemoryBufferHandle

To reduce the number of texture copies in camera and XR scenarios,
we need to be able to share textures between processes using Windows
handle objects.

To facilitate this, we implement the overload of
SharedImageBackingFactoryD3D::CreateSharedImage which accepts a
gfx::GpuMemoryBufferHandle.

Bug: 1131616
Change-Id: I9561229b7631d0a89a7ced4ee6fc0de43c029d45
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2438649
Commit-Queue: Rafael Cintron <rafael.cintron@microsoft.com>
Reviewed-by: default avatarZhenyao Mo <zmo@chromium.org>
Reviewed-by: default avatarSunny Sachanandani <sunnyps@chromium.org>
Cr-Commit-Position: refs/heads/master@{#812835}
parent ae4204a6
......@@ -4,7 +4,10 @@
#include "gpu/command_buffer/service/shared_image_backing_factory_d3d.h"
#include <d3d11_1.h>
#include "components/viz/common/resources/resource_format_utils.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/command_buffer/service/shared_image_backing_d3d.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gl/direct_composition_surface_win.h"
......@@ -141,13 +144,9 @@ std::unique_ptr<SharedImageBacking> SharedImageBackingFactoryD3D::MakeBacking(
return nullptr;
}
} else if (shared_handle.IsValid()) {
const HRESULT hr = d3d11_texture.As(&dxgi_keyed_mutex);
if (FAILED(hr)) {
DLOG(ERROR) << "Unable to QueryInterface for IDXGIKeyedMutex on texture "
"with shared handle "
<< std::hex;
return nullptr;
}
// Keyed mutexes are required for Dawn interop but are not used
// for XR composition where fences are used instead.
d3d11_texture.As(&dxgi_keyed_mutex);
}
DCHECK(d3d11_texture);
......@@ -380,15 +379,58 @@ SharedImageBackingFactoryD3D::CreateSharedImage(
GrSurfaceOrigin surface_origin,
SkAlphaType alpha_type,
uint32_t usage) {
NOTIMPLEMENTED();
return nullptr;
// TODO: Add support for shared memory GMBs.
DCHECK_EQ(handle.type, gfx::DXGI_SHARED_HANDLE);
if (!handle.dxgi_handle.IsValid()) {
DLOG(ERROR) << "Invalid handle type passed to CreateSharedImage";
return nullptr;
}
if (!gpu::IsImageSizeValidForGpuMemoryBufferFormat(size, format)) {
DLOG(ERROR) << "Invalid image size " << size.ToString() << " for "
<< gfx::BufferFormatToString(format);
return nullptr;
}
Microsoft::WRL::ComPtr<ID3D11Device1> d3d11_device1;
HRESULT hr = d3d11_device_.As(&d3d11_device1);
if (FAILED(hr)) {
DLOG(ERROR) << "Failed to query for ID3D11Device1. Error: "
<< logging::SystemErrorCodeToString(hr);
return nullptr;
}
Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11_texture;
hr = d3d11_device1->OpenSharedResource1(handle.dxgi_handle.Get(),
IID_PPV_ARGS(&d3d11_texture));
if (FAILED(hr)) {
DLOG(ERROR) << "Unable to open shared resource from DXGI handle. Error: "
<< logging::SystemErrorCodeToString(hr);
return nullptr;
}
D3D11_TEXTURE2D_DESC desc;
d3d11_texture->GetDesc(&desc);
// TODO: Add checks for device specific limits.
if (desc.Width != static_cast<UINT>(size.width()) ||
desc.Height != static_cast<UINT>(size.height())) {
DLOG(ERROR)
<< "Size passed to CreateSharedImage must match texture being opened";
return nullptr;
}
return MakeBacking(mailbox, viz::GetResourceFormat(format), size, color_space,
surface_origin, alpha_type, usage, /*swap_chain=*/nullptr,
/*buffer_index=*/0, std::move(d3d11_texture),
std::move(handle.dxgi_handle));
}
// Returns true if the specified GpuMemoryBufferType can be imported using
// this factory.
bool SharedImageBackingFactoryD3D::CanImportGpuMemoryBuffer(
gfx::GpuMemoryBufferType memory_buffer_type) {
return false;
return (memory_buffer_type == gfx::DXGI_SHARED_HANDLE);
}
} // namespace gpu
......@@ -96,6 +96,10 @@ class GPU_GLES2_EXPORT SharedImageBackingFactoryD3D
bool CanImportGpuMemoryBuffer(
gfx::GpuMemoryBufferType memory_buffer_type) override;
Microsoft::WRL::ComPtr<ID3D11Device> GetDeviceForTesting() const {
return d3d11_device_;
}
private:
// Wraps the optional swap chain buffer (front buffer/back buffer) and texture
// into GLimage and creates a GL texture and stores it as gles2::Texture or as
......
......@@ -11,6 +11,7 @@
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/command_buffer/service/service_utils.h"
#include "gpu/command_buffer/service/shared_context_state.h"
#include "gpu/command_buffer/service/shared_image_backing_d3d.h"
#include "gpu/command_buffer/service/shared_image_factory.h"
#include "gpu/command_buffer/service/shared_image_manager.h"
#include "gpu/command_buffer/service/shared_image_representation.h"
......@@ -846,5 +847,72 @@ TEST_F(SharedImageBackingFactoryD3DTest, SkiaAccessFirstFails) {
skia_representation->BeginScopedReadAccess(nullptr, nullptr);
EXPECT_EQ(scoped_read_access, nullptr);
}
TEST_F(SharedImageBackingFactoryD3DTest, CreateSharedImageFromHandle) {
if (!IsD3DSharedImageSupported())
return;
EXPECT_TRUE(
shared_image_factory_->CanImportGpuMemoryBuffer(gfx::DXGI_SHARED_HANDLE));
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
shared_image_factory_->GetDeviceForTesting();
const gfx::Size size(1, 1);
D3D11_TEXTURE2D_DESC desc;
desc.Width = size.width();
desc.Height = size.height();
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
desc.CPUAccessFlags = 0;
desc.MiscFlags =
D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED;
Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11_texture;
HRESULT hr = d3d11_device->CreateTexture2D(&desc, nullptr, &d3d11_texture);
ASSERT_EQ(hr, S_OK);
Microsoft::WRL::ComPtr<IDXGIResource1> dxgi_resource;
hr = d3d11_texture.As(&dxgi_resource);
ASSERT_EQ(hr, S_OK);
HANDLE shared_handle;
hr = dxgi_resource->CreateSharedHandle(
nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr,
&shared_handle);
ASSERT_EQ(hr, S_OK);
gfx::GpuMemoryBufferHandle gpu_memory_buffer_handle;
gpu_memory_buffer_handle.dxgi_handle.Set(shared_handle);
gpu_memory_buffer_handle.type = gfx::DXGI_SHARED_HANDLE;
auto mailbox = Mailbox::GenerateForSharedImage();
const auto format = gfx::BufferFormat::RGBA_8888;
const auto color_space = gfx::ColorSpace::CreateSRGB();
const uint32_t usage = SHARED_IMAGE_USAGE_GLES2 | SHARED_IMAGE_USAGE_DISPLAY;
const gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
const GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin;
const SkAlphaType alpha_type = kPremul_SkAlphaType;
auto backing = shared_image_factory_->CreateSharedImage(
mailbox, 0, std::move(gpu_memory_buffer_handle), format, surface_handle,
size, color_space, surface_origin, alpha_type, usage);
ASSERT_NE(backing, nullptr);
EXPECT_EQ(backing->format(), viz::RGBA_8888);
EXPECT_EQ(backing->size(), size);
EXPECT_EQ(backing->color_space(), color_space);
EXPECT_EQ(backing->surface_origin(), surface_origin);
EXPECT_EQ(backing->alpha_type(), alpha_type);
EXPECT_EQ(backing->mailbox(), mailbox);
SharedImageBackingD3D* backing_d3d =
static_cast<SharedImageBackingD3D*>(backing.get());
EXPECT_EQ(backing_d3d->GetSharedHandle(), shared_handle);
}
} // anonymous namespace
} // namespace gpu
......@@ -162,6 +162,7 @@ Mailbox SharedImageInterfaceProxy::CreateSharedImage(
uint32_t usage) {
DCHECK(gpu_memory_buffer->GetType() == gfx::NATIVE_PIXMAP ||
gpu_memory_buffer->GetType() == gfx::ANDROID_HARDWARE_BUFFER ||
gpu_memory_buffer->GetType() == gfx::DXGI_SHARED_HANDLE ||
gpu_memory_buffer_manager);
auto mailbox = Mailbox::GenerateForSharedImage();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment