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
This commit is contained in:
parent
0a0520afcc
commit
083617b9a7
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 &&
|
||||
@ -211,6 +221,11 @@ public:
|
||||
kMixedSamples_MSFBOType != fMSFBOType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user