diff --git a/infra/bots/recipes/test.expected/Test-Mac-Clang-MacBookPro11.5-GPU-RadeonHD8870M-x86_64-Debug-All-Metal.json b/infra/bots/recipes/test.expected/Test-Mac-Clang-MacBookPro11.5-GPU-RadeonHD8870M-x86_64-Debug-All-Metal.json index 324d266007..02c2e355fd 100644 --- a/infra/bots/recipes/test.expected/Test-Mac-Clang-MacBookPro11.5-GPU-RadeonHD8870M-x86_64-Debug-All-Metal.json +++ b/infra/bots/recipes/test.expected/Test-Mac-Clang-MacBookPro11.5-GPU-RadeonHD8870M-x86_64-Debug-All-Metal.json @@ -477,6 +477,8 @@ "_", ".SRW", "--match", + "CopySurface", + "GrTestingBackendTextureUploadTest", "GrUploadPixelsTests", "--nonativeFonts", "--verbose" diff --git a/infra/bots/recipes/test.py b/infra/bots/recipes/test.py index b1dfee5ce1..3740e37011 100644 --- a/infra/bots/recipes/test.py +++ b/infra/bots/recipes/test.py @@ -817,7 +817,10 @@ def dm_flags(api, bot): if 'Metal' in bot: # If we modify the whitelist to include GMs, also update infra/bots/cfg.json # to remove Metal from no_upload. - match = ['GrUploadPixelsTests'] + match = [] + match.append('CopySurface') + match.append('GrTestingBackendTextureUploadTest') + match.append('GrUploadPixelsTests') if match: args.append('--match') diff --git a/src/gpu/mtl/GrMtlCaps.h b/src/gpu/mtl/GrMtlCaps.h index 11eb322442..eaced6f649 100644 --- a/src/gpu/mtl/GrMtlCaps.h +++ b/src/gpu/mtl/GrMtlCaps.h @@ -54,6 +54,9 @@ public: bool canCopyAsDraw(GrPixelConfig dstConfig, bool dstIsRenderable, GrPixelConfig srcConfig, bool srcIsTextureable) const; + bool canCopyAsDrawThenBlit(GrPixelConfig dstConfig, GrPixelConfig srcConfig, + bool srcIsTextureable) const; + bool canCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src, const SkIRect& srcRect, const SkIPoint& dstPoint) const override; diff --git a/src/gpu/mtl/GrMtlCaps.mm b/src/gpu/mtl/GrMtlCaps.mm index dc70d28e2a..dc7de6186d 100644 --- a/src/gpu/mtl/GrMtlCaps.mm +++ b/src/gpu/mtl/GrMtlCaps.mm @@ -143,6 +143,19 @@ bool GrMtlCaps::canCopyAsDraw(GrPixelConfig dstConfig, bool dstIsRenderable, return true; } +bool GrMtlCaps::canCopyAsDrawThenBlit(GrPixelConfig dstConfig, GrPixelConfig srcConfig, + bool srcIsTextureable) const { + // TODO: Make copySurfaceAsDraw handle the swizzle + if (this->shaderCaps()->configOutputSwizzle(srcConfig) != + this->shaderCaps()->configOutputSwizzle(dstConfig)) { + return false; + } + if (!srcIsTextureable) { + return false; + } + return true; +} + bool GrMtlCaps::canCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src, const SkIRect& srcRect, const SkIPoint& dstPoint) const { GrSurfaceOrigin dstOrigin = dst->origin(); @@ -163,7 +176,9 @@ bool GrMtlCaps::canCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src->config(), srcSampleCnt, srcOrigin, srcRect, dstPoint, dst == src) || this->canCopyAsDraw(dst->config(), SkToBool(dst->asRenderTargetProxy()), - src->config(), SkToBool(src->asTextureProxy())); + src->config(), SkToBool(src->asTextureProxy())) || + this->canCopyAsDrawThenBlit(dst->config(), src->config(), + SkToBool(src->asTextureProxy())); } void GrMtlCaps::initGrCaps(const id device) { diff --git a/src/gpu/mtl/GrMtlGpu.h b/src/gpu/mtl/GrMtlGpu.h index 4ba07205e4..243eaa061e 100644 --- a/src/gpu/mtl/GrMtlGpu.h +++ b/src/gpu/mtl/GrMtlGpu.h @@ -68,6 +68,13 @@ public: GrSurface* src, GrSurfaceOrigin srcOrigin, const SkIRect& srcRect, const SkIPoint& dstPoint); + // This function is needed when we want to copy between two surfaces with different origins and + // the destination surface is not a render target. We will first draw to a temporary render + // target to adjust for the different origins and then blit from there to the destination. + bool copySurfaceAsDrawThenBlit(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, diff --git a/src/gpu/mtl/GrMtlGpu.mm b/src/gpu/mtl/GrMtlGpu.mm index 2c47c3c7aa..037f1752d5 100644 --- a/src/gpu/mtl/GrMtlGpu.mm +++ b/src/gpu/mtl/GrMtlGpu.mm @@ -591,6 +591,71 @@ bool GrMtlGpu::copySurfaceAsBlit(GrSurface* dst, GrSurfaceOrigin dstOrigin, return true; } +bool GrMtlGpu::copySurfaceAsDrawThenBlit(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(dstSampleCnt == 0); // dst shouldn't be a render target + SkASSERT(!this->mtlCaps().canCopyAsBlit(dst->config(), dstSampleCnt, dstOrigin, + src->config(), srcSampleCnt, srcOrigin, + srcRect, dstPoint, dst == src)); + SkASSERT(!this->mtlCaps().canCopyAsDraw(dst->config(), SkToBool(dst->asRenderTarget()), + src->config(), SkToBool(src->asTexture()))); + SkASSERT(this->mtlCaps().canCopyAsDrawThenBlit(dst->config(),src->config(), + SkToBool(src->asTexture()))); +#endif + GrSurfaceDesc surfDesc; + surfDesc.fFlags = kRenderTarget_GrSurfaceFlag; + surfDesc.fWidth = srcRect.width(); + surfDesc.fHeight = srcRect.height(); + surfDesc.fConfig = dst->config(); + surfDesc.fSampleCnt = 1; + + id dstTex = GrGetMTLTextureFromSurface(dst, false); + MTLTextureDescriptor* textureDesc = GrGetMTLTextureDescriptor(dstTex); + textureDesc.width = srcRect.width(); + textureDesc.height = srcRect.height(); + textureDesc.mipmapLevelCount = 1; + textureDesc.usage |= MTLTextureUsageRenderTarget; + + sk_sp transferTexture = + GrMtlTextureRenderTarget::CreateNewTextureRenderTarget(this, + SkBudgeted::kYes, + surfDesc, + textureDesc, + GrMipMapsStatus::kNotAllocated); + + GrSurfaceOrigin transferOrigin = dstOrigin; + SkASSERT(this->mtlCaps().canCopyAsDraw(transferTexture->config(), + SkToBool(transferTexture->asRenderTarget()), + src->config(), + SkToBool(src->asTexture()))); + // TODO: Eventually we will need to handle resolves either in this function or make a separate + // copySurfaceAsResolveThenBlit(). + if (!this->copySurface(transferTexture.get(), transferOrigin, + src, srcOrigin, + srcRect, SkIPoint::Make(0, 0))) { + return false; + } + + SkIRect transferRect = SkIRect::MakeXYWH(0, 0, srcRect.width(), srcRect.height()); + SkASSERT(this->mtlCaps().canCopyAsBlit(dst->config(), + get_surface_sample_cnt(dst), + dstOrigin, + transferTexture->config(), + get_surface_sample_cnt(transferTexture.get()), + transferOrigin, + transferRect, dstPoint, false)); + if (!this->copySurface(dst, dstOrigin, + transferTexture.get(), transferOrigin, + transferRect, dstPoint)) { + return false; + } + return true; +} + bool GrMtlGpu::onCopySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin, GrSurface* src, GrSurfaceOrigin srcOrigin, const SkIRect& srcRect, @@ -604,7 +669,7 @@ bool GrMtlGpu::onCopySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin, int srcSampleCnt = get_surface_sample_cnt(src); if (dstSampleCnt > 1 || srcSampleCnt > 1) { - SkASSERT(false); // Currently dont support MSAA + SkASSERT(false); // Currently dont support MSAA. TODO: add copySurfaceAsResolve(). return false; } @@ -617,6 +682,10 @@ bool GrMtlGpu::onCopySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin, srcConfig, srcSampleCnt, srcOrigin, srcRect, dstPoint, dst == src)) { success = this->copySurfaceAsBlit(dst, dstOrigin, src, srcOrigin, srcRect, dstPoint); + } else if (this->mtlCaps().canCopyAsDrawThenBlit(dst->config(), src->config(), + SkToBool(src->asTexture()))) { + success = this->copySurfaceAsDrawThenBlit(dst, dstOrigin, src, srcOrigin, + srcRect, dstPoint); } if (success) { SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.x(), dstPoint.y(),