Delete identity matrix shaders from tessellation

Every shader always has a matrix now. The 4 FMAs (literally) that this
saved by specializing the shader weren't worth it.

Bug: skia:10419
Change-Id: I506dbd6d723f6dd022345956fdb5b60b0dd94932
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/412416
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
This commit is contained in:
Chris Dalton 2021-05-25 15:16:29 -06:00 committed by Skia Commit-Bot
parent e1c2beb3be
commit 64d06ba897
7 changed files with 86 additions and 101 deletions

View File

@ -17,14 +17,18 @@ public:
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
auto& shader = args.fGeomProc.cast<GrFillPathShader>();
const char* viewMatrix;
fViewMatrixUniform = args.fUniformHandler->addUniform(
nullptr, kVertex_GrShaderFlag, kFloat3x3_GrSLType, "view_matrix", &viewMatrix);
args.fVaryingHandler->emitAttributes(shader);
const char* affineMatrix, *translate;
fAffineMatrixUniform = args.fUniformHandler->addUniform(
nullptr, kVertex_GrShaderFlag, kFloat4_GrSLType, "affineMatrix", &affineMatrix);
fTranslateUniform = args.fUniformHandler->addUniform(
nullptr, kVertex_GrShaderFlag, kFloat2_GrSLType, "translate", &translate);
args.fVertBuilder->codeAppendf("float2x2 AFFINE_MATRIX = float2x2(%s);", affineMatrix);
args.fVertBuilder->codeAppendf("float2 TRANSLATE = %s;", translate);
args.fVertBuilder->codeAppend("float2 localcoord, vertexpos;");
shader.emitVertexCode(this, args.fVertBuilder, viewMatrix, args.fUniformHandler);
shader.emitVertexCode(this, args.fVertBuilder, args.fUniformHandler);
gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord");
@ -41,13 +45,16 @@ public:
const GrShaderCaps&,
const GrGeometryProcessor& geomProc) override {
const GrFillPathShader& shader = geomProc.cast<GrFillPathShader>();
pdman.setSkMatrix(fViewMatrixUniform, shader.viewMatrix());
const SkMatrix& m = shader.viewMatrix();
pdman.set4f(fAffineMatrixUniform, m.getScaleX(), m.getSkewY(), m.getSkewX(), m.getScaleY());
pdman.set2f(fTranslateUniform, m.getTranslateX(), m.getTranslateY());
const SkPMColor4f& color = shader.fColor;
pdman.set4f(fColorUniform, color.fR, color.fG, color.fB, color.fA);
}
GrGLSLUniformHandler::UniformHandle fViewMatrixUniform;
GrGLSLUniformHandler::UniformHandle fAffineMatrixUniform;
GrGLSLUniformHandler::UniformHandle fTranslateUniform;
GrGLSLUniformHandler::UniformHandle fColorUniform;
};
@ -55,14 +62,14 @@ GrGLSLGeometryProcessor* GrFillPathShader::createGLSLInstance(const GrShaderCaps
return new Impl;
}
void GrFillTriangleShader::emitVertexCode(Impl*, GrGLSLVertexBuilder* v, const char* viewMatrix,
void GrFillTriangleShader::emitVertexCode(Impl*, GrGLSLVertexBuilder* v,
GrGLSLUniformHandler* uniformHandler) const {
v->codeAppendf(R"(
v->codeAppend(R"(
localcoord = input_point;
vertexpos = (%s * float3(localcoord, 1)).xy;)", viewMatrix);
vertexpos = AFFINE_MATRIX * localcoord + TRANSLATE;)");
}
void GrFillCubicHullShader::emitVertexCode(Impl*, GrGLSLVertexBuilder* v, const char* viewMatrix,
void GrFillCubicHullShader::emitVertexCode(Impl*, GrGLSLVertexBuilder* v,
GrGLSLUniformHandler* uniformHandler) const {
v->codeAppend(R"(
float4x2 P = float4x2(input_points_0_1, input_points_2_3);
@ -118,21 +125,19 @@ void GrFillCubicHullShader::emitVertexCode(Impl*, GrGLSLVertexBuilder* v, const
vertexidx = (vertexidx + 1) & 3;
}
localcoord = P[vertexidx];)");
v->codeAppendf("vertexpos = (%s * float3(localcoord, 1)).xy;", viewMatrix);
localcoord = P[vertexidx];
vertexpos = AFFINE_MATRIX * localcoord + TRANSLATE;)");
}
void GrFillBoundingBoxShader::emitVertexCode(Impl* impl, GrGLSLVertexBuilder* v,
const char* viewMatrix,
GrGLSLUniformHandler* uniformHandler) const {
v->codeAppendf(R"(
// Bloat the bounding box by 1/4px to avoid potential T-junctions at the edges.
float2x2 M_ = inverse(float2x2(%s));
float2x2 M_ = inverse(AFFINE_MATRIX);
float2 bloat = float2(abs(M_[0]) + abs(M_[1])) * .25;
// Find the vertex position.
float2 T = float2(sk_VertexID & 1, sk_VertexID >> 1);
localcoord = mix(pathBounds.xy - bloat, pathBounds.zw + bloat, T);
vertexpos = (%s * float3(localcoord, 1)).xy;)", viewMatrix, viewMatrix);
vertexpos = AFFINE_MATRIX * localcoord + TRANSLATE;)");
}

