Skip to content

Commit

Permalink
Make compound backing work with D3DImageBacking
Browse files Browse the repository at this point in the history
Removes the shared memory segment support from D3DImageBacking and use
compound backing instead. D3DImageBacking supports readback from texture
to memory so add SharedImageBacking::ReadbackToMemory() for compound
backing to use. The CopyToGpuMemoryBuffer() implementation is moved to
compound backing as well.

Bug: 1293509
Change-Id: Iaed0df60be5f629a54c62a36ce952f926d9c65d4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3852364
Reviewed-by: Vasiliy Telezhnikov <vasilyt@chromium.org>
Reviewed-by: Sunny Sachanandani <sunnyps@chromium.org>
Commit-Queue: Kyle Charbonneau <kylechar@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1044702}
  • Loading branch information
kylechar authored and Chromium LUCI CQ committed Sep 8, 2022
1 parent dee46b5 commit 153b479
Show file tree
Hide file tree
Showing 12 changed files with 235 additions and 236 deletions.
80 changes: 58 additions & 22 deletions gpu/command_buffer/service/shared_image/compound_image_backing.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,14 @@ bool IsValidSharedMemoryBufferFormat(const gfx::Size& size,
DLOG(ERROR) << "Invalid image size for format.";
return false;
}
if (gfx::NumberOfPlanesForLinearBufferFormat(buffer_format) != 1) {
DLOG(ERROR) << "Invalid image format.";
return false;
}
if (plane != gfx::BufferPlane::DEFAULT) {
DLOG(ERROR) << "Invalid plane " << gfx::BufferPlaneToString(plane);
return false;
switch (plane) {
case gfx::BufferPlane::DEFAULT:
case gfx::BufferPlane::Y:
case gfx::BufferPlane::UV:
break;
default:
DLOG(ERROR) << "Invalid plane " << gfx::BufferPlaneToString(plane);
return false;
}

return true;
Expand Down Expand Up @@ -293,22 +294,29 @@ std::unique_ptr<SharedImageBacking> CompoundImageBacking::CreateSharedMemory(
if (!IsValidSharedMemoryBufferFormat(size, buffer_format, plane))
return nullptr;

viz::ResourceFormat format = viz::GetResourceFormat(buffer_format);
const gfx::Size plane_size = GetPlaneSize(plane, size);
const viz::ResourceFormat plane_format =
viz::GetResourceFormat(GetPlaneBufferFormat(plane, buffer_format));

const size_t plane_index = plane == gfx::BufferPlane::UV ? 1 : 0;
handle.offset +=
gfx::BufferOffsetForBufferFormat(size, buffer_format, plane_index);

SharedMemoryRegionWrapper shm_wrapper;
if (!shm_wrapper.Initialize(handle, size, format)) {
if (!shm_wrapper.Initialize(handle, plane_size, plane_format)) {
DLOG(ERROR) << "Failed to create SharedMemoryRegionWrapper";
return nullptr;
}

auto shm_backing = std::make_unique<SharedMemoryImageBacking>(
mailbox, format, size, color_space, surface_origin, alpha_type,
SHARED_IMAGE_USAGE_CPU_WRITE, std::move(shm_wrapper));
mailbox, plane_format, plane_size, color_space, surface_origin,
alpha_type, SHARED_IMAGE_USAGE_CPU_WRITE, std::move(shm_wrapper));
shm_backing->SetNotRefCounted();

return std::make_unique<CompoundImageBacking>(
mailbox, format, size, color_space, surface_origin, alpha_type, usage,
surface_handle, allow_shm_overlays, std::move(shm_backing),
gpu_backing_factory->GetWeakPtr());
mailbox, plane_format, plane_size, color_space, surface_origin,
alpha_type, usage, surface_handle, allow_shm_overlays,
std::move(shm_backing), gpu_backing_factory->GetWeakPtr());
}

