Skip to content

Commit

Permalink
Remove shared memory from ExternalVkImageBacking
Browse files Browse the repository at this point in the history
Use CompoundImageBacking to hold shared memory segment for
ExternalVkImageBacking. ExternalVkImageBacking still has owns both
VkImage and GL texture with logic to copy between them as needed.

This is the last GPU backing that can directly handle shared memory GMBs
so SharedImageFactory::CreateSharedMemory() can now try to find a
compatible factory and if that fails fallback to using
CompoundImageBacking containing another GPU backing.

LOW_COVERAGE_REASON=Removing parts of ExternalVkImageBacking to use
shared (and tested) code in CompoundImageBacking.

Bug: 1293509
Change-Id: Id289a2ed8ef86443dc2067116253d561f93aef8f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3919314
Reviewed-by: Vasiliy Telezhnikov <vasilyt@chromium.org>
Commit-Queue: Kyle Charbonneau <kylechar@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1053156}
  • Loading branch information
kylechar authored and Chromium LUCI CQ committed Sep 29, 2022
1 parent f76e382 commit e06e2b9
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 118 deletions.
130 changes: 45 additions & 85 deletions gpu/command_buffer/service/shared_image/external_vk_image_backing.cc
Expand Up @@ -224,10 +224,12 @@ std::unique_ptr<ExternalVkImageBacking> ExternalVkImageBacking::Create(

if (!pixel_data.empty()) {
size_t stride = BitsPerPixel(format) / 8 * size.width();
backing->WritePixelsWithData(pixel_data, stride);
SkPixmap pixmap(backing->AsSkImageInfo(), pixel_data.data(), stride);
backing->UploadToVkImage(pixmap);

// Mark the backing as cleared.
backing->SetCleared();
backing->latest_content_ = kInVkImage;
}

return backing;
Expand Down Expand Up @@ -255,46 +257,24 @@ std::unique_ptr<ExternalVkImageBacking> ExternalVkImageBacking::CreateFromGMB(
context_state->vk_context_provider()->GetVulkanImplementation();
auto resource_format = viz::GetResourceFormat(buffer_format);
auto* device_queue = context_state->vk_context_provider()->GetDeviceQueue();
if (vulkan_implementation->CanImportGpuMemoryBuffer(device_queue,
handle.type)) {
VkFormat vk_format = ToVkFormat(resource_format);
auto image = vulkan_implementation->CreateImageFromGpuMemoryHandle(
device_queue, std::move(handle), size, vk_format, color_space);
if (!image) {
DLOG(ERROR) << "Failed to create VkImage from GpuMemoryHandle.";
return nullptr;
}

bool use_separate_gl_texture =
UseSeparateGLTexture(context_state.get(), resource_format);
auto backing = std::make_unique<ExternalVkImageBacking>(
base::PassKey<ExternalVkImageBacking>(), mailbox, resource_format, size,
color_space, surface_origin, alpha_type, usage,
std::move(context_state), std::move(image), command_pool,
use_separate_gl_texture);
backing->SetCleared();
return backing;
}

if (gfx::NumberOfPlanesForLinearBufferFormat(buffer_format) != 1) {
DLOG(ERROR) << "Invalid image format.";
DCHECK(vulkan_implementation->CanImportGpuMemoryBuffer(device_queue,
handle.type));

VkFormat vk_format = ToVkFormat(resource_format);
auto image = vulkan_implementation->CreateImageFromGpuMemoryHandle(
device_queue, std::move(handle), size, vk_format, color_space);
if (!image) {
DLOG(ERROR) << "Failed to create VkImage from GpuMemoryHandle.";
return nullptr;
}

DCHECK_EQ(handle.type, gfx::SHARED_MEMORY_BUFFER);

SharedMemoryRegionWrapper shared_memory_wrapper;
if (!shared_memory_wrapper.Initialize(handle, size, resource_format))
return nullptr;

auto backing = Create(std::move(context_state), command_pool, mailbox,
resource_format, size, color_space, surface_origin,
alpha_type, usage, image_usage_cache,
base::span<const uint8_t>(), true /* using_gmb */);
if (!backing)
return nullptr;

backing->InstallSharedMemory(std::move(shared_memory_wrapper));
bool use_separate_gl_texture =
UseSeparateGLTexture(context_state.get(), resource_format);
auto backing = std::make_unique<ExternalVkImageBacking>(
base::PassKey<ExternalVkImageBacking>(), mailbox, resource_format, size,
color_space, surface_origin, alpha_type, usage, std::move(context_state),
std::move(image), command_pool, use_separate_gl_texture);
backing->SetCleared();
return backing;
}

Expand Down Expand Up @@ -471,7 +451,7 @@ void ExternalVkImageBacking::EndAccess(bool readonly,
if (use_separate_gl_texture()) {
latest_content_ = is_gl ? kInGLTexture : kInVkImage;
} else {
latest_content_ = kInVkImage | kInGLTexture;
latest_content_ = kInVkImage;
}
}

Expand Down Expand Up @@ -514,8 +494,22 @@ SharedImageBackingType ExternalVkImageBacking::GetType() const {

void ExternalVkImageBacking::Update(std::unique_ptr<gfx::GpuFence> in_fence) {
DCHECK(!in_fence);
latest_content_ = kInSharedMemory;
}

bool ExternalVkImageBacking::UploadFromMemory(const SkPixmap& pixmap) {
if (!UploadToVkImage(pixmap))
return false;

SetCleared();
latest_content_ = kInVkImage;

// Also upload to GL texture if there is a separate one.
if (use_separate_gl_texture() && (texture_ || texture_passthrough_)) {
UploadToGLTexture(pixmap);
latest_content_ |= kInGLTexture;
}

return true;
}

void ExternalVkImageBacking::AddSemaphoresToPendingListOrRelease(
Expand Down Expand Up @@ -773,51 +767,27 @@ ExternalVkImageBacking::ProduceOverlay(SharedImageManager* manager,
manager, this, tracker);
}

void ExternalVkImageBacking::InstallSharedMemory(
SharedMemoryRegionWrapper shared_memory_wrapper) {
DCHECK(!shared_memory_wrapper_.IsValid());
DCHECK(shared_memory_wrapper.IsValid());
shared_memory_wrapper_ = std::move(shared_memory_wrapper);
Update(nullptr);
}

void ExternalVkImageBacking::UpdateContent(uint32_t content_flags) {
// Only support one backing for now.
DCHECK(content_flags == kInVkImage || content_flags == kInGLTexture ||
content_flags == kInSharedMemory);
DCHECK(content_flags == kInVkImage || content_flags == kInGLTexture);

if ((latest_content_ & content_flags) == content_flags)
// There is no need to update content when there is only one texture.
if (!use_separate_gl_texture())
return;

if (content_flags == kInGLTexture && !use_separate_gl_texture())
content_flags = kInVkImage;
if ((latest_content_ & content_flags) == content_flags)
return;

if (content_flags == kInVkImage) {
if (latest_content_ & kInSharedMemory) {
if (!shared_memory_wrapper_.IsValid())
return;
if (!WritePixels())
return;
latest_content_ |=
use_separate_gl_texture() ? kInVkImage : kInVkImage | kInGLTexture;
return;
}
if ((latest_content_ & kInGLTexture) && use_separate_gl_texture()) {
if ((latest_content_ & kInGLTexture)) {
CopyPixelsFromGLTextureToVkImage();
latest_content_ |= kInVkImage;
return;
}
} else if (content_flags == kInGLTexture) {
DCHECK(use_separate_gl_texture());
if (latest_content_ & kInSharedMemory) {
CopyPixelsFromShmToGLTexture();
} else if (latest_content_ & kInVkImage) {
if (latest_content_ & kInVkImage) {
CopyPixelsFromVkImageToGLTexture();
latest_content_ |= kInGLTexture;
}
} else if (content_flags == kInSharedMemory) {
// TODO(penghuang): read pixels back from VkImage to shared memory GMB, if
// this feature is needed.
NOTIMPLEMENTED_LOG_ONCE();
}
}

Expand Down Expand Up @@ -1000,9 +970,7 @@ bool ExternalVkImageBacking::ReadPixelsWithCallback(
return true;
}

bool ExternalVkImageBacking::WritePixelsWithData(
base::span<const uint8_t> pixel_data,
size_t stride) {
bool ExternalVkImageBacking::UploadToVkImage(const SkPixmap& pixmap) {
std::vector<ExternalSemaphore> external_semaphores;
if (!BeginAccessInternal(false /* readonly */, &external_semaphores)) {
DLOG(ERROR) << "BeginAccess() failed.";
Expand All @@ -1011,7 +979,6 @@ bool ExternalVkImageBacking::WritePixelsWithData(
auto* gr_context = context_state_->gr_context();
WaitSemaphoresOnGrContext(gr_context, &external_semaphores);

SkPixmap pixmap(AsSkImageInfo(), pixel_data.data(), stride);
if (!gr_context->updateBackendTexture(backend_texture_, &pixmap,
/*numLevels=*/1, nullptr, nullptr)) {
DLOG(ERROR) << "updateBackendTexture() failed.";
Expand Down Expand Up @@ -1049,11 +1016,6 @@ bool ExternalVkImageBacking::WritePixelsWithData(
return true;
}

bool ExternalVkImageBacking::WritePixels() {
return WritePixelsWithData(shared_memory_wrapper_.GetMemoryAsSpan(),
shared_memory_wrapper_.GetStride());
}

void ExternalVkImageBacking::CopyPixelsFromGLTextureToVkImage() {
DCHECK(use_separate_gl_texture());
DCHECK_NE(!!texture_, !!texture_passthrough_);
Expand Down Expand Up @@ -1167,7 +1129,7 @@ void ExternalVkImageBacking::CopyPixelsFromVkImageToGLTexture() {
api, size(), gl_format, gl_type));
}

void ExternalVkImageBacking::CopyPixelsFromShmToGLTexture() {
void ExternalVkImageBacking::UploadToGLTexture(const SkPixmap& pixmap) {
DCHECK(use_separate_gl_texture());
DCHECK_NE(!!texture_, !!texture_passthrough_);
const GLuint texture_service_id =
Expand Down Expand Up @@ -1208,10 +1170,8 @@ void ExternalVkImageBacking::CopyPixelsFromShmToGLTexture() {
checked_size *= size().height();
DCHECK(checked_size.IsValid());

auto pixel_data = shared_memory_wrapper_.GetMemoryAsSpan();
api->glTexSubImage2DFn(GL_TEXTURE_2D, 0, 0, 0, size().width(),
size().height(), gl_format, gl_type,
pixel_data.data());
size().height(), gl_format, gl_type, pixmap.addr());
DCHECK_EQ(api->glGetErrorFn(), static_cast<GLenum>(GL_NO_ERROR));
}

Expand Down
Expand Up @@ -135,6 +135,7 @@ class ExternalVkImageBacking final : public ClearTrackingSharedImageBacking {
// SharedImageBacking implementation.
SharedImageBackingType GetType() const override;
void Update(std::unique_ptr<gfx::GpuFence> in_fence) override;
bool UploadFromMemory(const SkPixmap& pixmap) override;
scoped_refptr<gfx::NativePixmap> GetNativePixmap() override;

// Add semaphores to a pending list for reusing or being released immediately.
Expand Down Expand Up @@ -172,8 +173,6 @@ class ExternalVkImageBacking final : public ClearTrackingSharedImageBacking {
MemoryTypeTracker* tracker) override;

private:
// Install a shared memory GMB to the backing.
void InstallSharedMemory(SharedMemoryRegionWrapper shared_memory_wrapper);
// Returns texture_service_id for ProduceGLTexture and GLTexturePassthrough.
GLuint ProduceGLTextureInternal();

Expand All @@ -187,10 +186,9 @@ class ExternalVkImageBacking final : public ClearTrackingSharedImageBacking {
bool ReadPixelsWithCallback(size_t data_size,
size_t stride,
ReadBufferCallback callback);
bool WritePixelsWithData(base::span<const uint8_t> pixel_data, size_t stride);
bool WritePixels();
bool UploadToVkImage(const SkPixmap& pixmap);
void UploadToGLTexture(const SkPixmap& pixmap);
void CopyPixelsFromGLTextureToVkImage();
void CopyPixelsFromShmToGLTexture();
void CopyPixelsFromVkImageToGLTexture();

scoped_refptr<SharedContextState> context_state_;
Expand All @@ -208,13 +206,9 @@ class ExternalVkImageBacking final : public ClearTrackingSharedImageBacking {
raw_ptr<gles2::Texture> texture_ = nullptr;
scoped_refptr<gles2::TexturePassthrough> texture_passthrough_;

// GMB related stuff.
SharedMemoryRegionWrapper shared_memory_wrapper_;

enum LatestContent {
kInVkImage = 1 << 0,
kInSharedMemory = 1 << 1,
kInGLTexture = 1 << 2,
kInGLTexture = 1 << 1,
};
uint32_t latest_content_ = 0;

Expand Down
Expand Up @@ -155,9 +155,8 @@ bool ExternalVkImageBackingFactory::CanImportGpuMemoryBuffer(
gfx::GpuMemoryBufferType memory_buffer_type) {
auto* device_queue = context_state_->vk_context_provider()->GetDeviceQueue();
return context_state_->vk_context_provider()
->GetVulkanImplementation()
->CanImportGpuMemoryBuffer(device_queue, memory_buffer_type) ||
memory_buffer_type == gfx::SHARED_MEMORY_BUFFER;
->GetVulkanImplementation()
->CanImportGpuMemoryBuffer(device_queue, memory_buffer_type);
}

bool ExternalVkImageBackingFactory::IsSupported(
Expand All @@ -174,8 +173,7 @@ bool ExternalVkImageBackingFactory::IsSupported(

// TODO(crbug.com/969114): Not all shared image factory implementations
// support concurrent read/write usage.
constexpr uint32_t kInvalidUsages =
SHARED_IMAGE_USAGE_CONCURRENT_READ_WRITE | SHARED_IMAGE_USAGE_CPU_UPLOAD;
constexpr uint32_t kInvalidUsages = SHARED_IMAGE_USAGE_CONCURRENT_READ_WRITE;
if (usage & kInvalidUsages) {
return false;
}
Expand Down
24 changes: 12 additions & 12 deletions gpu/command_buffer/service/shared_image/shared_image_factory.cc
Expand Up @@ -359,7 +359,17 @@ bool SharedImageFactory::CreateSharedImage(const Mailbox& mailbox,

bool use_compound = false;
auto* factory = GetFactoryByUsage(usage, resource_format, size,
/*pixel_data=*/{}, gmb_type, &use_compound);
/*pixel_data=*/{}, gmb_type);

if (!factory && gmb_type == gfx::SHARED_MEMORY_BUFFER) {
// Check if CompoundImageBacking can hold shared memory buffer plus
// another GPU backing type to satisfy requirements.
use_compound = true;
factory = GetFactoryByUsage(usage | SHARED_IMAGE_USAGE_CPU_UPLOAD,
resource_format, size,
/*pixel_data=*/{}, gfx::EMPTY_BUFFER);
}

if (!factory)
return false;

Expand Down Expand Up @@ -564,8 +574,7 @@ SharedImageBackingFactory* SharedImageFactory::GetFactoryByUsage(
viz::ResourceFormat format,
const gfx::Size& size,
base::span<const uint8_t> pixel_data,
gfx::GpuMemoryBufferType gmb_type,
bool* use_compound_backing) {
gfx::GpuMemoryBufferType gmb_type) {
if (backing_factory_for_testing_)
return backing_factory_for_testing_;

Expand All @@ -574,15 +583,6 @@ SharedImageBackingFactory* SharedImageFactory::GetFactoryByUsage(
if (factory->IsSupported(usage, format, size, share_between_threads,
gmb_type, gr_context_type_, pixel_data)) {
return factory.get();
} else if (use_compound_backing && gmb_type == gfx::SHARED_MEMORY_BUFFER) {
// Check if backing type supports CPU upload with no buffer handle so it
// can be used with a compound backing instead.
if (factory->IsSupported(usage | SHARED_IMAGE_USAGE_CPU_UPLOAD, format,
size, share_between_threads, gfx::EMPTY_BUFFER,
gr_context_type_, pixel_data)) {
*use_compound_backing = true;
return factory.get();
}
}
}

Expand Down
Expand Up @@ -132,17 +132,12 @@ class GPU_GLES2_EXPORT SharedImageFactory {
private:
bool IsSharedBetweenThreads(uint32_t usage);

// If `use_compound_backing` is not null and `gmb_type` is
// gfx::SHARED_MEMORY_BUFFER then we'll see if factory can be used with a
// compound backing. This is temporary until all backing types support
// compound backings.
SharedImageBackingFactory* GetFactoryByUsage(
uint32_t usage,
viz::ResourceFormat format,
const gfx::Size& size,
base::span<const uint8_t> pixel_data,
gfx::GpuMemoryBufferType gmb_type,
bool* use_compound_backing = nullptr);
gfx::GpuMemoryBufferType gmb_type);

raw_ptr<SharedImageManager> shared_image_manager_;
raw_ptr<SharedContextState> shared_context_state_;
Expand Down

0 comments on commit e06e2b9

Please sign in to comment.