diff --git a/include/gpu/GrCaps.h b/include/gpu/GrCaps.h index 82a4be2c25..0b4c2e7ee5 100644 --- a/include/gpu/GrCaps.h +++ b/include/gpu/GrCaps.h @@ -55,8 +55,6 @@ public: bool usesMixedSamples() const { return fUsesMixedSamples; } bool preferClientSideDynamicBuffers() const { return fPreferClientSideDynamicBuffers; } - bool useDrawInsteadOfClear() const { return fUseDrawInsteadOfClear; } - bool preferVRAMUseOverFlushes() const { return fPreferVRAMUseOverFlushes; } /** @@ -210,7 +208,6 @@ protected: bool fMustClearUploadedBufferData : 1; // Driver workaround - bool fUseDrawInsteadOfClear : 1; bool fAvoidInstancedDrawsToFPTargets : 1; bool fBlacklistCoverageCounting : 1; bool fAvoidStencilBuffers : 1; diff --git a/include/gpu/GrContextOptions.h b/include/gpu/GrContextOptions.h index 61dc8b0457..894813b5cc 100644 --- a/include/gpu/GrContextOptions.h +++ b/include/gpu/GrContextOptions.h @@ -15,6 +15,17 @@ class SkExecutor; struct GrContextOptions { + enum class Enable { + /** Forces an option to be disabled. */ + kNo, + /** Forces an option to be enabled. */ + kYes, + /** + * Uses Skia's default behavior, which may use runtime properties (e.g. driver version). + */ + kDefault + }; + GrContextOptions() {} // Suppress prints for the GrContext. @@ -88,6 +99,12 @@ struct GrContextOptions { */ bool fAvoidStencilBuffers = false; + /** + * Enables driver workaround to use draws instead of glClear. This only applies to + * kOpenGL_GrBackend. + */ + Enable fUseDrawInsteadOfGLClear = Enable::kDefault; + #if GR_TEST_UTILS /** * Private options that are only meant for testing within Skia's tools. diff --git a/src/gpu/GrCaps.cpp b/src/gpu/GrCaps.cpp index f4c7de7304..2e25845876 100644 --- a/src/gpu/GrCaps.cpp +++ b/src/gpu/GrCaps.cpp @@ -54,8 +54,6 @@ GrCaps::GrCaps(const GrContextOptions& options) { fFenceSyncSupport = false; fCrossContextTextureSupport = false; - fUseDrawInsteadOfClear = false; - fInstancedSupport = InstancedSupport::kNone; fBlendEquationSupport = kBasic_BlendEquationSupport; @@ -148,7 +146,6 @@ void GrCaps::dumpJSON(SkJSONWriter* writer) const { writer->appendBool("Fence sync support", fFenceSyncSupport); writer->appendBool("Cross context texture support", fCrossContextTextureSupport); - writer->appendBool("Draw Instead of Clear [workaround]", fUseDrawInsteadOfClear); writer->appendBool("Blacklist Coverage Counting Path Renderer [workaround]", fBlacklistCoverageCounting); writer->appendBool("Prefer VRAM Use over flushes [workaround]", fPreferVRAMUseOverFlushes); diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp index 9a61154d49..0c44ecf20e 100644 --- a/src/gpu/GrRenderTargetContext.cpp +++ b/src/gpu/GrRenderTargetContext.cpp @@ -264,29 +264,14 @@ void GrRenderTargetContextPriv::absClear(const SkIRect* clearRect, const GrColor // TODO: in a post-MDB world this should be handled at the OpList level. // An op-list that is initially cleared and has no other ops should receive an // extra draw. - if (fRenderTargetContext->fContext->caps()->useDrawInsteadOfClear()) { - // This works around a driver bug with clear by drawing a rect instead. - // The driver will ignore a clear if it is the only thing rendered to a - // target before the target is read. - GrPaint paint; - paint.setColor4f(GrColor4f::FromGrColor(color)); - paint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc)); - - // We don't call drawRect() here to avoid the cropping to the, possibly smaller, - // RenderTargetProxy bounds - std::unique_ptr op = GrRectOpFactory::MakeNonAAFill( - std::move(paint), SkMatrix::I(), SkRect::Make(rtRect), GrAAType::kNone); - fRenderTargetContext->addDrawOp(GrNoClip(), std::move(op)); - } else { - // This path doesn't handle coalescing of full screen clears b.c. it - // has to clear the entire render target - not just the content area. - // It could be done but will take more finagling. - std::unique_ptr op(GrClearOp::Make(rtRect, color, !clearRect)); - if (!op) { - return; - } - fRenderTargetContext->getRTOpList()->addOp(std::move(op), *fRenderTargetContext->caps()); + // This path doesn't handle coalescing of full screen clears b.c. it + // has to clear the entire render target - not just the content area. + // It could be done but will take more finagling. + std::unique_ptr op(GrClearOp::Make(rtRect, color, !clearRect)); + if (!op) { + return; } + fRenderTargetContext->getRTOpList()->addOp(std::move(op), *fRenderTargetContext->caps()); } void GrRenderTargetContextPriv::clear(const GrFixedClip& clip, @@ -312,23 +297,7 @@ void GrRenderTargetContext::internalClear(const GrFixedClip& clip, clip.scissorRect().contains(SkIRect::MakeWH(this->width(), this->height())); } - if (fContext->caps()->useDrawInsteadOfClear()) { - // This works around a driver bug with clear by drawing a rect instead. - // The driver will ignore a clear if it is the only thing rendered to a - // target before the target is read. - SkIRect clearRect = SkIRect::MakeWH(this->width(), this->height()); - if (isFull) { - this->discard(); - } else if (!clearRect.intersect(clip.scissorRect())) { - return; - } - - GrPaint paint; - paint.setColor4f(GrColor4f::FromGrColor(color)); - paint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc)); - - this->drawRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), SkRect::Make(clearRect)); - } else if (isFull) { + if (isFull) { this->getRTOpList()->fullClear(*this->caps(), color); } else { std::unique_ptr op(GrClearOp::Make(clip, color, this->asSurfaceProxy())); @@ -498,31 +467,28 @@ void GrRenderTargetContext::drawRect(const GrClip& clip, const SkStrokeRec& stroke = style->strokeRec(); if (stroke.getStyle() == SkStrokeRec::kFill_Style) { - - if (!fContext->caps()->useDrawInsteadOfClear()) { - // Check if this is a full RT draw and can be replaced with a clear. We don't bother - // checking cases where the RT is fully inside a stroke. - SkRect rtRect = fRenderTargetProxy->getBoundsRect(); - // Does the clip contain the entire RT? - if (clip.quickContains(rtRect)) { - SkMatrix invM; - if (!viewMatrix.invert(&invM)) { + // Check if this is a full RT draw and can be replaced with a clear. We don't bother + // checking cases where the RT is fully inside a stroke. + SkRect rtRect = fRenderTargetProxy->getBoundsRect(); + // Does the clip contain the entire RT? + if (clip.quickContains(rtRect)) { + SkMatrix invM; + if (!viewMatrix.invert(&invM)) { + return; + } + // Does the rect bound the RT? + GrQuad quad; + quad.setFromMappedRect(rtRect, invM); + if (rect_contains_inclusive(rect, quad.point(0)) && + rect_contains_inclusive(rect, quad.point(1)) && + rect_contains_inclusive(rect, quad.point(2)) && + rect_contains_inclusive(rect, quad.point(3))) { + // Will it blend? + GrColor clearColor; + if (paint.isConstantBlendedColor(&clearColor)) { + this->clear(nullptr, clearColor, true); return; } - // Does the rect bound the RT? - GrQuad quad; - quad.setFromMappedRect(rtRect, invM); - if (rect_contains_inclusive(rect, quad.point(0)) && - rect_contains_inclusive(rect, quad.point(1)) && - rect_contains_inclusive(rect, quad.point(2)) && - rect_contains_inclusive(rect, quad.point(3))) { - // Will it blend? - GrColor clearColor; - if (paint.isConstantBlendedColor(&clearColor)) { - this->clear(nullptr, clearColor, true); - return; - } - } } } diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index 2bbd72436c..eb2d2c3a3a 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -56,6 +56,7 @@ GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions, fClearToBoundaryValuesIsBroken = false; fClearTextureSupport = false; fDrawArraysBaseVertexIsBroken = false; + fUseDrawToClearColor = false; fUseDrawToClearStencilClip = false; fDisallowTexSubImageForUnormConfigTexturesEverBoundToFBO = false; fUseDrawInsteadOfAllRenderTargetWrites = false; @@ -565,7 +566,7 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, kPowerVRRogue_GrGLRenderer == ctxInfo.renderer() || (kAdreno3xx_GrGLRenderer == ctxInfo.renderer() && ctxInfo.driver() != kChromium_GrGLDriver)) { - fUseDrawInsteadOfClear = true; + fUseDrawToClearColor = true; } #ifdef SK_BUILD_FOR_MAC @@ -574,7 +575,7 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, // crbug.com/773107 - On MacBook Pros, a wide range of Intel GPUs don't always // perform full screen clears. if (kIntel_GrGLVendor == ctxInfo.vendor()) { - fUseDrawInsteadOfClear = true; + fUseDrawToClearColor = true; } #endif @@ -583,7 +584,7 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, // See crbug.com/768134. This is also needed for full clears and was seen on an nVidia K620 // but only for D3D11 ANGLE. if (GrGLANGLEBackend::kD3D11 == ctxInfo.angleBackend()) { - fUseDrawInsteadOfClear = true; + fUseDrawToClearColor = true; } if (kAdreno4xx_GrGLRenderer == ctxInfo.renderer()) { @@ -1389,6 +1390,8 @@ void GrGLCaps::onDumpJSON(SkJSONWriter* writer) const { writer->appendBool("Texture swizzle support", fTextureSwizzleSupport); writer->appendBool("BGRA to RGBA readback conversions are slow", fRGBAToBGRAReadbackConversionsAreSlow); + writer->appendBool("Draw To clear color", fUseDrawToClearColor); + writer->appendBool("Draw To clear stencil clip", fUseDrawToClearStencilClip); writer->appendBool("Intermediate texture for partial updates of unorm textures ever bound to FBOs", fDisallowTexSubImageForUnormConfigTexturesEverBoundToFBO); writer->appendBool("Intermediate texture for all updates of textures bound to FBOs", @@ -2354,6 +2357,11 @@ void GrGLCaps::onApplyOptionsOverrides(const GrContextOptions& options) { if (options.fUseDrawInsteadOfPartialRenderTargetWrite) { fUseDrawInsteadOfAllRenderTargetWrites = true; } + if (GrContextOptions::Enable::kNo == options.fUseDrawInsteadOfGLClear) { + fUseDrawToClearColor = false; + } else if (GrContextOptions::Enable::kYes == options.fUseDrawInsteadOfGLClear) { + fUseDrawToClearColor = true; + } } int GrGLCaps::getSampleCount(int requestedCount, GrPixelConfig config) const { diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h index 5140aeea2f..e9c325313a 100644 --- a/src/gpu/gl/GrGLCaps.h +++ b/src/gpu/gl/GrGLCaps.h @@ -376,6 +376,9 @@ public: // https://bugs.chromium.org/p/skia/issues/detail?id=6650 bool drawArraysBaseVertexIsBroken() const { return fDrawArraysBaseVertexIsBroken; } + // Many drivers have issues with color clears. + bool useDrawToClearColor() const { return fUseDrawToClearColor; } + /// Adreno 4xx devices experience an issue when there are a large number of stencil clip bit /// clears. The minimal repro steps are not precisely known but drawing a rect with a stencil /// op instead of using glClear seems to resolve the issue. @@ -482,6 +485,7 @@ private: bool fClearToBoundaryValuesIsBroken : 1; bool fClearTextureSupport : 1; bool fDrawArraysBaseVertexIsBroken : 1; + bool fUseDrawToClearColor : 1; bool fUseDrawToClearStencilClip : 1; bool fDisallowTexSubImageForUnormConfigTexturesEverBoundToFBO : 1; bool fUseDrawInsteadOfAllRenderTargetWrites : 1; diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index 3d347eca10..de614ba010 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -218,14 +218,6 @@ GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context) , fStencilClearFBOID(0) , fHWMaxUsedBufferTextureUnit(-1) , fHWMinSampleShading(0.0) { - for (size_t i = 0; i < SK_ARRAY_COUNT(fCopyPrograms); ++i) { - fCopyPrograms[i].fProgram = 0; - } - for (size_t i = 0; i < SK_ARRAY_COUNT(fMipmapPrograms); ++i) { - fMipmapPrograms[i].fProgram = 0; - } - fStencilClipClearProgram = 0; - SkASSERT(ctx); fCaps.reset(SkRef(ctx->caps())); @@ -269,19 +261,19 @@ GrGLGpu::~GrGLGpu() { fMipmapProgramArrayBuffer.reset(); fStencilClipClearArrayBuffer.reset(); - if (0 != fHWProgramID) { + if (fHWProgramID) { // detach the current program so there is no confusion on OpenGL's part // that we want it to be deleted GL_CALL(UseProgram(0)); } - if (0 != fTempSrcFBOID) { + if (fTempSrcFBOID) { GL_CALL(DeleteFramebuffers(1, &fTempSrcFBOID)); } - if (0 != fTempDstFBOID) { + if (fTempDstFBOID) { GL_CALL(DeleteFramebuffers(1, &fTempDstFBOID)); } - if (0 != fStencilClearFBOID) { + if (fStencilClearFBOID) { GL_CALL(DeleteFramebuffers(1, &fStencilClearFBOID)); } @@ -297,10 +289,14 @@ GrGLGpu::~GrGLGpu() { } } - if (0 != fStencilClipClearProgram) { + if (fStencilClipClearProgram) { GL_CALL(DeleteProgram(fStencilClipClearProgram)); } + if (fClearColorProgram.fProgram) { + GL_CALL(DeleteProgram(fClearColorProgram.fProgram)); + } + delete fProgramCache; } @@ -332,6 +328,10 @@ void GrGLGpu::disconnect(DisconnectType type) { if (fStencilClipClearProgram) { GL_CALL(DeleteProgram(fStencilClipClearProgram)); } + + if (fClearColorProgram.fProgram) { + GL_CALL(DeleteProgram(fClearColorProgram.fProgram)); + } } else { if (fProgramCache) { fProgramCache->abandon(); @@ -355,6 +355,8 @@ void GrGLGpu::disconnect(DisconnectType type) { } fStencilClipClearProgram = 0; fStencilClipClearArrayBuffer.reset(); + fClearColorProgram.fProgram = 0; + if (this->glCaps().shaderCaps()->pathRenderingSupport()) { this->glPathRendering()->disconnect(type); } @@ -1954,15 +1956,10 @@ void GrGLGpu::disableScissor() { void GrGLGpu::clear(const GrFixedClip& clip, GrColor color, GrRenderTarget* target, GrSurfaceOrigin origin) { - this->handleDirtyContext(); - // parent class should never let us get here with no RT SkASSERT(target); - GrGLRenderTarget* glRT = static_cast(target); - this->flushRenderTarget(glRT, clip.scissorEnabled() ? &clip.scissorRect() : nullptr); - this->flushScissor(clip.scissorState(), glRT->getViewport(), origin); - this->flushWindowRectangles(clip.windowRectsState(), glRT, origin); + this->handleDirtyContext(); GrGLfloat r, g, b, a; static const GrGLfloat scale255 = 1.f / 255.f; @@ -1972,6 +1969,17 @@ void GrGLGpu::clear(const GrFixedClip& clip, GrColor color, g = GrColorUnpackG(color) * scaleRGB; b = GrColorUnpackB(color) * scaleRGB; + if (this->glCaps().useDrawToClearColor()) { + this->clearColorAsDraw(clip, r, g, b, a, target, origin); + return; + } + + GrGLRenderTarget* glRT = static_cast(target); + + this->flushRenderTarget(glRT, clip.scissorEnabled() ? &clip.scissorRect() : nullptr); + this->flushScissor(clip.scissorState(), glRT->getViewport(), origin); + this->flushWindowRectangles(clip.windowRectsState(), glRT, origin); + GL_CALL(ColorMask(GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE)); fHWWriteToColor = kYes_TriState; @@ -3855,6 +3863,123 @@ void GrGLGpu::clearStencilClipAsDraw(const GrFixedClip& clip, bool insideStencil GL_CALL(DrawArrays(GR_GL_TRIANGLE_STRIP, 0, 4)); } +bool GrGLGpu::createClearColorProgram() { + TRACE_EVENT0("skia", TRACE_FUNC); + + if (!fClearProgramArrayBuffer) { + static const GrGLfloat vdata[] = {-1, -1, 1, -1, -1, 1, 1, 1}; + fClearProgramArrayBuffer.reset(GrGLBuffer::Create(this, sizeof(vdata), kVertex_GrBufferType, + kStatic_GrAccessPattern, vdata)); + if (!fClearProgramArrayBuffer) { + return false; + } + } + + SkASSERT(!fClearColorProgram.fProgram); + GL_CALL_RET(fClearColorProgram.fProgram, CreateProgram()); + if (!fClearColorProgram.fProgram) { + return false; + } + + GrShaderVar aVertex("a_vertex", kHalf2_GrSLType, GrShaderVar::kIn_TypeModifier); + const char* version = this->caps()->shaderCaps()->versionDeclString(); + + SkString vshaderTxt(version); + aVertex.appendDecl(this->caps()->shaderCaps(), &vshaderTxt); + vshaderTxt.append(";"); + vshaderTxt.append(R"( + // Clear Color Program VS + void main() { + sk_Position = float4(a_vertex.x, a_vertex.y, 0, 1); + })"); + + GrShaderVar uColor("u_color", kHalf4_GrSLType, GrShaderVar::kUniform_TypeModifier); + SkString fshaderTxt(version); + uColor.appendDecl(this->caps()->shaderCaps(), &fshaderTxt); + fshaderTxt.append(";"); + fshaderTxt.appendf(R"( + // Clear Color Program FS + void main() { + sk_FragColor = u_color; + })"); + + const char* str; + GrGLint length; + + str = vshaderTxt.c_str(); + length = SkToInt(vshaderTxt.size()); + SkSL::Program::Settings settings; + settings.fCaps = this->caps()->shaderCaps(); + SkSL::Program::Inputs inputs; + GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fClearColorProgram.fProgram, + GR_GL_VERTEX_SHADER, &str, &length, 1, &fStats, + settings, &inputs); + SkASSERT(inputs.isEmpty()); + + str = fshaderTxt.c_str(); + length = SkToInt(fshaderTxt.size()); + GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fClearColorProgram.fProgram, + GR_GL_FRAGMENT_SHADER, &str, &length, 1, &fStats, + settings, &inputs); + SkASSERT(inputs.isEmpty()); + + GL_CALL(LinkProgram(fClearColorProgram.fProgram)); + + GL_CALL(BindAttribLocation(fClearColorProgram.fProgram, 0, "a_vertex")); + + GL_CALL_RET(fClearColorProgram.fColorUniform, + GetUniformLocation(fClearColorProgram.fProgram, "u_color")); + + GL_CALL(DeleteShader(vshader)); + GL_CALL(DeleteShader(fshader)); + + return true; +} + +void GrGLGpu::clearColorAsDraw(const GrFixedClip& clip, GrGLfloat r, GrGLfloat g, GrGLfloat b, + GrGLfloat a, GrRenderTarget* dst, GrSurfaceOrigin origin) { + if (!fClearColorProgram.fProgram) { + if (!this->createClearColorProgram()) { + SkDebugf("Failed to create clear color program.\n"); + return; + } + } + + GrGLIRect dstVP; + this->bindSurfaceFBOForPixelOps(dst, GR_GL_FRAMEBUFFER, &dstVP, kDst_TempFBOTarget); + this->flushViewport(dstVP); + fHWBoundRenderTargetUniqueID.makeInvalid(); + + GL_CALL(UseProgram(fClearColorProgram.fProgram)); + fHWProgramID = fClearColorProgram.fProgram; + + fHWVertexArrayState.setVertexArrayID(this, 0); + + GrGLAttribArrayState* attribs = fHWVertexArrayState.bindInternalVertexArray(this); + attribs->enableVertexArrays(this, 1); + attribs->set(this, 0, fClearProgramArrayBuffer.get(), kHalf2_GrVertexAttribType, + 2 * sizeof(GrGLfloat), 0); + + GrGLRenderTarget* glrt = static_cast(dst); + this->flushScissor(clip.scissorState(), glrt->getViewport(), origin); + this->flushWindowRectangles(clip.windowRectsState(), glrt, origin); + + GL_CALL(Uniform4f(fClearColorProgram.fColorUniform, r, g, b, a)); + + GrXferProcessor::BlendInfo blendInfo; + blendInfo.reset(); + this->flushBlend(blendInfo, GrSwizzle::RGBA()); + this->flushColorWrite(true); + this->flushHWAAState(nullptr, false, false); + this->disableStencil(); + if (this->glCaps().srgbWriteControl()) { + this->flushFramebufferSRGB(true); + } + + GL_CALL(DrawArrays(GR_GL_TRIANGLE_STRIP, 0, 4)); + this->unbindTextureFBOForPixelOps(GR_GL_FRAMEBUFFER, dst); + this->didWriteToSurface(dst, &clip.scissorState().rect()); +} bool GrGLGpu::copySurfaceAsDraw(GrSurface* dst, GrSurfaceOrigin dstOrigin, GrSurface* src, GrSurfaceOrigin srcOrigin, diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h index 0fef2afb05..227409edd3 100644 --- a/src/gpu/gl/GrGLGpu.h +++ b/src/gpu/gl/GrGLGpu.h @@ -135,6 +135,8 @@ public: // Thus this is the implementation of the clear call for the corresponding passthrough function // on GrGLGpuRTCommandBuffer. void clear(const GrFixedClip&, GrColor, GrRenderTarget*, GrSurfaceOrigin); + void clearColorAsDraw(const GrFixedClip&, GrGLfloat r, GrGLfloat g, GrGLfloat b, GrGLfloat a, + GrRenderTarget*, GrSurfaceOrigin); // The GrGLGpuRTCommandBuffer does not buffer up draws before submitting them to the gpu. // Thus this is the implementation of the clearStencil call for the corresponding passthrough @@ -420,6 +422,7 @@ private: bool createCopyProgram(GrTexture* srcTexture); bool createMipmapProgram(int progIdx); bool createStencilClipClearProgram(); + bool createClearColorProgram(); // GL program-related state ProgramCache* fProgramCache; @@ -617,24 +620,31 @@ private: /** IDs for copy surface program. (4 sampler types) */ struct { - GrGLuint fProgram; - GrGLint fTextureUniform; - GrGLint fTexCoordXformUniform; - GrGLint fPosXformUniform; + GrGLuint fProgram = 0; + GrGLint fTextureUniform = 0; + GrGLint fTexCoordXformUniform = 0; + GrGLint fPosXformUniform = 0; } fCopyPrograms[4]; sk_sp fCopyProgramArrayBuffer; /** IDs for texture mipmap program. (4 filter configurations) */ struct { - GrGLuint fProgram; - GrGLint fTextureUniform; - GrGLint fTexCoordXformUniform; + GrGLuint fProgram = 0; + GrGLint fTextureUniform = 0; + GrGLint fTexCoordXformUniform = 0; } fMipmapPrograms[4]; sk_sp fMipmapProgramArrayBuffer; - GrGLuint fStencilClipClearProgram; + GrGLuint fStencilClipClearProgram = 0; sk_sp fStencilClipClearArrayBuffer; + /** IDs for clear render target color program. */ + struct { + GrGLuint fProgram = 0; + GrGLint fColorUniform = 0; + } fClearColorProgram; + sk_sp fClearProgramArrayBuffer; + static int TextureToCopyProgramIdx(GrTexture* texture); static int TextureSizeToMipmapProgramIdx(int width, int height) { diff --git a/src/gpu/mtl/GrMtlCaps.mm b/src/gpu/mtl/GrMtlCaps.mm index 4655b6fd1d..d431f0a1e1 100644 --- a/src/gpu/mtl/GrMtlCaps.mm +++ b/src/gpu/mtl/GrMtlCaps.mm @@ -160,7 +160,6 @@ void GrMtlCaps::initGrCaps(const id device) { fUsesMixedSamples = false; fGpuTracingSupport = false; - fUseDrawInsteadOfClear = false; fFenceSyncSupport = true; // always available in Metal fCrossContextTextureSupport = false; diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp index 1b0db7fb23..2b24205af8 100644 --- a/src/gpu/vk/GrVkCaps.cpp +++ b/src/gpu/vk/GrVkCaps.cpp @@ -35,7 +35,6 @@ GrVkCaps::GrVkCaps(const GrContextOptions& contextOptions, const GrVkInterface* fOversizedStencilSupport = false; //TODO: figure this out fInstanceAttribSupport = true; - fUseDrawInsteadOfClear = false; fBlacklistCoverageCounting = true; // blacklisting ccpr until we work through a few issues. fFenceSyncSupport = true; // always available in Vulkan fCrossContextTextureSupport = false; diff --git a/tests/ClearTest.cpp b/tests/ClearTest.cpp index bcd0899867..c1c39dc4ea 100644 --- a/tests/ClearTest.cpp +++ b/tests/ClearTest.cpp @@ -43,8 +43,7 @@ sk_sp newRTC(GrContext* context, int w, int h) { kRGBA_8888_GrPixelConfig, nullptr); } -DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ClearOp, reporter, ctxInfo) { - GrContext* context = ctxInfo.grContext(); +static void clear_op_test(skiatest::Reporter* reporter, GrContext* context) { static const int kW = 10; static const int kH = 10; @@ -202,4 +201,84 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ClearOp, reporter, ctxInfo) { failX, failY); } } + +DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ClearOp, reporter, ctxInfo) { + clear_op_test(reporter, ctxInfo.grContext()); + if (ctxInfo.backend() == kOpenGL_GrBackend) { + GrContextOptions options(ctxInfo.options()); + options.fUseDrawInsteadOfGLClear = GrContextOptions::Enable::kYes; + sk_gpu_test::GrContextFactory workaroundFactory(options); + clear_op_test(reporter, workaroundFactory.get(ctxInfo.type())); + } +} + +#if 0 + +void fullscreen_clear_with_layer_test(skiatest::Reporter* reporter, GrContext* context) { + const SkImageInfo ii = SkImageInfo::Make(400, 77, kRGBA_8888_SkColorType, kPremul_SkAlphaType); + + sk_sp surf = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, ii); + SkCanvas* canvas = surf->getCanvas(); + + SkPaint paints[2]; + paints[0].setColor(SK_ColorGREEN); + paints[1].setColor(SK_ColorGRAY); + + static const int kLeftX = 158; + static const int kMidX = 258; + static const int kRightX = 383; + static const int kTopY = 26; + static const int kBotY = 51; + + const SkRect rects[2] = { + { kLeftX, kTopY, kMidX, kBotY }, + { kMidX, kTopY, kRightX, kBotY }, + }; + + for (int i = 0; i < 2; ++i) { + // the bounds parameter is required to cause a full screen clear + canvas->saveLayer(&rects[i], nullptr); + canvas->drawRect(rects[i], paints[i]); + canvas->restore(); + } + + SkBitmap bm; + bm.allocPixels(ii, 0); + + SkAssertResult(surf->readPixels(bm, 0, 0)); + + bool isCorrect = true; + for (int y = kTopY; isCorrect && y < kBotY; ++y) { + const uint32_t* sl = bm.getAddr32(0, y); + + for (int x = kLeftX; x < kMidX; ++x) { + if (SK_ColorGREEN != sl[x]) { + isCorrect = false; + break; + } + } + + for (int x = kMidX; x < kRightX; ++x) { + if (SK_ColorGRAY != sl[x]) { + isCorrect = false; + break; + } + } + } + + REPORTER_ASSERT(reporter, isCorrect); +} +// From crbug.com/768134 +DEF_GPUTEST_FOR_RENDERING_CONTEXTS(FullScreenClearWithLayers, reporter, ctxInfo) { + fullscreen_clear_with_layer_test(reporter, ctxInfo.grContext()); + if (ctxInfo.backend() == kOpenGL_GrBackend) { + GrContextOptions options(ctxInfo.options()); + options.fUseDrawInsteadOfGLClear = GrContextOptions::Enable::kYes; + sk_gpu_test::GrContextFactory workaroundFactory(options); + fullscreen_clear_with_layer_test(reporter, workaroundFactory.get(ctxInfo.type())); + } +} + +#endif + #endif diff --git a/tests/OnFlushCallbackTest.cpp b/tests/OnFlushCallbackTest.cpp index 52bed86e48..09a7e7628a 100644 --- a/tests/OnFlushCallbackTest.cpp +++ b/tests/OnFlushCallbackTest.cpp @@ -517,11 +517,6 @@ DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) { GrContext* context = ctxInfo.grContext(); - if (context->caps()->useDrawInsteadOfClear()) { - // TODO: fix the buffer issues so this can run on all devices - return; - } - AtlasObject object; // For now (until we add a GrSuperDeferredSimpleTextureEffect), we create the final atlas diff --git a/tools/gpu/GrContextFactory.cpp b/tools/gpu/GrContextFactory.cpp index b3ca1d929e..1bc4655558 100644 --- a/tools/gpu/GrContextFactory.cpp +++ b/tools/gpu/GrContextFactory.cpp @@ -116,7 +116,8 @@ ContextInfo GrContextFactory::getContextInfoInternal(ContextType type, ContextOv context.fShareIndex == shareIndex && !context.fAbandoned) { context.fTestContext->makeCurrent(); - return ContextInfo(context.fType, context.fTestContext, context.fGrContext); + return ContextInfo(context.fType, context.fTestContext, context.fGrContext, + context.fOptions); } } @@ -288,7 +289,8 @@ ContextInfo GrContextFactory::getContextInfoInternal(ContextType type, ContextOv context.fAbandoned = false; context.fShareContext = shareContext; context.fShareIndex = shareIndex; - return ContextInfo(context.fType, context.fTestContext, context.fGrContext); + context.fOptions = grOptions; + return ContextInfo(context.fType, context.fTestContext, context.fGrContext, context.fOptions); } ContextInfo GrContextFactory::getContextInfo(ContextType type, ContextOverrides overrides) { diff --git a/tools/gpu/GrContextFactory.h b/tools/gpu/GrContextFactory.h index 8d3e69c765..1073f6a594 100644 --- a/tools/gpu/GrContextFactory.h +++ b/tools/gpu/GrContextFactory.h @@ -159,6 +159,7 @@ private: struct Context { ContextType fType; ContextOverrides fOverrides; + GrContextOptions fOptions; GrBackend fBackend; TestContext* fTestContext; GrContext* fGrContext; @@ -189,19 +190,18 @@ public: return static_cast(fTestContext); } + const GrContextOptions& options() const { return fOptions; } + private: - ContextInfo(GrContextFactory::ContextType type, - TestContext* testContext, - GrContext* grContext) - : fType(type) - , fTestContext(testContext) - , fGrContext(grContext) { - } + ContextInfo(GrContextFactory::ContextType type, TestContext* testContext, GrContext* grContext, + const GrContextOptions& options) + : fType(type), fTestContext(testContext), fGrContext(grContext), fOptions(options) {} GrContextFactory::ContextType fType = GrContextFactory::kGL_ContextType; // Valid until the factory destroys it via abandonContexts() or destroyContexts(). - TestContext* fTestContext = nullptr; - GrContext* fGrContext = nullptr; + TestContext* fTestContext = nullptr; + GrContext* fGrContext = nullptr; + GrContextOptions fOptions; friend class GrContextFactory; };