CompoundImageBacking::CompoundImageBacking(
Expand Down Expand Up @@ -338,11 +346,6 @@ CompoundImageBacking::CompoundImageBacking(
gpu_backing_factory_(std::move(gpu_backing_factory)) {
DCHECK(shm_backing_);
DCHECK_EQ(size, shm_backing_->size());

// First access will write pixels from shared memory backing to GPU backing
// clearing it.
shm_has_update_ = true;
SetClearedRect(gfx::Rect(size));
}

CompoundImageBacking::~CompoundImageBacking() = default;
Expand All @@ -355,7 +358,13 @@ void CompoundImageBacking::NotifyBeginAccess(SharedImageAccessStream stream,
// TODO(kylechar): Keep track of access to the compound backing as we
// only want to update a backing if it's not currently being accessed.

if (shm_has_update_ && stream != SharedImageAccessStream::kMemory) {
if (stream == SharedImageAccessStream::kMemory) {
DCHECK_EQ(mode, RepresentationAccessMode::kRead);
return;
}

if (!gpu_has_latest_content_) {
DCHECK(shm_has_latest_content_);
DCHECK(gpu_backing_);

auto& wrapper = static_cast<SharedMemoryImageBacking*>(shm_backing_.get())
Expand All @@ -366,11 +375,16 @@ void CompoundImageBacking::NotifyBeginAccess(SharedImageAccessStream stream,
wrapper.GetStride());

if (gpu_backing_->UploadFromMemory(pixmap)) {
shm_has_update_ = false;
gpu_has_latest_content_ = true;
} else {
DLOG(ERROR) << "Failed to upload from shared memory to GPU backing";
}
}

if (mode == RepresentationAccessMode::kWrite) {
// On GPU write access set shared memory contents as stale.
shm_has_latest_content_ = false;
}
}

SharedImageBackingType CompoundImageBacking::GetType() const {
Expand All @@ -379,7 +393,29 @@ SharedImageBackingType CompoundImageBacking::GetType() const {

void CompoundImageBacking::Update(std::unique_ptr<gfx::GpuFence> in_fence) {
DCHECK(!in_fence);
shm_has_update_ = true;
shm_has_latest_content_ = true;
gpu_has_latest_content_ = false;
}

bool CompoundImageBacking::CopyToGpuMemoryBuffer() {
// TODO(crbug.com/1293509): Return early if `shm_has_latest_content_` is true
// since shared memory should already be up to date. Just need to verify GL
// isn't modifying the texture without acquiring write access first.

auto& wrapper = static_cast<SharedMemoryImageBacking*>(shm_backing_.get())
->shared_memory_wrapper();
DCHECK(wrapper.IsValid());

SkPixmap pixmap(shm_backing_->AsSkImageInfo(), wrapper.GetMemory(),
wrapper.GetStride());

if (!gpu_backing_->ReadbackToMemory(pixmap)) {
DLOG(ERROR) << "Failed to copy from GPU backing to shared memory";
return false;
}

shm_has_latest_content_ = true;
return true;
}

gfx::Rect CompoundImageBacking::ClearedRect() const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class GPU_GLES2_EXPORT CompoundImageBacking : public SharedImageBacking {
// SharedImageBacking implementation.
SharedImageBackingType GetType() const override;
void Update(std::unique_ptr<gfx::GpuFence> in_fence) override;
bool CopyToGpuMemoryBuffer() override;
gfx::Rect ClearedRect() const override;
void SetClearedRect(const gfx::Rect& cleared_rect) override;

Expand Down Expand Up @@ -127,9 +128,9 @@ class GPU_GLES2_EXPORT CompoundImageBacking : public SharedImageBacking {
base::WeakPtr<SharedImageBackingFactory> gpu_backing_factory_;
std::unique_ptr<SharedImageBacking> gpu_backing_;

// This will be true when shared memory backing has newer pixels than GPU
// backing.
bool shm_has_update_ = false;
// Keeps track of if shared memory or GPU backing has latest pixels.
bool shm_has_latest_content_ = true;
bool gpu_has_latest_content_ = false;
};

} // namespace gpu
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,14 @@ class CompoundImageBackingTest : public testing::Test {
return static_cast<TestImageBacking*>(gpu_backing);
}

bool GetShmHasLatestContent(CompoundImageBacking* backing) {
return backing->shm_has_latest_content_;
}

bool GetGpuHasLatestContent(CompoundImageBacking* backing) {
return backing->gpu_has_latest_content_;
}

// Create a compound backing containing shared memory + GPU backing.
std::unique_ptr<SharedImageBacking> CreateCompoundBacking(
bool allow_shm_overlays = false) {
Expand Down Expand Up @@ -190,10 +198,18 @@ TEST_F(CompoundImageBackingTest, UploadOnAccess) {
// The compound backing hasn't been accessed yet.
EXPECT_FALSE(gpu_backing->GetUploadFromMemoryCalledAndReset());

// Only shared memory should have latest content initially.
EXPECT_TRUE(GetShmHasLatestContent(compound_backing));
EXPECT_FALSE(GetGpuHasLatestContent(compound_backing));

// First access should trigger upload from memory to GPU.
overlay_rep->BeginScopedReadAccess(false);
EXPECT_TRUE(gpu_backing->GetUploadFromMemoryCalledAndReset());

// After GPU read access both should have latest content.
EXPECT_TRUE(GetShmHasLatestContent(compound_backing));
EXPECT_TRUE(GetGpuHasLatestContent(compound_backing));

// Second access shouldn't trigger upload since no shared memory updates
// happened.
overlay_rep->BeginScopedReadAccess(false);
Expand Down Expand Up @@ -228,16 +244,54 @@ TEST_F(CompoundImageBackingTest, UploadOnAccess) {
manager_.ProduceSkia(compound_backing->mailbox(), &tracker_, nullptr);

compound_backing->Update(nullptr);

// After Update() only shared memory should have latest content.
EXPECT_TRUE(GetShmHasLatestContent(compound_backing));
EXPECT_FALSE(GetGpuHasLatestContent(compound_backing));

skia_rep->BeginScopedWriteAccess(
&begin_semaphores, &end_semaphores,
SharedImageRepresentation::AllowUnclearedAccess::kNo);
EXPECT_TRUE(gpu_backing->GetUploadFromMemoryCalledAndReset());

// On GPU write access only GPU should have latest content.
EXPECT_FALSE(GetShmHasLatestContent(compound_backing));
EXPECT_TRUE(GetGpuHasLatestContent(compound_backing));

compound_backing->Update(nullptr);
skia_rep->BeginScopedReadAccess(&begin_semaphores, &end_semaphores);
EXPECT_TRUE(gpu_backing->GetUploadFromMemoryCalledAndReset());
}

TEST_F(CompoundImageBackingTest, ReadbackToMemory) {
auto backing = CreateCompoundBacking();
auto* compound_backing = static_cast<CompoundImageBacking*>(backing.get());

auto factory_rep = manager_.Register(std::move(backing), &tracker_);

auto gl_passthrough_rep = manager_.ProduceGLTexturePassthrough(
compound_backing->mailbox(), &tracker_);
compound_backing->Update(nullptr);
gl_passthrough_rep->BeginScopedAccess(
0, SharedImageRepresentation::AllowUnclearedAccess::kNo);

auto* gpu_backing = GetGpuBacking(compound_backing);

// On write access UploadFromMemory() should be called and then only GPU
// texture has latest.
EXPECT_TRUE(gpu_backing->GetUploadFromMemoryCalledAndReset());
EXPECT_FALSE(GetShmHasLatestContent(compound_backing));
EXPECT_TRUE(GetGpuHasLatestContent(compound_backing));

compound_backing->CopyToGpuMemoryBuffer();

// On CopyToGpuMemoryBuffer() ReadbackToMemory() should have been called and
// shared memory has latest content again.
EXPECT_TRUE(gpu_backing->GetReadbackToMemoryCalledAndReset());
EXPECT_TRUE(GetShmHasLatestContent(compound_backing));
EXPECT_TRUE(GetGpuHasLatestContent(compound_backing));
}

TEST_F(CompoundImageBackingTest, NoUploadOnOverlayMemoryAccess) {
auto backing = CreateCompoundBacking(/*allow_shm_overlays=*/true);
auto* compound_backing = static_cast<CompoundImageBacking*>(backing.get());
Expand Down
73 changes: 11 additions & 62 deletions gpu/command_buffer/service/shared_image/d3d_image_backing.cc
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,7 @@ std::unique_ptr<D3DImageBacking> D3DImageBacking::CreateFromSwapChainBuffer(
return base::WrapUnique(new D3DImageBacking(
mailbox, format, size, color_space, surface_origin, alpha_type, usage,
std::move(d3d11_texture), std::move(gl_texture),
/*dxgi_shared_handle_state=*/{}, /*shared_memory_handle=*/{},
std::move(swap_chain), is_back_buffer));
/*dxgi_shared_handle_state=*/{}, std::move(swap_chain), is_back_buffer));
}

// static
Expand Down Expand Up @@ -329,17 +328,15 @@ D3DImageBacking::CreateFromVideoTexture(
}

// static
std::unique_ptr<D3DImageBacking> D3DImageBacking::CreateFromSharedMemoryHandle(
std::unique_ptr<D3DImageBacking> D3DImageBacking::CreateForSharedMemory(
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,
gfx::GpuMemoryBufferHandle shared_memory_handle) {
DCHECK_EQ(shared_memory_handle.type, gfx::SHARED_MEMORY_BUFFER);
Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11_texture) {
auto gl_texture = CreateGLTexture(format, size, color_space, d3d11_texture);
if (!gl_texture) {
LOG(ERROR) << "Failed to create GL texture";
Expand All @@ -348,7 +345,7 @@ std::unique_ptr<D3DImageBacking> D3DImageBacking::CreateFromSharedMemoryHandle(
auto backing = base::WrapUnique(new D3DImageBacking(
mailbox, format, size, color_space, surface_origin, alpha_type, usage,
std::move(d3d11_texture), std::move(gl_texture),
/*dxgi_shared_handle_state=*/{}, std::move(shared_memory_handle)));
/*dxgi_shared_handle_state=*/{}));
return backing;
}

Expand All @@ -363,7 +360,6 @@ D3DImageBacking::D3DImageBacking(
Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11_texture,
scoped_refptr<gles2::TexturePassthrough> gl_texture,
scoped_refptr<DXGISharedHandleState> dxgi_shared_handle_state,
gfx::GpuMemoryBufferHandle shared_memory_handle,
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain,
bool is_back_buffer)
: ClearTrackingSharedImageBacking(
Expand All @@ -381,7 +377,6 @@ D3DImageBacking::D3DImageBacking(
d3d11_texture_(std::move(d3d11_texture)),
gl_texture_(std::move(gl_texture)),
dxgi_shared_handle_state_(std::move(dxgi_shared_handle_state)),
shared_memory_handle_(std::move(shared_memory_handle)),
swap_chain_(std::move(swap_chain)),
is_back_buffer_(is_back_buffer) {
const bool has_webgpu_usage = !!(usage & SHARED_IMAGE_USAGE_WEBGPU);
Expand Down Expand Up @@ -441,25 +436,12 @@ SharedImageBackingType D3DImageBacking::GetType() const {
}

void D3DImageBacking::Update(std::unique_ptr<gfx::GpuFence> in_fence) {
DCHECK(!in_fence);
if (!shared_memory_handle_.is_null())
needs_upload_to_gpu_ = true;
NOTREACHED();
}

bool D3DImageBacking::UploadToGpuIfNeeded() {
if (!needs_upload_to_gpu_)
return true;

gpu::SharedMemoryRegionWrapper mapped_shared_memory;
mapped_shared_memory.Initialize(shared_memory_handle_, size(), format());

if (!mapped_shared_memory.IsValid()) {
LOG(ERROR) << "Failed to map shared memory";
return false;
}

const uint8_t* source_memory = mapped_shared_memory.GetMemory();
const size_t source_stride = mapped_shared_memory.GetStride();
bool D3DImageBacking::UploadFromMemory(const SkPixmap& pixmap) {
const uint8_t* source_memory = static_cast<const uint8_t*>(pixmap.addr());
const size_t source_stride = pixmap.info().minRowBytes();

Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device;
DCHECK(d3d11_texture_);
Expand Down Expand Up @@ -506,27 +488,12 @@ bool D3DImageBacking::UploadToGpuIfNeeded() {
device_context->CopySubresourceRegion(d3d11_texture_.Get(), 0, 0, 0, 0,
staging_texture, 0, nullptr);
}
needs_upload_to_gpu_ = false;
return true;
}

bool D3DImageBacking::CopyToGpuMemoryBuffer() {
if (shared_memory_handle_.is_null()) {
LOG(ERROR)
<< "Called CopyToGpuMemoryBuffer for backing without shared memory GMB";
return false;
}

gpu::SharedMemoryRegionWrapper mapped_shared_memory;
mapped_shared_memory.Initialize(shared_memory_handle_, size(), format());

if (!mapped_shared_memory.IsValid()) {
LOG(ERROR) << "Failed to map shared memory";
return false;
}

uint8_t* dest_memory = mapped_shared_memory.GetMemory();
const size_t dest_stride = mapped_shared_memory.GetStride();
bool D3DImageBacking::ReadbackToMemory(SkPixmap& pixmap) {
uint8_t* dest_memory = static_cast<uint8_t*>(pixmap.writable_addr());
const size_t dest_stride = pixmap.info().minRowBytes();

Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device;
DCHECK(d3d11_texture_);
Expand Down Expand Up @@ -764,10 +731,6 @@ std::unique_ptr<GLTexturePassthroughImageRepresentation>
D3DImageBacking::ProduceGLTexturePassthrough(SharedImageManager* manager,
MemoryTypeTracker* tracker) {
TRACE_EVENT0("gpu", "D3DImageBacking::ProduceGLTexturePassthrough");
if (!UploadToGpuIfNeeded()) {
LOG(ERROR) << "UploadToGpuIfNeeded failed";
return nullptr;
}
// Lazily create a GL texture if it wasn't provided on initialization.
auto gl_texture = gl_texture_;
if (!gl_texture) {
Expand Down Expand Up @@ -795,20 +758,6 @@ std::unique_ptr<OverlayImageRepresentation> D3DImageBacking::ProduceOverlay(
SharedImageManager* manager,
MemoryTypeTracker* tracker) {
TRACE_EVENT0("gpu", "D3DImageBacking::ProduceOverlay");
// Prefer GLImageMemory for shared memory case so that we don't upload to a
// texture if it ends up in an overlay.
if (!shared_memory_handle_.is_null()) {
auto gl_image = base::MakeRefCounted<gl::GLImageSharedMemory>(size());
if (!gl_image->Initialize(
shared_memory_handle_.region, shared_memory_handle_.id,
viz::BufferFormat(format()), shared_memory_handle_.offset,
shared_memory_handle_.stride)) {
LOG(ERROR) << "Failed to initialize GLImageSharedMemory";
return nullptr;
}
return std::make_unique<OverlayD3DImageRepresentation>(
manager, this, tracker, std::move(gl_image));
}
return std::make_unique<OverlayD3DImageRepresentation>(manager, this, tracker,
GetGLImage());
}
Expand Down
Loading

0 comments on commit 153b479

Please sign in to comment.