aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
authorGravatar egdaniel <egdaniel@google.com>2016-08-31 07:37:31 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-08-31 07:37:31 -0700
commit4bcd62e3313da60c3aa96ccd12b7ea440c7266d4 (patch)
tree695930fc9669667b6dfb4073c107560d3d9b41d1 /src/gpu
parent272b311298d78569c88130ceee3096b876fcbf25 (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')
-rw-r--r--src/gpu/GrDrawTarget.cpp2
-rw-r--r--src/gpu/GrGpu.h8
-rw-r--r--src/gpu/gl/GrGLGpu.cpp9
-rw-r--r--src/gpu/gl/GrGLGpu.h2
-rw-r--r--src/gpu/vk/GrVkGpu.cpp163
-rw-r--r--src/gpu/vk/GrVkGpu.h12
-rw-r--r--src/gpu/vk/GrVkRenderTarget.cpp4
-rw-r--r--src/gpu/vk/GrVkTextureRenderTarget.cpp4
8 files changed, 135 insertions, 69 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)) {