| Index: src/gpu/vk/GrVkGpu.cpp
|
| diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
|
| index 91da82d945888629775663209971c7aae5a9e8d2..9a8a6e4e8c5954f76b4dfa324260785fa7b0b70d 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;
|
| }
|
|
|
|
|