Revert "Revert "Workaround Adreno driver issue with stencil clears.""

This reverts commit 8b06ed7c9f.

Reason for revert: try again.

Original change's description:
> Revert "Workaround Adreno driver issue with stencil clears."
> 
> This reverts commit 4e8c581f2a.
> 
> Reason for revert: breaks Google3 roll
> 
> Original change's description:
> > Workaround Adreno driver issue with stencil clears.
> > 
> > This also removes the "debug wire rect" which was not used and not implemented for Vulkan.
> > 
> > Also some declared but not implemented methods are removed from GrGLGpu.
> > 
> > Bug: skia:5587
> > 
> > Change-Id: I750051e90e6cfbfad6a6fe20792226182f698bcf
> > Reviewed-on: https://skia-review.googlesource.com/18639
> > Reviewed-by: Chris Dalton <csmartdalton@google.com>
> > Commit-Queue: Brian Salomon <bsalomon@google.com>
> 
> TBR=bsalomon@google.com,csmartdalton@google.com
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: skia:5587
> 
> Change-Id: I65aa16b3f8c70cdef56ff16e16304ba09604c475
> Reviewed-on: https://skia-review.googlesource.com/18924
> Reviewed-by: Mike Klein <mtklein@google.com>
> Commit-Queue: Mike Klein <mtklein@google.com>

TBR=mtklein@google.com,bsalomon@google.com,reviews@skia.org,csmartdalton@google.com
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:5587

Change-Id: Ice49027bda1c1ff7e0362d0680341ac862159850
Reviewed-on: https://skia-review.googlesource.com/18928
Reviewed-by: Mike Klein <mtklein@google.com>
This commit is contained in:
Mike Klein 2017-06-06 23:29:53 +00:00
parent 8b06ed7c9f
commit 31550dbc98
9 changed files with 86 additions and 123 deletions

View File

@ -479,9 +479,6 @@ public:
// clears target's entire stencil buffer to 0
virtual void clearStencil(GrRenderTarget* target) = 0;
// draws an outline rectangle for debugging/visualization purposes.
virtual void drawDebugWireRect(GrRenderTarget*, const SkIRect&, GrColor) = 0;
// Determines whether a texture will need to be rescaled in order to be used with the
// GrSamplerParams. This variation is called when the caller will create a new texture using the
// resource provider from a non-texture src (cpu-backed image, ...).

View File

@ -455,6 +455,20 @@ GrUserStencilSettings const* const* GrStencilSettings::GetClipPasses(SkRegion::O
return gUserToClipTable[invertedFill][op];
}
static constexpr GrUserStencilSettings gZeroStencilClipBit(
GrUserStencilSettings::StaticInit<
0x0000,
GrUserStencilTest::kAlways,
0xffff,
GrUserStencilOp::kZeroClipBit,
GrUserStencilOp::kZeroClipBit,
0x0000>()
);
const GrUserStencilSettings* GrStencilSettings::SetClipBitSettings(bool setToInside) {
return setToInside ? &gReplaceClip : &gZeroStencilClipBit;
}
void GrStencilSettings::genKey(GrProcessorKeyBuilder* b) const {
b->add32(fFlags);
if (this->isDisabled()) {

View File

@ -109,6 +109,9 @@ public:
bool invertedFill,
bool* drawDirectToClip);
/** Gets the user stencil settings to directly set the clip bit. */
static const GrUserStencilSettings* SetClipBitSettings(bool setToInside);
private:
// Internal flag for backends to optionally mark their tracked stencil state as invalid.
enum { kInvalid_PrivateFlag = (kLast_StencilFlag << 1) };

View File

@ -55,6 +55,7 @@ GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions,
fClearToBoundaryValuesIsBroken = false;
fClearTextureSupport = false;
fDrawArraysBaseVertexIsBroken = false;
fUseDrawToClearStencilClip = false;
fBlitFramebufferFlags = kNoSupport_BlitFramebufferFlag;
@ -511,6 +512,7 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
if (kAdreno4xx_GrGLRenderer == ctxInfo.renderer()) {
fUseDrawInsteadOfPartialRenderTargetWrite = true;
fUseDrawToClearStencilClip = true;
}
// Texture uploads sometimes seem to be ignored to textures bound to FBOS on Tegra3.

View File

@ -368,6 +368,11 @@ public:
// https://bugs.chromium.org/p/skia/issues/detail?id=6650
bool drawArraysBaseVertexIsBroken() const { return fDrawArraysBaseVertexIsBroken; }
/// 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.
bool useDrawToClearStencilClip() const { return fUseDrawToClearStencilClip; }
bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc,
bool* rectsMustMatch, bool* disallowSubrect) const override;
@ -442,6 +447,7 @@ private:
bool fClearToBoundaryValuesIsBroken : 1;
bool fClearTextureSupport : 1;
bool fDrawArraysBaseVertexIsBroken : 1;
bool fUseDrawToClearStencilClip : 1;
uint32_t fBlitFramebufferFlags;

