From e35055f31c7f2a2c7f3c693b9231c44d181ec599 Mon Sep 17 00:00:00 2001 From: Timothy Liang Date: Fri, 20 Jul 2018 16:53:00 -0400 Subject: implemented copy surface as blit for metal gpu backend Bug: skia: Change-Id: Ic59fe585c02168a361985f0864242b3c11e9d98e Reviewed-on: https://skia-review.googlesource.com/142684 Reviewed-by: Greg Daniel Commit-Queue: Timothy Liang --- src/gpu/mtl/GrMtlCaps.h | 9 ++- src/gpu/mtl/GrMtlCaps.mm | 49 ++++++++++++++ src/gpu/mtl/GrMtlGpu.h | 6 +- src/gpu/mtl/GrMtlGpu.mm | 127 ++++++++++++++++++++++++++++++++---- src/gpu/mtl/GrMtlGpuCommandBuffer.h | 10 +-- 5 files changed, 179 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/gpu/mtl/GrMtlCaps.h b/src/gpu/mtl/GrMtlCaps.h index 1ff16adba4..5d6c82bea8 100644 --- a/src/gpu/mtl/GrMtlCaps.h +++ b/src/gpu/mtl/GrMtlCaps.h @@ -46,10 +46,13 @@ public: return fPreferedStencilFormat; } #endif + bool canCopyAsBlit(GrPixelConfig dstConfig, int dstSampleCount, GrSurfaceOrigin dstOrigin, + GrPixelConfig srcConfig, int srcSampleCount, GrSurfaceOrigin srcOrigin, + const SkIRect& srcRect, const SkIPoint& dstPoint, + bool areDstSrcSameObj) const; + bool canCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src, - const SkIRect& srcRect, const SkIPoint& dstPoint) const override { - return false; - } + 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/mtl/GrMtlCaps.mm b/src/gpu/mtl/GrMtlCaps.mm index 2527be9ceb..3093352272 100644 --- a/src/gpu/mtl/GrMtlCaps.mm +++ b/src/gpu/mtl/GrMtlCaps.mm @@ -9,7 +9,10 @@ #include "GrBackendSurface.h" #include "GrMtlUtil.h" +#include "GrRenderTargetProxy.h" #include "GrShaderCaps.h" +#include "GrSurfaceProxy.h" +#include "SkRect.h" GrMtlCaps::GrMtlCaps(const GrContextOptions& contextOptions, const id device, MTLFeatureSet featureSet) @@ -101,6 +104,52 @@ void GrMtlCaps::initFeatureSet(MTLFeatureSet featureSet) { SK_ABORT("Requested an unsupported feature set"); } +bool GrMtlCaps::canCopyAsBlit(GrPixelConfig dstConfig, int dstSampleCount, + GrSurfaceOrigin dstOrigin, + GrPixelConfig srcConfig, int srcSampleCount, + GrSurfaceOrigin srcOrigin, + const SkIRect& srcRect, const SkIPoint& dstPoint, + bool areDstSrcSameObj) const { + if (dstConfig != srcConfig) { + return false; + } + if ((dstSampleCount > 1 || srcSampleCount > 1) && (dstSampleCount != srcSampleCount)) { + return false; + } + if (dstOrigin != srcOrigin) { + return false; + } + if (areDstSrcSameObj) { + SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.x(), dstPoint.y(), + srcRect.width(), srcRect.height()); + if (dstRect.intersect(srcRect)) { + return false; + } + } + return true; +} + +bool GrMtlCaps::canCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src, + const SkIRect& srcRect, const SkIPoint& dstPoint) const { + GrSurfaceOrigin dstOrigin = dst->origin(); + GrSurfaceOrigin srcOrigin = src->origin(); + + 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->canCopyAsBlit(dst->config(), dstSampleCnt, dstOrigin, + src->config(), srcSampleCnt, srcOrigin, + srcRect, dstPoint, dst == src); +} + void GrMtlCaps::initGrCaps(const id device) { // Max vertex attribs is the same on all devices fMaxVertexAttributes = 31; diff --git a/src/gpu/mtl/GrMtlGpu.h b/src/gpu/mtl/GrMtlGpu.h index 054f1e6842..98132fa725 100644 --- a/src/gpu/mtl/GrMtlGpu.h +++ b/src/gpu/mtl/GrMtlGpu.h @@ -56,11 +56,15 @@ public: void testingOnly_flushGpuAndSync() override; #endif + bool copySurfaceAsBlit(GrSurface* dst, GrSurfaceOrigin dstOrigin, + GrSurface* src, GrSurfaceOrigin srcOrigin, + const SkIRect& srcRect, const SkIPoint& dstPoint); + bool onCopySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin, GrSurface* src, GrSurfaceOrigin srcOrigin, const SkIRect& srcRect, const SkIPoint& dstPoint, - bool canDiscardOutsideDstRect) override { return false; } + bool canDiscardOutsideDstRect) override; GrGpuRTCommandBuffer* createCommandBuffer( GrRenderTarget*, GrSurfaceOrigin, diff --git a/src/gpu/mtl/GrMtlGpu.mm b/src/gpu/mtl/GrMtlGpu.mm index e4c7c64e5f..79eeb3ad6b 100644 --- a/src/gpu/mtl/GrMtlGpu.mm +++ b/src/gpu/mtl/GrMtlGpu.mm @@ -527,6 +527,117 @@ void GrMtlGpu::testingOnly_flushGpuAndSync() { } #endif // GR_TEST_UTILS +id get_mtl_texture_from_surface(GrSurface* surface, bool doResolve) { + id mtlTexture = nil; + + GrMtlRenderTarget* renderTarget = static_cast(surface->asRenderTarget()); + GrMtlTexture* texture; + if (renderTarget) { + if (doResolve) { + // TODO: do resolve and set mtlTexture to resolved texture. As of now, we shouldn't + // have any multisampled render targets. + SkASSERT(false); + } else { + mtlTexture = renderTarget->mtlRenderTexture(); + } + } else { + texture = static_cast(surface->asTexture()); + if (texture) { + mtlTexture = texture->mtlTexture(); + } + } + return mtlTexture; +} + +static int get_surface_sample_cnt(GrSurface* surf) { + if (const GrRenderTarget* rt = surf->asRenderTarget()) { + return rt->numColorSamples(); + } + return 0; +} + +bool GrMtlGpu::copySurfaceAsBlit(GrSurface* dst, GrSurfaceOrigin dstOrigin, + GrSurface* src, GrSurfaceOrigin srcOrigin, + const SkIRect& srcRect, const SkIPoint& dstPoint) { +#ifdef SK_DEBUG + int dstSampleCnt = get_surface_sample_cnt(dst); + int srcSampleCnt = get_surface_sample_cnt(src); + SkASSERT(this->mtlCaps().canCopyAsBlit(dst->config(), dstSampleCnt, dstOrigin, + src->config(), srcSampleCnt, srcOrigin, + srcRect, dstPoint, dst == src)); +#endif + id dstTex = get_mtl_texture_from_surface(dst, false); + id srcTex = get_mtl_texture_from_surface(src, false); + + // Flip rect if necessary + SkIRect srcMtlRect; + srcMtlRect.fLeft = srcRect.fLeft; + srcMtlRect.fRight = srcRect.fRight; + SkIRect dstRect; + dstRect.fLeft = dstPoint.fX; + dstRect.fRight = dstPoint.fX + srcRect.width(); + + if (kBottomLeft_GrSurfaceOrigin == srcOrigin) { + srcMtlRect.fTop = srcTex.height - srcRect.fBottom; + srcMtlRect.fBottom = srcTex.height - srcRect.fTop; + } else { + srcMtlRect.fTop = srcRect.fTop; + srcMtlRect.fBottom = srcRect.fBottom; + } + + if (kBottomLeft_GrSurfaceOrigin == dstOrigin) { + dstRect.fTop = dstTex.height - dstPoint.fY - srcMtlRect.height(); + } else { + dstRect.fTop = dstPoint.fY; + } + dstRect.fBottom = dstRect.fTop + srcMtlRect.height(); + + id blitCmdEncoder = [fCmdBuffer blitCommandEncoder]; + [blitCmdEncoder copyFromTexture: srcTex + sourceSlice: 0 + sourceLevel: 0 + sourceOrigin: MTLOriginMake(srcMtlRect.x(), srcMtlRect.y(), 0) + sourceSize: MTLSizeMake(srcMtlRect.width(), srcMtlRect.height(), 1) + toTexture: dstTex + destinationSlice: 0 + destinationLevel: 0 + destinationOrigin: MTLOriginMake(dstRect.x(), dstRect.y(), 0)]; + [blitCmdEncoder endEncoding]; + + return true; +} + +bool GrMtlGpu::onCopySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin, + GrSurface* src, GrSurfaceOrigin srcOrigin, + const SkIRect& srcRect, + const SkIPoint& dstPoint, + bool canDiscardOutsideDstRect) { + + GrPixelConfig dstConfig = dst->config(); + GrPixelConfig srcConfig = src->config(); + + int dstSampleCnt = get_surface_sample_cnt(dst); + int srcSampleCnt = get_surface_sample_cnt(src); + + if (dstSampleCnt > 1 || srcSampleCnt > 1) { + SkASSERT(false); // Currently dont support MSAA + return false; + } + + bool success = false; + if (this->mtlCaps().canCopyAsBlit(dstConfig, dstSampleCnt, dstOrigin, + srcConfig, srcSampleCnt, srcOrigin, + srcRect, dstPoint, dst == src)) { + success = this->copySurfaceAsBlit(dst, dstOrigin, src, srcOrigin, srcRect, dstPoint); + } + if (success) { + SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.x(), dstPoint.y(), + srcRect.width(), srcRect.height()); + this->didWriteToSurface(dst, dstOrigin, &dstRect); + } + return success; +} + bool GrMtlGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height, GrColorType srcColorType, const GrMipLevel texels[], int mipLevelCount) { @@ -556,20 +667,8 @@ bool GrMtlGpu::onReadPixels(GrSurface* surface, int left, int top, int width, in return false; } - id mtlTexture = nil; - GrMtlRenderTarget* renderTarget = static_cast(surface->asRenderTarget()); - GrMtlTexture* texture; - if (renderTarget) { - // TODO: Handle resolving rt here when MSAA is supported. Right now we just grab the render - // texture since we cannot currently have a multi-sampled rt. - mtlTexture = renderTarget->mtlRenderTexture(); - } else { - texture = static_cast(surface->asTexture()); - if (texture) { - mtlTexture = texture->mtlTexture(); - } - } - + bool doResolve = get_surface_sample_cnt(surface) > 1; + id mtlTexture = get_mtl_texture_from_surface(surface, doResolve); if (!mtlTexture) { return false; } diff --git a/src/gpu/mtl/GrMtlGpuCommandBuffer.h b/src/gpu/mtl/GrMtlGpuCommandBuffer.h index 8f1fd20d62..df1738d4e8 100644 --- a/src/gpu/mtl/GrMtlGpuCommandBuffer.h +++ b/src/gpu/mtl/GrMtlGpuCommandBuffer.h @@ -18,14 +18,14 @@ public: GrMtlGpuTextureCommandBuffer(GrMtlGpu* gpu, GrTexture* texture, GrSurfaceOrigin origin) : INHERITED(texture, origin) , fGpu(gpu) { - // Silence unused var warning - (void)fGpu; } ~GrMtlGpuTextureCommandBuffer() override {} void copy(GrSurface* src, GrSurfaceOrigin srcOrigin, const SkIRect& srcRect, - const SkIPoint& dstPoint) override {} + const SkIPoint& dstPoint) override { + fGpu->copySurface(fTexture, fOrigin, src, srcOrigin, srcRect, dstPoint); + } void insertEventMarker(const char* msg) override {} @@ -63,7 +63,9 @@ public: void inlineUpload(GrOpFlushState* state, GrDeferredTextureUploadFn& upload) override {} void copy(GrSurface* src, GrSurfaceOrigin srcOrigin, const SkIRect& srcRect, - const SkIPoint& dstPoint) override {} + const SkIPoint& dstPoint) override { + fGpu->copySurface(fRenderTarget, fOrigin, src, srcOrigin, srcRect, dstPoint); + } void submit() override {} -- cgit v1.2.3