Add support for vkCmdCopyBuffer
This is then used when need to update GPU only buffers with data of size
greater than 65536. We create a temporary transfer buffer and then copy
that buffer into our GPU buffer.
Bug: skia:
Change-Id: I4bb9cb660f2ac1ccbbd1b508bb4ca6876342136f
Reviewed-on: https://skia-review.googlesource.com/38725
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/vk/GrVkBuffer.cpp b/src/gpu/vk/GrVkBuffer.cpp
index 9926ec4..b2af229 100644
--- a/src/gpu/vk/GrVkBuffer.cpp
+++ b/src/gpu/vk/GrVkBuffer.cpp
@@ -8,6 +8,7 @@
#include "GrVkBuffer.h"
#include "GrVkGpu.h"
#include "GrVkMemory.h"
+#include "GrVkTransferBuffer.h"
#include "GrVkUtil.h"
#define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)
@@ -192,7 +193,22 @@
VK_CALL(gpu, UnmapMemory(gpu->device(), this->alloc().fMemory));
fMapPtr = nullptr;
} else {
- gpu->updateBuffer(this, fMapPtr, this->offset(), size);
+ if (size <= 65536) {
+ gpu->updateBuffer(this, fMapPtr, this->offset(), size);
+ } else {
+ GrVkTransferBuffer* transferBuffer =
+ GrVkTransferBuffer::Create(gpu, size, GrVkBuffer::kCopyRead_Type);
+ if(!transferBuffer) {
+ return;
+ }
+
+ char* buffer = (char*) transferBuffer->map();
+ memcpy (buffer, fMapPtr, size);
+ transferBuffer->unmap();
+
+ gpu->copyBuffer(transferBuffer, this, 0, this->offset(), size);
+ transferBuffer->unref();
+ }
this->addMemoryBarrier(gpu,
VK_ACCESS_TRANSFER_WRITE_BIT,
buffer_type_to_access_flags(fDesc.fType),
diff --git a/src/gpu/vk/GrVkCommandBuffer.cpp b/src/gpu/vk/GrVkCommandBuffer.cpp
index 1f124a6..c44d121 100644
--- a/src/gpu/vk/GrVkCommandBuffer.cpp
+++ b/src/gpu/vk/GrVkCommandBuffer.cpp
@@ -637,6 +637,33 @@
copyRegions));
}
+
+void GrVkPrimaryCommandBuffer::copyBuffer(GrVkGpu* gpu,
+ GrVkBuffer* srcBuffer,
+ GrVkBuffer* dstBuffer,
+ uint32_t regionCount,
+ const VkBufferCopy* regions) {
+ SkASSERT(fIsActive);
+ SkASSERT(!fActiveRenderPass);
+#ifdef SK_DEBUG
+ for (uint32_t i = 0; i < regionCount; ++i) {
+ const VkBufferCopy& region = regions[i];
+ SkASSERT(region.size > 0);
+ SkASSERT(region.srcOffset < srcBuffer->size());
+ SkASSERT(region.dstOffset < dstBuffer->size());
+ SkASSERT(region.srcOffset + region.size <= srcBuffer->size());
+ SkASSERT(region.dstOffset + region.size <= dstBuffer->size());
+ }
+#endif
+ this->addResource(srcBuffer->resource());
+ this->addResource(dstBuffer->resource());
+ GR_VK_CALL(gpu->vkInterface(), CmdCopyBuffer(fCmdBuffer,
+ srcBuffer->buffer(),
+ dstBuffer->buffer(),
+ regionCount,
+ regions));
+}
+
void GrVkPrimaryCommandBuffer::updateBuffer(GrVkGpu* gpu,
GrVkBuffer* dstBuffer,
VkDeviceSize dstOffset,
diff --git a/src/gpu/vk/GrVkCommandBuffer.h b/src/gpu/vk/GrVkCommandBuffer.h
index 548efad..7d16242 100644
--- a/src/gpu/vk/GrVkCommandBuffer.h
+++ b/src/gpu/vk/GrVkCommandBuffer.h
@@ -250,6 +250,12 @@
uint32_t copyRegionCount,
const VkBufferImageCopy* copyRegions);
+ void copyBuffer(GrVkGpu* gpu,
+ GrVkBuffer* srcBuffer,
+ GrVkBuffer* dstBuffer,
+ uint32_t regionCount,
+ const VkBufferCopy* regions);
+
void updateBuffer(GrVkGpu* gpu,
GrVkBuffer* dstBuffer,
VkDeviceSize dstOffset,
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index a36bbe5..83d28de 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -690,8 +690,9 @@
// allocate buffer to hold our mip data
GrVkTransferBuffer* transferBuffer =
GrVkTransferBuffer::Create(this, combinedBufferSize, GrVkBuffer::kCopyRead_Type);
- if(!transferBuffer)
+ if(!transferBuffer) {
return false;
+ }
char* buffer = (char*) transferBuffer->map();
SkTArray<VkBufferImageCopy> regions(mipLevelCount);
@@ -844,9 +845,17 @@
////////////////////////////////////////////////////////////////////////////////
+void GrVkGpu::copyBuffer(GrVkBuffer* srcBuffer, GrVkBuffer* dstBuffer, VkDeviceSize srcOffset,
+ VkDeviceSize dstOffset, VkDeviceSize size) {
+ VkBufferCopy copyRegion;
+ copyRegion.srcOffset = srcOffset;
+ copyRegion.dstOffset = dstOffset;
+ copyRegion.size = size;
+ fCurrentCmdBuffer->copyBuffer(this, srcBuffer, dstBuffer, 1, ©Region);
+}
+
bool GrVkGpu::updateBuffer(GrVkBuffer* buffer, const void* src,
VkDeviceSize offset, VkDeviceSize size) {
-
// Update the buffer
fCurrentCmdBuffer->updateBuffer(this, buffer, offset, size, src);
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index ad157ca..f36ec31 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -144,6 +144,8 @@
void generateMipmap(GrVkTexture* tex);
+ void copyBuffer(GrVkBuffer* srcBuffer, GrVkBuffer* dstBuffer, VkDeviceSize srcOffset,
+ VkDeviceSize dstOffset, VkDeviceSize size);
bool updateBuffer(GrVkBuffer* buffer, const void* src, VkDeviceSize offset, VkDeviceSize size);
// Heaps
diff --git a/tests/TessellatingPathRendererTests.cpp b/tests/TessellatingPathRendererTests.cpp
index 78704d94..0ae5d55 100644
--- a/tests/TessellatingPathRendererTests.cpp
+++ b/tests/TessellatingPathRendererTests.cpp
@@ -454,9 +454,6 @@
test_path(ctx, rtc.get(), create_path_21(), SkMatrix(), GrAAType::kCoverage);
test_path(ctx, rtc.get(), create_path_22());
test_path(ctx, rtc.get(), create_path_23());
- // TODO: implement large buffer uploads in VK and remove this check.
- if (ctx->contextPriv().getBackend() != kVulkan_GrBackend) {
- test_path(ctx, rtc.get(), create_path_24());
- }
+ test_path(ctx, rtc.get(), create_path_24());
}
#endif