Use UpdateSubresource1() to write data to ID3D11Buffer

Since Windows 8, UpdateSubresource1() supports partial updating constant
buffers, so use it to avoid an extra copy.

Bug: none
Change-Id: I6b162e485b91df08364d6a1af128bd90b4e80f1d
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/171641
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Peng Huang <penghuang@chromium.org>
diff --git a/src/dawn/native/d3d11/BufferD3D11.cpp b/src/dawn/native/d3d11/BufferD3D11.cpp
index 80947d3..5f6c915 100644
--- a/src/dawn/native/d3d11/BufferD3D11.cpp
+++ b/src/dawn/native/d3d11/BufferD3D11.cpp
@@ -28,6 +28,7 @@
 #include "dawn/native/d3d11/BufferD3D11.h"
 
 #include <algorithm>
+#include <memory>
 #include <utility>
 #include <vector>
 
@@ -541,16 +542,17 @@
 
     if (mD3d11NonConstantBuffer) {
         D3D11_BOX box;
-        box.left = offset;
-        box.right = offset + size;
+        box.left = static_cast<UINT>(offset);
         box.top = 0;
-        box.bottom = 1;
         box.front = 0;
+        box.right = static_cast<UINT>(offset + size);
+        box.bottom = 1;
         box.back = 1;
-        commandContext->UpdateSubresource(mD3d11NonConstantBuffer.Get(), /*DstSubresource=*/0, &box,
-                                          data,
-                                          /*SrcRowPitch=*/0,
-                                          /*SrcDepthPitch*/ 0);
+        commandContext->UpdateSubresource1(mD3d11NonConstantBuffer.Get(), /*DstSubresource=*/0,
+                                           /*pDstBox=*/&box, data,
+                                           /*SrcRowPitch=*/0,
+                                           /*SrcDepthPitch=*/0,
+                                           /*CopyFlags=*/0);
         if (!mD3d11ConstantBuffer) {
             return {};
         }
@@ -565,33 +567,47 @@
         commandContext->CopySubresourceRegion(
             mD3d11ConstantBuffer.Get(), /*DstSubresource=*/0, /*DstX=*/offset,
             /*DstY=*/0,
-            /*DstZ=*/0, mD3d11NonConstantBuffer.Get(), /*SrcSubresource=*/0, &box);
+            /*DstZ=*/0, mD3d11NonConstantBuffer.Get(), /*SrcSubresource=*/0, /*pSrcBux=*/&box);
 
         return {};
     }
 
     DAWN_ASSERT(mD3d11ConstantBuffer);
 