View File

@ -56,8 +56,7 @@ public:
protected:
class Impl;
virtual void emitVertexCode(Impl*, GrGLSLVertexBuilder*, const char* viewMatrix,
GrGLSLUniformHandler*) const = 0;
virtual void emitVertexCode(Impl*, GrGLSLVertexBuilder*, GrGLSLUniformHandler*) const = 0;
private:
const SkPMColor4f fColor;
@ -76,8 +75,7 @@ public:
private:
const char* name() const override { return "GrFillTriangleShader"; }
void emitVertexCode(Impl*, GrGLSLVertexBuilder*, const char* viewMatrix,
GrGLSLUniformHandler*) const override;
void emitVertexCode(Impl*, GrGLSLVertexBuilder*, GrGLSLUniformHandler*) const override;
};
// Fills an array of convex hulls surrounding 4-point cubic instances.
@ -94,8 +92,7 @@ public:
private:
const char* name() const override { return "GrFillCubicHullShader"; }
void emitVertexCode(Impl*, GrGLSLVertexBuilder*, const char* viewMatrix,
GrGLSLUniformHandler*) const override;
void emitVertexCode(Impl*, GrGLSLVertexBuilder*, GrGLSLUniformHandler*) const override;
};
// Fills a path's bounding box, with subpixel outset to avoid possible T-junctions with extreme
@ -114,8 +111,7 @@ public:
private:
const char* name() const override { return "GrFillBoundingBoxShader"; }
void emitVertexCode(Impl*, GrGLSLVertexBuilder*, const char* viewMatrix,
GrGLSLUniformHandler*) const override;
void emitVertexCode(Impl*, GrGLSLVertexBuilder*, GrGLSLUniformHandler*) const override;
};
#endif

View File

