Move clear-as-draw workaround to GrGLGpu and expose via GrContextOptions.

Bug: skia:7154
Change-Id: I23ffc11dab4a377fbd6b7e4e33722b3fa0793d58
Reviewed-on: https://skia-review.googlesource.com/60681
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Brian Salomon 2017-10-18 08:33:29 -04:00 committed by Skia Commit-Bot
parent 57caa660c0
commit 43f8bf0f78
14 changed files with 316 additions and 118 deletions

View File

@ -55,8 +55,6 @@ public:
bool usesMixedSamples() const { return fUsesMixedSamples; } bool usesMixedSamples() const { return fUsesMixedSamples; }
bool preferClientSideDynamicBuffers() const { return fPreferClientSideDynamicBuffers; } bool preferClientSideDynamicBuffers() const { return fPreferClientSideDynamicBuffers; }
bool useDrawInsteadOfClear() const { return fUseDrawInsteadOfClear; }
bool preferVRAMUseOverFlushes() const { return fPreferVRAMUseOverFlushes; } bool preferVRAMUseOverFlushes() const { return fPreferVRAMUseOverFlushes; }
/** /**
@ -210,7 +208,6 @@ protected:
bool fMustClearUploadedBufferData : 1; bool fMustClearUploadedBufferData : 1;
// Driver workaround // Driver workaround
bool fUseDrawInsteadOfClear : 1;
bool fAvoidInstancedDrawsToFPTargets : 1; bool fAvoidInstancedDrawsToFPTargets : 1;
bool fBlacklistCoverageCounting : 1; bool fBlacklistCoverageCounting : 1;
bool fAvoidStencilBuffers : 1; bool fAvoidStencilBuffers : 1;

View File

@ -15,6 +15,17 @@
class SkExecutor; class SkExecutor;
struct GrContextOptions { 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() {} GrContextOptions() {}
// Suppress prints for the GrContext. // Suppress prints for the GrContext.
@ -88,6 +99,12 @@ struct GrContextOptions {
*/ */
bool fAvoidStencilBuffers = false; 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 #if GR_TEST_UTILS
/** /**
* Private options that are only meant for testing within Skia's tools. * Private options that are only meant for testing within Skia's tools.

View File

@ -54,8 +54,6 @@ GrCaps::GrCaps(const GrContextOptions& options) {
fFenceSyncSupport = false; fFenceSyncSupport = false;
fCrossContextTextureSupport = false; fCrossContextTextureSupport = false;
fUseDrawInsteadOfClear = false;
fInstancedSupport = InstancedSupport::kNone; fInstancedSupport = InstancedSupport::kNone;
fBlendEquationSupport = kBasic_BlendEquationSupport; fBlendEquationSupport = kBasic_BlendEquationSupport;
@ -148,7 +146,6 @@ void GrCaps::dumpJSON(SkJSONWriter* writer) const {
writer->appendBool("Fence sync support", fFenceSyncSupport); writer->appendBool("Fence sync support", fFenceSyncSupport);
writer->appendBool("Cross context texture support", fCrossContextTextureSupport); writer->appendBool("Cross context texture support", fCrossContextTextureSupport);
writer->appendBool("Draw Instead of Clear [workaround]", fUseDrawInsteadOfClear);
writer->appendBool("Blacklist Coverage Counting Path Renderer [workaround]", writer->appendBool("Blacklist Coverage Counting Path Renderer [workaround]",
fBlacklistCoverageCounting); fBlacklistCoverageCounting);
writer->appendBool("Prefer VRAM Use over flushes [workaround]", fPreferVRAMUseOverFlushes); writer->appendBool("Prefer VRAM Use over flushes [workaround]", fPreferVRAMUseOverFlushes);

View File

@ -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. // 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 // An op-list that is initially cleared and has no other ops should receive an
// extra draw. // extra draw.
if (fRenderTargetContext->fContext->caps()->useDrawInsteadOfClear()) { // This path doesn't handle coalescing of full screen clears b.c. it
// This works around a driver bug with clear by drawing a rect instead. // has to clear the entire render target - not just the content area.
// The driver will ignore a clear if it is the only thing rendered to a // It could be done but will take more finagling.
// target before the target is read. std::unique_ptr<GrOp> op(GrClearOp::Make(rtRect, color, !clearRect));
GrPaint paint; if (!op) {
paint.setColor4f(GrColor4f::FromGrColor(color)); return;
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<GrDrawOp> 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<GrOp> op(GrClearOp::Make(rtRect, color, !clearRect));
if (!op) {
return;
}
fRenderTargetContext->getRTOpList()->addOp(std::move(op), *fRenderTargetContext->caps());
} }
fRenderTargetContext->getRTOpList()->addOp(std::move(op), *fRenderTargetContext->caps());
} }
void GrRenderTargetContextPriv::clear(const GrFixedClip& clip, 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())); clip.scissorRect().contains(SkIRect::MakeWH(this->width(), this->height()));
} }
if (fContext->caps()->useDrawInsteadOfClear()) { if (isFull) {
// 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) {
this->getRTOpList()->fullClear(*this->caps(), color); this->getRTOpList()->fullClear(*this->caps(), color);
} else { } else {
std::unique_ptr<GrOp> op(GrClearOp::Make(clip, color, this->asSurfaceProxy())); std::unique_ptr<GrOp> op(GrClearOp::Make(clip, color, this->asSurfaceProxy()));
@ -498,31 +467,28 @@ void GrRenderTargetContext::drawRect(const GrClip& clip,
const SkStrokeRec& stroke = style->strokeRec(); const SkStrokeRec& stroke = style->strokeRec();
if (stroke.getStyle() == SkStrokeRec::kFill_Style) { if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
// Check if this is a full RT draw and can be replaced with a clear. We don't bother
if (!fContext->caps()->useDrawInsteadOfClear()) { // checking cases where the RT is fully inside a stroke.
// Check if this is a full RT draw and can be replaced with a clear. We don't bother SkRect rtRect = fRenderTargetProxy->getBoundsRect();
// checking cases where the RT is fully inside a stroke. // Does the clip contain the entire RT?
SkRect rtRect = fRenderTargetProxy->getBoundsRect(); if (clip.quickContains(rtRect)) {
// Does the clip contain the entire RT? SkMatrix invM;
if (clip.quickContains(rtRect)) { if (!viewMatrix.invert(&invM)) {
SkMatrix invM; return;
if (!viewMatrix.invert(&invM)) { }
// 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; 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;
}
}
} }
} }

View File

@ -56,6 +56,7 @@ GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions,
fClearToBoundaryValuesIsBroken = false; fClearToBoundaryValuesIsBroken = false;
fClearTextureSupport = false; fClearTextureSupport = false;
fDrawArraysBaseVertexIsBroken = false; fDrawArraysBaseVertexIsBroken = false;
fUseDrawToClearColor = false;
fUseDrawToClearStencilClip = false; fUseDrawToClearStencilClip = false;
fDisallowTexSubImageForUnormConfigTexturesEverBoundToFBO = false; fDisallowTexSubImageForUnormConfigTexturesEverBoundToFBO = false;
fUseDrawInsteadOfAllRenderTargetWrites = false; fUseDrawInsteadOfAllRenderTargetWrites = false;
@ -565,7 +566,7 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
kPowerVRRogue_GrGLRenderer == ctxInfo.renderer() || kPowerVRRogue_GrGLRenderer == ctxInfo.renderer() ||
(kAdreno3xx_GrGLRenderer == ctxInfo.renderer() && (kAdreno3xx_GrGLRenderer == ctxInfo.renderer() &&
ctxInfo.driver() != kChromium_GrGLDriver)) { ctxInfo.driver() != kChromium_GrGLDriver)) {
fUseDrawInsteadOfClear = true; fUseDrawToClearColor = true;
} }
#ifdef SK_BUILD_FOR_MAC #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 // crbug.com/773107 - On MacBook Pros, a wide range of Intel GPUs don't always
// perform full screen clears. // perform full screen clears.
if (kIntel_GrGLVendor == ctxInfo.vendor()) { if (kIntel_GrGLVendor == ctxInfo.vendor()) {
fUseDrawInsteadOfClear = true; fUseDrawToClearColor = true;
} }
#endif #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 // See crbug.com/768134. This is also needed for full clears and was seen on an nVidia K620
// but only for D3D11 ANGLE. // but only for D3D11 ANGLE.
if (GrGLANGLEBackend::kD3D11 == ctxInfo.angleBackend()) { if (GrGLANGLEBackend::kD3D11 == ctxInfo.angleBackend()) {
fUseDrawInsteadOfClear = true; fUseDrawToClearColor = true;
} }
if (kAdreno4xx_GrGLRenderer == ctxInfo.renderer()) { if (kAdreno4xx_GrGLRenderer == ctxInfo.renderer()) {
@ -1389,6 +1390,8 @@ void GrGLCaps::onDumpJSON(SkJSONWriter* writer) const {
writer->appendBool("Texture swizzle support", fTextureSwizzleSupport); writer->appendBool("Texture swizzle support", fTextureSwizzleSupport);
writer->appendBool("BGRA to RGBA readback conversions are slow", writer->appendBool("BGRA to RGBA readback conversions are slow",
fRGBAToBGRAReadbackConversionsAreSlow); 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", writer->appendBool("Intermediate texture for partial updates of unorm textures ever bound to FBOs",
fDisallowTexSubImageForUnormConfigTexturesEverBoundToFBO); fDisallowTexSubImageForUnormConfigTexturesEverBoundToFBO);
writer->appendBool("Intermediate texture for all updates of textures bound to FBOs", 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) { if (options.fUseDrawInsteadOfPartialRenderTargetWrite) {
fUseDrawInsteadOfAllRenderTargetWrites = true; 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 { int GrGLCaps::getSampleCount(int requestedCount, GrPixelConfig config) const {

View File

@ -376,6 +376,9 @@ public:
// https://bugs.chromium.org/p/skia/issues/detail?id=6650 // https://bugs.chromium.org/p/skia/issues/detail?id=6650
bool drawArraysBaseVertexIsBroken() const { return fDrawArraysBaseVertexIsBroken; } 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 /// 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 /// 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. /// op instead of using glClear seems to resolve the issue.
@ -482,6 +485,7 @@ private:
bool fClearToBoundaryValuesIsBroken : 1; bool fClearToBoundaryValuesIsBroken : 1;
bool fClearTextureSupport : 1; bool fClearTextureSupport : 1;
bool fDrawArraysBaseVertexIsBroken : 1; bool fDrawArraysBaseVertexIsBroken : 1;
bool fUseDrawToClearColor : 1;
bool fUseDrawToClearStencilClip : 1; bool fUseDrawToClearStencilClip : 1;
bool fDisallowTexSubImageForUnormConfigTexturesEverBoundToFBO : 1; bool fDisallowTexSubImageForUnormConfigTexturesEverBoundToFBO : 1;
bool fUseDrawInsteadOfAllRenderTargetWrites : 1; bool fUseDrawInsteadOfAllRenderTargetWrites : 1;

View File

@ -218,14 +218,6 @@ GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context)
, fStencilClearFBOID(0) , fStencilClearFBOID(0)
, fHWMaxUsedBufferTextureUnit(-1) , fHWMaxUsedBufferTextureUnit(-1)
, fHWMinSampleShading(0.0) { , 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); SkASSERT(ctx);
fCaps.reset(SkRef(ctx->caps())); fCaps.reset(SkRef(ctx->caps()));
@ -269,19 +261,19 @@ GrGLGpu::~GrGLGpu() {
fMipmapProgramArrayBuffer.reset(); fMipmapProgramArrayBuffer.reset();
fStencilClipClearArrayBuffer.reset(); fStencilClipClearArrayBuffer.reset();
if (0 != fHWProgramID) { if (fHWProgramID) {
// detach the current program so there is no confusion on OpenGL's part // detach the current program so there is no confusion on OpenGL's part
// that we want it to be deleted // that we want it to be deleted
GL_CALL(UseProgram(0)); GL_CALL(UseProgram(0));
} }
if (0 != fTempSrcFBOID) { if (fTempSrcFBOID) {
GL_CALL(DeleteFramebuffers(1, &fTempSrcFBOID)); GL_CALL(DeleteFramebuffers(1, &fTempSrcFBOID));
} }
if (0 != fTempDstFBOID) { if (fTempDstFBOID) {
GL_CALL(DeleteFramebuffers(1, &fTempDstFBOID)); GL_CALL(DeleteFramebuffers(1, &fTempDstFBOID));
} }
if (0 != fStencilClearFBOID) { if (fStencilClearFBOID) {
GL_CALL(DeleteFramebuffers(1, &fStencilClearFBOID)); GL_CALL(DeleteFramebuffers(1, &fStencilClearFBOID));
} }
@ -297,10 +289,14 @@ GrGLGpu::~GrGLGpu() {
} }
} }
if (0 != fStencilClipClearProgram) { if (fStencilClipClearProgram) {
GL_CALL(DeleteProgram(fStencilClipClearProgram)); GL_CALL(DeleteProgram(fStencilClipClearProgram));
} }
if (fClearColorProgram.fProgram) {
GL_CALL(DeleteProgram(fClearColorProgram.fProgram));
}
delete fProgramCache; delete fProgramCache;
} }
@ -332,6 +328,10 @@ void GrGLGpu::disconnect(DisconnectType type) {
if (fStencilClipClearProgram) { if (fStencilClipClearProgram) {
GL_CALL(DeleteProgram(fStencilClipClearProgram)); GL_CALL(DeleteProgram(fStencilClipClearProgram));
} }
if (fClearColorProgram.fProgram) {
GL_CALL(DeleteProgram(fClearColorProgram.fProgram));
}
} else { } else {
if (fProgramCache) { if (fProgramCache) {
fProgramCache->abandon(); fProgramCache->abandon();
@ -355,6 +355,8 @@ void GrGLGpu::disconnect(DisconnectType type) {
} }
fStencilClipClearProgram = 0; fStencilClipClearProgram = 0;
fStencilClipClearArrayBuffer.reset(); fStencilClipClearArrayBuffer.reset();
fClearColorProgram.fProgram = 0;
if (this->glCaps().shaderCaps()->pathRenderingSupport()) { if (this->glCaps().shaderCaps()->pathRenderingSupport()) {
this->glPathRendering()->disconnect(type); this->glPathRendering()->disconnect(type);
} }
@ -1954,15 +1956,10 @@ void GrGLGpu::disableScissor() {
void GrGLGpu::clear(const GrFixedClip& clip, GrColor color, void GrGLGpu::clear(const GrFixedClip& clip, GrColor color,
GrRenderTarget* target, GrSurfaceOrigin origin) { GrRenderTarget* target, GrSurfaceOrigin origin) {
this->handleDirtyContext();
// parent class should never let us get here with no RT // parent class should never let us get here with no RT
SkASSERT(target); SkASSERT(target);
GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(target);
this->flushRenderTarget(glRT, clip.scissorEnabled() ? &clip.scissorRect() : nullptr); this->handleDirtyContext();
this->flushScissor(clip.scissorState(), glRT->getViewport(), origin);
this->flushWindowRectangles(clip.windowRectsState(), glRT, origin);
GrGLfloat r, g, b, a; GrGLfloat r, g, b, a;
static const GrGLfloat scale255 = 1.f / 255.f; static const GrGLfloat scale255 = 1.f / 255.f;
@ -1972,6 +1969,17 @@ void GrGLGpu::clear(const GrFixedClip& clip, GrColor color,
g = GrColorUnpackG(color) * scaleRGB; g = GrColorUnpackG(color) * scaleRGB;
b = GrColorUnpackB(color) * scaleRGB; b = GrColorUnpackB(color) * scaleRGB;
if (this->glCaps().useDrawToClearColor()) {
this->clearColorAsDraw(clip, r, g, b, a, target, origin);
return;
}
GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(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)); GL_CALL(ColorMask(GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE));
fHWWriteToColor = kYes_TriState; fHWWriteToColor = kYes_TriState;
@ -3855,6 +3863,123 @@ void GrGLGpu::clearStencilClipAsDraw(const GrFixedClip& clip, bool insideStencil
GL_CALL(DrawArrays(GR_GL_TRIANGLE_STRIP, 0, 4)); 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<GrGLRenderTarget*>(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, bool GrGLGpu::copySurfaceAsDraw(GrSurface* dst, GrSurfaceOrigin dstOrigin,
GrSurface* src, GrSurfaceOrigin srcOrigin, GrSurface* src, GrSurfaceOrigin srcOrigin,

View File

@ -135,6 +135,8 @@ public:
// Thus this is the implementation of the clear call for the corresponding passthrough function // Thus this is the implementation of the clear call for the corresponding passthrough function
// on GrGLGpuRTCommandBuffer. // on GrGLGpuRTCommandBuffer.
void clear(const GrFixedClip&, GrColor, GrRenderTarget*, GrSurfaceOrigin); 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. // 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 // Thus this is the implementation of the clearStencil call for the corresponding passthrough
@ -420,6 +422,7 @@ private:
bool createCopyProgram(GrTexture* srcTexture); bool createCopyProgram(GrTexture* srcTexture);
bool createMipmapProgram(int progIdx); bool createMipmapProgram(int progIdx);
bool createStencilClipClearProgram(); bool createStencilClipClearProgram();
bool createClearColorProgram();
// GL program-related state // GL program-related state
ProgramCache* fProgramCache; ProgramCache* fProgramCache;
@ -617,24 +620,31 @@ private:
/** IDs for copy surface program. (4 sampler types) */ /** IDs for copy surface program. (4 sampler types) */
struct { struct {
GrGLuint fProgram; GrGLuint fProgram = 0;
GrGLint fTextureUniform; GrGLint fTextureUniform = 0;
GrGLint fTexCoordXformUniform; GrGLint fTexCoordXformUniform = 0;
GrGLint fPosXformUniform; GrGLint fPosXformUniform = 0;
} fCopyPrograms[4]; } fCopyPrograms[4];
sk_sp<GrGLBuffer> fCopyProgramArrayBuffer; sk_sp<GrGLBuffer> fCopyProgramArrayBuffer;
/** IDs for texture mipmap program. (4 filter configurations) */ /** IDs for texture mipmap program. (4 filter configurations) */
struct { struct {
GrGLuint fProgram; GrGLuint fProgram = 0;
GrGLint fTextureUniform; GrGLint fTextureUniform = 0;
GrGLint fTexCoordXformUniform; GrGLint fTexCoordXformUniform = 0;
} fMipmapPrograms[4]; } fMipmapPrograms[4];
sk_sp<GrGLBuffer> fMipmapProgramArrayBuffer; sk_sp<GrGLBuffer> fMipmapProgramArrayBuffer;
GrGLuint fStencilClipClearProgram; GrGLuint fStencilClipClearProgram = 0;
sk_sp<GrGLBuffer> fStencilClipClearArrayBuffer; sk_sp<GrGLBuffer> fStencilClipClearArrayBuffer;
/** IDs for clear render target color program. */
struct {
GrGLuint fProgram = 0;
GrGLint fColorUniform = 0;
} fClearColorProgram;
sk_sp<GrGLBuffer> fClearProgramArrayBuffer;
static int TextureToCopyProgramIdx(GrTexture* texture); static int TextureToCopyProgramIdx(GrTexture* texture);
static int TextureSizeToMipmapProgramIdx(int width, int height) { static int TextureSizeToMipmapProgramIdx(int width, int height) {

View File

@ -160,7 +160,6 @@ void GrMtlCaps::initGrCaps(const id<MTLDevice> device) {
fUsesMixedSamples = false; fUsesMixedSamples = false;
fGpuTracingSupport = false; fGpuTracingSupport = false;
fUseDrawInsteadOfClear = false;
fFenceSyncSupport = true; // always available in Metal fFenceSyncSupport = true; // always available in Metal
fCrossContextTextureSupport = false; fCrossContextTextureSupport = false;

View File

@ -35,7 +35,6 @@ GrVkCaps::GrVkCaps(const GrContextOptions& contextOptions, const GrVkInterface*
fOversizedStencilSupport = false; //TODO: figure this out fOversizedStencilSupport = false; //TODO: figure this out
fInstanceAttribSupport = true; fInstanceAttribSupport = true;
fUseDrawInsteadOfClear = false;
fBlacklistCoverageCounting = true; // blacklisting ccpr until we work through a few issues. fBlacklistCoverageCounting = true; // blacklisting ccpr until we work through a few issues.
fFenceSyncSupport = true; // always available in Vulkan fFenceSyncSupport = true; // always available in Vulkan
fCrossContextTextureSupport = false; fCrossContextTextureSupport = false;

View File

@ -43,8 +43,7 @@ sk_sp<GrRenderTargetContext> newRTC(GrContext* context, int w, int h) {
kRGBA_8888_GrPixelConfig, nullptr); kRGBA_8888_GrPixelConfig, nullptr);
} }
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ClearOp, reporter, ctxInfo) { static void clear_op_test(skiatest::Reporter* reporter, GrContext* context) {
GrContext* context = ctxInfo.grContext();
static const int kW = 10; static const int kW = 10;
static const int kH = 10; static const int kH = 10;
@ -202,4 +201,84 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ClearOp, reporter, ctxInfo) {
failX, failY); 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<SkSurface> 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 #endif

View File

@ -517,11 +517,6 @@ DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) {
GrContext* context = ctxInfo.grContext(); GrContext* context = ctxInfo.grContext();
if (context->caps()->useDrawInsteadOfClear()) {
// TODO: fix the buffer issues so this can run on all devices
return;
}
AtlasObject object; AtlasObject object;
// For now (until we add a GrSuperDeferredSimpleTextureEffect), we create the final atlas // For now (until we add a GrSuperDeferredSimpleTextureEffect), we create the final atlas

View File

@ -116,7 +116,8 @@ ContextInfo GrContextFactory::getContextInfoInternal(ContextType type, ContextOv
context.fShareIndex == shareIndex && context.fShareIndex == shareIndex &&
!context.fAbandoned) { !context.fAbandoned) {
context.fTestContext->makeCurrent(); 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.fAbandoned = false;
context.fShareContext = shareContext; context.fShareContext = shareContext;
context.fShareIndex = shareIndex; 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) { ContextInfo GrContextFactory::getContextInfo(ContextType type, ContextOverrides overrides) {

View File

@ -159,6 +159,7 @@ private:
struct Context { struct Context {
ContextType fType; ContextType fType;
ContextOverrides fOverrides; ContextOverrides fOverrides;
GrContextOptions fOptions;
GrBackend fBackend; GrBackend fBackend;
TestContext* fTestContext; TestContext* fTestContext;
GrContext* fGrContext; GrContext* fGrContext;
@ -189,19 +190,18 @@ public:
return static_cast<GLTestContext*>(fTestContext); return static_cast<GLTestContext*>(fTestContext);
} }
const GrContextOptions& options() const { return fOptions; }
private: private:
ContextInfo(GrContextFactory::ContextType type, ContextInfo(GrContextFactory::ContextType type, TestContext* testContext, GrContext* grContext,
TestContext* testContext, const GrContextOptions& options)
GrContext* grContext) : fType(type), fTestContext(testContext), fGrContext(grContext), fOptions(options) {}
: fType(type)
, fTestContext(testContext)
, fGrContext(grContext) {
}
GrContextFactory::ContextType fType = GrContextFactory::kGL_ContextType; GrContextFactory::ContextType fType = GrContextFactory::kGL_ContextType;
// Valid until the factory destroys it via abandonContexts() or destroyContexts(). // Valid until the factory destroys it via abandonContexts() or destroyContexts().
TestContext* fTestContext = nullptr; TestContext* fTestContext = nullptr;
GrContext* fGrContext = nullptr; GrContext* fGrContext = nullptr;
GrContextOptions fOptions;
friend class GrContextFactory; friend class GrContextFactory;
}; };