-    // For a full size write, UpdateSubresource() can be used to update mD3d11ConstantBuffer.
+    // For a full size write, UpdateSubresource1(D3D11_COPY_DISCARD) can be used to update
+    // mD3d11ConstantBuffer.
     if (size == GetSize() && offset == 0) {
-        if (size == mAllocatedSize) {
-            commandContext->UpdateSubresource(mD3d11ConstantBuffer.Get(), /*DstSubresource=*/0,
-                                              nullptr, data,
-                                              /*SrcRowPitch=*/size,
-                                              /*SrcDepthPitch*/ 0);
-        } else {
-            std::vector<uint8_t> allocatedData(mAllocatedSize, 0);
-            std::memcpy(allocatedData.data(), data, size);
-            commandContext->UpdateSubresource(mD3d11ConstantBuffer.Get(), /*DstSubresource=*/0,
-                                              nullptr, allocatedData.data(),
-                                              /*SrcRowPitch=*/mAllocatedSize,
-                                              /*SrcDepthPitch*/ 0);
+        // Offset and size must be aligned with 16 for using UpdateSubresource1() on constant
+        // buffer.
+        constexpr size_t kConstantBufferUpdateAlignment = 16;
+        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, we have to create a staging buffer for transfer the
-    // data to mD3d11ConstantBuffer.
+    // 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));
 
@@ -624,11 +640,11 @@
                                 Buffer* destination,
                                 uint64_t destinationOffset) {
     D3D11_BOX srcBox;
-    srcBox.left = sourceOffset;
-    srcBox.right = sourceOffset + size;
+    srcBox.left = static_cast<UINT>(sourceOffset);
     srcBox.top = 0;
-    srcBox.bottom = 1;
     srcBox.front = 0;
+    srcBox.right = static_cast<UINT>(sourceOffset + size);
+    srcBox.bottom = 1;
     srcBox.back = 1;
     ID3D11Buffer* d3d11SourceBuffer = source->mD3d11NonConstantBuffer
                                           ? source->mD3d11NonConstantBuffer.Get()
diff --git a/src/dawn/native/d3d11/CommandRecordingContextD3D11.cpp b/src/dawn/native/d3d11/CommandRecordingContextD3D11.cpp
index b226973..7d79769 100644
--- a/src/dawn/native/d3d11/CommandRecordingContextD3D11.cpp
+++ b/src/dawn/native/d3d11/CommandRecordingContextD3D11.cpp
@@ -50,14 +50,15 @@
     return Get()->mDevice.Get();
 }
 
-void ScopedCommandRecordingContext::UpdateSubresource(ID3D11Resource* pDstResource,
-                                                      UINT DstSubresource,
-                                                      const D3D11_BOX* pDstBox,
-                                                      const void* pSrcData,
-                                                      UINT SrcRowPitch,
-                                                      UINT SrcDepthPitch) const {
-    Get()->mD3D11DeviceContext4->UpdateSubresource(pDstResource, DstSubresource, pDstBox, pSrcData,
-                                                   SrcRowPitch, SrcDepthPitch);
+void ScopedCommandRecordingContext::UpdateSubresource1(ID3D11Resource* pDstResource,
+                                                       UINT DstSubresource,
+                                                       const D3D11_BOX* pDstBox,
+                                                       const void* pSrcData,
+                                                       UINT SrcRowPitch,
+                                                       UINT SrcDepthPitch,
+                                                       UINT CopyFlags) const {
+    Get()->mD3D11DeviceContext4->UpdateSubresource1(pDstResource, DstSubresource, pDstBox, pSrcData,
+                                                    SrcRowPitch, SrcDepthPitch, CopyFlags);
 }
 
 void ScopedCommandRecordingContext::CopyResource(ID3D11Resource* pDstResource,
diff --git a/src/dawn/native/d3d11/CommandRecordingContextD3D11.h b/src/dawn/native/d3d11/CommandRecordingContextD3D11.h
index 05f7197..63e9ea4 100644
--- a/src/dawn/native/d3d11/CommandRecordingContextD3D11.h
+++ b/src/dawn/native/d3d11/CommandRecordingContextD3D11.h
@@ -111,12 +111,13 @@
     Device* GetDevice() const;
 
     // Wrapper method which don't depend on context state.
-    void UpdateSubresource(ID3D11Resource* pDstResource,
-                           UINT DstSubresource,
-                           const D3D11_BOX* pDstBox,
-                           const void* pSrcData,
-                           UINT SrcRowPitch,
-                           UINT SrcDepthPitch) const;
+    void UpdateSubresource1(ID3D11Resource* pDstResource,
+                            UINT DstSubresource,
+                            const D3D11_BOX* pDstBox,
+                            const void* pSrcData,
+                            UINT SrcRowPitch,
+                            UINT SrcDepthPitch,
+                            UINT CopyFlags) const;
     void CopyResource(ID3D11Resource* pDstResource, ID3D11Resource* pSrcResource) const;
     void CopySubresourceRegion(ID3D11Resource* pDstResource,
                                UINT DstSubresource,
diff --git a/src/dawn/native/d3d11/TextureD3D11.cpp b/src/dawn/native/d3d11/TextureD3D11.cpp
index 4edaeb1..613080a 100644
--- a/src/dawn/native/d3d11/TextureD3D11.cpp
+++ b/src/dawn/native/d3d11/TextureD3D11.cpp
@@ -770,8 +770,9 @@
         dstBox.back = origin.z + size.depthOrArrayLayers;
         uint32_t subresource =
             GetSubresourceIndex(subresources.baseMipLevel, 0, D3D11Aspect(subresources.aspects));
-        commandContext->UpdateSubresource(GetD3D11Resource(), subresource, &dstBox, data,
-                                          bytesPerRow, bytesPerRow * rowsPerImage);
+        commandContext->UpdateSubresource1(GetD3D11Resource(), subresource, &dstBox, data,
+                                           bytesPerRow, bytesPerRow * rowsPerImage,
+                                           /*CopyFlags=*/0);
     } else {
         dstBox.front = 0;
         dstBox.back = 1;
@@ -780,8 +781,8 @@
                 GetSubresourceIndex(subresources.baseMipLevel, subresources.baseArrayLayer + layer,
                                     D3D11Aspect(subresources.aspects));
             D3D11_BOX* pDstBox = GetFormat().HasDepthOrStencil() ? nullptr : &dstBox;
-            commandContext->UpdateSubresource(GetD3D11Resource(), subresource, pDstBox, data,
-                                              bytesPerRow, 0);
+            commandContext->UpdateSubresource1(GetD3D11Resource(), subresource, pDstBox, data,
+                                               bytesPerRow, 0, /*CopyFlags=*/0);
             data += rowsPerImage * bytesPerRow;
         }
     }