From 17b892551465e5a44560a06e4b34dc3592b49622 Mon Sep 17 00:00:00 2001 From: egdaniel Date: Tue, 5 Apr 2016 07:23:38 -0700 Subject: [PATCH] Implement blit image for copySurface in Vulkan Also allows CopyImage to handle GrRenderTargets which are not textures. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1852413002 Review URL: https://codereview.chromium.org/1852413002 --- src/gpu/vk/GrVkCommandBuffer.cpp | 22 ++++ src/gpu/vk/GrVkCommandBuffer.h | 9 ++ src/gpu/vk/GrVkGpu.cpp | 187 ++++++++++++++++++++++++++----- src/gpu/vk/GrVkGpu.h | 9 ++ 4 files changed, 199 insertions(+), 28 deletions(-) diff --git a/src/gpu/vk/GrVkCommandBuffer.cpp b/src/gpu/vk/GrVkCommandBuffer.cpp index cd97337956..2868d8e1fd 100644 --- a/src/gpu/vk/GrVkCommandBuffer.cpp +++ b/src/gpu/vk/GrVkCommandBuffer.cpp @@ -253,6 +253,28 @@ void GrVkCommandBuffer::copyImage(const GrVkGpu* gpu, copyRegions)); } +void GrVkCommandBuffer::blitImage(const GrVkGpu* gpu, + GrVkImage* srcImage, + VkImageLayout srcLayout, + GrVkImage* dstImage, + VkImageLayout dstLayout, + uint32_t blitRegionCount, + const VkImageBlit* blitRegions, + VkFilter filter) { + SkASSERT(fIsActive); + SkASSERT(!fActiveRenderPass); + this->addResource(srcImage->resource()); + this->addResource(dstImage->resource()); + GR_VK_CALL(gpu->vkInterface(), CmdBlitImage(fCmdBuffer, + srcImage->textureImage(), + srcLayout, + dstImage->textureImage(), + dstLayout, + blitRegionCount, + blitRegions, + filter)); +} + void GrVkCommandBuffer::copyImageToBuffer(const GrVkGpu* gpu, GrVkImage* srcImage, VkImageLayout srcLayout, diff --git a/src/gpu/vk/GrVkCommandBuffer.h b/src/gpu/vk/GrVkCommandBuffer.h index 99a3563e8b..e9e3d767a9 100644 --- a/src/gpu/vk/GrVkCommandBuffer.h +++ b/src/gpu/vk/GrVkCommandBuffer.h @@ -124,6 +124,15 @@ public: uint32_t copyRegionCount, const VkImageCopy* copyRegions); + void blitImage(const GrVkGpu* gpu, + GrVkImage* srcImage, + VkImageLayout srcLayout, + GrVkImage* dstImage, + VkImageLayout dstLayout, + uint32_t blitRegionCount, + const VkImageBlit* blitRegions, + VkFilter filter); + void copyImageToBuffer(const GrVkGpu* gpu, GrVkImage* srcImage, VkImageLayout srcLayout, diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp index 55f1eae997..e1e99ed020 100644 --- a/src/gpu/vk/GrVkGpu.cpp +++ b/src/gpu/vk/GrVkGpu.cpp @@ -1057,31 +1057,35 @@ void GrVkGpu::onClear(GrRenderTarget* target, const SkIRect& rect, GrColor color inline bool can_copy_image(const GrSurface* dst, const GrSurface* src, const GrVkGpu* gpu) { - if (src->asTexture() && - dst->asTexture() && - src->origin() == dst->origin() && - src->config() == dst->config()) { + // Currently we don't support msaa + if ((dst->asRenderTarget() && dst->asRenderTarget()->numColorSamples() > 1) || + (src->asRenderTarget() && src->asRenderTarget()->numColorSamples() > 1)) { + return false; + } + + // We require that all vulkan GrSurfaces have been created with transfer_dst and transfer_src + // as image usage flags. + if (src->origin() == dst->origin() && + GrBytesPerPixel(src->config()) == GrBytesPerPixel(dst->config())) { return true; } // How does msaa play into this? If a VkTexture is multisampled, are we copying the multisampled - // or the resolved image here? + // or the resolved image here? Im multisampled, Vulkan requires sample counts to be the same. return false; } void GrVkGpu::copySurfaceAsCopyImage(GrSurface* dst, GrSurface* src, + GrVkImage* dstImage, + GrVkImage* srcImage, const SkIRect& srcRect, const SkIPoint& dstPoint) { SkASSERT(can_copy_image(dst, src, this)); - // Insert memory barriers to switch src and dst to transfer_source and transfer_dst layouts - GrVkTexture* dstTex = static_cast(dst->asTexture()); - GrVkTexture* srcTex = static_cast(src->asTexture()); - - VkImageLayout origDstLayout = dstTex->currentLayout(); - VkImageLayout origSrcLayout = srcTex->currentLayout(); + VkImageLayout origDstLayout = dstImage->currentLayout(); + VkImageLayout origSrcLayout = srcImage->currentLayout(); VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(origDstLayout); VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; @@ -1091,13 +1095,13 @@ void GrVkGpu::copySurfaceAsCopyImage(GrSurface* dst, VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origDstLayout);; VkAccessFlags dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - dstTex->setImageLayout(this, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - srcAccessMask, - dstAccessMask, - srcStageMask, - dstStageMask, - false); + dstImage->setImageLayout(this, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + srcAccessMask, + dstAccessMask, + srcStageMask, + dstStageMask, + false); srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(origSrcLayout); dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; @@ -1105,13 +1109,13 @@ void GrVkGpu::copySurfaceAsCopyImage(GrSurface* dst, srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origSrcLayout); dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - srcTex->setImageLayout(this, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - srcAccessMask, - dstAccessMask, - srcStageMask, - dstStageMask, - false); + srcImage->setImageLayout(this, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + srcAccessMask, + dstAccessMask, + srcStageMask, + dstStageMask, + false); // Flip rect if necessary SkIRect srcVkRect = srcRect; @@ -1133,14 +1137,121 @@ void GrVkGpu::copySurfaceAsCopyImage(GrSurface* dst, copyRegion.extent = { (uint32_t)srcVkRect.width(), (uint32_t)srcVkRect.height(), 0 }; fCurrentCmdBuffer->copyImage(this, - srcTex, + srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - dstTex, + dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region); } +inline bool can_copy_as_blit(const GrSurface* dst, + const GrSurface* src, + const GrVkImage* dstImage, + const GrVkImage* srcImage, + const GrVkGpu* gpu) { + // We require that all vulkan GrSurfaces have been created with transfer_dst and transfer_src + // as image usage flags. + const GrVkCaps& caps = gpu->vkCaps(); + if (!caps.configCanBeDstofBlit(dst->config(), dstImage->isLinearTiled()) || + !caps.configCanBeSrcofBlit(src->config(), srcImage->isLinearTiled())) { + return false; + } + + // We cannot blit images that are multisampled. Will need to figure out if we can blit the + // resolved msaa though. + if ((dst->asRenderTarget() && dst->asRenderTarget()->numColorSamples() > 1) || + (src->asRenderTarget() && src->asRenderTarget()->numColorSamples() > 1)) { + return false; + } + + return true; +} + +void GrVkGpu::copySurfaceAsBlit(GrSurface* dst, + GrSurface* src, + GrVkImage* dstImage, + GrVkImage* srcImage, + const SkIRect& srcRect, + const SkIPoint& dstPoint) { + SkASSERT(can_copy_as_blit(dst, src, dstImage, srcImage, this)); + + VkImageLayout origDstLayout = dstImage->currentLayout(); + VkImageLayout origSrcLayout = srcImage->currentLayout(); + + VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(origDstLayout); + VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; + + VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origDstLayout);; + VkAccessFlags dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + + dstImage->setImageLayout(this, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + srcAccessMask, + dstAccessMask, + srcStageMask, + dstStageMask, + false); + + srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(origSrcLayout); + dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; + + srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origSrcLayout); + dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + + srcImage->setImageLayout(this, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + srcAccessMask, + dstAccessMask, + srcStageMask, + dstStageMask, + false); + + // Flip rect if necessary + SkIRect srcVkRect; + SkIRect dstRect; + dstRect.fLeft = dstPoint.fX; + dstRect.fRight = dstPoint.fX + srcVkRect.width(); + + if (kBottomLeft_GrSurfaceOrigin == src->origin()) { + srcVkRect.fTop = src->height() - srcRect.fBottom; + srcVkRect.fBottom = src->height() - srcRect.fTop; + } else { + srcVkRect = srcRect; + } + + if (kBottomLeft_GrSurfaceOrigin == dst->origin()) { + dstRect.fTop = dst->height() - dstPoint.fY - srcVkRect.height(); + } else { + dstRect.fTop = dstPoint.fY; + } + dstRect.fBottom = dstRect.fTop + srcVkRect.height(); + + // If we have different origins, we need to flip the top and bottom of the dst rect so that we + // get the correct origintation of the copied data. + if (src->origin() != dst->origin()) { + SkTSwap(dstRect.fTop, dstRect.fBottom); + } + + VkImageBlit blitRegion; + memset(&blitRegion, 0, sizeof(VkImageBlit)); + blitRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; + blitRegion.srcOffsets[0] = { srcVkRect.fLeft, srcVkRect.fTop, 0 }; + blitRegion.srcOffsets[1] = { srcVkRect.fRight, srcVkRect.fBottom, 0 }; + blitRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; + blitRegion.dstOffsets[0] = { dstRect.fLeft, dstRect.fTop, 0 }; + blitRegion.dstOffsets[1] = { dstRect.fRight, dstRect.fBottom, 0 }; + + fCurrentCmdBuffer->blitImage(this, + srcImage, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + dstImage, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + &blitRegion, + VK_FILTER_NEAREST); // We never scale so any filter works here +} + inline bool can_copy_as_draw(const GrSurface* dst, const GrSurface* src, const GrVkGpu* gpu) { @@ -1158,8 +1269,28 @@ bool GrVkGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) { + GrVkImage* dstImage; + GrVkImage* srcImage; + if (dst->asTexture()) { + dstImage = static_cast(dst->asTexture()); + } else { + SkASSERT(dst->asRenderTarget()); + dstImage = static_cast(dst->asRenderTarget()); + } + if (src->asTexture()) { + srcImage = static_cast(src->asTexture()); + } else { + SkASSERT(src->asRenderTarget()); + srcImage = static_cast(src->asRenderTarget()); + } + if (can_copy_image(dst, src, this)) { - this->copySurfaceAsCopyImage(dst, src, srcRect, dstPoint); + this->copySurfaceAsCopyImage(dst, src, dstImage, srcImage, srcRect, dstPoint); + return true; + } + + if (can_copy_as_blit(dst, src, dstImage, srcImage, this)) { + this->copySurfaceAsBlit(dst, src, dstImage, srcImage, srcRect, dstPoint); return true; } diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h index 001e12c870..87fea90e32 100644 --- a/src/gpu/vk/GrVkGpu.h +++ b/src/gpu/vk/GrVkGpu.h @@ -174,9 +174,18 @@ private: void copySurfaceAsCopyImage(GrSurface* dst, GrSurface* src, + GrVkImage* dstImage, + GrVkImage* srcImage, const SkIRect& srcRect, const SkIPoint& dstPoint); + void copySurfaceAsBlit(GrSurface* dst, + GrSurface* src, + GrVkImage* dstImage, + GrVkImage* srcImage, + const SkIRect& srcRect, + const SkIPoint& dstPoint); + void copySurfaceAsDraw(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,