diff options
author | egdaniel <egdaniel@google.com> | 2016-08-31 07:37:31 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-08-31 07:37:31 -0700 |
commit | 4bcd62e3313da60c3aa96ccd12b7ea440c7266d4 (patch) | |
tree | 695930fc9669667b6dfb4073c107560d3d9b41d1 | |
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
-rw-r--r-- | src/gpu/GrDrawTarget.cpp | 2 | ||||
-rw-r--r-- | src/gpu/GrGpu.h | 8 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.cpp | 9 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.h | 2 | ||||
-rw-r--r-- | src/gpu/vk/GrVkGpu.cpp | 163 | ||||
-rw-r--r-- | src/gpu/vk/GrVkGpu.h | 12 | ||||
-rw-r--r-- | src/gpu/vk/GrVkRenderTarget.cpp | 4 | ||||
-rw-r--r-- | src/gpu/vk/GrVkTextureRenderTarget.cpp | 4 | ||||
-rw-r--r-- | tools/gpu/GrTest.cpp | 2 |
9 files changed, 136 insertions, 70 deletions
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp index dc2fd30861..d8b44b8cba 100644 --- a/src/gpu/GrDrawTarget.cpp +++ b/src/gpu/GrDrawTarget.cpp @@ -179,7 +179,7 @@ bool GrDrawTarget::setupDstReadIfNecessary(const GrPipelineBuilder& pipelineBuil // MSAA consideration: When there is support for reading MSAA samples in the shader we could // have per-sample dst values by making the copy multisampled. GrSurfaceDesc desc; - if (!fGpu->initCopySurfaceDstDesc(rt, &desc)) { + if (!fGpu->initDescForDstCopy(rt, &desc)) { desc.fOrigin = kDefault_GrSurfaceOrigin; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fConfig = rt->config(); diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h index 393df1a9b6..3e3a4cd676 100644 --- a/src/gpu/GrGpu.h +++ b/src/gpu/GrGpu.h @@ -308,12 +308,12 @@ public: size_t offset, size_t rowBytes); /** - * This is can be called before allocating a texture to be a dst for copySurface. It will + * This is can be called before allocating a texture to be a dst for copySurface. This is only + * used for doing dst copies needed in blends, thus the src is always a GrRenderTarget. It will * populate the origin, config, and flags fields of the desc such that copySurface can - * efficiently succeed. It should only succeed if it can allow copySurface to perform a copy - * that would be more effecient than drawing the src to a dst render target. + * efficiently succeed. */ - virtual bool initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc) const = 0; + virtual bool initDescForDstCopy(const GrRenderTarget* src, GrSurfaceDesc* desc) const = 0; // After the client interacts directly with the 3D context state the GrGpu // must resync its internal state and assumptions about 3D context state. diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index 9981b66075..1370bf992b 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -3586,7 +3586,7 @@ void GrGLGpu::unbindTextureFBOForCopy(GrGLenum fboTarget, GrSurface* surface) { } } -bool GrGLGpu::initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc) const { +bool GrGLGpu::initDescForDstCopy(const GrRenderTarget* src, GrSurfaceDesc* desc) const { // If the src is a texture, we can implement the blit as a draw assuming the config is // renderable. if (src->asTexture() && this->caps()->isConfigRenderable(src->config(), false)) { @@ -3625,13 +3625,10 @@ bool GrGLGpu::initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc) return true; } return false; - } else if (nullptr == src->asRenderTarget()) { - // CopyTexSubImage2D or fbo blit would require creating a temp fbo for the src. - return false; } - const GrGLRenderTarget* srcRT = static_cast<const GrGLRenderTarget*>(src->asRenderTarget()); - if (srcRT && srcRT->renderFBOID() != srcRT->textureFBOID()) { + const GrGLRenderTarget* srcRT = static_cast<const GrGLRenderTarget*>(src); + if (srcRT->renderFBOID() != srcRT->textureFBOID()) { // It's illegal to call CopyTexSubImage2D on a MSAA renderbuffer. Set up for FBO blit or // fail. if (this->caps()->isConfigRenderable(src->config(), false)) { diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h index 26c9588fcc..448c29243f 100644 --- a/src/gpu/gl/GrGLGpu.h +++ b/src/gpu/gl/GrGLGpu.h @@ -71,7 +71,7 @@ public: GrPixelConfig srcConfig, DrawPreference*, WritePixelTempDrawInfo*) override; - bool initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc) const override; + bool initDescForDstCopy(const GrRenderTarget* src, GrSurfaceDesc* desc) const override; // These functions should be used to bind GL objects. They track the GL state and skip redundant // bindings. Making the equivalent glBind calls directly will confuse the state tracking. 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; } diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h index ff9c3c7c5f..8df6e6cfdc 100644 --- a/src/gpu/vk/GrVkGpu.h +++ b/src/gpu/vk/GrVkGpu.h @@ -82,7 +82,7 @@ public: void onGetMultisampleSpecs(GrRenderTarget* rt, const GrStencilSettings&, int* effectiveSampleCnt, SamplePattern*) override; - bool initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc) const override; + bool initDescForDstCopy(const GrRenderTarget* src, GrSurfaceDesc* desc) const override; void xferBarrier(GrRenderTarget*, GrXferBarrierType) override {} @@ -220,6 +220,11 @@ private: const SkIRect& srcRect, const SkIPoint& dstPoint); + void copySurfaceAsResolve(GrSurface* dst, + GrSurface* src, + const SkIRect& srcRect, + const SkIPoint& dstPoint); + void copySurfaceAsDraw(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, @@ -236,6 +241,11 @@ private: GrPixelConfig dataConfig, const SkTArray<GrMipLevel>&); + void resolveImage(GrVkRenderTarget* dst, + GrVkRenderTarget* src, + const SkIRect& srcRect, + const SkIPoint& dstPoint); + SkAutoTUnref<const GrVkBackendContext> fBackendContext; SkAutoTUnref<GrVkCaps> fVkCaps; diff --git a/src/gpu/vk/GrVkRenderTarget.cpp b/src/gpu/vk/GrVkRenderTarget.cpp index 59fc0b980d..6d95ba0d00 100644 --- a/src/gpu/vk/GrVkRenderTarget.cpp +++ b/src/gpu/vk/GrVkRenderTarget.cpp @@ -135,7 +135,9 @@ GrVkRenderTarget::Create(GrVkGpu* gpu, msImageDesc.fLevels = 1; msImageDesc.fSamples = desc.fSampleCnt; msImageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL; - msImageDesc.fUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + msImageDesc.fUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT; msImageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; if (!GrVkImage::InitImageInfo(gpu, msImageDesc, &msInfo)) { diff --git a/src/gpu/vk/GrVkTextureRenderTarget.cpp b/src/gpu/vk/GrVkTextureRenderTarget.cpp index 532d0a2563..37b68af827 100644 --- a/src/gpu/vk/GrVkTextureRenderTarget.cpp +++ b/src/gpu/vk/GrVkTextureRenderTarget.cpp @@ -49,7 +49,9 @@ GrVkTextureRenderTarget* GrVkTextureRenderTarget::Create(GrVkGpu* gpu, msImageDesc.fLevels = 1; msImageDesc.fSamples = desc.fSampleCnt; msImageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL; - msImageDesc.fUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + msImageDesc.fUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT; msImageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; if (!GrVkImage::InitImageInfo(gpu, msImageDesc, &msInfo)) { diff --git a/tools/gpu/GrTest.cpp b/tools/gpu/GrTest.cpp index d2c72956ea..8a64ebcbf2 100644 --- a/tools/gpu/GrTest.cpp +++ b/tools/gpu/GrTest.cpp @@ -306,7 +306,7 @@ public: *effectiveSampleCnt = rt->desc().fSampleCnt; } - bool initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc) const override { + bool initDescForDstCopy(const GrRenderTarget* src, GrSurfaceDesc* desc) const override { return false; } |