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 =