@ -57,24 +57,23 @@ protected:
args.fVaryingHandler->emitAttributes(shader);
auto v = args.fVertBuilder;
GrShaderVar vertexPos = (*shader.vertexAttributes().begin()).asShaderVar();
if (!shader.viewMatrix().isIdentity()) {
const char* viewMatrix;
fViewMatrixUniform = args.fUniformHandler->addUniform(
nullptr, kVertex_GrShaderFlag, kFloat3x3_GrSLType, "view_matrix", &viewMatrix);
v->codeAppendf("float2 vertexpos = (%s * float3(inputPoint, 1)).xy;", viewMatrix);
if (shader.willUseTessellationShaders()) {
// If y is infinity then x is a conic weight. Don't transform.
v->codeAppendf("vertexpos = (isinf(inputPoint.y)) ? inputPoint : vertexpos;");
}
vertexPos.set(kFloat2_GrSLType, "vertexpos");
const char* affineMatrix, *translate;
fAffineMatrixUniform = args.fUniformHandler->addUniform(
nullptr, kVertex_GrShaderFlag, kFloat4_GrSLType, "affineMatrix", &affineMatrix);
fTranslateUniform = args.fUniformHandler->addUniform(
nullptr, kVertex_GrShaderFlag, kFloat2_GrSLType, "translate", &translate);
v->codeAppendf("float2 vertexpos = float2x2(%s) * inputPoint + %s;",
affineMatrix, translate);
if (shader.willUseTessellationShaders()) {
// If y is infinity then x is a conic weight. Don't transform.
v->codeAppendf("vertexpos = (isinf(inputPoint.y)) ? inputPoint : vertexpos;");
}
if (!shader.willUseTessellationShaders()) { // This is the case for the triangle shader.
gpArgs->fPositionVar = vertexPos;
gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
} else {
v->declareGlobal(GrShaderVar("P", kFloat2_GrSLType, GrShaderVar::TypeModifier::Out));
v->codeAppendf("P = %s;", vertexPos.c_str());
v->codeAppendf("P = %s;", "vertexpos");
}
// The fragment shader is normally disabled, but output fully opaque white.
@ -85,13 +84,13 @@ protected:
void setData(const GrGLSLProgramDataManager& pdman,
const GrShaderCaps&,
const GrGeometryProcessor& geomProc) override {
const auto& shader = geomProc.cast<GrStencilPathShader>();
if (!shader.viewMatrix().isIdentity()) {
pdman.setSkMatrix(fViewMatrixUniform, shader.viewMatrix());
}
const SkMatrix& m = geomProc.cast<GrStencilPathShader>().viewMatrix();
pdman.set4f(fAffineMatrixUniform, m.getScaleX(), m.getSkewY(), m.getSkewX(), m.getScaleY());
pdman.set2f(fTranslateUniform, m.getTranslateX(), m.getTranslateY());
}
GrGLSLUniformHandler::UniformHandle fViewMatrixUniform;
GrGLSLUniformHandler::UniformHandle fAffineMatrixUniform;
GrGLSLUniformHandler::UniformHandle fTranslateUniform;
};
GrGLSLGeometryProcessor* GrStencilPathShader::createGLSLInstance(const GrShaderCaps&) const {
@ -375,13 +374,13 @@ class GrCurveMiddleOutShader::Impl : public GrStencilPathShader::Impl {
float T = find_middle_out_T();
pos = eval_rational_cubic(P, T);
})");
if (!shader.viewMatrix().isIdentity()) {
const char* viewMatrix;
fViewMatrixUniform = args.fUniformHandler->addUniform(
nullptr, kVertex_GrShaderFlag, kFloat3x3_GrSLType, "view_matrix", &viewMatrix);
args.fVertBuilder->codeAppendf(R"(
pos = (%s * float3(pos, 1)).xy;)", viewMatrix);
}
const char* affineMatrix, *translate;
fAffineMatrixUniform = args.fUniformHandler->addUniform(
nullptr, kVertex_GrShaderFlag, kFloat4_GrSLType, "affineMatrix", &affineMatrix);
fTranslateUniform = args.fUniformHandler->addUniform(
nullptr, kVertex_GrShaderFlag, kFloat2_GrSLType, "translate", &translate);
args.fVertBuilder->codeAppendf(R"(
pos = float2x2(%s) * pos + %s;)", affineMatrix, translate);
gpArgs->fPositionVar.set(kFloat2_GrSLType, "pos");
// The fragment shader is normally disabled, but output fully opaque white.

View File

@ -85,9 +85,7 @@ public:
protected:
constexpr static Attribute kSinglePointAttrib{"inputPoint", kFloat2_GrVertexAttribType,
kFloat2_GrSLType};
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
b->add32(this->viewMatrix().isIdentity());
}
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {}
GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const override;
class Impl;

View File

