Index: src/gpu/vk/GrVkGpu.cpp |
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp |
index c14321937fe9004ab044b607d95aa0fc4ecc8e6b..e4314deeead02d891027948ba478e89ac4432705 100644 |
--- a/src/gpu/vk/GrVkGpu.cpp |
+++ b/src/gpu/vk/GrVkGpu.cpp |
@@ -249,11 +249,13 @@ GrBuffer* GrVkGpu::onCreateBuffer(size_t size, GrBufferType type, GrAccessPatter |
buff = GrVkIndexBuffer::Create(this, size, kDynamic_GrAccessPattern == accessPattern); |
break; |
case kXferCpuToGpu_GrBufferType: |
- SkASSERT(kStream_GrAccessPattern == accessPattern); |
+ SkASSERT(kDynamic_GrAccessPattern == accessPattern || |
+ kStream_GrAccessPattern == accessPattern); |
buff = GrVkTransferBuffer::Create(this, size, GrVkBuffer::kCopyRead_Type); |
break; |
case kXferGpuToCpu_GrBufferType: |
- SkASSERT(kStream_GrAccessPattern == accessPattern); |
+ SkASSERT(kDynamic_GrAccessPattern == accessPattern || |
+ kStream_GrAccessPattern == accessPattern); |
buff = GrVkTransferBuffer::Create(this, size, GrVkBuffer::kCopyWrite_Type); |
break; |
default: |
@@ -375,6 +377,86 @@ bool GrVkGpu::onWritePixels(GrSurface* surface, |
return success; |
} |
+bool GrVkGpu::onTransferPixels(GrTexture* texture, |
+ int left, int top, int width, int height, |
+ GrPixelConfig config, GrBuffer* transferBuffer, |
+ size_t bufferOffset, size_t rowBytes) { |
+ GrVkTexture* vkTex = static_cast<GrVkTexture*>(texture); |
+ if (!vkTex) { |
+ return false; |
+ } |
+ GrVkTransferBuffer* vkBuffer = static_cast<GrVkTransferBuffer*>(transferBuffer); |
+ if (!vkBuffer) { |
+ return false; |
+ } |
+ |
+ // We assume Vulkan doesn't do sRGB <-> linear conversions when reading and writing pixels. |
+ if (GrPixelConfigIsSRGB(texture->config()) != GrPixelConfigIsSRGB(config)) { |
+ return false; |
+ } |
+ |
+ // TODO: Handle y axis flip via copy to temp image, then blit to final |
+ if (kBottomLeft_GrSurfaceOrigin == vkTex->origin()) { |
+ return false; |
+ } |
+ |
+ bool success = false; |
+ if (GrPixelConfigIsCompressed(vkTex->desc().fConfig)) { |
+ // We check that config == desc.fConfig in GrGpu::getWritePixelsInfo() |
+ SkASSERT(config == vkTex->desc().fConfig); |
+ // TODO: add compressed texture support |
+ // delete the following two lines and uncomment the two after that when ready |
+ vkTex->unref(); |
+ return false; |
+ //success = this->uploadCompressedTexData(vkTex->desc(), buffer, false, left, top, width, |
+ // height); |
+ } else { |
+ // make sure the unmap has finished |
+ vkBuffer->addMemoryBarrier(this, |
+ VK_ACCESS_HOST_WRITE_BIT, |
+ VK_ACCESS_TRANSFER_READ_BIT, |
+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, |
+ VK_PIPELINE_STAGE_TRANSFER_BIT, |
+ false); |
+ |
+ // Set up copy region |
+ size_t bpp = GrBytesPerPixel(config); |
+ |
+ VkBufferImageCopy region; |
+ memset(®ion, 0, sizeof(VkBufferImageCopy)); |
+ region.bufferOffset = bufferOffset; |
+ region.bufferRowLength = (uint32_t)(rowBytes/bpp); |
+ region.bufferImageHeight = 0; |
+ region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; |
+ region.imageOffset = { left, top, 0 }; |
+ region.imageExtent = { (uint32_t)width, (uint32_t)height, 1 }; |
+ |
+ // Change layout of our target so it can be copied to |
+ vkTex->setImageLayout(this, |
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, |
+ VK_ACCESS_TRANSFER_WRITE_BIT, |
+ VK_PIPELINE_STAGE_TRANSFER_BIT, |
+ false); |
+ |
+ // Copy the buffer to the image |
+ fCurrentCmdBuffer->copyBufferToImage(this, |
+ vkBuffer, |
+ vkTex, |
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, |
+ 1, |
+ ®ion); |
+ |
+ success = true; |
+ } |
+ |
+ if (success) { |
+ vkTex->texturePriv().dirtyMipMaps(true); |
+ return true; |
+ } |
+ |
+ return false; |
+} |
+ |
void GrVkGpu::resolveImage(GrVkRenderTarget* dst, GrVkRenderTarget* src, const SkIRect& srcRect, |
const SkIPoint& dstPoint) { |
SkASSERT(dst); |
@@ -1888,3 +1970,32 @@ void GrVkGpu::submitSecondaryCommandBuffer(GrVkSecondaryCommandBuffer* buffer, |
this->didWriteToSurface(target, &bounds); |
} |
+GrFence SK_WARN_UNUSED_RESULT GrVkGpu::insertFence() const { |
+ VkFenceCreateInfo createInfo; |
+ memset(&createInfo, 0, sizeof(VkFenceCreateInfo)); |
+ createInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; |
+ createInfo.pNext = nullptr; |
+ createInfo.flags = 0; |
+ VkFence fence = VK_NULL_HANDLE; |
+ VkResult result = GR_VK_CALL(this->vkInterface(), CreateFence(this->device(), &createInfo, |
+ nullptr, &fence)); |
+ // TODO: verify that all QueueSubmits before this will finish before this fence signals |
+ if (VK_SUCCESS == result) { |
+ GR_VK_CALL(this->vkInterface(), QueueSubmit(this->queue(), 0, nullptr, fence)); |
+ } |
+ return (GrFence)fence; |
+} |
+ |
+bool GrVkGpu::waitFence(GrFence fence) const { |
+ const uint64_t kTimeout = 1000; |
+ VkResult result = GR_VK_CALL(this->vkInterface(), WaitForFences(this->device(), 1, |
+ (VkFence*)&fence, |
+ VK_TRUE, |
+ kTimeout)); |
+ return (VK_SUCCESS == result); |
+} |
+ |
+void GrVkGpu::deleteFence(GrFence fence) const { |
+ GR_VK_CALL(this->vkInterface(), DestroyFence(this->device(), (VkFence)fence, nullptr)); |
+} |
+ |