Memory manager: buffer uploads (Metal+refactor) - Part 3

Manages a single persistently mapped GPU heap which is sub-allocated
inside of ring-buffer for uploads. To handle larger buffers without additional
unused heaps, ring buffers are created on-demand.

BUG=dawn:28
TEST=dawn_unittests

Change-Id: If4d3e717186895b1409502c1dea5ab751a4776b2
Reviewed-on: https://dawn-review.googlesource.com/c/4440
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Bryan Bernhart <bryan.bernhart@intel.com>
diff --git a/src/dawn_native/Buffer.cpp b/src/dawn_native/Buffer.cpp
index d076f53..b70ae11 100644
--- a/src/dawn_native/Buffer.cpp
+++ b/src/dawn_native/Buffer.cpp
@@ -16,6 +16,7 @@
 
 #include "common/Assert.h"
 #include "dawn_native/Device.h"
+#include "dawn_native/DynamicUploader.h"
 #include "dawn_native/ValidationUtils_autogen.h"
 
 #include <cstdio>
@@ -183,6 +184,26 @@
         MapReadAsyncImpl(mMapSerial);
     }
 
+    MaybeError BufferBase::SetSubDataImpl(uint32_t start, uint32_t count, const uint8_t* data) {
+        DynamicUploader* uploader = nullptr;
+        DAWN_TRY_ASSIGN(uploader, GetDevice()->GetDynamicUploader());
+
+        // TODO(bryan.bernhart@intel.com): Remove once alignment constraint is added to validation
+        // (dawn:73). D3D12 does not specify so we assume 4-byte alignment to be safe.
+        static constexpr size_t kDefaultAlignment = 4;
+
+        UploadHandle uploadHandle;
+        DAWN_TRY_ASSIGN(uploadHandle, uploader->Allocate(count, kDefaultAlignment));
+        ASSERT(uploadHandle.mappedBuffer != nullptr);
+
+        memcpy(uploadHandle.mappedBuffer, data, count);
+
+        DAWN_TRY(GetDevice()->CopyFromStagingToBuffer(
+            uploadHandle.stagingBuffer, uploadHandle.startOffset, this, start, count));
+
+        return {};
+    }
+
     void BufferBase::MapWriteAsync(dawnBufferMapWriteCallback callback,
                                    dawnCallbackUserdata userdata) {
         if (GetDevice()->ConsumedError(ValidateMap(dawn::BufferUsageBit::MapWrite))) {