diff options
author | 2016-02-12 12:10:14 -0800 | |
---|---|---|
committer | 2016-02-12 12:10:14 -0800 | |
commit | 083617b9a7247dd4c52f8dfd195fa34a083e6f1d (patch) | |
tree | 39f3561e6b75b1129d7860ae4a214422e488d87e | |
parent | 0a0520afccb9dcad9db2258c936456e69012fa34 (diff) |
Make copySurface work in more situations.
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1693923002
Review URL: https://codereview.chromium.org/1693923002
-rw-r--r-- | src/gpu/gl/GrGLCaps.cpp | 15 | ||||
-rw-r--r-- | src/gpu/gl/GrGLCaps.h | 21 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.cpp | 79 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.h | 9 |
4 files changed, 101 insertions, 23 deletions
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index c2ace6cd36..79bb22efac 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -54,6 +54,8 @@ GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions, fRGBA8888PixelsOpsAreSlow = false; fPartialFBOReadIsSlow = false; + fBlitFramebufferSupport = kNone_BlitFramebufferSupport; + fShaderCaps.reset(new GrGLSLCaps(contextOptions)); this->init(contextOptions, ctxInfo, glInterface); @@ -766,15 +768,28 @@ void GrGLCaps::initFSAASupport(const GrGLContextInfo& ctxInfo, const GrGLInterfa } else if (ctxInfo.hasExtension("GL_APPLE_framebuffer_multisample")) { fMSFBOType = kES_Apple_MSFBOType; } + + // Above determined the preferred MSAA approach, now decide whether glBlitFramebuffer + // is available. + if (ctxInfo.version() >= GR_GL_VER(3, 0)) { + fBlitFramebufferSupport = kFull_BlitFramebufferSupport; + } else if (ctxInfo.hasExtension("GL_CHROMIUM_framebuffer_multisample")) { + // The CHROMIUM extension uses the ANGLE version of glBlitFramebuffer and includes its + // limitations. + fBlitFramebufferSupport = kNoScalingNoMirroring_BlitFramebufferSupport; + } } else { if (fUsesMixedSamples) { fMSFBOType = kMixedSamples_MSFBOType; + fBlitFramebufferSupport = kFull_BlitFramebufferSupport; } else if ((ctxInfo.version() >= GR_GL_VER(3,0)) || ctxInfo.hasExtension("GL_ARB_framebuffer_object")) { fMSFBOType = GrGLCaps::kDesktop_ARB_MSFBOType; + fBlitFramebufferSupport = kFull_BlitFramebufferSupport; } else if (ctxInfo.hasExtension("GL_EXT_framebuffer_multisample") && ctxInfo.hasExtension("GL_EXT_framebuffer_blit")) { fMSFBOType = GrGLCaps::kDesktop_EXT_MSFBOType; + fBlitFramebufferSupport = kFull_BlitFramebufferSupport; } } } diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h index abfcc285b7..fc29615cb5 100644 --- a/src/gpu/gl/GrGLCaps.h +++ b/src/gpu/gl/GrGLCaps.h @@ -77,10 +77,20 @@ public: kLast_MSFBOType = kMixedSamples_MSFBOType }; + enum BlitFramebufferSupport { + kNone_BlitFramebufferSupport, + /** + * ANGLE exposes a limited blit framebuffer extension that does not allow for stretching + * or mirroring. + */ + kNoScalingNoMirroring_BlitFramebufferSupport, + kFull_BlitFramebufferSupport + }; + enum InvalidateFBType { kNone_InvalidateFBType, kDiscard_InvalidateFBType, //<! glDiscardFramebuffer() - kInvalidate_InvalidateFBType, //<! glInvalidateFramebuffer() + kInvalidate_InvalidateFBType, //<! glInvalidateFramebuffer() kLast_InvalidateFBType = kInvalidate_InvalidateFBType }; @@ -202,7 +212,7 @@ public: MSFBOType msFBOType() const { return fMSFBOType; } /** - * Does the supported MSAA FBO extension have MSAA renderbuffers? + * Does the preferred MSAA FBO extension have MSAA renderbuffers? */ bool usesMSAARenderBuffers() const { return kNone_MSFBOType != fMSFBOType && @@ -212,6 +222,11 @@ public: } /** + * What functionality is supported by glBlitFramebuffer. + */ + BlitFramebufferSupport blitFramebufferSupport() const { return fBlitFramebufferSupport; } + + /** * Is the MSAA FBO extension one where the texture is multisampled when bound to an FBO and * then implicitly resolved when read. */ @@ -403,6 +418,8 @@ private: bool fRectangleTextureSupport : 1; bool fTextureSwizzleSupport : 1; + BlitFramebufferSupport fBlitFramebufferSupport; + /** Number type of the components (with out considering number of bits.) */ enum FormatType { kNormalizedFixedPoint_FormatType, diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index e29a7f81f3..b9a5ee9837 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -2438,7 +2438,7 @@ void GrGLGpu::performFlushWorkaround() { } } -void GrGLGpu::flushRenderTarget(GrGLRenderTarget* target, const SkIRect* bound) { +void GrGLGpu::flushRenderTarget(GrGLRenderTarget* target, const SkIRect* bounds) { SkASSERT(target); uint32_t rtID = target->getUniqueID(); @@ -2459,11 +2459,7 @@ void GrGLGpu::flushRenderTarget(GrGLRenderTarget* target, const SkIRect* bound) } #endif fHWBoundRenderTargetUniqueID = rtID; - const GrGLIRect& vp = target->getViewport(); - if (fHWViewport != vp) { - vp.pushToGLViewport(this->glInterface()); - fHWViewport = vp; - } + this->flushViewport(target->getViewport()); if (this->glCaps().srgbWriteControl()) { bool enableSRGBWrite = GrPixelConfigIsSRGB(target->config()); if (enableSRGBWrite && kYes_TriState != fHWSRGBFramebuffer) { @@ -2475,11 +2471,24 @@ void GrGLGpu::flushRenderTarget(GrGLRenderTarget* target, const SkIRect* bound) } } } + this->didWriteToSurface(target, bounds); +} + +void GrGLGpu::flushViewport(const GrGLIRect& viewport) { + if (fHWViewport != viewport) { + viewport.pushToGLViewport(this->glInterface()); + fHWViewport = viewport; + } +} +void GrGLGpu::didWriteToSurface(GrSurface* surface, const SkIRect* bounds) const { + SkASSERT(surface); // Mark any MIP chain and resolve buffer as dirty if and only if there is a non-empty bounds. - if (nullptr == bound || !bound->isEmpty()) { - target->flagAsNeedingResolve(bound); - if (GrTexture *texture = target->asTexture()) { + if (nullptr == bounds || !bounds->isEmpty()) { + if (GrRenderTarget* target = surface->asRenderTarget()) { + target->flagAsNeedingResolve(bounds); + } + if (GrTexture* texture = surface->asTexture()) { texture->texturePriv().dirtyMipMaps(true); } } @@ -2759,6 +2768,8 @@ void GrGLGpu::flushStencil(const GrStencilSettings& stencilSettings) { } void GrGLGpu::flushHWAAState(GrRenderTarget* rt, bool useHWAA, bool stencilEnabled) { + // rt is only optional if useHWAA is false. + SkASSERT(rt || !useHWAA); SkASSERT(!useHWAA || rt->isStencilBufferMultisampled()); if (this->glCaps().multisampleDisableSupport()) { @@ -3068,8 +3079,19 @@ static inline bool can_blit_framebuffer(const GrSurface* dst, const GrSurface* src, const GrGLGpu* gpu) { if (gpu->glCaps().isConfigRenderable(dst->config(), dst->desc().fSampleCnt > 0) && - gpu->glCaps().isConfigRenderable(src->config(), src->desc().fSampleCnt > 0) && - gpu->glCaps().usesMSAARenderBuffers()) { + gpu->glCaps().isConfigRenderable(src->config(), src->desc().fSampleCnt > 0)) { + switch (gpu->glCaps().blitFramebufferSupport()) { + case GrGLCaps::kNone_BlitFramebufferSupport: + return false; + case GrGLCaps::kNoScalingNoMirroring_BlitFramebufferSupport: + // Our copy surface doesn't support scaling so just check for mirroring. + if (dst->origin() != src->origin()) { + return false; + } + break; + case GrGLCaps::kFull_BlitFramebufferSupport: + break; + } // ES3 doesn't allow framebuffer blits when the src has MSAA and the configs don't match // or the rects are not the same (not just the same size but have the same edges). if (GrGLCaps::kES_3_0_MSFBOType == gpu->glCaps().msFBOType() && @@ -3140,7 +3162,7 @@ static inline bool can_copy_texsubimage(const GrSurface* dst, void GrGLGpu::bindSurfaceFBOForCopy(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport, TempFBOTarget tempFBOTarget) { GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(surface->asRenderTarget()); - if (nullptr == rt) { + if (!rt) { SkASSERT(surface->asTexture()); GrGLuint texID = static_cast<GrGLTexture*>(surface->asTexture())->textureID(); GrGLenum target = static_cast<GrGLTexture*>(surface->asTexture())->target(); @@ -3250,7 +3272,9 @@ bool GrGLGpu::onCopySurface(GrSurface* dst, this->glCaps().glslCaps()->configOutputSwizzle(dst->config())) { return false; } - if (src->asTexture() && dst->asRenderTarget()) { + // Don't prefer copying as a draw if the dst doesn't already have a FBO object. + bool preferCopy = SkToBool(dst->asRenderTarget()); + if (preferCopy && src->asTexture()) { this->copySurfaceAsDraw(dst, src, srcRect, dstPoint); return true; } @@ -3264,6 +3288,11 @@ bool GrGLGpu::onCopySurface(GrSurface* dst, return this->copySurfaceAsBlitFramebuffer(dst, src, srcRect, dstPoint); } + if (!preferCopy && src->asTexture()) { + this->copySurfaceAsDraw(dst, src, srcRect, dstPoint); + return true; + } + return false; } @@ -3560,9 +3589,12 @@ void GrGLGpu::copySurfaceAsDraw(GrSurface* dst, GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode); this->bindTexture(0, params, srcTex); - GrGLRenderTarget* dstRT = static_cast<GrGLRenderTarget*>(dst->asRenderTarget()); + GrGLIRect dstVP; + this->bindSurfaceFBOForCopy(dst, GR_GL_FRAMEBUFFER, &dstVP, kDst_TempFBOTarget); + this->flushViewport(dstVP); + fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; + SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, w, h); - this->flushRenderTarget(dstRT, &dstRect); int progIdx = TextureTargetToCopyProgramIdx(srcTex->target()); @@ -3618,13 +3650,16 @@ void GrGLGpu::copySurfaceAsDraw(GrSurface* dst, this->flushBlend(blendInfo, GrSwizzle::RGBA()); this->flushColorWrite(true); this->flushDrawFace(GrPipelineBuilder::kBoth_DrawFace); - this->flushHWAAState(dstRT, false, false); + this->flushHWAAState(nullptr, false, false); this->disableScissor(); GrStencilSettings stencil; stencil.setDisabled(); this->flushStencil(stencil); GL_CALL(DrawArrays(GR_GL_TRIANGLE_STRIP, 0, 4)); + this->unbindTextureFBOForCopy(GR_GL_FRAMEBUFFER, dst); + this->didWriteToSurface(dst, &dstRect); + } void GrGLGpu::copySurfaceAsCopyTexSubImage(GrSurface* dst, @@ -3634,7 +3669,7 @@ void GrGLGpu::copySurfaceAsCopyTexSubImage(GrSurface* dst, SkASSERT(can_copy_texsubimage(dst, src, this)); GrGLIRect srcVP; this->bindSurfaceFBOForCopy(src, GR_GL_FRAMEBUFFER, &srcVP, kSrc_TempFBOTarget); - GrGLTexture* dstTex = static_cast<GrGLTexture*>(dst->asTexture()); + GrGLTexture* dstTex = static_cast<GrGLTexture *>(dst->asTexture()); SkASSERT(dstTex); // We modified the bound FBO fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; @@ -3655,10 +3690,13 @@ void GrGLGpu::copySurfaceAsCopyTexSubImage(GrSurface* dst, dstY = dstPoint.fY; } GL_CALL(CopyTexSubImage2D(dstTex->target(), 0, - dstPoint.fX, dstY, - srcGLRect.fLeft, srcGLRect.fBottom, - srcGLRect.fWidth, srcGLRect.fHeight)); + dstPoint.fX, dstY, + srcGLRect.fLeft, srcGLRect.fBottom, + srcGLRect.fWidth, srcGLRect.fHeight)); this->unbindTextureFBOForCopy(GR_GL_FRAMEBUFFER, src); + SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, + srcRect.width(), srcRect.height()); + this->didWriteToSurface(dst, &dstRect); } bool GrGLGpu::copySurfaceAsBlitFramebuffer(GrSurface* dst, @@ -3719,6 +3757,7 @@ bool GrGLGpu::copySurfaceAsBlitFramebuffer(GrSurface* dst, GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST)); this->unbindTextureFBOForCopy(GR_GL_DRAW_FRAMEBUFFER, dst); this->unbindTextureFBOForCopy(GR_GL_READ_FRAMEBUFFER, src); + this->didWriteToSurface(dst, &dstRect); return true; } diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h index ce2f95ef30..48645cad53 100644 --- a/src/gpu/gl/GrGLGpu.h +++ b/src/gpu/gl/GrGLGpu.h @@ -317,11 +317,18 @@ private: // ensures that such operations don't negatively interact with tracking bound textures. void setScratchTextureUnit(); - // bounds is region that may be modified and therefore has to be resolved. + // bounds is region that may be modified. // nullptr means whole target. Can be an empty rect. void flushRenderTarget(GrGLRenderTarget*, const SkIRect* bounds); + // Handles cases where a surface will be updated without a call to flushRenderTarget + void didWriteToSurface(GrSurface*, const SkIRect* bounds) const; + + // Need not be called if flushRenderTarget is used. + void flushViewport(const GrGLIRect&); void flushStencil(const GrStencilSettings&); + + // rt is used only if useHWAA is true. void flushHWAAState(GrRenderTarget* rt, bool useHWAA, bool stencilEnabled); // helper for onCreateTexture and writeTexturePixels |