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:
parent
57caa660c0
commit
43f8bf0f78
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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<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());
|
||||
// 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());
|
||||
}
|
||||
|
||||
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<GrOp> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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<GrGLRenderTarget*>(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<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));
|
||||
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<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,
|
||||
GrSurface* src, GrSurfaceOrigin srcOrigin,
|
||||
|
@ -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<GrGLBuffer> 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<GrGLBuffer> fMipmapProgramArrayBuffer;
|
||||
|
||||
GrGLuint fStencilClipClearProgram;
|
||||
GrGLuint fStencilClipClearProgram = 0;
|
||||
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 TextureSizeToMipmapProgramIdx(int width, int height) {
|
||||
|
@ -160,7 +160,6 @@ void GrMtlCaps::initGrCaps(const id<MTLDevice> device) {
|
||||
fUsesMixedSamples = false;
|
||||
fGpuTracingSupport = false;
|
||||
|
||||
fUseDrawInsteadOfClear = false;
|
||||
fFenceSyncSupport = true; // always available in Metal
|
||||
fCrossContextTextureSupport = false;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -43,8 +43,7 @@ sk_sp<GrRenderTargetContext> 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<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
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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<GLTestContext*>(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;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user