Remove fExpression (matrix expression) from SampleUsage

Other than GMs, there is exactly one use of matrix-sampling
(GrMatrixEffect). It is always uniform (not literal or an
expression containing a uniform). The uniform always has the
same name. Bake these simplifications in, which also shrinks
SampleUsage quite a bit.

Change-Id: I0d5e32069d710af475ccc1030e2988c5fc965a98
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/411296
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Osman 2021-05-21 12:03:51 -04:00 committed by Skia Commit-Bot
parent 50cc5d4147
commit b1e9cb08c1
9 changed files with 43 additions and 218 deletions

View File

@ -14,37 +14,6 @@
#include "src/gpu/ops/GrFillRectOp.h"
#include "tools/ToolUtils.h"
// Samples child with a constant (literal) matrix
// Scales along X
class ConstantMatrixEffect : public GrFragmentProcessor {
public:
static constexpr GrProcessor::ClassID CLASS_ID = (GrProcessor::ClassID) 3;
ConstantMatrixEffect(std::unique_ptr<GrFragmentProcessor> child)
: GrFragmentProcessor(CLASS_ID, kNone_OptimizationFlags) {
this->registerChild(std::move(child),
SkSL::SampleUsage::UniformMatrix(
"float3x3(float3(0.5, 0.0, 0.0), "
"float3(0.0, 1.0, 0.0), "
"float3(0.0, 0.0, 1.0))"));
}
const char* name() const override { return "ConstantMatrixEffect"; }
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
bool onIsEqual(const GrFragmentProcessor& that) const override { return this == &that; }
std::unique_ptr<GrFragmentProcessor> clone() const override { return nullptr; }
std::unique_ptr<GrGLSLFragmentProcessor> onMakeProgramImpl() const override {
class Impl : public GrGLSLFragmentProcessor {
void emitCode(EmitArgs& args) override {
SkString sample = this->invokeChildWithMatrix(0, args);
args.fFragBuilder->codeAppendf("return %s;\n", sample.c_str());
}
};
return std::make_unique<Impl>();
}
};
// Samples child with a uniform matrix (functionally identical to GrMatrixEffect)
// Scales along Y
class UniformMatrixEffect : public GrFragmentProcessor {
@ -53,7 +22,8 @@ public:
UniformMatrixEffect(std::unique_ptr<GrFragmentProcessor> child)
: GrFragmentProcessor(CLASS_ID, kNone_OptimizationFlags) {
this->registerChild(std::move(child), SkSL::SampleUsage::UniformMatrix("matrix"));
this->registerChild(std::move(child),
SkSL::SampleUsage::UniformMatrix(/*hasPerspective=*/false));
}
const char* name() const override { return "UniformMatrixEffect"; }
@ -64,8 +34,11 @@ public:
std::unique_ptr<GrGLSLFragmentProcessor> onMakeProgramImpl() const override {
class Impl : public GrGLSLFragmentProcessor {
void emitCode(EmitArgs& args) override {
fMatrixVar = args.fUniformHandler->addUniform(&args.fFp, kFragment_GrShaderFlag,
kFloat3x3_GrSLType, "matrix");
fMatrixVar =
args.fUniformHandler->addUniform(&args.fFp,
kFragment_GrShaderFlag,
kFloat3x3_GrSLType,
SkSL::SampleUsage::MatrixUniformName());
SkString sample = this->invokeChildWithMatrix(0, args);
args.fFragBuilder->codeAppendf("return %s;\n", sample.c_str());
}
@ -160,7 +133,6 @@ SkBitmap make_test_bitmap() {
}
enum EffectType {
kConstant,
kUniform,
kExplicit,
};
@ -168,8 +140,6 @@ enum EffectType {
static std::unique_ptr<GrFragmentProcessor> wrap(std::unique_ptr<GrFragmentProcessor> fp,
EffectType effectType) {
switch (effectType) {
case kConstant:
return std::make_unique<ConstantMatrixEffect>(std::move(fp));
case kUniform:
return std::make_unique<UniformMatrixEffect>(std::move(fp));
case kExplicit:
@ -178,7 +148,7 @@ static std::unique_ptr<GrFragmentProcessor> wrap(std::unique_ptr<GrFragmentProce
SkUNREACHABLE;
}
DEF_SIMPLE_GPU_GM(fp_sample_chaining, ctx, rtCtx, canvas, 306, 232) {
DEF_SIMPLE_GPU_GM(fp_sample_chaining, ctx, rtCtx, canvas, 232, 232) {
SkBitmap bmp = make_test_bitmap();
int x = 10, y = 10;
@ -212,21 +182,16 @@ DEF_SIMPLE_GPU_GM(fp_sample_chaining, ctx, rtCtx, canvas, 306, 232) {
// First row: no transform, then each one independently applied
draw({}); // Identity (4 rows and columns)
draw({ kConstant }); // Scale X axis by 2x (2 visible columns)
draw({ kUniform }); // Scale Y axis by 2x (2 visible rows)
draw({ kExplicit }); // Translate up by 8px
nextRow();
// Second row: transform duplicated
draw({ kConstant, kUniform }); // Scale XY by 2x (2 rows and columns)
draw({ kConstant, kConstant }); // Scale X axis by 4x (1 visible column)
draw({ kUniform, kUniform }); // Scale Y axis by 4x (1 visible row)
draw({ kExplicit, kExplicit }); // Translate up by 16px
nextRow();
// Remember, these are applied inside out:
draw({ kConstant, kExplicit }); // Scale X by 2x and translate up by 8px
draw({ kUniform, kExplicit }); // Scale Y by 2x and translate up by 8px
draw({ kExplicit, kExplicit, kConstant }); // Scale X by 2x and translate up by 16px
draw({ kExplicit, kUniform }); // Scale Y by 2x and translate up by 16px
draw({ kExplicit, kUniform }); // Scale Y by 2x and translate up by 16px
}

View File

@ -1,105 +0,0 @@
/*
* Copyright 2019 Google LLC.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "gm/gm.h"
#include "include/effects/SkGradientShader.h"
#include "src/core/SkMatrixProvider.h"
#include "src/gpu/GrDirectContextPriv.h"
#include "src/gpu/SkGr.h"
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
#include "src/gpu/ops/GrFillRectOp.h"
#include "tools/Resources.h"
class SampleMatrixConstantEffect : public GrFragmentProcessor {
public:
static constexpr GrProcessor::ClassID CLASS_ID = (GrProcessor::ClassID) 1;
SampleMatrixConstantEffect(std::unique_ptr<GrFragmentProcessor> child)
: INHERITED(CLASS_ID, kNone_OptimizationFlags) {
this->registerChild(std::move(child),
SkSL::SampleUsage::UniformMatrix(
"float3x3(float3(0.5, 0.0, 0.0), "
"float3(0.0, 0.5, 0.0), "
"float3(0.0, 0.0, 1.0))"));
}
const char* name() const override { return "SampleMatrixConstantEffect"; }
std::unique_ptr<GrFragmentProcessor> clone() const override {
SkASSERT(false);
return nullptr;
}
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
bool onIsEqual(const GrFragmentProcessor& that) const override { return this == &that; }
private:
std::unique_ptr<GrGLSLFragmentProcessor> onMakeProgramImpl() const override;
using INHERITED = GrFragmentProcessor;
};
class GLSLSampleMatrixConstantEffect : public GrGLSLFragmentProcessor {
void emitCode(EmitArgs& args) override {
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
SkString sample = this->invokeChildWithMatrix(0, args);
fragBuilder->codeAppendf("return %s;\n", sample.c_str());
}
};
std::unique_ptr<GrGLSLFragmentProcessor> SampleMatrixConstantEffect::onMakeProgramImpl() const {
return std::make_unique<GLSLSampleMatrixConstantEffect>();
}
DEF_SIMPLE_GPU_GM(sample_matrix_constant, ctx, rtCtx, canvas, 1024, 256) {
auto wrap = [](std::unique_ptr<GrFragmentProcessor> baseFP) {
return std::unique_ptr<GrFragmentProcessor>(
new SampleMatrixConstantEffect(std::move(baseFP)));
};
auto draw = [rtCtx, &wrap](std::unique_ptr<GrFragmentProcessor> baseFP, int tx, int ty) {
auto fp = wrap(std::move(baseFP));
GrPaint paint;
paint.setColorFragmentProcessor(std::move(fp));
rtCtx->drawRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::Translate(tx, ty),
SkRect::MakeIWH(256, 256));
};
auto draw2 = [rtCtx, &wrap](std::unique_ptr<GrFragmentProcessor> baseFP, int tx, int ty) {
auto fp = wrap(wrap(std::move(baseFP)));
GrPaint paint;
paint.setColorFragmentProcessor(std::move(fp));
rtCtx->drawRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::Translate(tx, ty),
SkRect::MakeIWH(256, 256));
};
{
SkBitmap bmp;
GetResourceAsBitmap("images/mandrill_256.png", &bmp);
auto [view, ct] = GrMakeCachedBitmapProxyView(ctx, bmp, GrMipmapped::kNo);
std::unique_ptr<GrFragmentProcessor> imgFP = GrTextureEffect::Make(view,
bmp.alphaType(),
SkMatrix());
draw(std::move(imgFP), 0, 0);
imgFP = GrTextureEffect::Make(std::move(view), bmp.alphaType(), SkMatrix());
draw2(std::move(imgFP), 256, 0);
}
{
static constexpr SkColor colors[] = { 0xff00ff00, 0xffff00ff };
const SkPoint pts[] = {{ 0, 0 }, { 256, 0 }};
auto shader = SkGradientShader::MakeLinear(pts, colors, nullptr,
SK_ARRAY_COUNT(colors),
SkTileMode::kClamp);
SkMatrix matrix;
SkSimpleMatrixProvider matrixProvider(matrix);
GrColorInfo colorInfo;
GrFPArgs args(ctx, matrixProvider, &colorInfo);
std::unique_ptr<GrFragmentProcessor> gradientFP = as_SB(shader)->asFragmentProcessor(args);
draw(std::move(gradientFP), 512, 0);
gradientFP = as_SB(shader)->asFragmentProcessor(args);
draw2(std::move(gradientFP), 768, 0);
}
}

View File

@ -326,7 +326,6 @@ gm_sources = [
"$_gm/runtimefunctions.cpp",
"$_gm/runtimeintrinsics.cpp",
"$_gm/runtimeshader.cpp",
"$_gm/sample_matrix_constant.cpp",
"$_gm/samplerstress.cpp",
"$_gm/savelayer.cpp",
"$_gm/scaledemoji.cpp",

View File

@ -32,18 +32,20 @@ struct SampleUsage {
// Make a SampleUsage that corresponds to no sampling of the child at all
SampleUsage() = default;
// Child is sampled with a matrix whose value is uniform (some expression only involving
// literals and uniform variables).
static SampleUsage UniformMatrix(std::string expression, bool hasPerspective = true) {
return SampleUsage(Kind::kUniformMatrix, std::move(expression), hasPerspective);
// Child is sampled with a matrix whose value is uniform. The name is fixed.
static SampleUsage UniformMatrix(bool hasPerspective) {
return SampleUsage(Kind::kUniformMatrix, hasPerspective);
}
// Arbitrary name used by all uniform sampling matrices
static const char* MatrixUniformName() { return "matrix"; }
static SampleUsage Explicit() {
return SampleUsage(Kind::kExplicit, "", false);
return SampleUsage(Kind::kExplicit, false);
}
static SampleUsage PassThrough() {
return SampleUsage(Kind::kPassThrough, "", false);
return SampleUsage(Kind::kPassThrough, false);
}
SampleUsage merge(const SampleUsage& other);
@ -54,16 +56,11 @@ struct SampleUsage {
bool isUniformMatrix() const { return fKind == Kind::kUniformMatrix; }
Kind fKind = Kind::kNone;
// The uniform expression representing the matrix, or empty for non-matrix sampling
std::string fExpression;
bool fHasPerspective = false;
bool fHasPerspective = false; // Only valid if fKind is kUniformMatrix
SampleUsage(Kind kind, std::string expression, bool hasPerspective)
: fKind(kind), fExpression(expression), fHasPerspective(hasPerspective) {
if (kind == Kind::kUniformMatrix) {
SkASSERT(!fExpression.empty());
} else {
SkASSERT(fExpression.empty() && !fHasPerspective);
SampleUsage(Kind kind, bool hasPerspective) : fKind(kind), fHasPerspective(hasPerspective) {
if (kind != Kind::kUniformMatrix) {
SkASSERT(!fHasPerspective);
}
}

View File

@ -19,8 +19,10 @@ public:
GrGLSLMatrixEffect() {}
void emitCode(EmitArgs& args) override {
fMatrixVar = args.fUniformHandler->addUniform(&args.fFp, kFragment_GrShaderFlag,
kFloat3x3_GrSLType, "matrix");
fMatrixVar = args.fUniformHandler->addUniform(&args.fFp,
kFragment_GrShaderFlag,
kFloat3x3_GrSLType,
SkSL::SampleUsage::MatrixUniformName());
args.fFragBuilder->codeAppendf("return %s;\n",
this->invokeChildWithMatrix(0, args).c_str());
}

View File

@ -30,7 +30,7 @@ private:
, fMatrix(matrix) {
SkASSERT(child);
this->registerChild(std::move(child),
SkSL::SampleUsage::UniformMatrix("matrix", matrix.hasPerspective()));
SkSL::SampleUsage::UniformMatrix(matrix.hasPerspective()));
}
std::unique_ptr<GrGLSLFragmentProcessor> onMakeProgramImpl() const override;

View File

@ -87,24 +87,17 @@ SkString GrGLSLFragmentProcessor::invokeChildWithMatrix(int childIndex, const ch
SkASSERT(childProc->sampleUsage().isUniformMatrix());
// Empty matrix expression replaces with the sample matrix expression stored on the FP, but
// that is only valid for uniform sampled FPs
SkString matrixExpr(childProc->sampleUsage().fExpression);
// Attempt to resolve the uniform name from the raw name stored in the sample usage.
// Every uniform matrix has the same (initial) name. Resolve that into the mangled name:
GrShaderVar uniform = args.fUniformHandler->getUniformMapping(
args.fFp, SkString(childProc->sampleUsage().fExpression));
if (uniform.getType() != kVoid_GrSLType) {
// Found the uniform, so replace the expression with the actual uniform name
SkASSERT(uniform.getType() == kFloat3x3_GrSLType);
matrixExpr = uniform.getName().c_str();
} // else assume it's a constant expression
args.fFp, SkString(SkSL::SampleUsage::MatrixUniformName()));
SkASSERT(uniform.getType() == kFloat3x3_GrSLType);
const SkString& matrixName(uniform.getName());
// Produce a string containing the call to the helper function. We have a const-or-uniform
// expression containing our transform (matrixExpr). If the parent coords were produced by
// uniform transforms, then the entire expression (matrixExpr * coords) is lifted to a vertex
// shader and is stored in a varying. In that case, childProc will not be sampled explicitly,
// so its function signature will not take in coords.
// Produce a string containing the call to the helper function. We have a uniform variable
// containing our transform (matrixName). If the parent coords were produced by uniform
// transforms, then the entire expression (matrixName * coords) is lifted to a vertex shader
// and is stored in a varying. In that case, childProc will not be sampled explicitly, so its
// function signature will not take in coords.
//
// In all other cases, we need to insert sksl to compute matrix * parent coords and then invoke
// the function.
@ -113,14 +106,14 @@ SkString GrGLSLFragmentProcessor::invokeChildWithMatrix(int childIndex, const ch
// Any parent perspective will have already been applied when evaluated in the FS.
if (childProc->sampleUsage().fHasPerspective) {
return SkStringPrintf("%s(%s, proj((%s) * %s.xy1))", fFunctionNames[childIndex].c_str(),
inputColor, matrixExpr.c_str(), args.fSampleCoord);
inputColor, matrixName.c_str(), args.fSampleCoord);
} else if (args.fShaderCaps->nonsquareMatrixSupport()) {
return SkStringPrintf("%s(%s, float3x2(%s) * %s.xy1)",
fFunctionNames[childIndex].c_str(), inputColor,
matrixExpr.c_str(), args.fSampleCoord);
matrixName.c_str(), args.fSampleCoord);
} else {
return SkStringPrintf("%s(%s, ((%s) * %s.xy1).xy)", fFunctionNames[childIndex].c_str(),
inputColor, matrixExpr.c_str(), args.fSampleCoord);
inputColor, matrixName.c_str(), args.fSampleCoord);
}
} else {
// Since this is uniform and not explicitly sampled, it's transform has been promoted to

View File

@ -187,25 +187,16 @@ void GrGLSLGeometryProcessor::emitTransformCode(GrGLSLVertexBuilder* vb,
}
break;
} else if (base->sampleUsage().isUniformMatrix()) {
// The FP knows the matrix expression it's sampled with, but its parent defined
// the uniform (when the expression is not a constant).
// The matrix expression is always the same, but the parent defined the uniform
GrShaderVar uniform = uniformHandler->liftUniformToVertexShader(
*base->parent(), SkString(base->sampleUsage().fExpression));
*base->parent(), SkString(SkSL::SampleUsage::MatrixUniformName()));
SkASSERT(uniform.getType() == kFloat3x3_GrSLType);
// Accumulate the base matrix expression as a preConcat
SkString matrix;
if (uniform.getType() != kVoid_GrSLType) {
SkASSERT(uniform.getType() == kFloat3x3_GrSLType);
matrix = uniform.getName();
} else {
// No uniform found, so presumably this is a constant
matrix = SkString(base->sampleUsage().fExpression);
}
if (!transformExpression.isEmpty()) {
transformExpression.append(" * ");
}
transformExpression.appendf("(%s)", matrix.c_str());
transformExpression.appendf("(%s)", uniform.getName().c_str());
} else {
// This intermediate FP is just a pass through and doesn't need to be built
// in to the expression, but must visit its parents in case they add transforms

View File

@ -7,24 +7,7 @@
#include "include/private/SkSLSampleUsage.h"
#include "src/sksl/ir/SkSLBinaryExpression.h"
#include "src/sksl/ir/SkSLConstructor.h"
#include "src/sksl/ir/SkSLDoStatement.h"
#include "src/sksl/ir/SkSLExpression.h"
#include "src/sksl/ir/SkSLExpressionStatement.h"
#include "src/sksl/ir/SkSLFieldAccess.h"
#include "src/sksl/ir/SkSLForStatement.h"
#include "src/sksl/ir/SkSLFunctionCall.h"
#include "src/sksl/ir/SkSLIfStatement.h"
#include "src/sksl/ir/SkSLIndexExpression.h"
#include "src/sksl/ir/SkSLPostfixExpression.h"
#include "src/sksl/ir/SkSLPrefixExpression.h"
#include "src/sksl/ir/SkSLProgram.h"
#include "src/sksl/ir/SkSLReturnStatement.h"
#include "src/sksl/ir/SkSLSwitchStatement.h"
#include "src/sksl/ir/SkSLSwizzle.h"
#include "src/sksl/ir/SkSLTernaryExpression.h"
#include "src/sksl/ir/SkSLVariable.h"
#include <algorithm>
namespace SkSL {