D3D11: Refactor Buffer classes.

- GPUOnlyBuffer is renamed to GPUUsableBuffer. This will allow it
to be extended by a subclass in future which supports mapping
a draw buffer (with uniform, index, storage usages, etc).
- MapInternal now has additional MapMode parameter.
- Clear function used for Occlusion Query should be a special
function. It will be named PredicatedClear. To indicate that the
clearing will be affected by a predicate, unlike mapping based Clear
which won't be affected by it.
- GetD3D11ConstantBuffer() and EnsureConstantBufferIsUpdated() are
combined. They are currently always called together, there is no point
having two separate methods.
- Similarly for CreateD3D11UnorderedAccessView1() and MarkMutated().

Bug: 345471009
Change-Id: Ifa237e6bacb591a1ee8e9b9f76c2e5d809899efc
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/194800
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Quyen Le <lehoangquyen@chromium.org>
diff --git a/src/dawn/native/d3d11/BindGroupTrackerD3D11.cpp b/src/dawn/native/d3d11/BindGroupTrackerD3D11.cpp
index 8629f34..ba2cfbd 100644
--- a/src/dawn/native/d3d11/BindGroupTrackerD3D11.cpp
+++ b/src/dawn/native/d3d11/BindGroupTrackerD3D11.cpp
@@ -190,10 +190,9 @@
                                     bindingInfo.visibility,
                                     wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Compute));
                                 ComPtr<ID3D11UnorderedAccessView> d3d11UAV;
-                                DAWN_TRY_ASSIGN(d3d11UAV, ToGPUOnlyBuffer(binding.buffer)
-                                                              ->CreateD3D11UnorderedAccessView1(
-                                                                  offset, binding.size));
-                                ToGPUOnlyBuffer(binding.buffer)->MarkMutated();
+                                DAWN_TRY_ASSIGN(d3d11UAV, ToGPUUsableBuffer(binding.buffer)
+                                                              ->UseAsUAV(mCommandContext, offset,
+                                                                         binding.size));
                                 uavsInBindGroup.insert(uavsInBindGroup.begin(),
                                                        std::move(d3d11UAV));
                                 break;
@@ -309,10 +308,9 @@
 
                 switch (layout.type) {
                     case wgpu::BufferBindingType::Uniform: {
-                        ToGPUOnlyBuffer(binding.buffer)
-                            ->EnsureConstantBufferIsUpdated(mCommandContext);
-                        ID3D11Buffer* d3d11Buffer =
-                            ToGPUOnlyBuffer(binding.buffer)->GetD3D11ConstantBuffer();
+                        ID3D11Buffer* d3d11Buffer;
+                        DAWN_TRY_ASSIGN(d3d11Buffer, ToGPUUsableBuffer(binding.buffer)
+                                                         ->GetD3D11ConstantBuffer(mCommandContext));
                         // https://learn.microsoft.com/en-us/windows/win32/api/d3d11_1/nf-d3d11_1-id3d11devicecontext1-vssetconstantbuffers1
                         // Offset and size are measured in shader constants, which are 16 bytes
                         // (4*32-bit components). And the offsets and counts must be multiples
@@ -346,10 +344,9 @@
                                      wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Compute));
                         if (bindingVisibility & wgpu::ShaderStage::Compute) {
                             ComPtr<ID3D11UnorderedAccessView> d3d11UAV;
-                            DAWN_TRY_ASSIGN(d3d11UAV, ToGPUOnlyBuffer(binding.buffer)
-                                                          ->CreateD3D11UnorderedAccessView1(
-                                                              offset, binding.size));
-                            ToGPUOnlyBuffer(binding.buffer)->MarkMutated();
+                            DAWN_TRY_ASSIGN(d3d11UAV,
+                                            ToGPUUsableBuffer(binding.buffer)
+                                                ->UseAsUAV(mCommandContext, offset, binding.size));
                             deviceContext->CSSetUnorderedAccessViews(
                                 bindingSlot, 1, d3d11UAV.GetAddressOf(), nullptr);
                         }
