| // Copyright 2019 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/viz/test/test_gpu_service_holder.h" |
| #include "gpu/command_buffer/client/shared_image_interface.h" |
| #include "gpu/command_buffer/client/webgpu_implementation.h" |
| #include "gpu/command_buffer/common/mailbox.h" |
| #include "gpu/command_buffer/common/shared_image_usage.h" |
| #include "gpu/command_buffer/service/webgpu_decoder.h" |
| #include "gpu/command_buffer/tests/webgpu_test.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/gfx/color_space.h" |
| |
| namespace gpu { |
| namespace { |
| |
| class MockBufferMapCallback { |
| public: |
| MOCK_METHOD(void, Call, (WGPUBufferMapAsyncStatus status, void* userdata)); |
| }; |
| std::unique_ptr<testing::StrictMock<MockBufferMapCallback>> |
| mock_buffer_map_callback; |
| |
| void ToMockBufferMapCallback(WGPUBufferMapAsyncStatus status, void* userdata) { |
| mock_buffer_map_callback->Call(status, userdata); |
| } |
| |
| class MockUncapturedErrorCallback { |
| public: |
| MOCK_METHOD3(Call, |
| void(WGPUErrorType type, const char* message, void* userdata)); |
| }; |
| |
| std::unique_ptr<testing::StrictMock<MockUncapturedErrorCallback>> |
| mock_device_error_callback; |
| void ToMockUncapturedErrorCallback(WGPUErrorType type, |
| const char* message, |
| void* userdata) { |
| mock_device_error_callback->Call(type, message, userdata); |
| } |
| |
| } // namespace |
| |
| class WebGPUMailboxTest : public WebGPUTest { |
| protected: |
| void SetUp() override { |
| WebGPUTest::SetUp(); |
| Initialize(WebGPUTest::Options()); |
| mock_buffer_map_callback = |
| std::make_unique<testing::StrictMock<MockBufferMapCallback>>(); |
| mock_device_error_callback = |
| std::make_unique<testing::StrictMock<MockUncapturedErrorCallback>>(); |
| } |
| |
| void TearDown() override { |
| mock_buffer_map_callback = nullptr; |
| mock_device_error_callback = nullptr; |
| WebGPUTest::TearDown(); |
| } |
| |
| struct AssociateMailboxCmdStorage { |
| webgpu::cmds::AssociateMailboxImmediate cmd; |
| GLbyte data[GL_MAILBOX_SIZE_CHROMIUM]; |
| }; |
| |
| template <typename T> |
| static error::Error ExecuteCmd(webgpu::WebGPUDecoder* decoder, const T& cmd) { |
| static_assert(T::kArgFlags == cmd::kFixed, |
| "T::kArgFlags should equal cmd::kFixed"); |
| int entries_processed = 0; |
| return decoder->DoCommands(1, (const void*)&cmd, |
| ComputeNumEntries(sizeof(cmd)), |
| &entries_processed); |
| } |
| |
| template <typename T> |
| static error::Error ExecuteImmediateCmd(webgpu::WebGPUDecoder* decoder, |
| const T& cmd, |
| size_t data_size) { |
| static_assert(T::kArgFlags == cmd::kAtLeastN, |
| "T::kArgFlags should equal cmd::kAtLeastN"); |
| int entries_processed = 0; |
| return decoder->DoCommands(1, (const void*)&cmd, |
| ComputeNumEntries(sizeof(cmd) + data_size), |
| &entries_processed); |
| } |
| }; |
| |
| TEST_F(WebGPUMailboxTest, AssociateMailboxCmd) { |
| if (!WebGPUSupported()) { |
| LOG(ERROR) << "Test skipped because WebGPU isn't supported"; |
| return; |
| } |
| if (!WebGPUSharedImageSupported()) { |
| LOG(ERROR) << "Test skipped because WebGPUSharedImage isn't supported"; |
| return; |
| } |
| |
| // Create the shared image |
| SharedImageInterface* sii = GetSharedImageInterface(); |
| Mailbox mailbox = sii->CreateSharedImage( |
| viz::ResourceFormat::RGBA_8888, {1, 1}, gfx::ColorSpace::CreateSRGB(), |
| kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, SHARED_IMAGE_USAGE_WEBGPU, |
| kNullSurfaceHandle); |
| |
| wgpu::Device device = GetNewDevice(); |
| webgpu::ReservedTexture reservation = webgpu()->ReserveTexture(device.Get()); |
| |
| GetGpuServiceHolder()->ScheduleGpuTask(base::BindOnce( |
| [](webgpu::WebGPUDecoder* decoder, webgpu::ReservedTexture reservation, |
| gpu::Mailbox mailbox) { |
| // Error case: invalid mailbox |
| { |
| gpu::Mailbox bad_mailbox; |
| AssociateMailboxCmdStorage cmd; |
| cmd.cmd.Init(reservation.deviceId, reservation.deviceGeneration, |
| reservation.id, reservation.generation, |
| WGPUTextureUsage_Sampled, webgpu::WEBGPU_MAILBOX_NONE, |
| bad_mailbox.name); |
| EXPECT_EQ( |
| error::kInvalidArguments, |
| ExecuteImmediateCmd(decoder, cmd.cmd, sizeof(bad_mailbox.name))); |
| } |
| |
| // Error case: device client id doesn't exist. |
| { |
| AssociateMailboxCmdStorage cmd; |
| cmd.cmd.Init(reservation.deviceId + 1, reservation.deviceGeneration, |
| reservation.id, reservation.generation, |
| WGPUTextureUsage_Sampled, webgpu::WEBGPU_MAILBOX_NONE, |
| mailbox.name); |
| EXPECT_EQ( |
| error::kInvalidArguments, |
| ExecuteImmediateCmd(decoder, cmd.cmd, sizeof(mailbox.name))); |
| } |
| |
| // Error case: device generation is invalid. |
| { |
| AssociateMailboxCmdStorage cmd; |
| cmd.cmd.Init(reservation.deviceId, reservation.deviceGeneration + 1, |
| reservation.id, reservation.generation, |
| WGPUTextureUsage_Sampled, webgpu::WEBGPU_MAILBOX_NONE, |
| mailbox.name); |
| EXPECT_EQ( |
| error::kInvalidArguments, |
| ExecuteImmediateCmd(decoder, cmd.cmd, sizeof(mailbox.name))); |
| } |
| |
| // Error case: texture ID invalid for the wire server. |
| { |
| AssociateMailboxCmdStorage cmd; |
| cmd.cmd.Init(reservation.deviceId, reservation.deviceGeneration, |
| reservation.id + 1, reservation.generation, |
| WGPUTextureUsage_Sampled, webgpu::WEBGPU_MAILBOX_NONE, |
| mailbox.name); |
| EXPECT_EQ( |
| error::kInvalidArguments, |
| ExecuteImmediateCmd(decoder, cmd.cmd, sizeof(mailbox.name))); |
| } |
| |
| // Error case: invalid texture usage. |
| { |
| AssociateMailboxCmdStorage cmd; |
| cmd.cmd.Init(reservation.deviceId, reservation.deviceGeneration, |
| reservation.id, reservation.generation, |
| WGPUTextureUsage_Force32, webgpu::WEBGPU_MAILBOX_NONE, |
| mailbox.name); |
| EXPECT_EQ( |
| error::kInvalidArguments, |
| ExecuteImmediateCmd(decoder, cmd.cmd, sizeof(mailbox.name))); |
| } |
| |
| // Control case: test a successful call to AssociateMailbox. |
| // The control case is not put first because it modifies the internal |
| // state of the Dawn wire server and would make calls with the same |
| // texture ID and generation invalid. |
| { |
| AssociateMailboxCmdStorage cmd; |
| cmd.cmd.Init(reservation.deviceId, reservation.deviceGeneration, |
| reservation.id, reservation.generation, |
| WGPUTextureUsage_Sampled, webgpu::WEBGPU_MAILBOX_NONE, |
| mailbox.name); |
| EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(decoder, cmd.cmd, |
| sizeof(mailbox.name))); |
| } |
| |
| // Error case: associated to an already associated texture. |
| { |
| AssociateMailboxCmdStorage cmd; |
| cmd.cmd.Init(reservation.deviceId, reservation.deviceGeneration, |
| reservation.id, reservation.generation, |
| WGPUTextureUsage_Sampled, webgpu::WEBGPU_MAILBOX_NONE, |
| mailbox.name); |
| EXPECT_EQ( |
| error::kInvalidArguments, |
| ExecuteImmediateCmd(decoder, cmd.cmd, sizeof(mailbox.name))); |
| } |
| |
| // Dissociate the image from the control case to remove its reference. |
| { |
| webgpu::cmds::DissociateMailbox cmd; |
| cmd.Init(reservation.id, reservation.generation); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(decoder, cmd)); |
| } |
| }, |
| GetDecoder(), reservation, mailbox)); |
| |
| GetGpuServiceHolder()->gpu_thread_task_runner()->RunsTasksInCurrentSequence(); |
| } |
| |
| TEST_F(WebGPUMailboxTest, DissociateMailboxCmd) { |
| if (!WebGPUSupported()) { |
| LOG(ERROR) << "Test skipped because WebGPU isn't supported"; |
| return; |
| } |
| if (!WebGPUSharedImageSupported()) { |
| LOG(ERROR) << "Test skipped because WebGPUSharedImage isn't supported"; |
| return; |
| } |
| |
| // Create the shared image |
| SharedImageInterface* sii = GetSharedImageInterface(); |
| Mailbox mailbox = sii->CreateSharedImage( |
| viz::ResourceFormat::RGBA_8888, {1, 1}, gfx::ColorSpace::CreateSRGB(), |
| kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, SHARED_IMAGE_USAGE_WEBGPU, |
| kNullSurfaceHandle); |
| |
| wgpu::Device device = GetNewDevice(); |
| webgpu::ReservedTexture reservation = webgpu()->ReserveTexture(device.Get()); |
| |
| GetGpuServiceHolder()->ScheduleGpuTask(base::BindOnce( |
| [](webgpu::WebGPUDecoder* decoder, webgpu::ReservedTexture reservation, |
| gpu::Mailbox mailbox) { |
| // Associate a mailbox so we can later dissociate it. |
| { |
| AssociateMailboxCmdStorage cmd; |
| cmd.cmd.Init(reservation.deviceId, reservation.deviceGeneration, |
| reservation.id, reservation.generation, |
| WGPUTextureUsage_Sampled, webgpu::WEBGPU_MAILBOX_NONE, |
| mailbox.name); |
| EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(decoder, cmd.cmd, |
| sizeof(mailbox.name))); |
| } |
| |
| // Error case: wrong texture ID |
| { |
| webgpu::cmds::DissociateMailbox cmd; |
| cmd.Init(reservation.id + 1, reservation.generation); |
| EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(decoder, cmd)); |
| } |
| |
| // Error case: wrong texture generation |
| { |
| webgpu::cmds::DissociateMailbox cmd; |
| cmd.Init(reservation.id, reservation.generation + 1); |
| EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(decoder, cmd)); |
| } |
| |
| // Success case |
| { |
| webgpu::cmds::DissociateMailbox cmd; |
| cmd.Init(reservation.id, reservation.generation); |
| EXPECT_EQ(error::kNoError, ExecuteCmd(decoder, cmd)); |
| } |
| |
| // Error case: dissociate an already dissociated mailbox |
| { |
| webgpu::cmds::DissociateMailbox cmd; |
| cmd.Init(reservation.id, reservation.generation); |
| EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(decoder, cmd)); |
| } |
| }, |
| GetDecoder(), reservation, mailbox)); |
| |
| GetGpuServiceHolder()->gpu_thread_task_runner()->RunsTasksInCurrentSequence(); |
| } |
| |
| // Tests using Associate/DissociateMailbox to share an image with Dawn. |
| // For simplicity of the test the image is shared between a Dawn device and |
| // itself: we render to it using the Dawn device, then re-associate it to a |
| // Dawn texture and read back the values that were written. |
| TEST_F(WebGPUMailboxTest, WriteToMailboxThenReadFromIt) { |
| if (!WebGPUSupported()) { |
| LOG(ERROR) << "Test skipped because WebGPU isn't supported"; |
| return; |
| } |
| if (!WebGPUSharedImageSupported()) { |
| LOG(ERROR) << "Test skipped because WebGPUSharedImage isn't supported"; |
| return; |
| } |
| |
| // Create the shared image |
| SharedImageInterface* sii = GetSharedImageInterface(); |
| Mailbox mailbox = sii->CreateSharedImage( |
| viz::ResourceFormat::RGBA_8888, {1, 1}, gfx::ColorSpace::CreateSRGB(), |
| kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, SHARED_IMAGE_USAGE_WEBGPU, |
| kNullSurfaceHandle); |
| SyncToken mailbox_produced_token = sii->GenVerifiedSyncToken(); |
| webgpu()->WaitSyncTokenCHROMIUM(mailbox_produced_token.GetConstData()); |
| |
| wgpu::Device device = GetNewDevice(); |
| |
| // Part 1: Write to the texture using Dawn |
| { |
| // Register the shared image as a Dawn texture in the wire. |
| gpu::webgpu::ReservedTexture reservation = |
| webgpu()->ReserveTexture(device.Get()); |
| |
| webgpu()->AssociateMailbox( |
| reservation.deviceId, reservation.deviceGeneration, reservation.id, |
| reservation.generation, WGPUTextureUsage_RenderAttachment, |
| webgpu::WEBGPU_MAILBOX_NONE, reinterpret_cast<GLbyte*>(&mailbox)); |
| wgpu::Texture texture = wgpu::Texture::Acquire(reservation.texture); |
| |
| // Clear the texture using a render pass. |
| wgpu::RenderPassColorAttachmentDescriptor color_desc = {}; |
| color_desc.view = texture.CreateView(); |
| color_desc.loadOp = wgpu::LoadOp::Clear; |
| color_desc.storeOp = wgpu::StoreOp::Store; |
| color_desc.clearColor = {0, 255, 0, 255}; |
| |
| wgpu::RenderPassDescriptor render_pass_desc = {}; |
| render_pass_desc.colorAttachmentCount = 1; |
| render_pass_desc.colorAttachments = &color_desc; |
| |
| wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); |
| wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&render_pass_desc); |
| pass.EndPass(); |
| wgpu::CommandBuffer commands = encoder.Finish(); |
| |
| wgpu::Queue queue = device.GetQueue(); |
| queue.Submit(1, &commands); |
| |
| webgpu()->DissociateMailbox(reservation.id, reservation.generation); |
| } |
| |
| // Part 2: Read back the texture using Dawn |
| { |
| // Register the shared image as a Dawn texture in the wire. |
| gpu::webgpu::ReservedTexture reservation = |
| webgpu()->ReserveTexture(device.Get()); |
| |
| webgpu()->AssociateMailbox( |
| reservation.deviceId, reservation.deviceGeneration, reservation.id, |
| reservation.generation, WGPUTextureUsage_CopySrc, |
| webgpu::WEBGPU_MAILBOX_NONE, reinterpret_cast<GLbyte*>(&mailbox)); |
| wgpu::Texture texture = wgpu::Texture::Acquire(reservation.texture); |
| |
| // Copy the texture in a mappable buffer. |
| wgpu::BufferDescriptor buffer_desc; |
| buffer_desc.size = 4; |
| buffer_desc.usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst; |
| wgpu::Buffer readback_buffer = device.CreateBuffer(&buffer_desc); |
| |
| wgpu::ImageCopyTexture copy_src = {}; |
| copy_src.texture = texture; |
| copy_src.mipLevel = 0; |
| copy_src.origin = {0, 0, 0}; |
| |
| wgpu::ImageCopyBuffer copy_dst = {}; |
| copy_dst.buffer = readback_buffer; |
| copy_dst.layout.offset = 0; |
| copy_dst.layout.bytesPerRow = 256; |
| |
| wgpu::Extent3D copy_size = {1, 1, 1}; |
| |
| wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); |
| encoder.CopyTextureToBuffer(©_src, ©_dst, ©_size); |
| wgpu::CommandBuffer commands = encoder.Finish(); |
| |
| wgpu::Queue queue = device.GetQueue(); |
| queue.Submit(1, &commands); |
| |
| webgpu()->DissociateMailbox(reservation.id, reservation.generation); |
| |
| // Map the buffer and assert the pixel is the correct value. |
| readback_buffer.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapCallback, |
| nullptr); |
| EXPECT_CALL(*mock_buffer_map_callback, |
| Call(WGPUBufferMapAsyncStatus_Success, nullptr)) |
| .Times(1); |
| |
| WaitForCompletion(device); |
| |
| const void* data = readback_buffer.GetConstMappedRange(0, 4); |
| EXPECT_EQ(0xFF00FF00, *static_cast<const uint32_t*>(data)); |
| } |
| } |
| |
| // Tests that using a shared image aftr it is dissociated produces an error. |
| TEST_F(WebGPUMailboxTest, ErrorWhenUsingTextureAfterDissociate) { |
| if (!WebGPUSupported()) { |
| LOG(ERROR) << "Test skipped because WebGPU isn't supported"; |
| return; |
| } |
| if (!WebGPUSharedImageSupported()) { |
| LOG(ERROR) << "Test skipped because WebGPUSharedImage isn't supported"; |
| return; |
| } |
| |
| // Create a the shared image |
| SharedImageInterface* sii = GetSharedImageInterface(); |
| Mailbox mailbox = sii->CreateSharedImage( |
| viz::ResourceFormat::BGRA_8888, {1, 1}, gfx::ColorSpace::CreateSRGB(), |
| kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, SHARED_IMAGE_USAGE_WEBGPU, |
| kNullSurfaceHandle); |
| SyncToken mailbox_produced_token = sii->GenVerifiedSyncToken(); |
| webgpu()->WaitSyncTokenCHROMIUM(mailbox_produced_token.GetConstData()); |
| |
| // Create the device, and expect a validation error. |
| wgpu::Device device = GetNewDevice(); |
| |
| device.SetUncapturedErrorCallback(ToMockUncapturedErrorCallback, 0); |
| |
| // Associate and immediately dissociate the image. |
| gpu::webgpu::ReservedTexture reservation = |
| webgpu()->ReserveTexture(device.Get()); |
| wgpu::Texture texture = wgpu::Texture::Acquire(reservation.texture); |
| |
| webgpu()->AssociateMailbox( |
| reservation.deviceId, reservation.deviceGeneration, reservation.id, |
| reservation.generation, WGPUTextureUsage_CopySrc, |
| webgpu::WEBGPU_MAILBOX_NONE, reinterpret_cast<GLbyte*>(&mailbox)); |
| webgpu()->DissociateMailbox(reservation.id, reservation.generation); |
| |
| wgpu::TextureDescriptor dst_desc = {}; |
| dst_desc.size = {1, 1}; |
| dst_desc.usage = wgpu::TextureUsage::CopyDst; |
| dst_desc.format = wgpu::TextureFormat::BGRA8Unorm; |
| |
| wgpu::ImageCopyTexture src_image = {}; |
| src_image.texture = texture; |
| |
| wgpu::ImageCopyTexture dst_image = {}; |
| dst_image.texture = device.CreateTexture(&dst_desc); |
| |
| wgpu::Extent3D extent = {1, 1}; |
| |
| // Try using the texture in a copy command; it should produce a validation |
| // error. |
| wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); |
| encoder.CopyTextureToTexture(&src_image, &dst_image, &extent); |
| wgpu::CommandBuffer commandBuffer = encoder.Finish(); |
| |
| // Wait so it's clear the validation error after this when we call Submit. |
| WaitForCompletion(device); |
| device.GetQueue().Submit(1, &commandBuffer); |
| |
| EXPECT_CALL(*mock_device_error_callback, |
| Call(WGPUErrorType_Validation, testing::_, testing::_)) |
| .Times(1); |
| WaitForCompletion(device); |
| } |
| |
| // This is a regression test for an issue when using multiple shared images |
| // where a `ScopedAccess` was destroyed after it's `SharedImageRepresentation`. |
| // The code was similar to the following. |
| // |
| // struct Pair { |
| // unique_ptr<Representation> representation; |
| // unique_ptr<Access> access; |
| // }; |
| // |
| // base::flat_map<Key, Pair> map; |
| // map.erase(some_iterator); |
| // |
| // In the Pair destructor C++ guarantees that `access` is destroyed before |
| // `representation` but `erase` can move one element over another, causing |
| // the move-assignment operator to be called. In this case the defaulted |
| // move-assignment would first move `representation` then `access`. Causing |
| // incorrect member destruction order for the move-to object. |
| TEST_F(WebGPUMailboxTest, UseA_UseB_DestroyA_DestroyB) { |
| if (!WebGPUSupported()) { |
| LOG(ERROR) << "Test skipped because WebGPU isn't supported"; |
| return; |
| } |
| if (!WebGPUSharedImageSupported()) { |
| LOG(ERROR) << "Test skipped because WebGPUSharedImage isn't supported"; |
| return; |
| } |
| |
| // Create a the shared images. |
| SharedImageInterface* sii = GetSharedImageInterface(); |
| Mailbox mailbox_a = sii->CreateSharedImage( |
| viz::ResourceFormat::RGBA_8888, {1, 1}, gfx::ColorSpace::CreateSRGB(), |
| kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, SHARED_IMAGE_USAGE_WEBGPU, |
| kNullSurfaceHandle); |
| Mailbox mailbox_b = sii->CreateSharedImage( |
| viz::ResourceFormat::RGBA_8888, {1, 1}, gfx::ColorSpace::CreateSRGB(), |
| kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, SHARED_IMAGE_USAGE_WEBGPU, |
| kNullSurfaceHandle); |
| |
| // Get a WebGPU device to associate the shared images to. |
| wgpu::Device device = GetNewDevice(); |
| |
| // Associate both mailboxes |
| gpu::webgpu::ReservedTexture reservation_a = |
| webgpu()->ReserveTexture(device.Get()); |
| webgpu()->AssociateMailbox( |
| reservation_a.deviceId, reservation_a.deviceGeneration, reservation_a.id, |
| reservation_a.generation, WGPUTextureUsage_RenderAttachment, |
| webgpu::WEBGPU_MAILBOX_NONE, reinterpret_cast<GLbyte*>(&mailbox_a)); |
| |
| gpu::webgpu::ReservedTexture reservation_b = |
| webgpu()->ReserveTexture(device.Get()); |
| webgpu()->AssociateMailbox( |
| reservation_b.deviceId, reservation_b.deviceGeneration, reservation_b.id, |
| reservation_b.generation, WGPUTextureUsage_RenderAttachment, |
| webgpu::WEBGPU_MAILBOX_NONE, reinterpret_cast<GLbyte*>(&mailbox_b)); |
| |
| // Dissociate both mailboxes in the same order. |
| webgpu()->DissociateMailbox(reservation_a.id, reservation_a.generation); |
| webgpu()->DissociateMailbox(reservation_b.id, reservation_b.generation); |
| |
| // Send all the previous commands to the WebGPU decoder. |
| webgpu()->FlushCommands(); |
| } |
| |
| // Regression test for a bug where the (id, generation) for associated shared |
| // images was stored globally instead of per-device. This meant that of two |
| // devices tried to create shared images with the same (id, generation) (which |
| // is possible because they can be on different Dawn wires) they would conflict. |
| TEST_F(WebGPUMailboxTest, AssociateOnTwoDevicesAtTheSameTime) { |
| if (!WebGPUSupported()) { |
| LOG(ERROR) << "Test skipped because WebGPU isn't supported"; |
| return; |
| } |
| if (!WebGPUSharedImageSupported()) { |
| LOG(ERROR) << "Test skipped because WebGPUSharedImage isn't supported"; |
| return; |
| } |
| |
| // Create a the shared images. |
| SharedImageInterface* sii = GetSharedImageInterface(); |
| Mailbox mailbox_a = sii->CreateSharedImage( |
| viz::ResourceFormat::RGBA_8888, {1, 1}, gfx::ColorSpace::CreateSRGB(), |
| kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, SHARED_IMAGE_USAGE_WEBGPU, |
| kNullSurfaceHandle); |
| |
| Mailbox mailbox_b = sii->CreateSharedImage( |
| viz::ResourceFormat::RGBA_8888, {1, 1}, gfx::ColorSpace::CreateSRGB(), |
| kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, SHARED_IMAGE_USAGE_WEBGPU, |
| kNullSurfaceHandle); |
| |
| // Two WebGPU devices to associate the shared images to. |
| wgpu::Device device_a = GetNewDevice(); |
| wgpu::Device device_b = GetNewDevice(); |
| |
| // Associate both mailboxes |
| gpu::webgpu::ReservedTexture reservation_a = |
| webgpu()->ReserveTexture(device_a.Get()); |
| webgpu()->AssociateMailbox( |
| reservation_a.deviceId, reservation_a.deviceGeneration, reservation_a.id, |
| reservation_a.generation, WGPUTextureUsage_RenderAttachment, |
| webgpu::WEBGPU_MAILBOX_NONE, reinterpret_cast<GLbyte*>(&mailbox_a)); |
| |
| gpu::webgpu::ReservedTexture reservation_b = |
| webgpu()->ReserveTexture(device_b.Get()); |
| webgpu()->AssociateMailbox( |
| reservation_b.deviceId, reservation_b.deviceGeneration, reservation_b.id, |
| reservation_b.generation, WGPUTextureUsage_RenderAttachment, |
| webgpu::WEBGPU_MAILBOX_NONE, reinterpret_cast<GLbyte*>(&mailbox_b)); |
| |
| // Dissociate both mailboxes in the same order. |
| webgpu()->DissociateMailbox(reservation_a.id, reservation_a.generation); |
| webgpu()->DissociateMailbox(reservation_b.id, reservation_b.generation); |
| |
| // Send all the previous commands to the WebGPU decoder. |
| webgpu()->FlushCommands(); |
| } |
| |
| } // namespace gpu |