@ -79,17 +79,15 @@ void GrStrokeInstancedShaderImpl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
}
// View matrix uniforms.
if (!shader.viewMatrix().isIdentity()) {
const char* translateName, *affineMatrixName;
fAffineMatrixUniform = args.fUniformHandler->addUniform(
nullptr, kVertex_GrShaderFlag, kFloat4_GrSLType, "affineMatrix",
&affineMatrixName);
fTranslateUniform = args.fUniformHandler->addUniform(
nullptr, kVertex_GrShaderFlag, kFloat2_GrSLType, "translate", &translateName);
args.fVertBuilder->codeAppendf("float2x2 AFFINE_MATRIX = float2x2(%s);\n",
affineMatrixName);
args.fVertBuilder->codeAppendf("float2 TRANSLATE = %s;\n", translateName);
}
const char* translateName, *affineMatrixName;
fAffineMatrixUniform = args.fUniformHandler->addUniform(nullptr, kVertex_GrShaderFlag,
kFloat4_GrSLType, "affineMatrix",
&affineMatrixName);
fTranslateUniform = args.fUniformHandler->addUniform(nullptr, kVertex_GrShaderFlag,
kFloat2_GrSLType, "translate",
&translateName);
args.fVertBuilder->codeAppendf("float2x2 AFFINE_MATRIX = float2x2(%s);\n", affineMatrixName);
args.fVertBuilder->codeAppendf("float2 TRANSLATE = %s;\n", translateName);
// Tessellation code.
args.fVertBuilder->codeAppend(R"(
@ -103,7 +101,7 @@ void GrStrokeInstancedShaderImpl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
P[3] = P[2]; // Setting p3 equal to p2 works for the remaining rotational logic.
})");
}
if (shader.stroke().isHairlineStyle() && !shader.viewMatrix().isIdentity()) {
if (shader.stroke().isHairlineStyle()) {
// Hairline case. Transform the points before tessellation. We can still hold off on the
// translate until the end; we just need to perform the scale and skew right now.
args.fVertBuilder->codeAppend(R"(

View File

@ -251,11 +251,7 @@ void GrStrokeShaderImpl::emitTessellationCode(const GrStrokeShader& shader, SkSt
float2 ortho = normalize(float2(tangent.y, -tangent.x));
strokeCoord += ortho * (STROKE_RADIUS * strokeOutset);)");
if (shader.viewMatrix().isIdentity()) {
// No transform matrix.
gpArgs->fPositionVar.set(kFloat2_GrSLType, "strokeCoord");
gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "strokeCoord");
} else if (!shader.stroke().isHairlineStyle()) {
if (!shader.stroke().isHairlineStyle()) {
// Normal case. Do the transform after tessellation.
code->append(R"(
float2 devCoord = AFFINE_MATRIX * strokeCoord + TRANSLATE;)");
@ -322,11 +318,9 @@ void GrStrokeShaderImpl::setData(const GrGLSLProgramDataManager& pdman, const Gr
// Set up the view matrix, if any.
const SkMatrix& m = shader.viewMatrix();
if (!m.isIdentity()) {
pdman.set2f(fTranslateUniform, m.getTranslateX(), m.getTranslateY());
pdman.set4f(fAffineMatrixUniform, m.getScaleX(), m.getSkewY(), m.getSkewX(),
m.getScaleY());
}
pdman.set2f(fTranslateUniform, m.getTranslateX(), m.getTranslateY());
pdman.set4f(fAffineMatrixUniform, m.getScaleX(), m.getSkewY(), m.getSkewX(),
m.getScaleY());
if (!shader.hasDynamicColor()) {
pdman.set4fv(fColorUniform, 1, shader.color().vec());
@ -344,7 +338,6 @@ void GrStrokeShader::getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuil
key = (key << 2) | (uint32_t)fMode;
key = (key << 2) | ((keyNeedsJoin) ? fStroke.getJoin() : 0);
key = (key << 1) | (uint32_t)fStroke.isHairlineStyle();
key = (key << 1) | (uint32_t)this->viewMatrix().isIdentity();
b->add32(key);
}

View File

@ -87,22 +87,20 @@ void GrStrokeTessellationShaderImpl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs
float JOIN_TYPE = dynamicStrokeAttr.y;)", parametricPrecisionName);
}
if (!shader.viewMatrix().isIdentity()) {
fTranslateUniform = uniHandler->addUniform(nullptr, kTessEvaluation_GrShaderFlag,
kFloat2_GrSLType, "translate", nullptr);
const char* affineMatrixName;
// Hairlines apply the affine matrix in their vertex shader, prior to tessellation.
// Otherwise the entire view matrix gets applied at the end of the tess eval shader.
auto affineMatrixVisibility = kTessEvaluation_GrShaderFlag;
if (shader.stroke().isHairlineStyle()) {
affineMatrixVisibility |= kVertex_GrShaderFlag;
}
fAffineMatrixUniform = uniHandler->addUniform(nullptr, affineMatrixVisibility,
kFloat4_GrSLType, "affineMatrix",
&affineMatrixName);
if (affineMatrixVisibility & kVertex_GrShaderFlag) {
v->codeAppendf("float2x2 AFFINE_MATRIX = float2x2(%s);\n", affineMatrixName);
}
fTranslateUniform = uniHandler->addUniform(nullptr, kTessEvaluation_GrShaderFlag,
kFloat2_GrSLType, "translate", nullptr);
// View matrix uniforms.
const char* affineMatrixName;
// Hairlines apply the affine matrix in their vertex shader, prior to tessellation.
// Otherwise the entire view matrix gets applied at the end of the tess eval shader.
auto affineMatrixVisibility = kTessEvaluation_GrShaderFlag;
if (shader.stroke().isHairlineStyle()) {
affineMatrixVisibility |= kVertex_GrShaderFlag;
}
fAffineMatrixUniform = uniHandler->addUniform(nullptr, affineMatrixVisibility, kFloat4_GrSLType,
"affineMatrix", &affineMatrixName);
if (affineMatrixVisibility & kVertex_GrShaderFlag) {
v->codeAppendf("float2x2 AFFINE_MATRIX = float2x2(%s);\n", affineMatrixName);
}
v->codeAppend(R"(
@ -110,7 +108,7 @@ void GrStrokeTessellationShaderImpl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs
float2 prevControlPoint = prevCtrlPtAttr;
float4x2 P = float4x2(pts01Attr, pts23Attr);)");
if (shader.stroke().isHairlineStyle() && !shader.viewMatrix().isIdentity()) {
if (shader.stroke().isHairlineStyle()) {
// Hairline case. Transform the points before tessellation. We can still hold off on the
// translate until the end; we just need to perform the scale and skew right now.
if (shader.hasConics()) {
@ -558,14 +556,12 @@ SkString GrStrokeTessellationShaderImpl::getTessEvaluationShaderGLSL(
code.appendf("#define STROKE_RADIUS tcsStrokeRadius\n");
}
if (!shader.viewMatrix().isIdentity()) {
const char* translateName = uniformHandler.getUniformCStr(fTranslateUniform);
code.appendf("uniform vec2 %s;\n", translateName);
code.appendf("#define TRANSLATE %s\n", translateName);
const char* affineMatrixName = uniformHandler.getUniformCStr(fAffineMatrixUniform);
code.appendf("uniform vec4 %s;\n", affineMatrixName);
code.appendf("#define AFFINE_MATRIX mat2(%s)\n", affineMatrixName);
}
const char* translateName = uniformHandler.getUniformCStr(fTranslateUniform);
code.appendf("uniform vec2 %s;\n", translateName);
code.appendf("#define TRANSLATE %s\n", translateName);
const char* affineMatrixName = uniformHandler.getUniformCStr(fAffineMatrixUniform);
code.appendf("uniform vec4 %s;\n", affineMatrixName);
code.appendf("#define AFFINE_MATRIX mat2(%s)\n", affineMatrixName);
code.append(R"(
in vec4 tcsPts01[];