Chrome · GPU
CVE-2026-113324
UAF in GPU
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifgpu/command_buffer/service/shared_image/external_vk_image_backing.cc |
modified | |
forgpu/command_buffer/service/shared_image/external_vk_image_backing.cc |
modified | |
VulkanCommandPoolgpu/command_buffer/service/shared_image/external_vk_image_backing.h |
modified | |
VulkanImagegpu/command_buffer/service/shared_image/external_vk_image_backing.h |
modified | |
ExternalVkImageBackinggpu/command_buffer/service/shared_image/external_vk_image_backing.h |
modified | |
GPU_GLES2_EXPORTgpu/command_buffer/service/shared_image/external_vk_image_backing.h |
modified | |
TEST_Fgpu/command_buffer/service/shared_image/external_vk_image_backing_factory_unittest.cc |
modified |
Files Changed
gpu/command_buffer/service/shared_image/external_vk_image_backing.ccgpu/command_buffer/service/shared_image/external_vk_image_dawn_representation.cctesting/buildbot/filters/linux.swiftshader.tsan.gl_tests_passthrough.filtergpu/command_buffer/service/shared_image/external_vk_image_backing.hgpu/command_buffer/service/shared_image/external_vk_image_backing_factory_unittest.cc
Patch
From 7f1931770c353b2770af4c8bdd15e0f20b7dbb01 Mon Sep 17 00:00:00 2001
From: Tom Anderson <thomasanderson@chromium.org>
Date: Wed, 07 Oct 2026 17:12:04 -0700
Subject: [PATCH] Sync separate GL texture content on write access in ExternalVkImageBacking
crrev.com/c/8436737 made ExternalVkImageBacking reject the separate GL
texture mode under WebGPU GL-Vk interop and stopped UpdateContent() from
masking failed copies. This handles the remaining issues:
- The interop/separate-GL bail-outs in Create() and CreateFromGMB() ran
after the VkImage(s) had been allocated/imported. Returning nullptr
there drops VulkanImages without calling Destroy(), which hits
DCHECK(!device_queue_) and leaks the images in release builds. Move
the checks ahead of any allocation. Likewise, destroy the images
already allocated for earlier planes if a later plane fails to
allocate in Create().
- BeginAccess() only synchronized content between the separate GL
texture and the VkImage on read-only access. On write/read-write
access EndAccess() then marks the written side as exclusively holding
the latest content, so a partial write or READWRITE access that does
not overwrite everything exposes stale or uninitialized storage.
Synchronize the accessed side on write accesses too, after rejecting
conflicting accesses up front so no copy runs for an access that will
fail.
- Only report descriptor.isInitialized to Dawn when the VkImage holds
the latest content, so a failed GL->Vk sync is not treated as valid
data.
Bug: 563357593
Fixed: 563357593
Change-Id: I8a492e00009eb89f87695f3d296ca13a380d166b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8427415
Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
Reviewed-by: vikas soni <vikassoni@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1714023}
---
diff --git a/gpu/command_buffer/service/shared_image/external_vk_image_backing.cc b/gpu/command_buffer/service/shared_image/external_vk_image_backing.cc
index 766c4b77..09e1dc43 100644
--- a/gpu/command_buffer/service/shared_image/external_vk_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/external_vk_image_backing.cc
@@ -171,6 +171,22 @@
base::span<const uint8_t> pixel_data) {
auto format = si_info.format;
auto usage = si_info.usage;
+
+ bool use_separate_gl_texture =
+ ExternalVkImageBacking::UseSeparateGLTexture(context_state.get(), format);
+ // The separate GL texture path keeps an independent GL texture in sync with
+ // the VkImage by copying pixels on access. WebGPU interop requires a single
+ // allocation aliased into both APIs, and ExternalVkImageBackingFactory
+ // already refuses formats that would end up here, so this is unreachable
+ // unless a caller bypasses IsSupported(). Fail rather than silently handing
+ // back a backing that cannot keep its two copies coherent. This must happen
+ // before any VulkanImage is allocated, since those must be explicitly
+ // destroyed.
+ if (enable_webgpu_on_vk_via_gl_interop && use_separate_gl_texture) {
+ DLOG(ERROR) << "Separate GL texture is not supported with WebGPU interop";
+ return nullptr;
+ }
+
bool is_external = context_state->support_vulkan_external_object();
auto* device_queue = context_state->vk_context_provider()->GetDeviceQueue();
@@ -232,6 +248,11 @@
VK_IMAGE_TILING_OPTIMAL);
}
if (!image) {
+ // VulkanImages must be explicitly destroyed, so release the images
+ // already allocated for earlier planes.
+ for (auto& texture : textures) {
+ texture.vulkan_image->Destroy();
+ }
return nullptr;
}
@@ -239,18 +260,6 @@
textures.emplace_back(std::move(image), format, si_info.color_space);
}
- bool use_separate_gl_texture =
- ExternalVkImageBacking::UseSeparateGLTexture(context_state.get(), format);
- // The separate GL texture path keeps an independent GL texture in sync with
- // the VkImage by copying pixels on access. WebGPU interop requires a single
- // allocation aliased into both APIs, and ExternalVkImageBackingFactory
- // already refuses formats that would end up here, so this is unreachable
- // unless a caller bypasses IsSupported(). Fail rather than silently handing
- // back a backing that cannot keep its two copies coherent.
- if (enable_webgpu_on_vk_via_gl_interop && use_separate_gl_texture) {
- DLOG(ERROR) << "Separate GL texture is not supported with WebGPU interop";
- return nullptr;
- }
auto backing = std::make_unique<ExternalVkImageBacking>(
base::PassKey<ExternalVkImageBacking>(), mailbox, si_info, estimated_size,
std::move(context_state), std::move(textures), command_pool,
@@ -295,6 +304,14 @@
return nullptr;
}
+ bool use_separate_gl_texture =
+ ExternalVkImageBacking::UseSeparateGLTexture(context_state.get(), format);
+ // See the comment on the same check in Create().
+ if (enable_webgpu_on_vk_via_gl_interop && use_separate_gl_texture) {
+ DLOG(ERROR) << "Separate GL texture is not supported with WebGPU interop";
+ return nullptr;
+ }
+
auto* vulkan_implementation =
context_state->vk_context_provider()->GetVulkanImplementation();
auto* device_queue = context_state->vk_context_provider()->GetDeviceQueue();
@@ -319,13 +336,6 @@
textures.reserve(1);
textures.emplace_back(std::move(image), format, color_space);
- bool use_separate_gl_texture =
- ExternalVkImageBacking::UseSeparateGLTexture(context_state.get(), format);
- // See the comment on the same check in Create().
- if (enable_webgpu_on_vk_via_gl_interop && use_separate_gl_texture) {
- DLOG(ERROR) << "Separate GL texture is not supported with WebGPU interop";
- return nullptr;
- }
auto backing = std::make_unique<ExternalVkImageBacking>(
base::PassKey<ExternalVkImageBacking>(), mailbox, si_info, estimated_size,
std::move(context_state), std::move(textures), command_pool,
@@ -474,6 +484,12 @@
return true;
}
+ if (is_write_in_progress_ || (!readonly && reads_in_progress_)) {
+ DLOG(ERROR) << "Unable to begin read or write access because another "
+ "conflicting access is in progress";
+ return false;
+ }
+
if (readonly && !reads_in_progress_) {
if (!is_updating_content_) {
UpdateContent(kInVkImage);
@@ -481,6 +497,8 @@
if (!gl_textures_.empty() && !is_updating_content_) {
UpdateContent(kInGLTexture);
}
+ } else if (!readonly && !is_updating_content_) {
+ UpdateContent(is_gl ? kInGLTexture : kInVkImage);
}
if (gl_reads_in_progress_ && need_synchronization()) {
diff --git a/gpu/command_buffer/service/shared_image/external_vk_image_backing.h b/gpu/command_buffer/service/shared_image/external_vk_image_backing.h
index 39fb77bc..23724ea 100644
--- a/gpu/command_buffer/service/shared_image/external_vk_image_backing.h
+++ b/gpu/command_buffer/service/shared_image/external_vk_image_backing.h
@@ -21,6 +21,7 @@
#include "gpu/command_buffer/service/shared_image/texture_holder_vk.h"
#include "gpu/command_buffer/service/shared_memory_region_wrapper.h"
#include "gpu/command_buffer/service/vulkan_context_provider.h"
+#include "gpu/gpu_gles2_export.h"
#include "gpu/ipc/common/surface_handle.h"
#include "gpu/vulkan/vulkan_device_queue.h"
#include "third_party/skia/include/private/chromium/GrPromiseImageTexture.h"
@@ -32,7 +33,8 @@
class VulkanCommandPool;
class VulkanImage;
-class ExternalVkImageBacking final : public ClearTrackingSharedImageBacking {
+class GPU_GLES2_EXPORT ExternalVkImageBacking final
+ : public ClearTrackingSharedImageBacking {
public:
static std::unique_ptr<ExternalVkImageBacking> Create(
scoped_refptr<SharedContextState> context_state,
@@ -107,6 +109,9 @@
bool enable_webgpu_on_vk_via_gl_interop() const {
return enable_webgpu_on_vk_via_gl_interop_;
}
+ bool HasLatestContentInVkImage() const {
+ return (latest_content_ & kInVkImage) != 0;
+ }
bool need_synchronization() const {
if (usage().HasAny(SHARED_IMAGE_USAGE_WEBGPU_READ |
diff --git a/gpu/command_buffer/service/shared_image/external_vk_image_dawn_representation.cc b/gpu/command_buffer/service/shared_image/external_vk_image_dawn_representation.cc
index d45a90f..f2c17c6 100644
--- a/gpu/command_buffer/service/shared_image/external_vk_image_dawn_representation.cc
+++ b/gpu/command_buffer/service/shared_image/external_vk_image_dawn_representation.cc
@@ -88,7 +88,8 @@
dawn::native::vulkan::ExternalImageDescriptorOpaqueFD descriptor = {};
descriptor.cTextureDescriptor =
reinterpret_cast<WGPUTextureDescriptor*>(&texture_descriptor);
- descriptor.isInitialized = IsCleared();
+ descriptor.isInitialized =
+ IsCleared() && backing_impl()->HasLatestContentInVkImage();
descriptor.allocationSize = backing_impl()->image()->device_size();
descriptor.memoryTypeIndex = backing_impl()->image()->memory_type_index();
descriptor.memoryFD = dup(memory_fd_.get());
diff --git a/testing/buildbot/filters/linux.swiftshader.tsan.gl_tests_passthrough.filter b/testing/buildbot/filters/linux.swiftshader.tsan.gl_tests_passthrough.filter
index 8a826c5..a9f41df 100644
--- a/testing/buildbot/filters/linux.swiftshader.tsan.gl_tests_passthrough.filter
+++ b/testing/buildbot/filters/linux.swiftshader.tsan.gl_tests_passthrough.filter
@@ -1,4 +1,6 @@
# crbug.com/462477487
+-ExternalVkImageBackingFactoryTest.InteropRejectsSeparateGLTexture
+-ExternalVkImageBackingFactoryTest.SeparateGLTextureWriteAccessSyncsContent
-ExternalVkImageBackingFactoryWithFormatTest.Basic/*
-ExternalVkImageBackingFactoryWithFormatTest.InitialPixelUpload*/*
-ExternalVkImageBackingFactoryWithFormatTest.ReadbackToMemory/*
diff --git a/gpu/command_buffer/service/shared_image/external_vk_image_backing_factory_unittest.cc b/gpu/command_buffer/service/shared_image/external_vk_image_backing_factory_unittest.cc
index 380f99e..03cf375 100644
--- a/gpu/command_buffer/service/shared_image/external_vk_image_backing_factory_unittest.cc
+++ b/gpu/command_buffer/service/shared_image/external_vk_image_backing_factory_unittest.cc
@@ -16,6 +16,7 @@
#include "components/viz/common/resources/shared_image_format.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/external_vk_image_backing.h"
#include "gpu/command_buffer/service/shared_image/external_vk_image_dawn_representation.h"
#include "gpu/command_buffer/service/shared_image/external_vk_image_skia_representation.h"
#include "gpu/command_buffer/service/shared_image/shared_image_factory.h"
@@ -704,5 +705,149 @@
kSharedImageFormats,
TestParamToString);
+#if BUILDFLAG(USE_WEBGPU_ON_VULKAN_VIA_GL_INTEROP)
+TEST_F(ExternalVkImageBackingFactoryTest, InteropRejectsSeparateGLTexture) {
+ const auto format = viz::SinglePlaneFormat::kBGRA_8888;
+ if (!ExternalVkImageBacking::UseSeparateGLTexture(context_state_.get(),
+ format)) {
+ GTEST_SKIP() << "Test requires separate GL texture mode";
+ }
+
+ auto interop_factory = std::make_unique<ExternalVkImageBackingFactory>(
+ context_state_, /*enable_webgpu_on_vk_via_gl_interop=*/true);
+
+ const gfx::Size size(64, 64);
+ const auto color_space = gfx::ColorSpace::CreateSRGB();
+ const gpu::SharedImageUsageSet usage =
+ SHARED_IMAGE_USAGE_WEBGPU_READ | SHARED_IMAGE_USAGE_WEBGPU_WRITE |
+ SHARED_IMAGE_USAGE_GLES2_READ | SHARED_IMAGE_USAGE_GLES2_WRITE;
+
+ EXPECT_FALSE(interop_factory->IsSupported(
+ usage, format, size, /*thread_safe=*/false, gfx::EMPTY_BUFFER,
+ GrContextType::kGL, /*pixel_data=*/{}));
+
+ auto backing = interop_factory->CreateSharedImage(
+ Mailbox::Generate(),
+ {format, size, color_space, kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
+ usage, "TestInteropSeparateGL"},
+ gpu::kNullSurfaceHandle, /*is_thread_safe=*/false);
+ EXPECT_EQ(backing, nullptr);
+}
+#endif // BUILDFLAG(USE_WEBGPU_ON_VULKAN_VIA_GL_INTEROP)
+
+TEST_F(ExternalVkImageBackingFactoryTest,
+ SeparateGLTextureWriteAccessSyncsContent) {
+ const auto format = viz::SinglePlaneFormat::kBGRA_8888;
+ if (!ExternalVkImageBacking::UseSeparateGLTexture(context_state_.get(),
+ format)) {
+ GTEST_SKIP() << "Test requires separate GL texture mode";
+ }
+
+ auto mailbox = Mailbox::Generate();
+ const gfx::Size size(16, 16);
+ const auto color_space = gfx::ColorSpace::CreateSRGB();
+ const gpu::SharedImageUsageSet usage =
+ SHARED_IMAGE_USAGE_DISPLAY_READ | SHARED_IMAGE_USAGE_RASTER_WRITE |
+ SHARED_IMAGE_USAGE_GLES2_READ | SHARED_IMAGE_USAGE_GLES2_WRITE;
+
+ auto backing = backing_factory_->CreateSharedImage(
+ mailbox,
+ {format, size, color_space, kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
+ usage, "TestSeparateGLSync"},
+ gpu::kNullSurfaceHandle, /*is_thread_safe=*/false);
+ ASSERT_TRUE(backing);
+
+ auto* vk_backing = static_cast<ExternalVkImageBacking*>(backing.get());
+ ASSERT_TRUE(vk_backing->use_separate_gl_texture());
+ EXPECT_FALSE(vk_backing->HasLatestContentInVkImage());
+
+ std::unique_ptr<SharedImageRepresentationFactoryRef> shared_image =
+ shared_image_manager_.Register(std::move(backing), &memory_type_tracker_);
+ ASSERT_TRUE(shared_image);
+
+ // Write red pixels using Skia (Vulkan) write access.
+ std::vector<SkBitmap> red_bitmaps = AllocateRedBitmaps(format, size);
+ {
+ auto skia_representation = shared_image_representation_factory_.ProduceSkia(
+ mailbox, context_state_.get());
+ ASSERT_TRUE(skia_representation);
+
+ std::vector<GrBackendSemaphore> begin_semaphores;
+ std::vector<GrBackendSemaphore> end_semaphores;
+ auto scoped_write = skia_representation->BeginScopedWriteAccess(
+ &begin_semaphores, &end_semaphores,
+ SharedImageRepresentation::AllowUnclearedAccess::kYes);
+ ASSERT_TRUE(scoped_write);
+ scoped_write->surface()->writePixels(red_bitmaps[0], 0, 0);
+ scoped_write->ApplyBackendSurfaceEndState();
+ if (!end_semaphores.empty()) {
+ GrFlushInfo flush_info = {
+ .fNumSemaphores = end_semaphores.size(),
+ .fSignalSemaphores = end_semaphores.data(),
+ };
+ gr_context()->flush(scoped_write->surface(), flush_info, nullptr);
+ gr_context()->submit();
+ }
+ skia_representation->SetCleared();
+ }
+ EXPECT_TRUE(vk_backing->HasLatestContentInVkImage());
+
+ // Perform a GL READWRITE access without modifying the GL texture. The
+ // Vulkan-side content must be synchronized into the separate GL texture on
+ // BeginAccess so that when EndAccess marks the GL texture as holding the
+ // latest content, it is not stale/uninitialized.
+ if (use_passthrough()) {
+ auto gl_representation =
+ shared_image_representation_factory_.ProduceGLTexturePassthrough(
+ mailbox);
+ ASSERT_TRUE(gl_representation);
+ auto scoped_access = gl_representation->BeginScopedAccess(
+ GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM,
+ SharedImageRepresentation::AllowUnclearedAccess::kNo);
+ ASSERT_TRUE(scoped_access);
+ } else {
+ auto gl_representation =
+ shared_image_representation_factory_.ProduceGLTexture(mailbox);
+ ASSERT_TRUE(gl_representation);
+ auto scoped_access = gl_representation->BeginScopedAccess(
+ GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM,
+ SharedImageRepresentation::AllowUnclearedAccess::kNo);
+ ASSERT_TRUE(scoped_access);
+ }
+
+ // After the GL READWRITE access ends, latest_content_ is exclusively
+ // kInGLTexture until the next Vulkan access synchronizes it back.
+ EXPECT_FALSE(vk_backing->HasLatestContentInVkImage());
+
+ // Now begin a Vulkan write access (mirroring Dawn/Skia write-mode
+ // BeginAccess) and verify that BeginAccess synchronizes the GL texture back
+ // to VkImage.
+ {
+ auto skia_representation = shared_image_representation_factory_.ProduceSkia(
+ mailbox, context_state_.get());
+ ASSERT_TRUE(skia_representation);
+
+ std::vector<GrBackendSemaphore> begin_semaphores;
+ std::vector<GrBackendSemaphore> end_semaphores;
+ auto scoped_write = skia_representation->BeginScopedWriteAccess(
+ &begin_semaphores, &end_semaphores,
+ SharedImageRepresentation::AllowUnclearedAccess::kNo);
+ ASSERT_TRUE(scoped_write);
+ EXPECT_TRUE(vk_backing->HasLatestContentInVkImage());
+
+ scoped_write->ApplyBackendSurfaceEndState();
+ if (!end_semaphores.empty()) {
+ GrFlushInfo flush_info = {
+ .fNumSemaphores = end_semaphores.size(),
+ .fSignalSemaphores = end_semaphores.data(),
+ };
+ gr_context()->flush(scoped_write->surface(), flush_info, nullptr);
+ gr_context()->submit();
+ }
+ }
+
+ VerifyPixelsWithReadbackGanesh(mailbox, red_bitmaps);
+}
+
} // anonymous namespace
} // namespace gpu
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/gpu/command_buffer/service/shared_image/external_vk_image_backing_factory_unittest.cc b/gpu/command_buffer/service/shared_image/external_vk_image_backing_factory_unittest.cc
index 380f99e..03cf375 100644
--- a/gpu/command_buffer/service/shared_image/external_vk_image_backing_factory_unittest.cc
+++ b/gpu/command_buffer/service/shared_image/external_vk_image_backing_factory_unittest.cc
@@ -16,6 +16,7 @@
#include "components/viz/common/resources/shared_image_format.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/external_vk_image_backing.h"
#include "gpu/command_buffer/service/shared_image/external_vk_image_dawn_representation.h"
#include "gpu/command_buffer/service/shared_image/external_vk_image_skia_representation.h"
#include "gpu/command_buffer/service/shared_image/shared_image_factory.h"
@@ -704,5 +705,149 @@
kSharedImageFormats,
TestParamToString);
+#if BUILDFLAG(USE_WEBGPU_ON_VULKAN_VIA_GL_INTEROP)
+TEST_F(ExternalVkImageBackingFactoryTest, InteropRejectsSeparateGLTexture) {
+ const auto format = viz::SinglePlaneFormat::kBGRA_8888;
+ if (!ExternalVkImageBacking::UseSeparateGLTexture(context_state_.get(),
+ format)) {
+ GTEST_SKIP() << "Test requires separate GL texture mode";
+ }
+
+ auto interop_factory = std::make_unique<ExternalVkImageBackingFactory>(
+ context_state_, /*enable_webgpu_on_vk_via_gl_interop=*/true);
+
+ const gfx::Size size(64, 64);
+ const auto color_space = gfx::ColorSpace::CreateSRGB();
+ const gpu::SharedImageUsageSet usage =
+ SHARED_IMAGE_USAGE_WEBGPU_READ | SHARED_IMAGE_USAGE_WEBGPU_WRITE |
+ SHARED_IMAGE_USAGE_GLES2_READ | SHARED_IMAGE_USAGE_GLES2_WRITE;
+
+ EXPECT_FALSE(interop_factory->IsSupported(
+ usage, format, size, /*thread_safe=*/false, gfx::EMPTY_BUFFER,
+ GrContextType::kGL, /*pixel_data=*/{}));
+
+ auto backing = interop_factory->CreateSharedImage(
+ Mailbox::Generate(),
+ {format, size, color_space, kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
+ usage, "TestInteropSeparateGL"},
+ gpu::kNullSurfaceHandle, /*is_thread_safe=*/false);
+ EXPECT_EQ(backing, nullptr);
+}
+#endif // BUILDFLAG(USE_WEBGPU_ON_VULKAN_VIA_GL_INTEROP)
+
+TEST_F(ExternalVkImageBackingFactoryTest,
+ SeparateGLTextureWriteAccessSyncsContent) {
+ const auto format = viz::SinglePlaneFormat::kBGRA_8888;
+ if (!ExternalVkImageBacking::UseSeparateGLTexture(context_state_.get(),
+ format)) {
+ GTEST_SKIP() << "Test requires separate GL texture mode";
+ }
+
+ auto mailbox = Mailbox::Generate();
+ const gfx::Size size(16, 16);
+ const auto color_space = gfx::ColorSpace::CreateSRGB();
+ const gpu::SharedImageUsageSet usage =
+ SHARED_IMAGE_USAGE_DISPLAY_READ | SHARED_IMAGE_USAGE_RASTER_WRITE |
+ SHARED_IMAGE_USAGE_GLES2_READ | SHARED_IMAGE_USAGE_GLES2_WRITE;
+
+ auto backing = backing_factory_->CreateSharedImage(
+ mailbox,
+ {format, size, color_space, kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
+ usage, "TestSeparateGLSync"},
+ gpu::kNullSurfaceHandle, /*is_thread_safe=*/false);
+ ASSERT_TRUE(backing);
+
+ auto* vk_backing = static_cast<ExternalVkImageBacking*>(backing.get());
+ ASSERT_TRUE(vk_backing->use_separate_gl_texture());
+ EXPECT_FALSE(vk_backing->HasLatestContentInVkImage());
+
+ std::unique_ptr<SharedImageRepresentationFactoryRef> shared_image =
+ shared_image_manager_.Register(std::move(backing), &memory_type_tracker_);
+ ASSERT_TRUE(shared_image);
+
+ // Write red pixels using Skia (Vulkan) write access.
+ std::vector<SkBitmap> red_bitmaps = AllocateRedBitmaps(format, size);
+ {
+ auto skia_representation = shared_image_representation_factory_.ProduceSkia(
+ mailbox, context_state_.get());
+ ASSERT_TRUE(skia_representation);
+
+ std::vector<GrBackendSemaphore> begin_semaphores;
+ std::vector<GrBackendSemaphore> end_semaphores;
+ auto scoped_write = skia_representation->BeginScopedWriteAccess(
+ &begin_semaphores, &end_semaphores,
+ SharedImageRepresentation::AllowUnclearedAccess::kYes);
+ ASSERT_TRUE(scoped_write);
+ scoped_write->surface()->writePixels(red_bitmaps[0], 0, 0);
+ scoped_write->ApplyBackendSurfaceEndState();
+ if (!end_semaphores.empty()) {
+ GrFlushInfo flush_info = {
+ .fNumSemaphores = end_semaphores.size(),
+ .fSignalSemaphores = end_semaphores.data(),
+ };
+ gr_context()->flush(scoped_write->surface(), flush_info, nullptr);
+ gr_context()->submit();
+ }
+ skia_representation->SetCleared();
+ }
+ EXPECT_TRUE(vk_backing->HasLatestContentInVkImage());
+
+ // Perform a GL READWRITE access without modifying the GL texture. The
+ // Vulkan-side content must be synchronized into the separate GL texture on
+ // BeginAccess so that when EndAccess marks the GL texture as holding the
+ // latest content, it is not stale/uninitialized.
+ if (use_passthrough()) {
+ auto gl_representation =
+ shared_image_representation_factory_.ProduceGLTexturePassthrough(
+ mailbox);
+ ASSERT_TRUE(gl_representation);
+ auto scoped_access = gl_representation->BeginScopedAccess(
+ GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM,
+ SharedImageRepresentation::AllowUnclearedAccess::kNo);
+ ASSERT_TRUE(scoped_access);
+ } else {
+ auto gl_representation =
+ shared_image_representation_factory_.ProduceGLTexture(mailbox);
+ ASSERT_TRUE(gl_representation);
+ auto scoped_access = gl_representation->BeginScopedAccess(
+ GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM,
+ SharedImageRepresentation::AllowUnclearedAccess::kNo);
+ ASSERT_TRUE(scoped_access);
+ }
+
+ // After the GL READWRITE access ends, latest_content_ is exclusively
+ // kInGLTexture until the next Vulkan access synchronizes it back.
+ EXPECT_FALSE(vk_backing->HasLatestContentInVkImage());
+
+ // Now begin a Vulkan write access (mirroring Dawn/Skia write-mode
+ // BeginAccess) and verify that BeginAccess synchronizes the GL texture back
+ // to VkImage.
+ {
+ auto skia_representation = shared_image_representation_factory_.ProduceSkia(
+ mailbox, context_state_.get());
+ ASSERT_TRUE(skia_representation);
+
+ std::vector<GrBackendSemaphore> begin_semaphores;
+ std::vector<GrBackendSemaphore> end_semaphores;
+ auto scoped_write = skia_representation->BeginScopedWriteAccess(
+ &begin_semaphores, &end_semaphores,
+ SharedImageRepresentation::AllowUnclearedAccess::kNo);
+ ASSERT_TRUE(scoped_write);
+ EXPECT_TRUE(vk_backing->HasLatestContentInVkImage());
+
+ scoped_write->ApplyBackendSurfaceEndState();
+ if (!end_semaphores.empty()) {
+ GrFlushInfo flush_info = {
+ .fNumSemaphores = end_semaphores.size(),
+ .fSignalSemaphores = end_semaphores.data(),
+ };
+ gr_context()->flush(scoped_write->surface(), flush_info, nullptr);
+ gr_context()->submit();
+ }
+ }
+
+ VerifyPixelsWithReadbackGanesh(mailbox, red_bitmaps);
+}
+
} // anonymous namespace
} // namespace gpu
Loading diff…
Original Bug Report
The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.
References
On This Page