diff options
author | 2016-08-31 07:37:31 -0700 | |
---|---|---|
committer | 2016-08-31 07:37:31 -0700 | |
commit | 4bcd62e3313da60c3aa96ccd12b7ea440c7266d4 (patch) | |
tree | 695930fc9669667b6dfb4073c107560d3d9b41d1 /src/gpu/vk/GrVkGpu.cpp | |
parent | 272b311298d78569c88130ceee3096b876fcbf25 (diff) |
Add some copy support for vulkan msaa
This allows us to do copies from:
msaa->msaa with same sample count
msaa->no-msaa with a resolve
Still missing support for no-msaa to msaa which will require a copyAsDraw
which is currently stalled and fixing possible driver bugs.
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2294533002
Review-Url: https://codereview.chromium.org/2294533002
Diffstat (limited to 'src/gpu/vk/GrVkGpu.cpp')
-rw-r--r-- | src/gpu/vk/GrVkGpu.cpp | 163 |
1 files changed, 109 insertions, 54 deletions
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp index 91da82d945..9a8a6e4e8c 100644 --- a/src/gpu/vk/GrVkGpu.cpp +++ b/src/gpu/vk/GrVkGpu.cpp @@ -366,42 +366,55 @@ bool GrVkGpu::onWritePixels(GrSurface* surface, return success; } +void GrVkGpu::resolveImage(GrVkRenderTarget* dst, GrVkRenderTarget* src, const SkIRect& srcRect, + const SkIPoint& dstPoint) { + SkASSERT(dst); + SkASSERT(src && src->numColorSamples() > 1 && src->msaaImage()); + + // Flip rect if necessary + SkIRect srcVkRect = srcRect; + int32_t dstY = dstPoint.fY; + + if (kBottomLeft_GrSurfaceOrigin == src->origin()) { + SkASSERT(kBottomLeft_GrSurfaceOrigin == dst->origin()); + srcVkRect.fTop = src->height() - srcRect.fBottom; + srcVkRect.fBottom = src->height() - srcRect.fTop; + dstY = dst->height() - dstPoint.fY - srcVkRect.height(); + } + + VkImageResolve resolveInfo; + resolveInfo.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; + resolveInfo.srcOffset = { srcVkRect.fLeft, srcVkRect.fTop, 0 }; + resolveInfo.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; + resolveInfo.dstOffset = { dstPoint.fX, dstY, 0 }; + // By the spec the depth of the extent should be ignored for 2D images, but certain devices + // (e.g. nexus 5x) currently fail if it is not 1 + resolveInfo.extent = { (uint32_t)srcVkRect.width(), (uint32_t)srcVkRect.height(), 1 }; + + dst->setImageLayout(this, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + false); + + src->msaaImage()->setImageLayout(this, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_ACCESS_TRANSFER_READ_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + false); + + fCurrentCmdBuffer->resolveImage(this, *src->msaaImage(), *dst, 1, &resolveInfo); +} + void GrVkGpu::onResolveRenderTarget(GrRenderTarget* target) { if (target->needsResolve()) { SkASSERT(target->numColorSamples() > 1); GrVkRenderTarget* rt = static_cast<GrVkRenderTarget*>(target); SkASSERT(rt->msaaImage()); + + const SkIRect& srcRect = rt->getResolveRect(); - // Flip rect if necessary - SkIRect srcVkRect = rt->getResolveRect(); - - if (kBottomLeft_GrSurfaceOrigin == rt->origin()) { - srcVkRect.fTop = rt->height() - rt->getResolveRect().fBottom; - srcVkRect.fBottom = rt->height() - rt->getResolveRect().fTop; - } - - VkImageResolve resolveInfo; - resolveInfo.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; - resolveInfo.srcOffset = { srcVkRect.fLeft, srcVkRect.fTop, 0 }; - resolveInfo.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; - resolveInfo.dstOffset = { srcVkRect.fLeft, srcVkRect.fTop, 0 }; - // By the spec the depth of the extent should be ignored for 2D images, but certain devices - // (e.g. nexus 5x) currently fail if it is not 1 - resolveInfo.extent = { (uint32_t)srcVkRect.width(), (uint32_t)srcVkRect.height(), 1 }; - - rt->setImageLayout(this, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_ACCESS_TRANSFER_WRITE_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - false); - - rt->msaaImage()->setImageLayout(this, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_ACCESS_TRANSFER_READ_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - false); - - fCurrentCmdBuffer->resolveImage(this, *rt->msaaImage(), *rt, 1, &resolveInfo); + this->resolveImage(rt, rt, srcRect, SkIPoint::Make(srcRect.fLeft, srcRect.fTop)); rt->flagAsResolved(); } @@ -1333,10 +1346,20 @@ void GrVkGpu::clearStencil(GrRenderTarget* target) { inline bool can_copy_image(const GrSurface* dst, const GrSurface* src, const GrVkGpu* gpu) { - // Currently we don't support msaa - if ((dst->asRenderTarget() && dst->asRenderTarget()->numColorSamples() > 1) || - (src->asRenderTarget() && src->asRenderTarget()->numColorSamples() > 1)) { - return false; + const GrRenderTarget* dstRT = dst->asRenderTarget(); + const GrRenderTarget* srcRT = src->asRenderTarget(); + if (dstRT && srcRT) { + if (srcRT->numColorSamples() != dstRT->numColorSamples()) { + return false; + } + } else if (dstRT) { + if (dstRT->numColorSamples() > 1) { + return false; + } + } else if (srcRT) { + if (srcRT->numColorSamples() > 1) { + return false; + } } // We require that all vulkan GrSurfaces have been created with transfer_dst and transfer_src @@ -1346,9 +1369,6 @@ inline bool can_copy_image(const GrSurface* dst, return true; } - // How does msaa play into this? If a VkTexture is multisampled, are we copying the multisampled - // or the resolved image here? Im multisampled, Vulkan requires sample counts to be the same. - return false; } @@ -1500,6 +1520,37 @@ void GrVkGpu::copySurfaceAsBlit(GrSurface* dst, this->didWriteToSurface(dst, &dstRect); } +inline bool can_copy_as_resolve(const GrSurface* dst, + const GrSurface* src, + const GrVkGpu* gpu) { + // Our src must be a multisampled render target + if (!src->asRenderTarget() || src->asRenderTarget()->numColorSamples() <= 1) { + return false; + } + + // The dst must be a render target but not multisampled + if (!dst->asRenderTarget() || dst->asRenderTarget()->numColorSamples() > 1) { + return false; + } + + // Surfaces must have the same origin. + if (src->origin() != dst->origin()) { + return false; + } + + return true; +} + +void GrVkGpu::copySurfaceAsResolve(GrSurface* dst, + GrSurface* src, + const SkIRect& srcRect, + const SkIPoint& dstPoint) { + GrVkRenderTarget* dstRT = static_cast<GrVkRenderTarget*>(dst->asRenderTarget()); + GrVkRenderTarget* srcRT = static_cast<GrVkRenderTarget*>(src->asRenderTarget()); + SkASSERT(dstRT && dstRT->numColorSamples() <= 1); + this->resolveImage(dstRT, srcRT, srcRect, dstPoint); +} + inline bool can_copy_as_draw(const GrSurface* dst, const GrSurface* src, const GrVkGpu* gpu) { @@ -1517,19 +1568,27 @@ bool GrVkGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) { + if (can_copy_as_resolve(dst, src, this)) { + this->copySurfaceAsResolve(dst, src, srcRect, dstPoint); + } + GrVkImage* dstImage; GrVkImage* srcImage; - if (dst->asTexture()) { - dstImage = static_cast<GrVkTexture*>(dst->asTexture()); + GrRenderTarget* dstRT = dst->asRenderTarget(); + if (dstRT) { + GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(dstRT); + dstImage = vkRT->numColorSamples() > 1 ? vkRT->msaaImage() : vkRT; } else { - SkASSERT(dst->asRenderTarget()); - dstImage = static_cast<GrVkRenderTarget*>(dst->asRenderTarget()); + SkASSERT(dst->asTexture()); + dstImage = static_cast<GrVkTexture*>(dst->asTexture()); } - if (src->asTexture()) { - srcImage = static_cast<GrVkTexture*>(src->asTexture()); + GrRenderTarget* srcRT = src->asRenderTarget(); + if (srcRT) { + GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(srcRT); + srcImage = vkRT->numColorSamples() > 1 ? vkRT->msaaImage() : vkRT; } else { - SkASSERT(src->asRenderTarget()); - srcImage = static_cast<GrVkRenderTarget*>(src->asRenderTarget()); + SkASSERT(src->asTexture()); + srcImage = static_cast<GrVkTexture*>(src->asTexture()); } if (can_copy_image(dst, src, this)) { @@ -1550,17 +1609,13 @@ bool GrVkGpu::onCopySurface(GrSurface* dst, return false; } -bool GrVkGpu::initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc) const { - // Currently we don't support msaa - if (src->asRenderTarget() && src->asRenderTarget()->numColorSamples() > 1) { - return false; - } - - // This will support copying the dst as CopyImage since all of our surfaces require transferSrc - // and transferDst usage flags in Vulkan. +bool GrVkGpu::initDescForDstCopy(const GrRenderTarget* src, GrSurfaceDesc* desc) const { + // We can always succeed here with either a CopyImage (none msaa src) or ResolveImage (msaa). + // For CopyImage we can make a simple texture, for ResolveImage we require the dst to be a + // render target as well. desc->fOrigin = src->origin(); desc->fConfig = src->config(); - desc->fFlags = kNone_GrSurfaceFlags; + desc->fFlags = src->numColorSamples() > 1 ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags; return true; } |