From 1e0fe36cae8128820f8a2314060e139f5ec6de93 Mon Sep 17 00:00:00 2001
From: Philip Rebohle <philip.rebohle@tu-dortmund.de>
Date: Sat, 25 May 2019 14:42:32 +0200
Subject: [PATCH] [d3d11] Respect COPY_FLAG_NO_OVERWRITE when updating constant
 buffers

Heavy Rain uses this to update constan buffers on deferred contexts.
---
 src/d3d11/d3d11_context.cpp | 35 +++++++++++++++++------------------
 1 file changed, 17 insertions(+), 18 deletions(-)

diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp
index 039c2904a..4af284fef 100644
--- a/src/d3d11/d3d11_context.cpp
+++ b/src/d3d11/d3d11_context.cpp
@@ -1111,6 +1111,9 @@ namespace dxvk {
     if (!pDstResource)
       return;
     
+    // Filter out invalid copy flags
+    CopyFlags &= D3D11_COPY_NO_OVERWRITE | D3D11_COPY_DISCARD;
+
     // We need a different code path for buffers
     D3D11_RESOURCE_DIMENSION resourceType;
     pDstResource->GetType(&resourceType);
@@ -1118,9 +1121,6 @@ namespace dxvk {
     if (resourceType == D3D11_RESOURCE_DIMENSION_BUFFER) {
       const auto bufferResource = static_cast<D3D11Buffer*>(pDstResource);
       const auto bufferSlice = bufferResource->GetBufferSlice();
-
-      if (CopyFlags & D3D11_COPY_DISCARD)
-        DiscardBuffer(bufferResource);
       
       VkDeviceSize offset = bufferSlice.offset();
       VkDeviceSize size   = bufferSlice.length();
@@ -1130,26 +1130,25 @@ namespace dxvk {
         size   = pDstBox->right - pDstBox->left;
       }
       
-      if (offset + size > bufferSlice.length()) {
-        Logger::err(str::format(
-          "D3D11: UpdateSubresource: Buffer update range out of bounds",
-          "\n  Dst slice offset: ", bufferSlice.offset(),
-          "\n  Dst slice length: ", bufferSlice.length(),
-          "\n  Src slice offset: ", offset,
-          "\n  Src slice length: ", size));
+      if (!size || offset + size > bufferSlice.length())
         return;
-      }
+
+      bool useMap = (bufferSlice.buffer()->memFlags() & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
+                 && (size == bufferSlice.length() || CopyFlags);
       
-      if (size == 0)
-        return;
-      
-      if (((size == bufferSlice.length())
-       && (bufferSlice.buffer()->memFlags() & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))) {
+      if (useMap) {
+        D3D11_MAP mapType = (CopyFlags & D3D11_COPY_NO_OVERWRITE)
+          ? D3D11_MAP_WRITE_NO_OVERWRITE
+          : D3D11_MAP_WRITE_DISCARD;
+
         D3D11_MAPPED_SUBRESOURCE mappedSr;
-        Map(pDstResource, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedSr);
-        std::memcpy(mappedSr.pData, pSrcData, size);
+        Map(pDstResource, 0, mapType, 0, &mappedSr);
+        std::memcpy(reinterpret_cast<char*>(mappedSr.pData) + offset, pSrcData, size);
         Unmap(pDstResource, 0);
       } else {
+        if (CopyFlags & D3D11_COPY_DISCARD)
+          DiscardBuffer(bufferResource);
+        
         DxvkDataSlice dataSlice = AllocUpdateBufferSlice(size);
         std::memcpy(dataSlice.ptr(), pSrcData, size);