aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
authorGravatar Greg Daniel <egdaniel@google.com>2018-04-25 10:44:38 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-04-25 19:38:57 +0000
commit25af671a3d7d790b31b085172952df3867337431 (patch)
tree31105df7304db512ed5456852329347a70bb974d /src/gpu
parentb66099b9fbcfd0be347767a0161268452339a9f4 (diff)
Add GrCap check for whether we can do a copy or not, and implement in Vk backend
Today, we only know if we fail a copy during the flush so we have no way to cleanly handle a failed copy. This will allow us to know if we'll fail a copy during recording and allow us to do some appropriate fallback and/or dropping of the draw. Bug: skia: Change-Id: I38f209dbd4ebb4e762210b4609147d4b0a1b01b1 Reviewed-on: https://skia-review.googlesource.com/123560 Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com> Commit-Queue: Greg Daniel <egdaniel@google.com>
Diffstat (limited to 'src/gpu')
-rw-r--r--src/gpu/GrSurfaceContext.cpp6
-rw-r--r--src/gpu/vk/GrVkCaps.cpp122
-rw-r--r--src/gpu/vk/GrVkCaps.h22
-rw-r--r--src/gpu/vk/GrVkGpu.cpp113
4 files changed, 183 insertions, 80 deletions
diff --git a/src/gpu/GrSurfaceContext.cpp b/src/gpu/GrSurfaceContext.cpp
index 37d0b71fb0..56d6d7de6a 100644
--- a/src/gpu/GrSurfaceContext.cpp
+++ b/src/gpu/GrSurfaceContext.cpp
@@ -85,7 +85,11 @@ bool GrSurfaceContext::copy(GrSurfaceProxy* src, const SkIRect& srcRect, const S
ASSERT_SINGLE_OWNER
RETURN_FALSE_IF_ABANDONED
SkDEBUGCODE(this->validate();)
- GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrSurfaceContext::onCopy");
+ GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrSurfaceContext::copy");
+
+ if (!fContext->caps()->canCopySurface(this->asSurfaceProxy(), src, srcRect, dstPoint)) {
+ return false;
+ }
return this->getOpList()->copySurface(*fContext->caps(),
this->asSurfaceProxy(), src, srcRect, dstPoint);
diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp
index ae1570cd71..1c36a1494c 100644
--- a/src/gpu/vk/GrVkCaps.cpp
+++ b/src/gpu/vk/GrVkCaps.cpp
@@ -74,6 +74,128 @@ bool GrVkCaps::initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc*
return true;
}
+bool GrVkCaps::canCopyImage(GrPixelConfig dstConfig, int dstSampleCnt, GrSurfaceOrigin dstOrigin,
+ GrPixelConfig srcConfig, int srcSampleCnt,
+ GrSurfaceOrigin srcOrigin) const {
+ if ((dstSampleCnt > 1 || srcSampleCnt > 1) && dstSampleCnt != srcSampleCnt) {
+ return false;
+ }
+
+ // We require that all vulkan GrSurfaces have been created with transfer_dst and transfer_src
+ // as image usage flags.
+ if (srcOrigin != dstOrigin || GrBytesPerPixel(srcConfig) != GrBytesPerPixel(dstConfig)) {
+ return false;
+ }
+
+ if (this->shaderCaps()->configOutputSwizzle(srcConfig) !=
+ this->shaderCaps()->configOutputSwizzle(dstConfig)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool GrVkCaps::canCopyAsBlit(GrPixelConfig dstConfig, int dstSampleCnt, bool dstIsLinear,
+ GrPixelConfig srcConfig, int srcSampleCnt, bool srcIsLinear) const {
+ // We require that all vulkan GrSurfaces have been created with transfer_dst and transfer_src
+ // as image usage flags.
+ if (!this->configCanBeDstofBlit(dstConfig, dstIsLinear) ||
+ !this->configCanBeSrcofBlit(srcConfig, srcIsLinear)) {
+ return false;
+ }
+
+ if (this->shaderCaps()->configOutputSwizzle(srcConfig) !=
+ this->shaderCaps()->configOutputSwizzle(dstConfig)) {
+ return false;
+ }
+
+ // We cannot blit images that are multisampled. Will need to figure out if we can blit the
+ // resolved msaa though.
+ if (dstSampleCnt > 1 || srcSampleCnt > 1) {
+ return false;
+ }
+
+ return true;
+}
+
+bool GrVkCaps::canCopyAsResolve(GrPixelConfig dstConfig, int dstSampleCnt,
+ GrSurfaceOrigin dstOrigin, GrPixelConfig srcConfig,
+ int srcSampleCnt, GrSurfaceOrigin srcOrigin) const {
+ // The src surface must be multisampled.
+ if (srcSampleCnt <= 1) {
+ return false;
+ }
+
+ // The dst must not be multisampled.
+ if (dstSampleCnt > 1) {
+ return false;
+ }
+
+ // Surfaces must have the same format.
+ if (dstConfig != srcConfig) {
+ return false;
+ }
+
+ // Surfaces must have the same origin.
+ if (srcOrigin != dstOrigin) {
+ return false;
+ }
+
+ return true;
+}
+
+bool GrVkCaps::canCopyAsDraw(GrPixelConfig dstConfig, bool dstIsRenderable,
+ GrPixelConfig srcConfig, bool srcIsTextureable) const {
+ // TODO: Make copySurfaceAsDraw handle the swizzle
+ if (this->shaderCaps()->configOutputSwizzle(srcConfig) !=
+ this->shaderCaps()->configOutputSwizzle(dstConfig)) {
+ return false;
+ }
+
+ // Make sure the dst is a render target and the src is a texture.
+ if (!dstIsRenderable || !srcIsTextureable) {
+ return false;
+ }
+
+ return true;
+}
+
+bool GrVkCaps::canCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src,
+ const SkIRect& srcRect, const SkIPoint& dstPoint) const {
+ GrSurfaceOrigin dstOrigin = dst->origin();
+ GrSurfaceOrigin srcOrigin = src->origin();
+
+ GrPixelConfig dstConfig = dst->config();
+ GrPixelConfig srcConfig = src->config();
+
+ // TODO: Figure out a way to track if we've wrapped a linear texture in a proxy (e.g.
+ // PromiseImage which won't get instantiated right away. Does this need a similar thing like the
+ // tracking of external or rectangle textures in GL? For now we don't create linear textures
+ // internally, and I don't believe anyone is wrapping them.
+ bool srcIsLinear = false;
+ bool dstIsLinear = false;
+
+ int dstSampleCnt = 0;
+ int srcSampleCnt = 0;
+ if (const GrRenderTargetProxy* rtProxy = dst->asRenderTargetProxy()) {
+ dstSampleCnt = rtProxy->numColorSamples();
+ }
+ if (const GrRenderTargetProxy* rtProxy = src->asRenderTargetProxy()) {
+ srcSampleCnt = rtProxy->numColorSamples();
+ }
+ SkASSERT((dstSampleCnt > 0) == SkToBool(dst->asRenderTargetProxy()));
+ SkASSERT((srcSampleCnt > 0) == SkToBool(src->asRenderTargetProxy()));
+
+ return this->canCopyImage(dstConfig, dstSampleCnt, dstOrigin,
+ srcConfig, srcSampleCnt, srcOrigin) ||
+ this->canCopyAsBlit(dstConfig, dstSampleCnt, dstIsLinear,
+ srcConfig, srcSampleCnt, srcIsLinear) ||
+ this->canCopyAsResolve(dstConfig, dstSampleCnt, dstOrigin,
+ srcConfig, srcSampleCnt, srcOrigin) ||
+ this->canCopyAsDraw(dstConfig, dstSampleCnt > 0,
+ srcConfig, SkToBool(src->asTextureProxy()));
+}
+
void GrVkCaps::init(const GrContextOptions& contextOptions, const GrVkInterface* vkInterface,
VkPhysicalDevice physDev, uint32_t featureFlags, uint32_t extensionFlags) {
diff --git a/src/gpu/vk/GrVkCaps.h b/src/gpu/vk/GrVkCaps.h
index 881aacc9dc..69298d7f5e 100644
--- a/src/gpu/vk/GrVkCaps.h
+++ b/src/gpu/vk/GrVkCaps.h
@@ -110,6 +110,28 @@ public:
return fPreferedStencilFormat;
}
+ /**
+ * Helpers used by canCopySurface. In all cases if the SampleCnt parameter is zero that means
+ * the surface is not a render target, otherwise it is the number of samples in the render
+ * target.
+ */
+ bool canCopyImage(GrPixelConfig dstConfig, int dstSampleCnt, GrSurfaceOrigin dstOrigin,
+ GrPixelConfig srcConfig, int srcSamplecnt, GrSurfaceOrigin srcOrigin) const;
+
+ bool canCopyAsBlit(GrPixelConfig dstConfig, int dstSampleCnt, bool dstIsLinear,
+ GrPixelConfig srcConfig, int srcSampleCnt, bool srcIsLinear) const;
+
+ bool canCopyAsResolve(GrPixelConfig dstConfig, int dstSampleCnt, GrSurfaceOrigin dstOrigin,
+ GrPixelConfig srcConfig, int srcSamplecnt,
+ GrSurfaceOrigin srcOrigin) const;
+
+ bool canCopyAsDraw(GrPixelConfig dstConfig, bool dstIsRenderable,
+ GrPixelConfig srcConfig, bool srcIsTextureable) const;
+
+ bool canCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src,
+ const SkIRect& srcRect, const SkIPoint& dstPoint) const override;
+
+
bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc, GrSurfaceOrigin*,
bool* rectsMustMatch, bool* disallowSubrect) const override;
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index bc47ae6558..428a74bae7 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -503,6 +503,7 @@ void GrVkGpu::resolveImage(GrSurface* dst, GrVkRenderTarget* src, const SkIRect&
SkASSERT(dst->asTexture());
dstImage = static_cast<GrVkTexture*>(dst->asTexture());
}
+ SkASSERT(1 == dstImage->mipLevels());
dstImage->setImageLayout(this,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_ACCESS_TRANSFER_WRITE_BIT,
@@ -1669,33 +1670,11 @@ void GrVkGpu::clearStencil(GrRenderTarget* target, int clearValue) {
fCurrentCmdBuffer->clearDepthStencilImage(this, vkStencil, &vkStencilColor, 1, &subRange);
}
-inline bool can_copy_image(const GrSurface* dst, GrSurfaceOrigin dstOrigin,
- const GrSurface* src, GrSurfaceOrigin srcOrigin,
- const GrVkGpu* gpu) {
- 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;
- }
+static int get_surface_sample_cnt(GrSurface* surf) {
+ if (const GrRenderTarget* rt = surf->asRenderTarget()) {
+ return rt->numColorSamples();
}
-
- // We require that all vulkan GrSurfaces have been created with transfer_dst and transfer_src
- // as image usage flags.
- if (srcOrigin == dstOrigin &&
- GrBytesPerPixel(src->config()) == GrBytesPerPixel(dst->config())) {
- return true;
- }
-
- return false;
+ return 0;
}
void GrVkGpu::copySurfaceAsCopyImage(GrSurface* dst, GrSurfaceOrigin dstOrigin,
@@ -1704,7 +1683,13 @@ void GrVkGpu::copySurfaceAsCopyImage(GrSurface* dst, GrSurfaceOrigin dstOrigin,
GrVkImage* srcImage,
const SkIRect& srcRect,
const SkIPoint& dstPoint) {
- SkASSERT(can_copy_image(dst, dstOrigin, src, srcOrigin, this));
+#ifdef SK_DEBUG
+ int dstSampleCnt = get_surface_sample_cnt(dst);
+ int srcSampleCnt = get_surface_sample_cnt(src);
+ SkASSERT(this->vkCaps().canCopyImage(dst->config(), dstSampleCnt, dstOrigin,
+ src->config(), srcSampleCnt, srcOrigin));
+
+#endif
// These flags are for flushing/invalidating caches and for the dst image it doesn't matter if
// the cache is flushed since it is only being written to.
@@ -1752,37 +1737,19 @@ void GrVkGpu::copySurfaceAsCopyImage(GrSurface* dst, GrSurfaceOrigin dstOrigin,
this->didWriteToSurface(dst, dstOrigin, &dstRect);
}
-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, GrSurfaceOrigin dstOrigin,
GrSurface* src, GrSurfaceOrigin srcOrigin,
GrVkImage* dstImage,
GrVkImage* srcImage,
const SkIRect& srcRect,
const SkIPoint& dstPoint) {
- SkASSERT(can_copy_as_blit(dst, src, dstImage, srcImage, this));
+#ifdef SK_DEBUG
+ int dstSampleCnt = get_surface_sample_cnt(dst);
+ int srcSampleCnt = get_surface_sample_cnt(src);
+ SkASSERT(this->vkCaps().canCopyAsBlit(dst->config(), dstSampleCnt, dstImage->isLinearTiled(),
+ src->config(), srcSampleCnt, srcImage->isLinearTiled()));
+#endif
dstImage->setImageLayout(this,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_ACCESS_TRANSFER_WRITE_BIT,
@@ -1843,29 +1810,6 @@ void GrVkGpu::copySurfaceAsBlit(GrSurface* dst, GrSurfaceOrigin dstOrigin,
this->didWriteToSurface(dst, dstOrigin, &dstRect);
}
-inline bool can_copy_as_resolve(const GrSurface* dst, GrSurfaceOrigin dstOrigin,
- const GrSurface* src, GrSurfaceOrigin srcOrigin,
- const GrVkGpu* gpu) {
- // Our src must be a multisampled render target
- if (!src->asRenderTarget() || 1 == src->asRenderTarget()->numColorSamples()) {
- return false;
- }
-
- // The dst must not be a multisampled render target, expect in the case where the dst is the
- // resolve texture connected to the msaa src. We check for this in case we are copying a part of
- // a surface to a different region in the same surface.
- if (dst->asRenderTarget() && dst->asRenderTarget()->numColorSamples() > 1 && dst != src) {
- return false;
- }
-
- // Surfaces must have the same origin.
- if (srcOrigin != dstOrigin) {
- return false;
- }
-
- return true;
-}
-
void GrVkGpu::copySurfaceAsResolve(GrSurface* dst, GrSurfaceOrigin dstOrigin, GrSurface* src,
GrSurfaceOrigin srcOrigin, const SkIRect& origSrcRect,
const SkIPoint& origDstPoint) {
@@ -1885,7 +1829,14 @@ bool GrVkGpu::onCopySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin,
GrSurface* src, GrSurfaceOrigin srcOrigin,
const SkIRect& srcRect, const SkIPoint& dstPoint,
bool canDiscardOutsideDstRect) {
- if (can_copy_as_resolve(dst, dstOrigin, src, srcOrigin, this)) {
+ GrPixelConfig dstConfig = dst->config();
+ GrPixelConfig srcConfig = src->config();
+
+ int dstSampleCnt = get_surface_sample_cnt(dst);
+ int srcSampleCnt = get_surface_sample_cnt(src);
+
+ if (this->vkCaps().canCopyAsResolve(dstConfig, dstSampleCnt, dstOrigin,
+ srcConfig, srcSampleCnt, srcOrigin)) {
this->copySurfaceAsResolve(dst, dstOrigin, src, srcOrigin, srcRect, dstPoint);
return true;
}
@@ -1894,8 +1845,10 @@ bool GrVkGpu::onCopySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin,
this->submitCommandBuffer(GrVkGpu::kSkip_SyncQueue);
}
- if (fCopyManager.copySurfaceAsDraw(this, dst, dstOrigin, src, srcOrigin, srcRect, dstPoint,
- canDiscardOutsideDstRect)) {
+ if (this->vkCaps().canCopyAsDraw(dstConfig, SkToBool(dst->asRenderTarget()),
+ srcConfig, SkToBool(src->asTexture()))) {
+ SkAssertResult(fCopyManager.copySurfaceAsDraw(this, dst, dstOrigin, src, srcOrigin, srcRect,
+ dstPoint, canDiscardOutsideDstRect));
auto dstRect = srcRect.makeOffset(dstPoint.fX, dstPoint.fY);
this->didWriteToSurface(dst, dstOrigin, &dstRect);
return true;
@@ -1920,13 +1873,15 @@ bool GrVkGpu::onCopySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin,
srcImage = static_cast<GrVkTexture*>(src->asTexture());
}
- if (can_copy_image(dst, dstOrigin, src, srcOrigin, this)) {
+ if (this->vkCaps().canCopyImage(dstConfig, dstSampleCnt, dstOrigin,
+ srcConfig, srcSampleCnt, srcOrigin)) {
this->copySurfaceAsCopyImage(dst, dstOrigin, src, srcOrigin, dstImage, srcImage,
srcRect, dstPoint);
return true;
}
- if (can_copy_as_blit(dst, src, dstImage, srcImage, this)) {
+ if (this->vkCaps().canCopyAsBlit(dstConfig, dstSampleCnt, dstImage->isLinearTiled(),
+ srcConfig, srcSampleCnt, srcImage->isLinearTiled())) {
this->copySurfaceAsBlit(dst, dstOrigin, src, srcOrigin, dstImage, srcImage,
srcRect, dstPoint);
return true;