Require MapWrite on SBM when creating buffer with mappedAtCreation = true This patch adds a validation that require the shared buffer memory must have `MapWrite` usage when we create a buffer on it with `mappedAtCreation == true` because to support such case we need to create staging buffer and do multiple copies, which adds extra complexity and currently we have no plan to support. Bug: 386255678 Change-Id: Ic10693d7079274d226fcb388b1ecb660ad8e027d Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/322215 Commit-Queue: Shao, Jiawei <jiawei.shao@intel.com> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/native/SharedBufferMemory.cpp b/src/dawn/native/SharedBufferMemory.cpp index e6dcf6a..ba278e4 100644 --- a/src/dawn/native/SharedBufferMemory.cpp +++ b/src/dawn/native/SharedBufferMemory.cpp
@@ -135,6 +135,12 @@ "The buffer usage (%s) is incompatible with the SharedBufferMemory usage (%s).", descriptor->usage, mProperties.usage); + // Require MapWrite usage on the shared buffer memory when mappedAtCreation is true. + DAWN_INVALID_IF( + descriptor->mappedAtCreation && !(mProperties.usage & wgpu::BufferUsage::MapWrite), + "Buffer created from SharedBufferMemory with mappedAtCreation=true requires " + "the SharedBufferMemory to have MapWrite usage."); + // Validate that the buffer size does not exceed the shared buffer memory's size. DAWN_INVALID_IF(descriptor->size > mProperties.size, "The buffer size (%u) is larger than SharedBufferMemory size (%u).",
diff --git a/src/dawn/tests/white_box/SharedBufferMemoryTests.cpp b/src/dawn/tests/white_box/SharedBufferMemoryTests.cpp index ae2a2cb..a38640d 100644 --- a/src/dawn/tests/white_box/SharedBufferMemoryTests.cpp +++ b/src/dawn/tests/white_box/SharedBufferMemoryTests.cpp
@@ -868,40 +868,37 @@ buffer2.Unmap(); } -// Test that creating a buffer from SharedBufferMemory with mappedAtCreation works correctly, -// both with map usages and without (mappedAtCreation grants write access regardless of usage). +// Test that creating a buffer from SharedBufferMemory with mappedAtCreation works correctly +// when the shared buffer memory has MapWrite usage. TEST_P(SharedBufferMemoryTests, CreateBufferMappedAtCreation) { - for (wgpu::BufferUsage usage : {kMapWriteUsages, kStorageUsages}) { - SCOPED_TRACE(absl::StrFormat("usage = %u", static_cast<uint32_t>(usage))); - wgpu::SharedBufferMemory memory = - GetParam().mBackend->CreateSharedBufferMemory(device, usage, kBufferSize); - wgpu::SharedBufferMemoryProperties properties; - memory.GetProperties(&properties); + wgpu::SharedBufferMemory memory = + GetParam().mBackend->CreateSharedBufferMemory(device, kMapWriteUsages, kBufferSize); + wgpu::SharedBufferMemoryProperties properties; + memory.GetProperties(&properties); - wgpu::BufferDescriptor bufferDesc = {}; - bufferDesc.size = properties.size; - bufferDesc.usage = usage; - bufferDesc.mappedAtCreation = true; + wgpu::BufferDescriptor bufferDesc = {}; + bufferDesc.size = properties.size; + bufferDesc.usage = kMapWriteUsages; + bufferDesc.mappedAtCreation = true; - wgpu::SharedBufferMemoryBeginAccessDescriptor beginAccessDesc; - beginAccessDesc.initialized = false; + wgpu::SharedBufferMemoryBeginAccessDescriptor beginAccessDesc; + beginAccessDesc.initialized = false; - wgpu::Buffer buffer = memory.CreateBuffer(&bufferDesc); - memory.BeginAccess(buffer, &beginAccessDesc); + wgpu::Buffer buffer = memory.CreateBuffer(&bufferDesc); + memory.BeginAccess(buffer, &beginAccessDesc); - // Write data directly through the mapped range. - uint32_t* mappedData = static_cast<uint32_t*>(buffer.GetMappedRange(0, kBufferSize)); - ASSERT_NE(mappedData, nullptr); - *mappedData = kBufferData; - buffer.Unmap(); + // Write data directly through the mapped range. + uint32_t* mappedData = static_cast<uint32_t*>(buffer.GetMappedRange(0, kBufferSize)); + ASSERT_NE(mappedData, nullptr); + *mappedData = kBufferData; + buffer.Unmap(); - // Verify the written data is correct by reading it back. - EXPECT_BUFFER_U32_EQ(kBufferData, buffer, 0); + // Verify the written data is correct by reading it back. + EXPECT_BUFFER_U32_EQ(kBufferData, buffer, 0); - wgpu::SharedBufferMemoryEndAccessState endState; - memory.EndAccess(buffer, &endState); - EXPECT_EQ(endState.initialized, true); - } + wgpu::SharedBufferMemoryEndAccessState endState; + memory.EndAccess(buffer, &endState); + EXPECT_EQ(endState.initialized, true); } GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SharedBufferMemoryTests);
diff --git a/src/dawn/tests/white_box/SharedBufferMemoryTests_win.cpp b/src/dawn/tests/white_box/SharedBufferMemoryTests_win.cpp index 54d12dd..6bd5889 100644 --- a/src/dawn/tests/white_box/SharedBufferMemoryTests_win.cpp +++ b/src/dawn/tests/white_box/SharedBufferMemoryTests_win.cpp
@@ -334,6 +334,28 @@ ASSERT_TRUE(sharedBufferMemory.CreateBuffer().Get()); } +// Tests that creating a buffer from SharedBufferMemory with mappedAtCreation=true is an error +// when the shared buffer memory does not have MapWrite usage. +TEST_P(SharedBufferMemoryExistingD3D12ResourceTests, + CreateBufferMappedAtCreationWithoutMapWriteIsError) { + constexpr wgpu::BufferUsage kStorageUsages = + wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Storage; + wgpu::SharedBufferMemory memory = + GetParam().mBackend->CreateSharedBufferMemory(device, kStorageUsages, kBufferSize); + wgpu::SharedBufferMemoryProperties properties; + memory.GetProperties(&properties); + + wgpu::BufferDescriptor bufferDesc = {}; + bufferDesc.size = properties.size; + bufferDesc.usage = kStorageUsages; + bufferDesc.mappedAtCreation = true; + + ASSERT_DEVICE_ERROR_MSG( + memory.CreateBuffer(&bufferDesc), + testing::HasSubstr( + "mappedAtCreation=true requires the SharedBufferMemory to have MapWrite usage")); +} + // Tests that creating SharedBufferMemory emits a specific error message if Uniform usage specified. TEST_P(SharedBufferMemoryExistingD3D12ResourceTests, UniformUsageValidation) { constexpr wgpu::BufferUsage kMapWriteUsages =