gpu: Use correct synchronization in D3D overlay representation
Until now the D3D overlay representation was only used for D3D11 video decoder images which don't have a keyed mutex and therefore don't need synchronization. However, with MF video capture starting to use NV12 shared images, synchronization is now needed. Change overlay Begin/EndReadAccess to call Begin/EndAccessD3D11 on the backing. Also includes a unit test that uses the overlay path. Bug: 1214149 Change-Id: I51f045257ebb41663cd0a9ffd7ebac4ea2012acb Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2971277 Commit-Queue: Sunny Sachanandani <sunnyps@chromium.org> Auto-Submit: Sunny Sachanandani <sunnyps@chromium.org> Reviewed-by: Rafael Cintron <rafael.cintron@microsoft.com> Cr-Commit-Position: refs/heads/master@{#894345}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
1034e67a3a
commit
45bb99bee7
gpu/command_buffer/service
@ -8,6 +8,7 @@
|
||||
#include <utility>
|
||||
|
||||
#include "base/callback_helpers.h"
|
||||
#include "base/logging.h"
|
||||
#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"
|
||||
@ -461,7 +462,15 @@ class SharedImageBackingFactoryD3DTest
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<SharedImageRepresentationFactoryRef>>
|
||||
CreateVideoImages(const gfx::Size& size,
|
||||
unsigned char y_fill_value,
|
||||
unsigned char u_fill_value,
|
||||
unsigned char v_fill_value,
|
||||
bool use_shared_handle,
|
||||
bool use_factory);
|
||||
void RunVideoTest(bool use_shared_handle, bool use_factory);
|
||||
void RunOverlayTest(bool use_shared_handle, bool use_factory);
|
||||
|
||||
scoped_refptr<SharedContextState> context_state_;
|
||||
};
|
||||
@ -1049,28 +1058,26 @@ TEST_F(SharedImageBackingFactoryD3DTest, Dawn_ReuseExternalImage) {
|
||||
}
|
||||
#endif // BUILDFLAG(USE_DAWN)
|
||||
|
||||
void SharedImageBackingFactoryD3DTest::RunVideoTest(bool use_shared_handle,
|
||||
std::vector<std::unique_ptr<SharedImageRepresentationFactoryRef>>
|
||||
SharedImageBackingFactoryD3DTest::CreateVideoImages(const gfx::Size& size,
|
||||
unsigned char y_fill_value,
|
||||
unsigned char u_fill_value,
|
||||
unsigned char v_fill_value,
|
||||
bool use_shared_handle,
|
||||
bool use_factory) {
|
||||
if (!IsD3DSharedImageSupported())
|
||||
return;
|
||||
DCHECK(IsD3DSharedImageSupported());
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
|
||||
shared_image_factory_->GetDeviceForTesting();
|
||||
|
||||
const gfx::Size size(32, 32);
|
||||
|
||||
const unsigned kYFillValue = 0x12;
|
||||
const unsigned kUFillValue = 0x23;
|
||||
const unsigned kVFillValue = 0x34;
|
||||
|
||||
const size_t kYPlaneSize = size.width() * size.height();
|
||||
|
||||
std::vector<unsigned char> video_data;
|
||||
video_data.resize(kYPlaneSize * 3 / 2);
|
||||
memset(video_data.data(), kYFillValue, kYPlaneSize);
|
||||
memset(video_data.data(), y_fill_value, kYPlaneSize);
|
||||
for (size_t i = 0; i < kYPlaneSize / 2; i += 2) {
|
||||
video_data[kYPlaneSize + i] = kUFillValue;
|
||||
video_data[kYPlaneSize + i + 1] = kVFillValue;
|
||||
video_data[kYPlaneSize + i] = u_fill_value;
|
||||
video_data[kYPlaneSize + i + 1] = v_fill_value;
|
||||
}
|
||||
|
||||
D3D11_SUBRESOURCE_DATA data = {};
|
||||
@ -1086,7 +1093,8 @@ void SharedImageBackingFactoryD3DTest::RunVideoTest(bool use_shared_handle,
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11_texture;
|
||||
HRESULT hr = d3d11_device->CreateTexture2D(&desc, &data, &d3d11_texture);
|
||||
ASSERT_TRUE(SUCCEEDED(hr));
|
||||
if (FAILED(hr))
|
||||
return {};
|
||||
|
||||
uint32_t usage =
|
||||
gpu::SHARED_IMAGE_USAGE_VIDEO_DECODE | gpu::SHARED_IMAGE_USAGE_GLES2 |
|
||||
@ -1097,16 +1105,17 @@ void SharedImageBackingFactoryD3DTest::RunVideoTest(bool use_shared_handle,
|
||||
if (use_shared_handle) {
|
||||
Microsoft::WRL::ComPtr<IDXGIResource1> dxgi_resource;
|
||||
hr = d3d11_texture.As(&dxgi_resource);
|
||||
ASSERT_TRUE(SUCCEEDED(hr));
|
||||
DCHECK_EQ(hr, S_OK);
|
||||
|
||||
HANDLE handle;
|
||||
hr = dxgi_resource->CreateSharedHandle(
|
||||
nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE,
|
||||
nullptr, &handle);
|
||||
ASSERT_TRUE(SUCCEEDED(hr));
|
||||
if (FAILED(hr))
|
||||
return {};
|
||||
|
||||
shared_handle.Set(handle);
|
||||
ASSERT_TRUE(shared_handle.IsValid());
|
||||
DCHECK(shared_handle.IsValid());
|
||||
|
||||
usage |= gpu::SHARED_IMAGE_USAGE_WEBGPU;
|
||||
}
|
||||
@ -1127,7 +1136,7 @@ void SharedImageBackingFactoryD3DTest::RunVideoTest(bool use_shared_handle,
|
||||
mailboxes, DXGI_FORMAT_NV12, size, usage, d3d11_texture,
|
||||
/*array_slice=*/0, std::move(shared_handle));
|
||||
}
|
||||
ASSERT_EQ(shared_image_backings.size(), 2u);
|
||||
EXPECT_EQ(shared_image_backings.size(), 2u);
|
||||
|
||||
const gfx::Size plane_sizes[] = {
|
||||
size, gfx::Size(size.width() / 2, size.height() / 2)};
|
||||
@ -1151,6 +1160,22 @@ void SharedImageBackingFactoryD3DTest::RunVideoTest(bool use_shared_handle,
|
||||
std::move(backing), memory_type_tracker_.get()));
|
||||
}
|
||||
|
||||
return shared_image_refs;
|
||||
}
|
||||
|
||||
void SharedImageBackingFactoryD3DTest::RunVideoTest(bool use_shared_handle,
|
||||
bool use_factory) {
|
||||
const gfx::Size size(32, 32);
|
||||
|
||||
const unsigned char kYFillValue = 0x12;
|
||||
const unsigned char kUFillValue = 0x23;
|
||||
const unsigned char kVFillValue = 0x34;
|
||||
|
||||
auto shared_image_refs =
|
||||
CreateVideoImages(size, kYFillValue, kUFillValue, kVFillValue,
|
||||
use_shared_handle, use_factory);
|
||||
ASSERT_EQ(shared_image_refs.size(), 2u);
|
||||
|
||||
// Setup GL shaders, framebuffers, uniforms, etc.
|
||||
static const char* kVideoFragmentShaderSrc =
|
||||
"#extension GL_OES_EGL_image_external : require\n"
|
||||
@ -1245,12 +1270,12 @@ void SharedImageBackingFactoryD3DTest::RunVideoTest(bool use_shared_handle,
|
||||
{
|
||||
auto y_texture =
|
||||
shared_image_representation_factory_->ProduceGLTexturePassthrough(
|
||||
mailboxes[0]);
|
||||
shared_image_refs[0]->mailbox());
|
||||
ASSERT_NE(y_texture, nullptr);
|
||||
|
||||
auto uv_texture =
|
||||
shared_image_representation_factory_->ProduceGLTexturePassthrough(
|
||||
mailboxes[1]);
|
||||
shared_image_refs[1]->mailbox());
|
||||
ASSERT_NE(uv_texture, nullptr);
|
||||
|
||||
auto y_texture_access = y_texture->BeginScopedAccess(
|
||||
@ -1307,5 +1332,82 @@ TEST_F(SharedImageBackingFactoryD3DTest, CreateSharedImageVideoPlanes) {
|
||||
RunVideoTest(/*use_shared_handle=*/true, /*use_factory=*/true);
|
||||
}
|
||||
|
||||
void SharedImageBackingFactoryD3DTest::RunOverlayTest(bool use_shared_handle,
|
||||
bool use_factory) {
|
||||
const gfx::Size size(32, 32);
|
||||
|
||||
const unsigned char kYFillValue = 0x12;
|
||||
const unsigned char kUFillValue = 0x23;
|
||||
const unsigned char kVFillValue = 0x34;
|
||||
|
||||
auto shared_image_refs =
|
||||
CreateVideoImages(size, kYFillValue, kUFillValue, kVFillValue,
|
||||
use_shared_handle, use_factory);
|
||||
ASSERT_EQ(shared_image_refs.size(), 2u);
|
||||
|
||||
auto overlay_representation =
|
||||
shared_image_representation_factory_->ProduceOverlay(
|
||||
shared_image_refs[0]->mailbox());
|
||||
|
||||
auto scoped_read_access =
|
||||
overlay_representation->BeginScopedReadAccess(/*needs_gl_image=*/true);
|
||||
ASSERT_TRUE(scoped_read_access);
|
||||
|
||||
auto* gl_image_d3d =
|
||||
gl::GLImageD3D::FromGLImage(scoped_read_access->gl_image());
|
||||
ASSERT_TRUE(gl_image_d3d);
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
|
||||
shared_image_factory_->GetDeviceForTesting();
|
||||
|
||||
CD3D11_TEXTURE2D_DESC staging_desc(
|
||||
DXGI_FORMAT_NV12, size.width(), size.height(), 1, 1, 0,
|
||||
D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ);
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3D11Texture2D> staging_texture;
|
||||
HRESULT hr =
|
||||
d3d11_device->CreateTexture2D(&staging_desc, nullptr, &staging_texture);
|
||||
ASSERT_EQ(hr, S_OK);
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3D11DeviceContext> device_context;
|
||||
d3d11_device->GetImmediateContext(&device_context);
|
||||
|
||||
device_context->CopyResource(staging_texture.Get(),
|
||||
gl_image_d3d->texture().Get());
|
||||
D3D11_MAPPED_SUBRESOURCE mapped_resource = {};
|
||||
hr = device_context->Map(staging_texture.Get(), 0, D3D11_MAP_READ, 0,
|
||||
&mapped_resource);
|
||||
ASSERT_EQ(hr, S_OK);
|
||||
|
||||
const unsigned char* pixels =
|
||||
static_cast<const unsigned char*>(mapped_resource.pData);
|
||||
const size_t stride = mapped_resource.RowPitch;
|
||||
const size_t kYPlaneSize = stride * size.height();
|
||||
for (size_t i = 0; i < size.height(); i++) {
|
||||
for (size_t j = 0; j < size.width(); j++) {
|
||||
EXPECT_EQ(*(pixels + i * stride + j), kYFillValue);
|
||||
if (i < size.height() / 2 && j % 2 == 0) {
|
||||
EXPECT_EQ(*(pixels + kYPlaneSize + i * stride + j), kUFillValue);
|
||||
EXPECT_EQ(*(pixels + kYPlaneSize + i * stride + j + 1), kVFillValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
device_context->Unmap(staging_texture.Get(), 0);
|
||||
}
|
||||
|
||||
TEST_F(SharedImageBackingFactoryD3DTest, CreateFromVideoTextureOverlay) {
|
||||
RunOverlayTest(/*use_shared_handle=*/false, /*use_factory=*/false);
|
||||
}
|
||||
|
||||
TEST_F(SharedImageBackingFactoryD3DTest,
|
||||
CreateFromVideoTextureSharedHandleOverlay) {
|
||||
RunOverlayTest(/*use_shared_handle=*/true, /*use_factory=*/false);
|
||||
}
|
||||
|
||||
TEST_F(SharedImageBackingFactoryD3DTest, CreateSharedImageVideoPlanesOverlay) {
|
||||
RunOverlayTest(/*use_shared_handle=*/true, /*use_factory=*/true);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
} // namespace gpu
|
||||
|
@ -123,14 +123,13 @@ SharedImageRepresentationOverlayD3D::SharedImageRepresentationOverlayD3D(
|
||||
|
||||
bool SharedImageRepresentationOverlayD3D::BeginReadAccess(
|
||||
std::vector<gfx::GpuFence>* acquire_fences) {
|
||||
// Note: only the DX11 video decoder uses this overlay and does not need to
|
||||
// synchronize read access from different devices.
|
||||
return true;
|
||||
return static_cast<SharedImageBackingD3D*>(backing())->BeginAccessD3D11();
|
||||
}
|
||||
|
||||
void SharedImageRepresentationOverlayD3D::EndReadAccess(
|
||||
gfx::GpuFenceHandle release_fence) {
|
||||
DCHECK(release_fence.is_null());
|
||||
static_cast<SharedImageBackingD3D*>(backing())->EndAccessD3D11();
|
||||
}
|
||||
|
||||
gl::GLImage* SharedImageRepresentationOverlayD3D::GetGLImage() {
|
||||
|
Reference in New Issue
Block a user