@@ -358,8 +355,8 @@
                     case wgpu::BufferBindingType::ReadOnlyStorage: {
                         ComPtr<ID3D11ShaderResourceView> d3d11SRV;
                         DAWN_TRY_ASSIGN(d3d11SRV,
-                                        ToGPUOnlyBuffer(binding.buffer)
-                                            ->CreateD3D11ShaderResourceView(offset, binding.size));
+                                        ToGPUUsableBuffer(binding.buffer)
+                                            ->UseAsSRV(mCommandContext, offset, binding.size));
                         if (bindingVisibility & wgpu::ShaderStage::Vertex) {
                             deviceContext->VSSetShaderResources(bindingSlot, 1,
                                                                 d3d11SRV.GetAddressOf());
diff --git a/src/dawn/native/d3d11/BufferD3D11.cpp b/src/dawn/native/d3d11/BufferD3D11.cpp
index 3401b6b..307e905 100644
--- a/src/dawn/native/d3d11/BufferD3D11.cpp
+++ b/src/dawn/native/d3d11/BufferD3D11.cpp
@@ -52,11 +52,13 @@
 
 namespace {
 
-constexpr wgpu::BufferUsage kD3D11AllowedUniformBufferUsages =
+constexpr wgpu::BufferUsage kD3D11GPUOnlyUniformBufferUsages =
     wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::CopySrc;
 
 constexpr wgpu::BufferUsage kCopyUsages = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
 
+constexpr wgpu::BufferUsage kStagingUsages = kMappableBufferUsages | kCopyUsages;
+
 // Resource usage    Default    Dynamic   Immutable   Staging
 // ------------------------------------------------------------
 //  GPU-read         Yes        Yes       Yes         Yes[1]
@@ -78,7 +80,7 @@
 
 bool IsStaging(wgpu::BufferUsage usage) {
     // Must have at least MapWrite or MapRead bit
-    return IsMappable(usage) && IsSubset(usage, kMappableBufferUsages | kCopyUsages);
+    return IsMappable(usage) && IsSubset(usage, kStagingUsages);
 }
 
 UINT D3D11BufferBindFlags(wgpu::BufferUsage usage) {
@@ -94,6 +96,7 @@
         bindFlags |= D3D11_BIND_CONSTANT_BUFFER;
     }
     if (usage & (wgpu::BufferUsage::Storage | kInternalStorageBuffer)) {
+        DAWN_ASSERT(!IsMappable(usage));
         bindFlags |= D3D11_BIND_UNORDERED_ACCESS;
     }
     if (usage & kReadOnlyStorageBuffer) {
@@ -113,7 +116,7 @@
 
 UINT D3D11BufferMiscFlags(wgpu::BufferUsage usage) {
     UINT miscFlags = 0;
-    if (usage & (wgpu::BufferUsage::Storage | kInternalStorageBuffer)) {
+    if (usage & (wgpu::BufferUsage::Storage | kInternalStorageBuffer | kReadOnlyStorageBuffer)) {
         miscFlags |= D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
     }
     if (usage & wgpu::BufferUsage::Indirect) {
@@ -144,9 +147,14 @@
 // For CPU-to-GPU upload buffers(CopySrc|MapWrite), they can be emulated in the system memory, and
 // then written into the dest GPU buffer via ID3D11DeviceContext::UpdateSubresource.
 class UploadBuffer final : public Buffer {
-    using Buffer::Buffer;
+  public:
+    UploadBuffer(DeviceBase* device, const UnpackedPtr<BufferDescriptor>& descriptor)
+        : Buffer(device,
+                 descriptor,
+                 /*internalMappableFlags=*/kMappableBufferUsages) {}
     ~UploadBuffer() override = default;
 
+  private:
     MaybeError InitializeInternal() override {
         mUploadData = std::unique_ptr<uint8_t[]>(AllocNoThrow<uint8_t>(GetAllocatedSize()));
         if (mUploadData == nullptr) {
@@ -155,7 +163,8 @@
         return {};
     }
 
-    MaybeError MapInternal(const ScopedCommandRecordingContext* commandContext) override {
+    MaybeError MapInternal(const ScopedCommandRecordingContext* commandContext,
+                           wgpu::MapMode) override {
         mMappedData = mUploadData.get();
         return {};
     }
@@ -205,8 +214,11 @@
 
 // Buffer that supports mapping and copying.
 class StagingBuffer final : public Buffer {
-    using Buffer::Buffer;
+  public:
+    StagingBuffer(DeviceBase* device, const UnpackedPtr<BufferDescriptor>& descriptor)
+        : Buffer(device, descriptor, /*internalMappableFlags=*/kMappableBufferUsages) {}
 
+  private:
     void DestroyImpl() override {
         // TODO(crbug.com/dawn/831): DestroyImpl is called from two places.
         // - It may be called if the buffer is explicitly destroyed with APIDestroy.
@@ -251,7 +263,8 @@
         return {};
     }
 
-    MaybeError MapInternal(const ScopedCommandRecordingContext* commandContext) override {
+    MaybeError MapInternal(const ScopedCommandRecordingContext* commandContext,
+                           wgpu::MapMode) override {
         DAWN_ASSERT(IsMappable(GetUsage()));
         DAWN_ASSERT(!mMappedData);
 
@@ -317,7 +330,7 @@
         }
 
         ScopedMap scopedMap;
-        DAWN_TRY_ASSIGN(scopedMap, ScopedMap::Create(commandContext, this));
+        DAWN_TRY_ASSIGN(scopedMap, ScopedMap::Create(commandContext, this, wgpu::MapMode::Write));
 
         DAWN_ASSERT(scopedMap.GetMappedData());
         memcpy(scopedMap.GetMappedData() + offset, data, size);
@@ -328,6 +341,65 @@
     ComPtr<ID3D11Buffer> mD3d11Buffer;
 };
 
+// Buffer that can only be written/read by GPU.
+class GPUOnlyBuffer final : public GPUUsableBuffer {
+  public:
+    GPUOnlyBuffer(DeviceBase* device, const UnpackedPtr<BufferDescriptor>& descriptor)
+        : GPUUsableBuffer(device, descriptor, /*internalMappableFlags=*/wgpu::BufferUsage::None) {}
+
+    ResultOrError<ID3D11Buffer*> GetD3D11ConstantBuffer(
+        const ScopedCommandRecordingContext* commandContext) override;
+    ResultOrError<ID3D11Buffer*> GetD3D11NonConstantBuffer(
+        const ScopedCommandRecordingContext* commandContext) override;
+
+    ResultOrError<ComPtr<ID3D11ShaderResourceView>> UseAsSRV(
+        const ScopedCommandRecordingContext* commandContext,
+        uint64_t offset,
+        uint64_t size) override;
+    ResultOrError<ComPtr<ID3D11UnorderedAccessView1>> UseAsUAV(
+        const ScopedCommandRecordingContext* commandContext,
+        uint64_t offset,
+        uint64_t size) override;
+
+    MaybeError PredicatedClear(const ScopedSwapStateCommandRecordingContext* commandContext,
+                               ID3D11Predicate* predicate,
+                               uint8_t clearValue,
+                               uint64_t offset,
+                               uint64_t size) override;
+
+  private:
+    // Dawn API
+    void DestroyImpl() override;
+    void SetLabelImpl() override;
+
+    MaybeError InitializeInternal() override;
+
+    MaybeError CopyToInternal(const ScopedCommandRecordingContext* commandContext,
+                              uint64_t sourceOffset,
+                              size_t size,
+                              Buffer* destination,
+                              uint64_t destinationOffset) override;
+    MaybeError CopyFromD3DInternal(const ScopedCommandRecordingContext* commandContext,
+                                   ID3D11Buffer* srcD3D11Buffer,
+                                   uint64_t sourceOffset,
+                                   size_t size,
+                                   uint64_t destinationOffset) override;
+
+    MaybeError WriteInternal(const ScopedCommandRecordingContext* commandContext,
+                             uint64_t bufferOffset,
+                             const void* data,
+                             size_t size) override;
+
+    MaybeError ClearPaddingInternal(const ScopedCommandRecordingContext* commandContext) override;
+
+    // The buffer object for constant buffer usage.
+    ComPtr<ID3D11Buffer> mD3d11ConstantBuffer;
+    // The buffer object for non-constant buffer usages(e.g. storage buffer, vertex buffer, etc.)
+    ComPtr<ID3D11Buffer> mD3d11NonConstantBuffer;
+
+    bool mConstantBufferIsUpdated = true;
+};
+
 // static
 ResultOrError<Ref<Buffer>> Buffer::Create(Device* device,
                                           const UnpackedPtr<BufferDescriptor>& descriptor,
@@ -349,6 +421,11 @@
     return buffer;
 }
 
+Buffer::Buffer(DeviceBase* device,
+               const UnpackedPtr<BufferDescriptor>& descriptor,
+               wgpu::BufferUsage internalMappableFlags)
+    : BufferBase(device, descriptor), mInternalMappableFlags(internalMappableFlags) {}
+
 MaybeError Buffer::Initialize(bool mappedAtCreation,
                               const ScopedCommandRecordingContext* commandContext) {
     // TODO(dawn:1705): handle mappedAtCreation for NonzeroClearResourcesOnCreationForTesting
@@ -373,14 +450,14 @@
     SetLabelImpl();
 
     if (!mappedAtCreation) {
-            if (commandContext) {
-                DAWN_TRY(ClearInitialResource(commandContext));
-            } else {
-                auto tmpCommandContext =
-                    ToBackend(GetDevice()->GetQueue())
-                        ->GetScopedPendingCommandContext(QueueBase::SubmitMode::Normal);
-                DAWN_TRY(ClearInitialResource(&tmpCommandContext));
-            }
+        if (commandContext) {
+            DAWN_TRY(ClearInitialResource(commandContext));
+        } else {
+            auto tmpCommandContext =
+                ToBackend(GetDevice()->GetQueue())
+                    ->GetScopedPendingCommandContext(QueueBase::SubmitMode::Normal);
+            DAWN_TRY(ClearInitialResource(&tmpCommandContext));
+        }
     }
 
     return {};
@@ -401,18 +478,38 @@
 Buffer::~Buffer() = default;
 
 bool Buffer::IsCPUWritableAtCreation() const {
-    return IsMappable(GetUsage());
+    return IsCPUWritable();
+}
+
+bool Buffer::IsCPUWritable() const {
+    return mInternalMappableFlags & wgpu::BufferUsage::MapWrite;
+}
+
+bool Buffer::IsCPUReadable() const {
+    return mInternalMappableFlags & wgpu::BufferUsage::MapRead;
 }
 
 MaybeError Buffer::MapAtCreationImpl() {
-    DAWN_ASSERT(IsMappable(GetUsage()));
+    DAWN_ASSERT(IsCPUWritable());
     auto commandContext = ToBackend(GetDevice()->GetQueue())
                               ->GetScopedPendingCommandContext(QueueBase::SubmitMode::Normal);
-    return MapInternal(&commandContext);
+    return MapInternal(&commandContext, wgpu::MapMode::Write);
+}
+
+MaybeError Buffer::MapInternal(const ScopedCommandRecordingContext* commandContext,
+                               wgpu::MapMode mode) {
+    DAWN_UNREACHABLE();
+
+    return {};
+}
+
+void Buffer::UnmapInternal(const ScopedCommandRecordingContext* commandContext) {
+    DAWN_UNREACHABLE();
 }
 
 MaybeError Buffer::MapAsyncImpl(wgpu::MapMode mode, size_t offset, size_t size) {
-    DAWN_ASSERT(IsMappable(GetUsage()));
+    DAWN_ASSERT((mode == wgpu::MapMode::Write && IsCPUWritable()) ||
+                (mode == wgpu::MapMode::Read && IsCPUReadable()));
 
     mMapReadySerial = mLastUsageSerial;
     const ExecutionSerial completedSerial = GetDevice()->GetQueue()->GetCompletedCommandSerial();
@@ -420,22 +517,23 @@
     // commands. To avoid that, instead we ask Queue to do the map later when mLastUsageSerial has
     // passed.
     if (mMapReadySerial > completedSerial) {
-        ToBackend(GetDevice()->GetQueue())->TrackPendingMapBuffer({this}, mMapReadySerial);
+        ToBackend(GetDevice()->GetQueue())->TrackPendingMapBuffer({this}, mode, mMapReadySerial);
     } else {
         auto commandContext = ToBackend(GetDevice()->GetQueue())
                                   ->GetScopedPendingCommandContext(QueueBase::SubmitMode::Normal);
-        DAWN_TRY(FinalizeMap(&commandContext, completedSerial));
+        DAWN_TRY(FinalizeMap(&commandContext, completedSerial, mode));
     }
 
     return {};
 }
 
 MaybeError Buffer::FinalizeMap(ScopedCommandRecordingContext* commandContext,
-                               ExecutionSerial completedSerial) {
+                               ExecutionSerial completedSerial,
+                               wgpu::MapMode mode) {
     // Needn't map the buffer if this is for a previous mapAsync that was cancelled.
     if (completedSerial >= mMapReadySerial) {
         // TODO(dawn:1705): make sure the map call is not blocked by the GPU operations.
-        DAWN_TRY(MapInternal(commandContext));
+        DAWN_TRY(MapInternal(commandContext, mode));
 
         DAWN_TRY(EnsureDataInitialized(commandContext));
     }
@@ -525,6 +623,15 @@
     return {};
 }
 
+MaybeError Buffer::PredicatedClear(const ScopedSwapStateCommandRecordingContext* commandContext,
+                                   ID3D11Predicate* predicate,
+                                   uint8_t clearValue,
+                                   uint64_t offset,
+                                   uint64_t size) {
+    DAWN_UNREACHABLE();
+    return {};
+}
+
 MaybeError Buffer::Clear(const ScopedCommandRecordingContext* commandContext,
                          uint8_t clearValue,
                          uint64_t offset,
@@ -538,7 +645,7 @@
     // Map the buffer if it is possible, so EnsureDataInitializedAsDestination() and ClearInternal()
     // can write the mapped memory directly.
     ScopedMap scopedMap;
-    DAWN_TRY_ASSIGN(scopedMap, ScopedMap::Create(commandContext, this));
+    DAWN_TRY_ASSIGN(scopedMap, ScopedMap::Create(commandContext, this, wgpu::MapMode::Write));
 
     // For non-staging buffers, we can use UpdateSubresource to write the data.
     DAWN_TRY(EnsureDataInitializedAsDestination(commandContext, offset, size));
@@ -584,7 +691,7 @@
     // Map the buffer if it is possible, so EnsureDataInitializedAsDestination() and WriteInternal()
     // can write the mapped memory directly.
     ScopedMap scopedMap;
-    DAWN_TRY_ASSIGN(scopedMap, ScopedMap::Create(commandContext, this));
+    DAWN_TRY_ASSIGN(scopedMap, ScopedMap::Create(commandContext, this, wgpu::MapMode::Write));
 
     // For non-staging buffers, we can use UpdateSubresource to write the data.
     DAWN_TRY(EnsureDataInitializedAsDestination(commandContext, offset, size));
@@ -609,8 +716,12 @@
 
 ResultOrError<Buffer::ScopedMap> Buffer::ScopedMap::Create(
     const ScopedCommandRecordingContext* commandContext,
-    Buffer* buffer) {
-    if (!IsMappable(buffer->GetUsage())) {
+    Buffer* buffer,
+    wgpu::MapMode mode) {
+    if (mode == wgpu::MapMode::Write && !buffer->IsCPUWritable()) {
+        return ScopedMap();
+    }
+    if (mode == wgpu::MapMode::Read && !buffer->IsCPUReadable()) {
         return ScopedMap();
     }
 
@@ -618,7 +729,7 @@
         return ScopedMap(commandContext, buffer, /*needsUnmap=*/false);
     }
 
-    DAWN_TRY(buffer->MapInternal(commandContext));
+    DAWN_TRY(buffer->MapInternal(commandContext, mode));
     return ScopedMap(commandContext, buffer, /*needsUnmap=*/true);
 }
 
@@ -661,6 +772,153 @@
     return mBuffer ? mBuffer->mMappedData.get() : nullptr;
 }
 
+// GPUUsableBuffer
+ID3D11Buffer* GPUUsableBuffer::GetD3D11ConstantBufferForTesting() {
+    ID3D11Buffer* buffer;
+    if (GetDevice()->ConsumedError(GetD3D11ConstantBuffer(nullptr), &buffer)) {
+        return nullptr;
+    }
+
+    return buffer;
+}
+
+ID3D11Buffer* GPUUsableBuffer::GetD3D11NonConstantBufferForTesting() {
+    ID3D11Buffer* buffer;
+    if (GetDevice()->ConsumedError(GetD3D11NonConstantBuffer(nullptr), &buffer)) {
+        return nullptr;
+    }
+
+    return buffer;
+}
+
+ResultOrError<ComPtr<ID3D11ShaderResourceView>>
+GPUUsableBuffer::CreateD3D11ShaderResourceViewFromD3DBuffer(ID3D11Buffer* d3d11Buffer,
+                                                            uint64_t offset,
+                                                            uint64_t size) {
+    DAWN_ASSERT(IsAligned(offset, 4u));
+    DAWN_ASSERT(IsAligned(size, 4u));
+    UINT firstElement = static_cast<UINT>(offset / 4);
+    UINT numElements = static_cast<UINT>(size / 4);
+
+    D3D11_SHADER_RESOURCE_VIEW_DESC desc;
+    desc.Format = DXGI_FORMAT_R32_TYPELESS;
+    desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX;
+    desc.BufferEx.FirstElement = firstElement;
+    desc.BufferEx.NumElements = numElements;
+    desc.BufferEx.Flags = D3D11_BUFFEREX_SRV_FLAG_RAW;
+    ComPtr<ID3D11ShaderResourceView> srv;
+    DAWN_TRY(CheckHRESULT(ToBackend(GetDevice())
+                              ->GetD3D11Device()
+                              ->CreateShaderResourceView(d3d11Buffer, &desc, &srv),
+                          "ShaderResourceView creation"));
+
+    return srv;
+}
+
+ResultOrError<ComPtr<ID3D11UnorderedAccessView1>>
+GPUUsableBuffer::CreateD3D11UnorderedAccessViewFromD3DBuffer(ID3D11Buffer* d3d11Buffer,
+                                                             uint64_t offset,
+                                                             uint64_t size) {
+    DAWN_ASSERT(IsAligned(offset, 4u));
+    DAWN_ASSERT(IsAligned(size, 4u));
+
+    UINT firstElement = static_cast<UINT>(offset / 4);
+    UINT numElements = static_cast<UINT>(size / 4);
+
+    D3D11_UNORDERED_ACCESS_VIEW_DESC1 desc;
+    desc.Format = DXGI_FORMAT_R32_TYPELESS;
+    desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
+    desc.Buffer.FirstElement = firstElement;
+    desc.Buffer.NumElements = numElements;
+    desc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW;
+
+    ComPtr<ID3D11UnorderedAccessView1> uav;
+    DAWN_TRY(CheckHRESULT(ToBackend(GetDevice())
+                              ->GetD3D11Device5()
+                              ->CreateUnorderedAccessView1(d3d11Buffer, &desc, &uav),
+                          "UnorderedAccessView creation"));
+
+    return uav;
+}
+
+MaybeError GPUUsableBuffer::UpdateD3D11ConstantBuffer(
+    const ScopedCommandRecordingContext* commandContext,
+    ID3D11Buffer* d3d11Buffer,
+    bool firstTimeUpdate,
+    uint64_t offset,
+    const void* data,
+    size_t size) {
+    DAWN_ASSERT(size > 0);
+
+    // For a full size write, UpdateSubresource1(D3D11_COPY_DISCARD) can be used to update
+    // constant buffer.
+    // WriteInternal() can be called with GetAllocatedSize(). We treat it as a full buffer write as
+    // well.
+    bool fullSizeUpdate = size >= GetSize() && offset == 0;
+    if (fullSizeUpdate || firstTimeUpdate) {
+        // Offset and size must be aligned with 16 for using UpdateSubresource1() on constant
+        // buffer.
+        size_t alignedOffset;
+        if (offset < kConstantBufferUpdateAlignment - 1) {
+            alignedOffset = 0;
+        } else {
+            // For offset we align to value <= offset.
+            alignedOffset = Align(offset - (kConstantBufferUpdateAlignment - 1),
+                                  kConstantBufferUpdateAlignment);
+        }
+        size_t alignedEnd = Align(offset + size, kConstantBufferUpdateAlignment);
+        size_t alignedSize = alignedEnd - alignedOffset;
+
+        DAWN_ASSERT((alignedSize % kConstantBufferUpdateAlignment) == 0);
+        DAWN_ASSERT(alignedSize <= GetAllocatedSize());
+        DAWN_ASSERT(offset >= alignedOffset);
+
+        // Extra bytes on the left of offset we could write to. This is only valid if
+        // firstTimeUpdate = true.
+        size_t leftExtraBytes = offset - alignedOffset;
+        DAWN_ASSERT(leftExtraBytes == 0 || firstTimeUpdate);
+
+        // The layout of the buffer is like this:
+        // |..........................| leftExtraBytes |     data   | ............... |
+        // |<----------------- offset ---------------->|<-- size -->|
+        // |<----- alignedOffset ---->|<--------- alignedSize --------->|
+        std::unique_ptr<uint8_t[]> alignedBuffer;
+        if (size != alignedSize) {
+            alignedBuffer.reset(new uint8_t[alignedSize]);
+            std::memcpy(alignedBuffer.get() + leftExtraBytes, data, size);
+            data = alignedBuffer.get();
+        }
+
+        D3D11_BOX dstBox;
+        dstBox.left = static_cast<UINT>(alignedOffset);
+        dstBox.top = 0;
+        dstBox.front = 0;
+        dstBox.right = static_cast<UINT>(alignedOffset + alignedSize);
+        dstBox.bottom = 1;
+        dstBox.back = 1;
+        // For full buffer write, D3D11_COPY_DISCARD is used to avoid GPU CPU synchronization.
+        commandContext->UpdateSubresource1(d3d11Buffer, /*DstSubresource=*/0, &dstBox, data,
+                                           /*SrcRowPitch=*/0,
+                                           /*SrcDepthPitch=*/0,
+                                           /*CopyFlags=*/D3D11_COPY_DISCARD);
+        return {};
+    }
+
+    // If copy offset and size are not 16 bytes aligned, we have to create a staging buffer for
+    // transfer the data to constant buffer.
+    Ref<BufferBase> stagingBuffer;
+    DAWN_TRY_ASSIGN(stagingBuffer, ToBackend(GetDevice())->GetStagingBuffer(commandContext, size));
+    stagingBuffer->MarkUsedInPendingCommands();
+    DAWN_TRY(ToBackend(stagingBuffer)->WriteInternal(commandContext, 0, data, size));
+    DAWN_TRY(ToBackend(stagingBuffer.Get())
+                 ->CopyToInternal(commandContext,
+                                  /*sourceOffset=*/0,
+                                  /*size=*/size, this, offset));
+    ToBackend(GetDevice())->ReturnStagingBuffer(std::move(stagingBuffer));
+
+    return {};
+}
+
 // GPUOnlyBuffer
 void GPUOnlyBuffer::DestroyImpl() {
     // TODO(crbug.com/dawn/831): DestroyImpl is called from two places.
@@ -670,7 +928,7 @@
     // - It may be called when the last ref to the buffer is dropped and the buffer
     //   is implicitly destroyed. This case is thread-safe because there are no
     //   other threads using the buffer since there are no other live refs.
-    Buffer::DestroyImpl();
+    GPUUsableBuffer::DestroyImpl();
 
     mD3d11ConstantBuffer = nullptr;
     mD3d11NonConstantBuffer = nullptr;
@@ -687,7 +945,7 @@
 
     bool needsConstantBuffer = GetUsage() & wgpu::BufferUsage::Uniform;
     bool onlyNeedsConstantBuffer =
-        needsConstantBuffer && IsSubset(GetUsage(), kD3D11AllowedUniformBufferUsages);
+        needsConstantBuffer && IsSubset(GetUsage(), kD3D11GPUOnlyUniformBufferUsages);
 
     if (!onlyNeedsConstantBuffer) {
         // Create mD3d11NonConstantBuffer
@@ -729,78 +987,60 @@
     return {};
 }
 
-MaybeError GPUOnlyBuffer::MapInternal(const ScopedCommandRecordingContext* commandContext) {
-    DAWN_UNREACHABLE();
-
-    return {};
+MaybeError GPUOnlyBuffer::PredicatedClear(
+    const ScopedSwapStateCommandRecordingContext* commandContext,
+    ID3D11Predicate* predicate,
+    uint8_t clearValue,
+    uint64_t offset,
+    uint64_t size) {
+    // The clear will *NOT* be performed if the predicate's data is false.
+    commandContext->GetD3D11DeviceContext4()->SetPredication(predicate, false);
+    auto result = Clear(commandContext, clearValue, offset, size);
+    commandContext->GetD3D11DeviceContext4()->SetPredication(nullptr, false);
+    return result;
 }
 
-void GPUOnlyBuffer::UnmapInternal(const ScopedCommandRecordingContext* commandContext) {
-    DAWN_UNREACHABLE();
-}
-
-void GPUOnlyBuffer::MarkMutated() {
-    mConstantBufferIsUpdated = false;
-}
-
-void GPUOnlyBuffer::EnsureConstantBufferIsUpdated(
+ResultOrError<ID3D11Buffer*> GPUOnlyBuffer::GetD3D11ConstantBuffer(
     const ScopedCommandRecordingContext* commandContext) {
     if (mConstantBufferIsUpdated) {
-        return;
+        return mD3d11ConstantBuffer.Get();
     }
 
     DAWN_ASSERT(mD3d11NonConstantBuffer);
     DAWN_ASSERT(mD3d11ConstantBuffer);
-    commandContext->CopyResource(mD3d11ConstantBuffer.Get(), mD3d11NonConstantBuffer.Get());
+    if (commandContext) {
+        commandContext->CopyResource(mD3d11ConstantBuffer.Get(), mD3d11NonConstantBuffer.Get());
+    } else {
+        auto tempCommandContext =
+            ToBackend(GetDevice()->GetQueue())
+                ->GetScopedPendingCommandContext(QueueBase::SubmitMode::Normal);
+        tempCommandContext.CopyResource(mD3d11ConstantBuffer.Get(), mD3d11NonConstantBuffer.Get());
+    }
     mConstantBufferIsUpdated = true;
+
+    return mD3d11ConstantBuffer.Get();
 }
 
-ResultOrError<ComPtr<ID3D11ShaderResourceView>> GPUOnlyBuffer::CreateD3D11ShaderResourceView(
-    uint64_t offset,
-    uint64_t size) const {
-    DAWN_ASSERT(IsAligned(offset, 4u));
-    DAWN_ASSERT(IsAligned(size, 4u));
-    UINT firstElement = static_cast<UINT>(offset / 4);
-    UINT numElements = static_cast<UINT>(size / 4);
-
-    D3D11_SHADER_RESOURCE_VIEW_DESC desc;
-    desc.Format = DXGI_FORMAT_R32_TYPELESS;
-    desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX;
-    desc.BufferEx.FirstElement = firstElement;
-    desc.BufferEx.NumElements = numElements;
-    desc.BufferEx.Flags = D3D11_BUFFEREX_SRV_FLAG_RAW;
-    ComPtr<ID3D11ShaderResourceView> srv;
-    DAWN_TRY(
-        CheckHRESULT(ToBackend(GetDevice())
-                         ->GetD3D11Device()
-                         ->CreateShaderResourceView(mD3d11NonConstantBuffer.Get(), &desc, &srv),
-                     "ShaderResourceView creation"));
-
-    return srv;
+ResultOrError<ID3D11Buffer*> GPUOnlyBuffer::GetD3D11NonConstantBuffer(
+    const ScopedCommandRecordingContext*) {
+    return mD3d11NonConstantBuffer.Get();
 }
 
-ResultOrError<ComPtr<ID3D11UnorderedAccessView1>> GPUOnlyBuffer::CreateD3D11UnorderedAccessView1(
-    uint64_t offset,
-    uint64_t size) const {
-    DAWN_ASSERT(IsAligned(offset, 4u));
-    DAWN_ASSERT(IsAligned(size, 4u));
+ResultOrError<ComPtr<ID3D11ShaderResourceView>>
+GPUOnlyBuffer::UseAsSRV(const ScopedCommandRecordingContext*, uint64_t offset, uint64_t size) {
+    return CreateD3D11ShaderResourceViewFromD3DBuffer(mD3d11NonConstantBuffer.Get(), offset, size);
+}
 
-    UINT firstElement = static_cast<UINT>(offset / 4);
-    UINT numElements = static_cast<UINT>(size / 4);
-
-    D3D11_UNORDERED_ACCESS_VIEW_DESC1 desc;
-    desc.Format = DXGI_FORMAT_R32_TYPELESS;
-    desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
-    desc.Buffer.FirstElement = firstElement;
-    desc.Buffer.NumElements = numElements;
-    desc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW;
-
+ResultOrError<ComPtr<ID3D11UnorderedAccessView1>>
+GPUOnlyBuffer::UseAsUAV(const ScopedCommandRecordingContext*, uint64_t offset, uint64_t size) {
     ComPtr<ID3D11UnorderedAccessView1> uav;
-    DAWN_TRY(
-        CheckHRESULT(ToBackend(GetDevice())
-                         ->GetD3D11Device5()
-                         ->CreateUnorderedAccessView1(mD3d11NonConstantBuffer.Get(), &desc, &uav),
-                     "UnorderedAccessView creation"));
+    DAWN_TRY_ASSIGN(uav, CreateD3D11UnorderedAccessViewFromD3DBuffer(mD3d11NonConstantBuffer.Get(),
+                                                                     offset, size));
+
+    // Since UAV will modify the non-constant buffer's content, the constant buffer's content would
+    // also need to be updated afterwards.
+    mConstantBufferIsUpdated = false;
+
     return uav;
 }
 
@@ -846,52 +1086,8 @@
 
     DAWN_ASSERT(mD3d11ConstantBuffer);
 
-    // For a full size write, UpdateSubresource1(D3D11_COPY_DISCARD) can be used to update
-    // mD3d11ConstantBuffer.
-    // WriteInternal() can be called with GetAllocatedSize(). We treat it as a full buffer write as
-    // well.
-    if (size >= GetSize() && offset == 0) {
-        // Offset and size must be aligned with 16 for using UpdateSubresource1() on constant
-        // buffer.
-        size_t alignedSize = Align(size, kConstantBufferUpdateAlignment);
-        DAWN_ASSERT(alignedSize <= GetAllocatedSize());
-        std::unique_ptr<uint8_t[]> alignedBuffer;
-        if (size != alignedSize) {
-            alignedBuffer.reset(new uint8_t[alignedSize]);
-            std::memcpy(alignedBuffer.get(), data, size);
-            data = alignedBuffer.get();
-        }
-
-        D3D11_BOX dstBox;
-        dstBox.left = 0;
-        dstBox.top = 0;
-        dstBox.front = 0;
-        dstBox.right = static_cast<UINT>(alignedSize);
-        dstBox.bottom = 1;
-        dstBox.back = 1;
-        // For full buffer write, D3D11_COPY_DISCARD is used to avoid GPU CPU synchronization.
-        commandContext->UpdateSubresource1(mD3d11ConstantBuffer.Get(), /*DstSubresource=*/0,
-                                           &dstBox, data,
-                                           /*SrcRowPitch=*/0,
-                                           /*SrcDepthPitch=*/0,
-                                           /*CopyFlags=*/D3D11_COPY_DISCARD);
-        return {};
-    }
-
-    // If the mD3d11NonConstantBuffer is null and copy offset and size are not 16 bytes
-    // aligned, we have to create a staging buffer for transfer the data to
-    // mD3d11ConstantBuffer.
-    Ref<BufferBase> stagingBuffer;
-    DAWN_TRY_ASSIGN(stagingBuffer, ToBackend(GetDevice())->GetStagingBuffer(commandContext, size));
-    stagingBuffer->MarkUsedInPendingCommands();
-    DAWN_TRY(ToBackend(stagingBuffer)->WriteInternal(commandContext, 0, data, size));
-    DAWN_TRY(ToBackend(stagingBuffer.Get())
-                 ->CopyToInternal(commandContext,
-                                  /*sourceOffset=*/0,
-                                  /*size=*/size, this, offset));
-    ToBackend(GetDevice())->ReturnStagingBuffer(std::move(stagingBuffer));
-
-    return {};
+    return UpdateD3D11ConstantBuffer(commandContext, mD3d11ConstantBuffer.Get(),
+                                     /*firstUpdate=*/false, offset, data, size);
 }
 
 MaybeError GPUOnlyBuffer::CopyToInternal(const ScopedCommandRecordingContext* commandContext,
@@ -956,26 +1152,16 @@
     uint64_t clearOffset = GetSize();
     // 'UpdateSubresource1' is more preferable for updating uniform buffers, as it incurs no
     // GPU stall.
-    if (GetUsage() & wgpu::BufferUsage::Uniform && !GetD3D11NonConstantBuffer()) {
+    if (mD3d11ConstantBuffer && !mD3d11NonConstantBuffer) {
         clearSize = Align(paddingBytes, kConstantBufferUpdateAlignment);
         clearOffset = GetAllocatedSize() - clearSize;
 
-        D3D11_BOX dstBox;
-        dstBox.left = clearOffset;
-        dstBox.top = 0;
-        dstBox.front = 0;
-        dstBox.right = GetAllocatedSize();
-        dstBox.bottom = 1;
-        dstBox.back = 1;
-
         std::vector<uint8_t> clearData(clearSize, 0);
-        commandContext->UpdateSubresource1(GetD3D11ConstantBuffer(),
-                                           /*DstSubresource=*/0, &dstBox, clearData.data(),
-                                           /*SrcRowPitch=*/0,
-                                           /*SrcDepthPitch=*/0,
-                                           /*CopyFlags=*/D3D11_COPY_DISCARD);
+        DAWN_TRY(UpdateD3D11ConstantBuffer(commandContext, mD3d11ConstantBuffer.Get(),
+                                           /*firstTimeUpdate=*/true, clearOffset, clearData.data(),
+                                           clearSize));
     } else {
-        DAWN_TRY(ClearInternal(commandContext, 0, clearOffset, clearSize));
+        DAWN_TRY(ClearInternal(commandContext, 0, clearOffset, paddingBytes));
     }
 
     return {};
diff --git a/src/dawn/native/d3d11/BufferD3D11.h b/src/dawn/native/d3d11/BufferD3D11.h
index f8e1175..268ebbd9 100644
--- a/src/dawn/native/d3d11/BufferD3D11.h
+++ b/src/dawn/native/d3d11/BufferD3D11.h
@@ -41,6 +41,7 @@
 
 class Device;
 class ScopedCommandRecordingContext;
+class ScopedSwapStateCommandRecordingContext;
 
 class Buffer : public BufferBase {
   public:
@@ -76,7 +77,19 @@
 
     // Actually map the buffer when its last usage serial has passed.
     MaybeError FinalizeMap(ScopedCommandRecordingContext* commandContext,
-                           ExecutionSerial completedSerial);
+                           ExecutionSerial completedSerial,
+                           wgpu::MapMode mode);
+
+    bool IsCPUWritable() const;
+    bool IsCPUReadable() const;
+
+    // This performs GPU Clear. Unlike Clear(), this will always be affected by ID3D11Predicate.
+    // Whereas Clear() might be unaffected by ID3D11Predicate if it's pure CPU clear.
+    virtual MaybeError PredicatedClear(const ScopedSwapStateCommandRecordingContext* commandContext,
+                                       ID3D11Predicate* predicate,
+                                       uint8_t clearValue,
+                                       uint64_t offset,
+                                       uint64_t size);
 
     // Write the buffer without checking if the buffer is initialized.
     virtual MaybeError WriteInternal(const ScopedCommandRecordingContext* commandContext,
@@ -101,7 +114,8 @@
         // Map buffer and return a ScopedMap object. If the buffer is not mappable,
         // scopedMap.GetMappedData() will return nullptr.
         static ResultOrError<ScopedMap> Create(const ScopedCommandRecordingContext* commandContext,
-                                               Buffer* buffer);
+                                               Buffer* buffer,
+                                               wgpu::MapMode mode);
 
         ScopedMap();
         ~ScopedMap();
@@ -125,16 +139,18 @@
     };
 
   protected:
-    using BufferBase::BufferBase;
-
+    Buffer(DeviceBase* device,
+           const UnpackedPtr<BufferDescriptor>& descriptor,
+           wgpu::BufferUsage internalMappableFlags);
     ~Buffer() override;
 
     void DestroyImpl() override;
 
     virtual MaybeError InitializeInternal() = 0;
 
-    virtual MaybeError MapInternal(const ScopedCommandRecordingContext* commandContext) = 0;
-    virtual void UnmapInternal(const ScopedCommandRecordingContext* commandContext) = 0;
+    virtual MaybeError MapInternal(const ScopedCommandRecordingContext* commandContext,
+                                   wgpu::MapMode mode);
+    virtual void UnmapInternal(const ScopedCommandRecordingContext* commandContext);
 
     // Clear the buffer without checking if the buffer is initialized.
     MaybeError ClearWholeBuffer(const ScopedCommandRecordingContext* commandContext,
@@ -160,69 +176,58 @@
 
     MaybeError InitializeToZero(const ScopedCommandRecordingContext* commandContext);
 
+    // Internal usage indicating the native buffer supports mapping for read and/or write or not.
+    const wgpu::BufferUsage mInternalMappableFlags;
     ExecutionSerial mMapReadySerial = kMaxExecutionSerial;
 };
 
-// Buffer that doesn't support mapping.
-class GPUOnlyBuffer final : public Buffer {
+// Buffer that can be used by GPU.
+class GPUUsableBuffer : public Buffer {
   public:
-    ID3D11Buffer* GetD3D11ConstantBuffer() const { return mD3d11ConstantBuffer.Get(); }
-    ID3D11Buffer* GetD3D11NonConstantBuffer() const { return mD3d11NonConstantBuffer.Get(); }
+    virtual ResultOrError<ID3D11Buffer*> GetD3D11ConstantBuffer(
+        const ScopedCommandRecordingContext* commandContext) = 0;
+    virtual ResultOrError<ID3D11Buffer*> GetD3D11NonConstantBuffer(
+        const ScopedCommandRecordingContext* commandContext) = 0;
+    ID3D11Buffer* GetD3D11ConstantBufferForTesting();
+    ID3D11Buffer* GetD3D11NonConstantBufferForTesting();
 
-    // Mark the mD3d11NonConstantBuffer is mutated by shaders, if mD3d11ConstantBuffer exists,
-    // it will be synced with mD3d11NonConstantBuffer before binding it to the constant buffer slot.
-    void MarkMutated();
-    // Update content of the mD3d11ConstantBuffer from mD3d11NonConstantBuffer if needed.
-    void EnsureConstantBufferIsUpdated(const ScopedCommandRecordingContext* commandContext);
-    ResultOrError<ComPtr<ID3D11ShaderResourceView>> CreateD3D11ShaderResourceView(
+    virtual ResultOrError<ComPtr<ID3D11ShaderResourceView>> UseAsSRV(
+        const ScopedCommandRecordingContext* commandContext,
         uint64_t offset,
-        uint64_t size) const;
-    ResultOrError<ComPtr<ID3D11UnorderedAccessView1>> CreateD3D11UnorderedAccessView1(
-        uint64_t offset,
-        uint64_t size) const;
+        uint64_t size) = 0;
 
-  private:
+    // Use this buffer as UAV and mark it as being mutated by shader.
+    virtual ResultOrError<ComPtr<ID3D11UnorderedAccessView1>> UseAsUAV(
+        const ScopedCommandRecordingContext* commandContext,
+        uint64_t offset,
+        uint64_t size) = 0;
+
+  protected:
     using Buffer::Buffer;
 
-    // Dawn API
-    void DestroyImpl() override;
-    void SetLabelImpl() override;
+    ResultOrError<ComPtr<ID3D11ShaderResourceView>> CreateD3D11ShaderResourceViewFromD3DBuffer(
+        ID3D11Buffer* d3d11Buffer,
+        uint64_t offset,
+        uint64_t size);
+    ResultOrError<ComPtr<ID3D11UnorderedAccessView1>> CreateD3D11UnorderedAccessViewFromD3DBuffer(
+        ID3D11Buffer* d3d11Buffer,
+        uint64_t offset,
+        uint64_t size);
 
-    // The buffer object for constant buffer usage.
-    ComPtr<ID3D11Buffer> mD3d11ConstantBuffer;
-    // The buffer object for non-constant buffer usages(e.g. storage buffer, vertex buffer, etc.)
-    ComPtr<ID3D11Buffer> mD3d11NonConstantBuffer;
-
-    MaybeError InitializeInternal() override;
-    MaybeError MapInternal(const ScopedCommandRecordingContext* commandContext) override;
-    void UnmapInternal(const ScopedCommandRecordingContext* commandContext) override;
-    MaybeError CopyToInternal(const ScopedCommandRecordingContext* commandContext,
-                              uint64_t sourceOffset,
-                              size_t size,
-                              Buffer* destination,
-                              uint64_t destinationOffset) override;
-    MaybeError CopyFromD3DInternal(const ScopedCommandRecordingContext* commandContext,
-                                   ID3D11Buffer* srcD3D11Buffer,
-                                   uint64_t sourceOffset,
-                                   size_t size,
-                                   uint64_t destinationOffset) override;
-
-    MaybeError WriteInternal(const ScopedCommandRecordingContext* commandContext,
-                             uint64_t bufferOffset,
-                             const void* data,
-                             size_t size) override;
-
-    MaybeError ClearPaddingInternal(const ScopedCommandRecordingContext* commandContext) override;
-
-    bool mConstantBufferIsUpdated = true;
+    MaybeError UpdateD3D11ConstantBuffer(const ScopedCommandRecordingContext* commandContext,
+                                         ID3D11Buffer* d3d11Buffer,
+                                         bool firstTimeUpdate,
+                                         uint64_t bufferOffset,
+                                         const void* data,
+                                         size_t size);
 };
 
-static inline GPUOnlyBuffer* ToGPUOnlyBuffer(BufferBase* buffer) {
-    return static_cast<GPUOnlyBuffer*>(ToBackend(buffer));
+static inline GPUUsableBuffer* ToGPUUsableBuffer(BufferBase* buffer) {
+    return static_cast<GPUUsableBuffer*>(ToBackend(buffer));
 }
 
-static inline Ref<GPUOnlyBuffer> ToGPUOnlyBuffer(Ref<BufferBase>&& buffer) {
-    return std::move(buffer).Cast<Ref<GPUOnlyBuffer>>();
+static inline Ref<GPUUsableBuffer> ToGPUUsableBuffer(Ref<BufferBase>&& buffer) {
+    return std::move(buffer).Cast<Ref<GPUUsableBuffer>>();
 }
 
 }  // namespace dawn::native::d3d11
diff --git a/src/dawn/native/d3d11/CommandBufferD3D11.cpp b/src/dawn/native/d3d11/CommandBufferD3D11.cpp
index 4cee230..571289d 100644
--- a/src/dawn/native/d3d11/CommandBufferD3D11.cpp
+++ b/src/dawn/native/d3d11/CommandBufferD3D11.cpp
@@ -315,7 +315,7 @@
                 Ref<BufferBase> stagingBuffer;
                 // If the buffer is not mappable, we need to create a staging buffer and copy the
                 // data from the buffer to the staging buffer.
-                if (!(buffer->GetUsage() & kMappableBufferUsages)) {
+                if (!buffer->IsCPUReadable()) {
                     const TexelBlockInfo& blockInfo =
                         ToBackend(dst.texture)->GetFormat().GetAspectInfo(dst.aspect).block;
                     // TODO(dawn:1768): use compute shader to copy data from buffer to texture.
@@ -335,7 +335,8 @@
                 }
 
                 Buffer::ScopedMap scopedMap;
-                DAWN_TRY_ASSIGN(scopedMap, Buffer::ScopedMap::Create(commandContext, buffer));
+                DAWN_TRY_ASSIGN(scopedMap, Buffer::ScopedMap::Create(commandContext, buffer,
+                                                                     wgpu::MapMode::Read));
                 DAWN_TRY(buffer->EnsureDataInitialized(commandContext));
 
                 Texture* texture = ToBackend(dst.texture.Get());
@@ -370,7 +371,8 @@
 
                 Buffer* buffer = ToBackend(dst.buffer.Get());
                 Buffer::ScopedMap scopedDstMap;
-                DAWN_TRY_ASSIGN(scopedDstMap, Buffer::ScopedMap::Create(commandContext, buffer));
+                DAWN_TRY_ASSIGN(scopedDstMap, Buffer::ScopedMap::Create(commandContext, buffer,
+                                                                        wgpu::MapMode::Write));
 
                 DAWN_TRY(buffer->EnsureDataInitializedAsDestination(commandContext, copy));
 
@@ -495,7 +497,7 @@
 
                 DAWN_TRY(bindGroupTracker.Apply());
 
-                auto* indirectBuffer = ToGPUOnlyBuffer(dispatch->indirectBuffer.Get());
+                auto* indirectBuffer = ToGPUUsableBuffer(dispatch->indirectBuffer.Get());
 
                 if (lastPipeline->UsesNumWorkgroups()) {
                     // Copy indirect args into the uniform buffer for built-in workgroup variables.
@@ -504,9 +506,11 @@
                                           0));
                 }
 
+                ID3D11Buffer* d3dBuffer;
+                DAWN_TRY_ASSIGN(d3dBuffer,
+                                indirectBuffer->GetD3D11NonConstantBuffer(commandContext));
                 commandContext->GetD3D11DeviceContext4()->DispatchIndirect(
-                    indirectBuffer->GetD3D11NonConstantBuffer(), dispatch->indirectOffset);
-
+                    d3dBuffer, dispatch->indirectOffset);
                 break;
             }
 
@@ -667,7 +671,7 @@
             case Command::DrawIndirect: {
                 DrawIndirectCmd* draw = iter->NextCommand<DrawIndirectCmd>();
 
-                auto* indirectBuffer = ToGPUOnlyBuffer(draw->indirectBuffer.Get());
+                auto* indirectBuffer = ToGPUUsableBuffer(draw->indirectBuffer.Get());
                 DAWN_ASSERT(indirectBuffer != nullptr);
 
                 DAWN_TRY(bindGroupTracker.Apply());
@@ -684,8 +688,11 @@
                                           0));
                 }
 
+                ID3D11Buffer* d3dBuffer;
+                DAWN_TRY_ASSIGN(d3dBuffer,
+                                indirectBuffer->GetD3D11NonConstantBuffer(commandContext));
                 commandContext->GetD3D11DeviceContext4()->DrawInstancedIndirect(
-                    indirectBuffer->GetD3D11NonConstantBuffer(), draw->indirectOffset);
+                    d3dBuffer, draw->indirectOffset);
 
                 break;
             }
@@ -693,7 +700,7 @@
             case Command::DrawIndexedIndirect: {
                 DrawIndexedIndirectCmd* draw = iter->NextCommand<DrawIndexedIndirectCmd>();
 
-                auto* indirectBuffer = ToGPUOnlyBuffer(draw->indirectBuffer.Get());
+                auto* indirectBuffer = ToGPUUsableBuffer(draw->indirectBuffer.Get());
                 DAWN_ASSERT(indirectBuffer != nullptr);
 
                 DAWN_TRY(bindGroupTracker.Apply());
@@ -710,8 +717,11 @@
                                           0));
                 }
 
+                ID3D11Buffer* d3dBuffer;
+                DAWN_TRY_ASSIGN(d3dBuffer,
+                                indirectBuffer->GetD3D11NonConstantBuffer(commandContext));
                 commandContext->GetD3D11DeviceContext4()->DrawIndexedInstancedIndirect(
-                    indirectBuffer->GetD3D11NonConstantBuffer(), draw->indirectOffset);
+                    d3dBuffer, draw->indirectOffset);
 
                 break;
             }
@@ -745,18 +755,21 @@
                 UINT indexBufferBaseOffset = cmd->offset;
                 DXGI_FORMAT indexBufferFormat = DXGIIndexFormat(cmd->format);
 
+                ID3D11Buffer* d3dBuffer;
+                DAWN_TRY_ASSIGN(d3dBuffer, ToGPUUsableBuffer(cmd->buffer.Get())
+                                               ->GetD3D11NonConstantBuffer(commandContext));
                 commandContext->GetD3D11DeviceContext4()->IASetIndexBuffer(
-                    ToGPUOnlyBuffer(cmd->buffer.Get())->GetD3D11NonConstantBuffer(),
-                    indexBufferFormat, indexBufferBaseOffset);
+                    d3dBuffer, indexBufferFormat, indexBufferBaseOffset);
 
                 break;
             }
 
             case Command::SetVertexBuffer: {
                 SetVertexBufferCmd* cmd = iter->NextCommand<SetVertexBufferCmd>();
-                ID3D11Buffer* buffer =
-                    ToGPUOnlyBuffer(cmd->buffer.Get())->GetD3D11NonConstantBuffer();
-                vertexBufferTracker.OnSetVertexBuffer(cmd->slot, buffer, cmd->offset);
+                ID3D11Buffer* d3dBuffer;
+                DAWN_TRY_ASSIGN(d3dBuffer, ToGPUUsableBuffer(cmd->buffer.Get())
+                                               ->GetD3D11NonConstantBuffer(commandContext));
+                vertexBufferTracker.OnSetVertexBuffer(cmd->slot, d3dBuffer, cmd->offset);
                 break;
             }
 
diff --git a/src/dawn/native/d3d11/CommandRecordingContextD3D11.cpp b/src/dawn/native/d3d11/CommandRecordingContextD3D11.cpp
index 2c7e400..130e7ae 100644
--- a/src/dawn/native/d3d11/CommandRecordingContextD3D11.cpp
+++ b/src/dawn/native/d3d11/CommandRecordingContextD3D11.cpp
@@ -260,16 +260,19 @@
     return device->CreateBuffer(&descriptor);
 }
 
-void CommandRecordingContext::SetInternalUniformBuffer(Ref<BufferBase> uniformBuffer) {
-    mUniformBuffer = ToGPUOnlyBuffer(std::move(uniformBuffer));
+MaybeError CommandRecordingContext::SetInternalUniformBuffer(Ref<BufferBase> uniformBuffer) {
+    mUniformBuffer = ToGPUUsableBuffer(std::move(uniformBuffer));
 
     // Always bind the uniform buffer to the reserved slot for all pipelines.
     // This buffer will be updated with the correct values before each draw or dispatch call.
-    ID3D11Buffer* bufferPtr = mUniformBuffer->GetD3D11ConstantBuffer();
+    ID3D11Buffer* bufferPtr;
+    DAWN_TRY_ASSIGN(bufferPtr, mUniformBuffer->GetD3D11ConstantBuffer(nullptr));
     mD3D11DeviceContext4->VSSetConstantBuffers(PipelineLayout::kReservedConstantBufferSlot, 1,
                                                &bufferPtr);
     mD3D11DeviceContext4->CSSetConstantBuffers(PipelineLayout::kReservedConstantBufferSlot, 1,
                                                &bufferPtr);
+
+    return {};
 }
 
 void CommandRecordingContext::ReleaseKeyedMutexes() {
diff --git a/src/dawn/native/d3d11/CommandRecordingContextD3D11.h b/src/dawn/native/d3d11/CommandRecordingContextD3D11.h
index 40370a2..6b4f2c9 100644
--- a/src/dawn/native/d3d11/CommandRecordingContextD3D11.h
+++ b/src/dawn/native/d3d11/CommandRecordingContextD3D11.h
@@ -40,7 +40,7 @@
 
 class CommandAllocatorManager;
 class Buffer;
-class GPUOnlyBuffer;
+class GPUUsableBuffer;
 class Device;
 
 class CommandRecordingContext;
@@ -84,7 +84,7 @@
     void Destroy();
 
     static ResultOrError<Ref<BufferBase>> CreateInternalUniformBuffer(DeviceBase* device);
-    void SetInternalUniformBuffer(Ref<BufferBase> uniformBuffer);
+    MaybeError SetInternalUniformBuffer(Ref<BufferBase> uniformBuffer);
 
     void ReleaseKeyedMutexes();
 
@@ -107,7 +107,7 @@
     // The maximum number of builtin elements is 4 (vec4). It must be multiple of 4.
     static constexpr size_t kMaxNumBuiltinElements = 4;
     // The uniform buffer for built-in variables.
-    Ref<GPUOnlyBuffer> mUniformBuffer;
+    Ref<GPUUsableBuffer> mUniformBuffer;
     std::array<uint32_t, kMaxNumBuiltinElements> mUniformBufferData;
     bool mUniformBufferDirty = true;
 
diff --git a/src/dawn/native/d3d11/QuerySetD3D11.cpp b/src/dawn/native/d3d11/QuerySetD3D11.cpp
index 38cddce..2948277 100644
--- a/src/dawn/native/d3d11/QuerySetD3D11.cpp
+++ b/src/dawn/native/d3d11/QuerySetD3D11.cpp
@@ -93,15 +93,12 @@
                              uint64_t offset) {
     DAWN_TRY(destination->Clear(commandContext, 0, offset, queryCount * sizeof(uint64_t)));
     const auto& queryAvailability = GetQueryAvailability();
-    ID3D11DeviceContext* d3d11DeviceContext = commandContext->GetD3D11DeviceContext4();
     for (uint32_t i = 0; i < queryCount; ++i) {
         uint32_t queryIndex = i + firstQuery;
         if (queryAvailability[queryIndex]) {
             auto& predicate = mPredicates[queryIndex];
-            d3d11DeviceContext->SetPredication(predicate.Get(), false);
-            DAWN_TRY(destination->Clear(commandContext, 1, offset + i * sizeof(uint64_t),
-                                        sizeof(uint64_t)));
-            d3d11DeviceContext->SetPredication(nullptr, false);
+            DAWN_TRY(destination->PredicatedClear(commandContext, predicate.Get(), 1,
+                                                  offset + i * sizeof(uint64_t), sizeof(uint64_t)));
         }
     }
     return {};
diff --git a/src/dawn/native/d3d11/QueueD3D11.cpp b/src/dawn/native/d3d11/QueueD3D11.cpp
index e0ac29a..0b83880 100644
--- a/src/dawn/native/d3d11/QueueD3D11.cpp
+++ b/src/dawn/native/d3d11/QueueD3D11.cpp
@@ -144,7 +144,7 @@
     Ref<BufferBase> uniformBuffer;
     DAWN_TRY_ASSIGN(uniformBuffer,
                     CommandRecordingContext::CreateInternalUniformBuffer(GetDevice()));
-    mPendingCommands->SetInternalUniformBuffer(std::move(uniformBuffer));
+    DAWN_TRY(mPendingCommands->SetInternalUniformBuffer(std::move(uniformBuffer)));
 
     return {};
 }
@@ -219,15 +219,18 @@
 
 MaybeError Queue::CheckAndMapReadyBuffers(ExecutionSerial completedSerial) {
     auto commandContext = GetScopedPendingCommandContext(QueueBase::SubmitMode::Passive);
-    for (auto buffer : mPendingMapBuffers.IterateUpTo(completedSerial)) {
-        DAWN_TRY(buffer->FinalizeMap(&commandContext, completedSerial));
+    for (const auto& bufferEntry : mPendingMapBuffers.IterateUpTo(completedSerial)) {
+        DAWN_TRY(
+            bufferEntry.buffer->FinalizeMap(&commandContext, completedSerial, bufferEntry.mode));
     }
     mPendingMapBuffers.ClearUpTo(completedSerial);
     return {};
 }
 
-void Queue::TrackPendingMapBuffer(Ref<Buffer>&& buffer, ExecutionSerial readySerial) {
-    mPendingMapBuffers.Enqueue(buffer, readySerial);
+void Queue::TrackPendingMapBuffer(Ref<Buffer>&& buffer,
+                                  wgpu::MapMode mode,
+                                  ExecutionSerial readySerial) {
+    mPendingMapBuffers.Enqueue({buffer, mode}, readySerial);
 }
 
 MaybeError Queue::WriteBufferImpl(BufferBase* buffer,
diff --git a/src/dawn/native/d3d11/QueueD3D11.h b/src/dawn/native/d3d11/QueueD3D11.h
index 657e5ad..3c8bb0e 100644
--- a/src/dawn/native/d3d11/QueueD3D11.h
+++ b/src/dawn/native/d3d11/QueueD3D11.h
@@ -54,7 +54,9 @@
     MaybeError InitializePendingContext();
 
     // Register the pending map buffer to be checked.
-    void TrackPendingMapBuffer(Ref<Buffer>&& buffer, ExecutionSerial readySerial);
+    void TrackPendingMapBuffer(Ref<Buffer>&& buffer,
+                               wgpu::MapMode mode,
+                               ExecutionSerial readySerial);
 
   protected:
     using d3d::Queue::Queue;
@@ -88,7 +90,12 @@
     Ref<SharedFence> mSharedFence;
     MutexProtected<CommandRecordingContext, CommandRecordingContextGuard> mPendingCommands;
     std::atomic<bool> mPendingCommandsNeedSubmit = false;
-    SerialMap<ExecutionSerial, Ref<Buffer>> mPendingMapBuffers;
+
+    struct BufferMapEntry {
+        Ref<Buffer> buffer;
+        wgpu::MapMode mode;
+    };
+    SerialMap<ExecutionSerial, BufferMapEntry> mPendingMapBuffers;
 };
 
 }  // namespace dawn::native::d3d11
diff --git a/src/dawn/tests/white_box/D3D11BufferTests.cpp b/src/dawn/tests/white_box/D3D11BufferTests.cpp
index eb21c0a..8b19545 100644
--- a/src/dawn/tests/white_box/D3D11BufferTests.cpp
+++ b/src/dawn/tests/white_box/D3D11BufferTests.cpp
@@ -109,66 +109,66 @@
     {
         wgpu::BufferUsage usage = wgpu::BufferUsage::Uniform;
         wgpu::Buffer buffer = CreateBuffer(4, usage);
-        native::d3d11::GPUOnlyBuffer* d3d11Buffer =
-            native::d3d11::ToGPUOnlyBuffer(native::FromAPI(buffer.Get()));
+        native::d3d11::GPUUsableBuffer* d3d11Buffer =
+            native::d3d11::ToGPUUsableBuffer(native::FromAPI(buffer.Get()));
 
-        EXPECT_EQ(d3d11Buffer->GetD3D11NonConstantBuffer(), nullptr);
-        EXPECT_NE(d3d11Buffer->GetD3D11ConstantBuffer(), nullptr);
+        EXPECT_EQ(d3d11Buffer->GetD3D11NonConstantBufferForTesting(), nullptr);
+        EXPECT_NE(d3d11Buffer->GetD3D11ConstantBufferForTesting(), nullptr);
     }
     {
         wgpu::BufferUsage usage =
             wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::CopySrc;
         wgpu::Buffer buffer = CreateBuffer(4, usage);
-        native::d3d11::GPUOnlyBuffer* d3d11Buffer =
-            native::d3d11::ToGPUOnlyBuffer(native::FromAPI(buffer.Get()));
+        native::d3d11::GPUUsableBuffer* d3d11Buffer =
+            native::d3d11::ToGPUUsableBuffer(native::FromAPI(buffer.Get()));
 
-        EXPECT_EQ(d3d11Buffer->GetD3D11NonConstantBuffer(), nullptr);
-        EXPECT_NE(d3d11Buffer->GetD3D11ConstantBuffer(), nullptr);
+        EXPECT_EQ(d3d11Buffer->GetD3D11NonConstantBufferForTesting(), nullptr);
+        EXPECT_NE(d3d11Buffer->GetD3D11ConstantBufferForTesting(), nullptr);
     }
     {
         wgpu::BufferUsage usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::Vertex;
         wgpu::Buffer buffer = CreateBuffer(4, usage);
-        native::d3d11::GPUOnlyBuffer* d3d11Buffer =
-            native::d3d11::ToGPUOnlyBuffer(native::FromAPI(buffer.Get()));
+        native::d3d11::GPUUsableBuffer* d3d11Buffer =
+            native::d3d11::ToGPUUsableBuffer(native::FromAPI(buffer.Get()));
 
-        EXPECT_NE(d3d11Buffer->GetD3D11NonConstantBuffer(), nullptr);
-        EXPECT_NE(d3d11Buffer->GetD3D11ConstantBuffer(), nullptr);
+        EXPECT_NE(d3d11Buffer->GetD3D11NonConstantBufferForTesting(), nullptr);
+        EXPECT_NE(d3d11Buffer->GetD3D11ConstantBufferForTesting(), nullptr);
     }
     {
         wgpu::BufferUsage usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::Index;
         wgpu::Buffer buffer = CreateBuffer(4, usage);
-        native::d3d11::GPUOnlyBuffer* d3d11Buffer =
-            native::d3d11::ToGPUOnlyBuffer(native::FromAPI(buffer.Get()));
+        native::d3d11::GPUUsableBuffer* d3d11Buffer =
+            native::d3d11::ToGPUUsableBuffer(native::FromAPI(buffer.Get()));
 
-        EXPECT_NE(d3d11Buffer->GetD3D11NonConstantBuffer(), nullptr);
-        EXPECT_NE(d3d11Buffer->GetD3D11ConstantBuffer(), nullptr);
+        EXPECT_NE(d3d11Buffer->GetD3D11NonConstantBufferForTesting(), nullptr);
+        EXPECT_NE(d3d11Buffer->GetD3D11ConstantBufferForTesting(), nullptr);
     }
     {
         wgpu::BufferUsage usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::Indirect;
         wgpu::Buffer buffer = CreateBuffer(4, usage);
-        native::d3d11::GPUOnlyBuffer* d3d11Buffer =
-            native::d3d11::ToGPUOnlyBuffer(native::FromAPI(buffer.Get()));
+        native::d3d11::GPUUsableBuffer* d3d11Buffer =
+            native::d3d11::ToGPUUsableBuffer(native::FromAPI(buffer.Get()));
 
-        EXPECT_NE(d3d11Buffer->GetD3D11NonConstantBuffer(), nullptr);
-        EXPECT_NE(d3d11Buffer->GetD3D11ConstantBuffer(), nullptr);
+        EXPECT_NE(d3d11Buffer->GetD3D11NonConstantBufferForTesting(), nullptr);
+        EXPECT_NE(d3d11Buffer->GetD3D11ConstantBufferForTesting(), nullptr);
     }
     {
         wgpu::BufferUsage usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::Storage;
         wgpu::Buffer buffer = CreateBuffer(4, usage);
-        native::d3d11::GPUOnlyBuffer* d3d11Buffer =
-            native::d3d11::ToGPUOnlyBuffer(native::FromAPI(buffer.Get()));
+        native::d3d11::GPUUsableBuffer* d3d11Buffer =
+            native::d3d11::ToGPUUsableBuffer(native::FromAPI(buffer.Get()));
 
-        EXPECT_NE(d3d11Buffer->GetD3D11NonConstantBuffer(), nullptr);
-        EXPECT_NE(d3d11Buffer->GetD3D11ConstantBuffer(), nullptr);
+        EXPECT_NE(d3d11Buffer->GetD3D11NonConstantBufferForTesting(), nullptr);
+        EXPECT_NE(d3d11Buffer->GetD3D11ConstantBufferForTesting(), nullptr);
     }
     {
         wgpu::BufferUsage usage = wgpu::BufferUsage::Storage;
         wgpu::Buffer buffer = CreateBuffer(4, usage);
-        native::d3d11::GPUOnlyBuffer* d3d11Buffer =
-            native::d3d11::ToGPUOnlyBuffer(native::FromAPI(buffer.Get()));
+        native::d3d11::GPUUsableBuffer* d3d11Buffer =
+            native::d3d11::ToGPUUsableBuffer(native::FromAPI(buffer.Get()));
 
-        EXPECT_NE(d3d11Buffer->GetD3D11NonConstantBuffer(), nullptr);
-        EXPECT_EQ(d3d11Buffer->GetD3D11ConstantBuffer(), nullptr);
+        EXPECT_NE(d3d11Buffer->GetD3D11NonConstantBufferForTesting(), nullptr);
+        EXPECT_EQ(d3d11Buffer->GetD3D11ConstantBufferForTesting(), nullptr);
     }
 }
 
@@ -179,34 +179,34 @@
         wgpu::BufferUsage usage =
             wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::CopySrc;
         wgpu::Buffer buffer = CreateBuffer(data.size(), usage);
-        native::d3d11::GPUOnlyBuffer* d3d11Buffer =
-            native::d3d11::ToGPUOnlyBuffer(native::FromAPI(buffer.Get()));
+        native::d3d11::GPUUsableBuffer* d3d11Buffer =
+            native::d3d11::ToGPUUsableBuffer(native::FromAPI(buffer.Get()));
 
-        EXPECT_EQ(d3d11Buffer->GetD3D11NonConstantBuffer(), nullptr);
-        EXPECT_NE(d3d11Buffer->GetD3D11ConstantBuffer(), nullptr);
+        EXPECT_EQ(d3d11Buffer->GetD3D11NonConstantBufferForTesting(), nullptr);
+        EXPECT_NE(d3d11Buffer->GetD3D11ConstantBufferForTesting(), nullptr);
 
         queue.WriteBuffer(buffer, 0, data.data(), data.size());
         EXPECT_BUFFER_U8_RANGE_EQ(data.data(), buffer, 0, data.size());
 
-        CheckBuffer(d3d11Buffer->GetD3D11ConstantBuffer(), data);
+        CheckBuffer(d3d11Buffer->GetD3D11ConstantBufferForTesting(), data);
     }
     {
         std::vector<uint8_t> data = {0x12, 0x34, 0x56, 0x78};
         wgpu::BufferUsage usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::Vertex |
                                   wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::CopySrc;
         wgpu::Buffer buffer = CreateBuffer(data.size(), usage);
-        native::d3d11::GPUOnlyBuffer* d3d11Buffer =
-            native::d3d11::ToGPUOnlyBuffer(native::FromAPI(buffer.Get()));
+        native::d3d11::GPUUsableBuffer* d3d11Buffer =
+            native::d3d11::ToGPUUsableBuffer(native::FromAPI(buffer.Get()));
 
-        EXPECT_NE(d3d11Buffer->GetD3D11NonConstantBuffer(), nullptr);
-        EXPECT_NE(d3d11Buffer->GetD3D11ConstantBuffer(), nullptr);
+        EXPECT_NE(d3d11Buffer->GetD3D11NonConstantBufferForTesting(), nullptr);
+        EXPECT_NE(d3d11Buffer->GetD3D11ConstantBufferForTesting(), nullptr);
 
         queue.WriteBuffer(buffer, 0, data.data(), data.size());
         EXPECT_BUFFER_U8_RANGE_EQ(data.data(), buffer, 0, data.size());
 
         // both buffers should be updated.
-        CheckBuffer(d3d11Buffer->GetD3D11NonConstantBuffer(), data);
-        CheckBuffer(d3d11Buffer->GetD3D11ConstantBuffer(), data);
+        CheckBuffer(d3d11Buffer->GetD3D11NonConstantBufferForTesting(), data);
+        CheckBuffer(d3d11Buffer->GetD3D11ConstantBufferForTesting(), data);
     }
 }
 
@@ -218,17 +218,17 @@
     wgpu::BufferUsage usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::Storage |
                               wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::CopySrc;
     wgpu::Buffer buffer = CreateBuffer(bufferSize, usage);
-    native::d3d11::GPUOnlyBuffer* d3d11Buffer =
-        native::d3d11::ToGPUOnlyBuffer(native::FromAPI(buffer.Get()));
+    native::d3d11::GPUUsableBuffer* d3d11Buffer =
+        native::d3d11::ToGPUUsableBuffer(native::FromAPI(buffer.Get()));
 
-    EXPECT_NE(d3d11Buffer->GetD3D11NonConstantBuffer(), nullptr);
-    EXPECT_NE(d3d11Buffer->GetD3D11ConstantBuffer(), nullptr);
+    EXPECT_NE(d3d11Buffer->GetD3D11NonConstantBufferForTesting(), nullptr);
+    EXPECT_NE(d3d11Buffer->GetD3D11ConstantBufferForTesting(), nullptr);
 
     queue.WriteBuffer(buffer, 0, data.data(), bufferSize);
     EXPECT_BUFFER_U32_RANGE_EQ(data.data(), buffer, 0, data.size());
 
-    CheckBuffer(d3d11Buffer->GetD3D11NonConstantBuffer(), data);
-    CheckBuffer(d3d11Buffer->GetD3D11ConstantBuffer(), data);
+    CheckBuffer(d3d11Buffer->GetD3D11NonConstantBufferForTesting(), data);
+    CheckBuffer(d3d11Buffer->GetD3D11ConstantBufferForTesting(), data);
 
     // Fill the buffer with 0x11223344 with a compute shader
     {
@@ -268,9 +268,9 @@
         std::vector<uint32_t> expectedData(kNumValues, 0x11223344);
         EXPECT_BUFFER_U32_RANGE_EQ(expectedData.data(), buffer, 0, expectedData.size());
         // The non-constant buffer should be updated.
-        CheckBuffer(d3d11Buffer->GetD3D11NonConstantBuffer(), expectedData);
-        // The constant buffer should not be updated, until the constant buffer is used a pipeline
-        CheckBuffer(d3d11Buffer->GetD3D11ConstantBuffer(), data);
+        CheckBuffer(d3d11Buffer->GetD3D11NonConstantBufferForTesting(), expectedData);
+        // The constant buffer should be updated too.
+        CheckBuffer(d3d11Buffer->GetD3D11ConstantBufferForTesting(), expectedData);
     }
 
     // Copy the uniform buffer content to a new buffer with Compute shader
@@ -316,9 +316,9 @@
         EXPECT_BUFFER_U32_RANGE_EQ(expectedData.data(), newBuffer, 0, expectedData.size());
 
         // The non-constant buffer should be updated.
-        CheckBuffer(d3d11Buffer->GetD3D11NonConstantBuffer(), expectedData);
+        CheckBuffer(d3d11Buffer->GetD3D11NonConstantBufferForTesting(), expectedData);
         // The constant buffer should be updated too.
-        CheckBuffer(d3d11Buffer->GetD3D11ConstantBuffer(), expectedData);
+        CheckBuffer(d3d11Buffer->GetD3D11ConstantBufferForTesting(), expectedData);
     }
 }