View File

@ -220,7 +220,7 @@ GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context)
for (size_t i = 0; i < SK_ARRAY_COUNT(fMipmapPrograms); ++i) {
fMipmapPrograms[i].fProgram = 0;
}
fWireRectProgram.fProgram = 0;
fStencilClipClearProgram = 0;
SkASSERT(ctx);
fCaps.reset(SkRef(ctx->caps()));
@ -277,7 +277,7 @@ GrGLGpu::~GrGLGpu() {
fPathRendering.reset();
fCopyProgramArrayBuffer.reset();
fMipmapProgramArrayBuffer.reset();
fWireRectArrayBuffer.reset();
fStencilClipClearArrayBuffer.reset();
if (0 != fHWProgramID) {
// detach the current program so there is no confusion on OpenGL's part
@ -307,8 +307,8 @@ GrGLGpu::~GrGLGpu() {
}
}
if (0 != fWireRectProgram.fProgram) {
GL_CALL(DeleteProgram(fWireRectProgram.fProgram));
if (0 != fStencilClipClearProgram) {
GL_CALL(DeleteProgram(fStencilClipClearProgram));
}
delete fProgramCache;
@ -339,8 +339,8 @@ void GrGLGpu::disconnect(DisconnectType type) {
GL_CALL(DeleteProgram(fMipmapPrograms[i].fProgram));
}
}
if (fWireRectProgram.fProgram) {
GL_CALL(DeleteProgram(fWireRectProgram.fProgram));
if (fStencilClipClearProgram) {
GL_CALL(DeleteProgram(fStencilClipClearProgram));
}
} else {
if (fProgramCache) {
@ -363,8 +363,8 @@ void GrGLGpu::disconnect(DisconnectType type) {
for (size_t i = 0; i < SK_ARRAY_COUNT(fMipmapPrograms); ++i) {
fMipmapPrograms[i].fProgram = 0;
}
fWireRectProgram.fProgram = 0;
fWireRectArrayBuffer.reset();
fStencilClipClearProgram = 0;
fStencilClipClearArrayBuffer.reset();
if (this->glCaps().shaderCaps()->pathRenderingSupport()) {
this->glPathRendering()->disconnect(type);
}
@ -1943,6 +1943,11 @@ void GrGLGpu::clearStencilClip(const GrFixedClip& clip,
SkASSERT(target);
this->handleDirtyContext();
if (this->glCaps().useDrawToClearStencilClip()) {
this->clearStencilClipAsDraw(clip, insideStencilMask, target);
return;
}
GrStencilAttachment* sb = target->renderTargetPriv().getStencilAttachment();
// this should only be called internally when we know we have a
// stencil buffer.
@ -3611,64 +3616,43 @@ bool GrGLGpu::createMipmapProgram(int progIdx) {
return true;
}
bool GrGLGpu::createWireRectProgram() {
if (!fWireRectArrayBuffer) {
static const GrGLfloat vdata[] = {
0, 0,
0, 1,
1, 1,
1, 0
};
fWireRectArrayBuffer.reset(GrGLBuffer::Create(this, sizeof(vdata), kVertex_GrBufferType,
kStatic_GrAccessPattern, vdata));
if (!fWireRectArrayBuffer) {
bool GrGLGpu::createStencilClipClearProgram() {
if (!fStencilClipClearArrayBuffer) {
static const GrGLfloat vdata[] = {-1, -1, 1, -1, -1, 1, 1, 1};
fStencilClipClearArrayBuffer.reset(GrGLBuffer::Create(
this, sizeof(vdata), kVertex_GrBufferType, kStatic_GrAccessPattern, vdata));
if (!fStencilClipClearArrayBuffer) {
return false;
}
}
SkASSERT(!fWireRectProgram.fProgram);
GL_CALL_RET(fWireRectProgram.fProgram, CreateProgram());
if (!fWireRectProgram.fProgram) {
SkASSERT(!fStencilClipClearProgram);
GL_CALL_RET(fStencilClipClearProgram, CreateProgram());
if (!fStencilClipClearProgram) {
return false;
}
GrShaderVar uColor("u_color", kVec4f_GrSLType, GrShaderVar::kUniform_TypeModifier);
GrShaderVar uRect("u_rect", kVec4f_GrSLType, GrShaderVar::kUniform_TypeModifier);
GrShaderVar aVertex("a_vertex", kVec2f_GrSLType, GrShaderVar::kIn_TypeModifier);
const char* version = this->caps()->shaderCaps()->versionDeclString();
// The rect uniform specifies the rectangle in NDC space as a vec4 (left,top,right,bottom). The
// program is used with a vbo containing the unit square. Vertices are computed from the rect
// uniform using the 4 vbo vertices.
SkString vshaderTxt(version);
aVertex.appendDecl(this->caps()->shaderCaps(), &vshaderTxt);
vshaderTxt.append(";");
uRect.appendDecl(this->caps()->shaderCaps(), &vshaderTxt);
vshaderTxt.append(";");
vshaderTxt.append(
"// Wire Rect Program VS\n"
"void main() {"
" gl_Position.x = u_rect.x + a_vertex.x * (u_rect.z - u_rect.x);"
" gl_Position.y = u_rect.y + a_vertex.y * (u_rect.w - u_rect.y);"
" gl_Position.zw = vec2(0, 1);"
"}"
);
GrShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_TypeModifier);
"// Stencil Clip Clear Program VS\n"
"void main() {"
" gl_Position = vec4(a_vertex.x, a_vertex.y, 0, 1);"
"}");
SkString fshaderTxt(version);
GrGLSLAppendDefaultFloatPrecisionDeclaration(kMedium_GrSLPrecision,
*this->caps()->shaderCaps(),
&fshaderTxt);
uColor.appendDecl(this->caps()->shaderCaps(), &fshaderTxt);
fshaderTxt.append(";");
fshaderTxt.appendf(
"// Write Rect Program FS\n"
"void main() {"
" sk_FragColor = %s;"
"}",
uColor.c_str()
);
"// Stencil Clip Clear Program FS\n"
"void main() {"
" sk_FragColor = vec4(0);"
"}");
const char* str;
GrGLint length;
@ -3678,25 +3662,21 @@ bool GrGLGpu::createWireRectProgram() {
SkSL::Program::Settings settings;
settings.fCaps = this->caps()->shaderCaps();
SkSL::Program::Inputs inputs;
GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fWireRectProgram.fProgram,
GR_GL_VERTEX_SHADER, &str, &length, 1,
&fStats, settings, &inputs);
GrGLuint vshader =
GrGLCompileAndAttachShader(*fGLContext, fStencilClipClearProgram, 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, fWireRectProgram.fProgram,
GR_GL_FRAGMENT_SHADER, &str, &length, 1,
&fStats, settings, &inputs);
GrGLuint fshader =
GrGLCompileAndAttachShader(*fGLContext, fStencilClipClearProgram, GR_GL_FRAGMENT_SHADER,
&str, &length, 1, &fStats, settings, &inputs);
SkASSERT(inputs.isEmpty());
GL_CALL(LinkProgram(fWireRectProgram.fProgram));
GL_CALL(LinkProgram(fStencilClipClearProgram));
GL_CALL_RET(fWireRectProgram.fColorUniform,
GetUniformLocation(fWireRectProgram.fProgram, "u_color"));
GL_CALL_RET(fWireRectProgram.fRectUniform,
GetUniformLocation(fWireRectProgram.fProgram, "u_rect"));
GL_CALL(BindAttribLocation(fWireRectProgram.fProgram, 0, "a_vertex"));
GL_CALL(BindAttribLocation(fStencilClipClearProgram, 0, "a_vertex"));
GL_CALL(DeleteShader(vshader));
GL_CALL(DeleteShader(fshader));
@ -3704,71 +3684,46 @@ bool GrGLGpu::createWireRectProgram() {
return true;
}
void GrGLGpu::drawDebugWireRect(GrRenderTarget* rt, const SkIRect& rect, GrColor color) {
void GrGLGpu::clearStencilClipAsDraw(const GrFixedClip& clip, bool insideStencilMask,
GrRenderTarget* rt) {
// TODO: This should swizzle the output to match dst's config, though it is a debugging
// visualization.
this->handleDirtyContext();
if (!fWireRectProgram.fProgram) {
if (!this->createWireRectProgram()) {
SkDebugf("Failed to create wire rect program.\n");
if (!fStencilClipClearProgram) {
if (!this->createStencilClipClearProgram()) {
SkDebugf("Failed to create stencil clip clear program.\n");
return;
}
}
int w = rt->width();
int h = rt->height();
// Compute the edges of the rectangle (top,left,right,bottom) in NDC space. Must consider
// whether the render target is flipped or not.
GrGLfloat edges[4];
edges[0] = SkIntToScalar(rect.fLeft) + 0.5f;
edges[2] = SkIntToScalar(rect.fRight) - 0.5f;
if (kBottomLeft_GrSurfaceOrigin == rt->origin()) {
edges[1] = h - (SkIntToScalar(rect.fTop) + 0.5f);
edges[3] = h - (SkIntToScalar(rect.fBottom) - 0.5f);
} else {
edges[1] = SkIntToScalar(rect.fTop) + 0.5f;
edges[3] = SkIntToScalar(rect.fBottom) - 0.5f;
}
edges[0] = 2 * edges[0] / w - 1.0f;
edges[1] = 2 * edges[1] / h - 1.0f;
edges[2] = 2 * edges[2] / w - 1.0f;
edges[3] = 2 * edges[3] / h - 1.0f;
GrGLfloat channels[4];
static const GrGLfloat scale255 = 1.f / 255.f;
channels[0] = GrColorUnpackR(color) * scale255;
channels[1] = GrColorUnpackG(color) * scale255;
channels[2] = GrColorUnpackB(color) * scale255;
channels[3] = GrColorUnpackA(color) * scale255;
GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(rt->asRenderTarget());
this->flushRenderTarget(glRT, &rect);
this->flushRenderTarget(glRT, nullptr);
GL_CALL(UseProgram(fWireRectProgram.fProgram));
fHWProgramID = fWireRectProgram.fProgram;
GL_CALL(UseProgram(fStencilClipClearProgram));
fHWProgramID = fStencilClipClearProgram;
fHWVertexArrayState.setVertexArrayID(this, 0);
GrGLAttribArrayState* attribs = fHWVertexArrayState.bindInternalVertexArray(this);
attribs->enableVertexArrays(this, 1);
attribs->set(this, 0, fWireRectArrayBuffer.get(), kVec2f_GrVertexAttribType,
attribs->set(this, 0, fStencilClipClearArrayBuffer.get(), kVec2f_GrVertexAttribType,
2 * sizeof(GrGLfloat), 0);
GL_CALL(Uniform4fv(fWireRectProgram.fRectUniform, 1, edges));
GL_CALL(Uniform4fv(fWireRectProgram.fColorUniform, 1, channels));
GrXferProcessor::BlendInfo blendInfo;
blendInfo.reset();
this->flushBlend(blendInfo, GrSwizzle::RGBA());
this->flushColorWrite(true);
this->flushColorWrite(false);
this->flushHWAAState(glRT, false, false);
this->disableScissor();
this->disableWindowRectangles();
this->disableStencil();
GL_CALL(DrawArrays(GR_GL_LINE_LOOP, 0, 4));
this->flushScissor(clip.scissorState(), glRT->getViewport(), glRT->origin());
this->flushWindowRectangles(clip.windowRectsState(), glRT);
GrStencilAttachment* sb = rt->renderTargetPriv().getStencilAttachment();
// This should only be called internally when we know we have a stencil buffer.
SkASSERT(sb);
GrStencilSettings settings = GrStencilSettings(
*GrStencilSettings::SetClipBitSettings(insideStencilMask), false, sb->bits());
this->flushStencil(settings);
GL_CALL(DrawArrays(GR_GL_TRIANGLE_STRIP, 0, 4));
}

View File

@ -162,8 +162,6 @@ public:
void resetShaderCacheForTesting() const override;
void drawDebugWireRect(GrRenderTarget*, const SkIRect&, GrColor) override;
GrFence SK_WARN_UNUSED_RESULT insertFence() override;
bool waitFence(GrFence, uint64_t timeout) override;
void deleteFence(GrFence) const override;
@ -296,6 +294,7 @@ private:
const SkIRect& srcRect,
const SkIPoint& dstPoint);
bool generateMipmap(GrGLTexture* texture, bool gammaCorrect);
void clearStencilClipAsDraw(const GrFixedClip&, bool insideStencilMask, GrRenderTarget*);
static bool BlendCoeffReferencesConstant(GrBlendCoeff coeff);
@ -349,11 +348,6 @@ private:
void flushWindowRectangles(const GrWindowRectsState&, const GrGLRenderTarget*);
void disableWindowRectangles();
void initFSAASupport();
// determines valid stencil formats
void initStencilFormats();
// sets a texture unit to use for texture operations other than binding a texture to a program.
// ensures that such operations don't negatively interact with tracking bound textures.
void setScratchTextureUnit();
@ -407,7 +401,7 @@ private:
bool createCopyProgram(GrTexture* srcTexture);
bool createMipmapProgram(int progIdx);
bool createWireRectProgram();
bool createStencilClipClearProgram();
// GL program-related state
ProgramCache* fProgramCache;
@ -620,12 +614,8 @@ private:
} fMipmapPrograms[4];
sk_sp<GrGLBuffer> fMipmapProgramArrayBuffer;
struct {
GrGLuint fProgram;
GrGLint fColorUniform;
GrGLint fRectUniform;
} fWireRectProgram;
sk_sp<GrGLBuffer> fWireRectArrayBuffer;
GrGLuint fStencilClipClearProgram;
sk_sp<GrGLBuffer> fStencilClipClearArrayBuffer;
static int TextureToCopyProgramIdx(GrTexture* texture) {
switch (texture->texturePriv().samplerType()) {

View File

@ -98,8 +98,6 @@ public:
const GrGpuCommandBuffer::LoadAndStoreInfo& colorInfo,
const GrGpuCommandBuffer::LoadAndStoreInfo& stencilInfo) override;
void drawDebugWireRect(GrRenderTarget*, const SkIRect&, GrColor) override {}
void addMemoryBarrier(VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask,
bool byRegion,

View File

@ -339,8 +339,6 @@ public:
return nullptr;
}
void drawDebugWireRect(GrRenderTarget*, const SkIRect&, GrColor) override {}
GrFence SK_WARN_UNUSED_RESULT insertFence() override { return 0; }
bool waitFence(GrFence, uint64_t) override { return true; }
void deleteFence(GrFence) const override {}