Index: src/gpu/vk/GrVkGpu.cpp |
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp |
index 85bfce87679c696ba720e6ff84f6747a5207b6d2..55fb533a53237797bc56af5e38b6d4e3d4e46b24 100644 |
--- a/src/gpu/vk/GrVkGpu.cpp |
+++ b/src/gpu/vk/GrVkGpu.cpp |
@@ -949,6 +949,31 @@ GrStencilAttachment* GrVkGpu::createStencilAttachmentForRenderTarget(const GrRen |
//////////////////////////////////////////////////////////////////////////////// |
+bool copy_testing_data(GrVkGpu* gpu, void* srcData, GrVkAlloc* alloc, |
+ size_t srcRowBytes, size_t dstRowBytes, int h) { |
+ void* mapPtr; |
+ VkResult err = GR_VK_CALL(gpu->vkInterface(), MapMemory(gpu->device(), |
+ alloc->fMemory, |
+ alloc->fOffset, |
+ dstRowBytes * h, |
+ 0, |
+ &mapPtr)); |
+ if (err) { |
+ return false; |
+ } |
+ |
+ // If there is no padding on dst we can do a single memcopy. |
+ // This assumes the srcData comes in with no padding. |
+ if (srcRowBytes == dstRowBytes) { |
+ memcpy(mapPtr, srcData, srcRowBytes * h); |
+ } else { |
+ SkRectMemcpy(mapPtr, static_cast<size_t>(dstRowBytes), srcData, srcRowBytes, |
+ srcRowBytes, h); |
+ } |
+ GR_VK_CALL(gpu->vkInterface(), UnmapMemory(gpu->device(), alloc->fMemory)); |
+ return true; |
+} |
+ |
GrBackendObject GrVkGpu::createTestingOnlyBackendTexture(void* srcData, int w, int h, |
GrPixelConfig config, |
bool isRenderTarget) { |
@@ -972,11 +997,6 @@ GrBackendObject GrVkGpu::createTestingOnlyBackendTexture(void* srcData, int w, i |
linearTiling = true; |
} |
- // Currently this is not supported since it requires a copy which has not yet been implemented. |
- if (srcData && !linearTiling) { |
- return 0; |
- } |
- |
VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT; |
usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
usageFlags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; |
@@ -1024,6 +1044,8 @@ GrBackendObject GrVkGpu::createTestingOnlyBackendTexture(void* srcData, int w, i |
} |
if (srcData) { |
+ size_t bpp = GrBytesPerPixel(config); |
+ size_t rowCopyBytes = bpp * w; |
if (linearTiling) { |
const VkImageSubresource subres = { |
VK_IMAGE_ASPECT_COLOR_BIT, |
@@ -1031,33 +1053,181 @@ GrBackendObject GrVkGpu::createTestingOnlyBackendTexture(void* srcData, int w, i |
0, // arraySlice |
}; |
VkSubresourceLayout layout; |
- VkResult err; |
VK_CALL(GetImageSubresourceLayout(fDevice, image, &subres, &layout)); |
- void* mapPtr; |
- err = VK_CALL(MapMemory(fDevice, alloc.fMemory, alloc.fOffset, layout.rowPitch * h, |
- 0, &mapPtr)); |
+ if (!copy_testing_data(this, srcData, &alloc, rowCopyBytes, layout.rowPitch, h)) { |
+ GrVkMemory::FreeImageMemory(this, linearTiling, alloc); |
+ VK_CALL(DestroyImage(fDevice, image, nullptr)); |
+ return 0; |
+ } |
+ } else { |
+ SkASSERT(w && h); |
+ |
+ VkBuffer buffer; |
+ VkBufferCreateInfo bufInfo; |
+ memset(&bufInfo, 0, sizeof(VkBufferCreateInfo)); |
+ bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; |
+ bufInfo.flags = 0; |
+ bufInfo.size = rowCopyBytes * h; |
+ bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; |
+ bufInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
+ bufInfo.queueFamilyIndexCount = 0; |
+ bufInfo.pQueueFamilyIndices = nullptr; |
+ VkResult err; |
+ err = VK_CALL(CreateBuffer(fDevice, &bufInfo, nullptr, &buffer)); |
+ |
if (err) { |
GrVkMemory::FreeImageMemory(this, linearTiling, alloc); |
- VK_CALL(DestroyImage(this->device(), image, nullptr)); |
+ VK_CALL(DestroyImage(fDevice, image, nullptr)); |
return 0; |
} |
- size_t bpp = GrBytesPerPixel(config); |
- size_t rowCopyBytes = bpp * w; |
- // If there is no padding on dst (layout.rowPitch) we can do a single memcopy. |
- // This assumes the srcData comes in with no padding. |
- if (rowCopyBytes == layout.rowPitch) { |
- memcpy(mapPtr, srcData, rowCopyBytes * h); |
- } else { |
- SkRectMemcpy(mapPtr, static_cast<size_t>(layout.rowPitch), srcData, rowCopyBytes, |
- rowCopyBytes, h); |
+ GrVkAlloc bufferAlloc = { VK_NULL_HANDLE, 0, 0 }; |
+ if (!GrVkMemory::AllocAndBindBufferMemory(this, buffer, GrVkBuffer::kCopyRead_Type, |
+ true, &bufferAlloc)) { |
+ GrVkMemory::FreeImageMemory(this, linearTiling, alloc); |
+ VK_CALL(DestroyImage(fDevice, image, nullptr)); |
+ VK_CALL(DestroyBuffer(fDevice, buffer, nullptr)); |
+ return 0; |
} |
- VK_CALL(UnmapMemory(fDevice, alloc.fMemory)); |
- } else { |
- // TODO: Add support for copying to optimal tiling |
- SkASSERT(false); |
+ |
+ if (!copy_testing_data(this, srcData, &bufferAlloc, rowCopyBytes, rowCopyBytes, h)) { |
+ GrVkMemory::FreeImageMemory(this, linearTiling, alloc); |
+ VK_CALL(DestroyImage(fDevice, image, nullptr)); |
+ GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc); |
+ VK_CALL(DestroyBuffer(fDevice, buffer, nullptr)); |
+ return 0; |
+ } |
+ |
+ const VkCommandBufferAllocateInfo cmdInfo = { |
+ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // sType |
+ NULL, // pNext |
+ fCmdPool, // commandPool |
+ VK_COMMAND_BUFFER_LEVEL_PRIMARY, // level |
+ 1 // bufferCount |
+ }; |
+ |
+ VkCommandBuffer cmdBuffer; |
+ err = VK_CALL(AllocateCommandBuffers(fDevice, &cmdInfo, &cmdBuffer)); |
+ if (err) { |
+ GrVkMemory::FreeImageMemory(this, linearTiling, alloc); |
+ VK_CALL(DestroyImage(fDevice, image, nullptr)); |
+ GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc); |
+ VK_CALL(DestroyBuffer(fDevice, buffer, nullptr)); |
+ return 0; |
+ } |
+ |
+ VkCommandBufferBeginInfo cmdBufferBeginInfo; |
+ memset(&cmdBufferBeginInfo, 0, sizeof(VkCommandBufferBeginInfo)); |
+ cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; |
+ cmdBufferBeginInfo.pNext = nullptr; |
+ cmdBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; |
+ cmdBufferBeginInfo.pInheritanceInfo = nullptr; |
+ |
+ err = VK_CALL(BeginCommandBuffer(cmdBuffer, &cmdBufferBeginInfo)); |
+ SkASSERT(!err); |
+ |
+ // Set image layout and add barrier |
+ VkImageMemoryBarrier barrier; |
+ memset(&barrier, 0, sizeof(VkImageMemoryBarrier)); |
+ barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
+ barrier.pNext = nullptr; |
+ barrier.srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(initialLayout); |
+ barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; |
+ barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; |
+ barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
+ barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
+ barrier.image = image; |
+ barrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0 , 1}; |
+ |
+ VK_CALL(CmdPipelineBarrier(cmdBuffer, |
+ GrVkMemory::LayoutToPipelineStageFlags(initialLayout), |
+ VK_PIPELINE_STAGE_TRANSFER_BIT, |
+ 0, |
+ 0, nullptr, |
+ 0, nullptr, |
+ 1, &barrier)); |
+ initialLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; |
+ |
+ // Make sure buffer has finished the unmap |
+ VkBufferMemoryBarrier bufBarrier; |
+ memset(&barrier, 0, sizeof(VkImageMemoryBarrier)); |
+ bufBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; |
+ bufBarrier.pNext = nullptr; |
+ bufBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; |
+ bufBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; |
+ bufBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
+ bufBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
+ bufBarrier.buffer = buffer; |
+ bufBarrier.offset = 0; |
+ bufBarrier.size = bufInfo.size; |
+ |
+ VK_CALL(CmdPipelineBarrier(cmdBuffer, |
+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, |
+ VK_PIPELINE_STAGE_TRANSFER_BIT, |
+ 0, |
+ 0, nullptr, |
+ 1, &bufBarrier, |
+ 0, nullptr)); |
+ |
+ // Submit copy command |
+ VkBufferImageCopy region; |
+ memset(®ion, 0, sizeof(VkBufferImageCopy)); |
+ region.bufferOffset = 0; |
+ region.bufferRowLength = (uint32_t)rowCopyBytes; |
+ region.bufferImageHeight = h; |
+ region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; |
+ region.imageOffset = { 0, 0, 0 }; |
+ region.imageExtent = { (uint32_t)w, (uint32_t)h, 1 }; |
+ |
+ VK_CALL(CmdCopyBufferToImage(cmdBuffer, buffer, image, initialLayout, 1, ®ion)); |
+ |
+ // End CommandBuffer |
+ err = VK_CALL(EndCommandBuffer(cmdBuffer)); |
+ SkASSERT(!err); |
+ |
+ // Create Fence for queue |
+ VkFence fence; |
+ VkFenceCreateInfo fenceInfo; |
+ memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo)); |
+ fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; |
+ |
+ err = VK_CALL(CreateFence(fDevice, &fenceInfo, nullptr, &fence)); |
+ SkASSERT(!err); |
+ |
+ VkSubmitInfo submitInfo; |
+ memset(&submitInfo, 0, sizeof(VkSubmitInfo)); |
+ submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; |
+ submitInfo.pNext = nullptr; |
+ submitInfo.waitSemaphoreCount = 0; |
+ submitInfo.pWaitSemaphores = nullptr; |
+ submitInfo.pWaitDstStageMask = 0; |
+ submitInfo.commandBufferCount = 1; |
+ submitInfo.pCommandBuffers = &cmdBuffer; |
+ submitInfo.signalSemaphoreCount = 0; |
+ submitInfo.pSignalSemaphores = nullptr; |
+ err = VK_CALL(QueueSubmit(this->queue(), 1, &submitInfo, fence)); |
+ SkASSERT(!err); |
+ |
+ err = VK_CALL(WaitForFences(fDevice, 1, &fence, true, UINT64_MAX)); |
+ if (VK_TIMEOUT == err) { |
+ GrVkMemory::FreeImageMemory(this, linearTiling, alloc); |
+ VK_CALL(DestroyImage(fDevice, image, nullptr)); |
+ GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc); |
+ VK_CALL(DestroyBuffer(fDevice, buffer, nullptr)); |
+ VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer)); |
+ VK_CALL(DestroyFence(fDevice, fence, nullptr)); |
+ SkDebugf("Fence failed to signal: %d\n", err); |
+ SkFAIL("failing"); |
+ } |
+ SkASSERT(!err); |
+ |
+ // Clean up transfer resources |
+ GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc); |
+ VK_CALL(DestroyBuffer(fDevice, buffer, nullptr)); |
+ VK_CALL(FreeCommandBuffers(fDevice, fCmdPool, 1, &cmdBuffer)); |
+ VK_CALL(DestroyFence(fDevice, fence, nullptr)); |
} |
} |