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>
This commit is contained in:
parent
ba83233e68
commit
4e8c581f2a
@ -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, ...).
|
||||
|
@ -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()) {
|
||||
|
@ -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) };
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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,
|
||||
|
@ -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 {}
|
||||
|
Loading…
Reference in New Issue
Block a user