Specialize scale+translate transforms for explicitly sampled FPs.

This is to support using YUV->RGB in more places where we would incur a
full 3x3 matrix multiply for each plane in the fragment shader without
this.

Change-Id: I27c2a403429c36662eba91f61b08e5331ec678b5
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/278356
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2020-03-20 21:06:41 -04:00 committed by Skia Commit-Bot
parent 973236fcd4
commit 8d1dcd7d98
7 changed files with 115 additions and 100 deletions

View File

@ -62,12 +62,10 @@ public:
FPCoordTransformHandler* transformHandler) { FPCoordTransformHandler* transformHandler) {
for (int i = 0; *transformHandler; ++*transformHandler, ++i) { for (int i = 0; *transformHandler; ++*transformHandler, ++i) {
auto [coordTransform, fp] = transformHandler->get(); auto [coordTransform, fp] = transformHandler->get();
GrSLType varyingType =
coordTransform.matrix().hasPerspective() ? kHalf3_GrSLType : kHalf2_GrSLType;
SkString matrix; SkString matrix;
UniformHandle uniformHandle;
GrShaderVar fragmentVar; GrShaderVar fragmentVar;
GrShaderVar transformVar;
if (fp.isSampledWithExplicitCoords()) { if (fp.isSampledWithExplicitCoords()) {
if (coordTransform.isNoOp()) { if (coordTransform.isNoOp()) {
transformHandler->omitCoordsForCurrCoordTransform(); transformHandler->omitCoordsForCurrCoordTransform();
@ -76,19 +74,25 @@ public:
const char* name; const char* name;
SkString strUniName; SkString strUniName;
strUniName.printf("CoordTransformMatrix_%d", i); strUniName.printf("CoordTransformMatrix_%d", i);
fUniformTransform.push_back().fHandle = auto& uni = fUniformTransform.push_back();
uniformHandler if (coordTransform.matrix().isScaleTranslate()) {
->addUniform(kFragment_GrShaderFlag, uni.fType = kFloat4_GrSLType;
kFloat3x3_GrSLType, } else {
strUniName.c_str(), uni.fType = kFloat3x3_GrSLType;
&name) }
.toIndex(); uni.fHandle = uniformHandler
uniformHandle = fUniformTransform.back().fHandle; ->addUniform(kFragment_GrShaderFlag,
matrix = name; uni.fType,
strUniName.c_str(),
&name)
.toIndex();
transformVar = uniformHandler->getUniformVariable(uni.fHandle);
} }
} else { } else {
SkString strVaryingName; SkString strVaryingName;
strVaryingName.printf("TransformedCoord_%d", i); strVaryingName.printf("TransformedCoord_%d", i);
GrSLType varyingType = coordTransform.matrix().hasPerspective() ? kHalf3_GrSLType
: kHalf2_GrSLType;
GrGLSLVarying v(varyingType); GrGLSLVarying v(varyingType);
#ifdef SK_GL #ifdef SK_GL
GrGLVaryingHandler* glVaryingHandler = (GrGLVaryingHandler*)varyingHandler; GrGLVaryingHandler* glVaryingHandler = (GrGLVaryingHandler*)varyingHandler;
@ -100,8 +104,7 @@ public:
matrix = matrix_to_sksl(coordTransform.matrix()); matrix = matrix_to_sksl(coordTransform.matrix());
fragmentVar = {SkString(v.fsIn()), varyingType}; fragmentVar = {SkString(v.fsIn()), varyingType};
} }
transformHandler->specifyCoordsForCurrCoordTransform(matrix, uniformHandle, transformHandler->specifyCoordsForCurrCoordTransform(transformVar, fragmentVar);
fragmentVar);
} }
} }
@ -124,7 +127,14 @@ public:
SkMatrix m = GetTransformMatrix(transform, SkMatrix::I()); SkMatrix m = GetTransformMatrix(transform, SkMatrix::I());
if (!SkMatrixPriv::CheapEqual(fUniformTransform[u].fCurrentValue, m)) { if (!SkMatrixPriv::CheapEqual(fUniformTransform[u].fCurrentValue, m)) {
fUniformTransform[u].fCurrentValue = m; fUniformTransform[u].fCurrentValue = m;
pd.setSkMatrix(fUniformTransform[u].fHandle.toIndex(), m); if (fUniformTransform[u].fType == kFloat4_GrSLType) {
float values[4] = {m.getScaleX(), m.getTranslateX(),
m.getScaleY(), m.getTranslateY()};
pd.set4fv(fUniformTransform[u].fHandle.toIndex(), 1, values);
} else {
SkASSERT(fUniformTransform[u].fType == kFloat3x3_GrSLType);
pd.setSkMatrix(fUniformTransform[u].fHandle.toIndex(), m);
}
} }
} }
++u; ++u;
@ -159,6 +169,7 @@ private:
struct TransformUniform { struct TransformUniform {
UniformHandle fHandle; UniformHandle fHandle;
SkMatrix fCurrentValue = SkMatrix::InvalidMatrix(); SkMatrix fCurrentValue = SkMatrix::InvalidMatrix();
GrSLType fType = kVoid_GrSLType;
}; };
SkTArray<TransformVarying, true> fVaryingTransform; SkTArray<TransformVarying, true> fVaryingTransform;

View File

@ -11,12 +11,15 @@
#include "src/gpu/GrFragmentProcessor.h" #include "src/gpu/GrFragmentProcessor.h"
/** /**
* We specialize the vertex code for each of these matrix types. * We specialize the vertex or fragment coord transform code for these matrix types.
* Some specializations are only applied when the coord transform is applied in the fragment
* shader.
*/ */
enum MatrixType { enum MatrixType {
kNone_MatrixType = 0, kNone_MatrixType = 0, // Used only in FS for explicitly sampled FPs
kNoPersp_MatrixType = 1, kScaleTranslate_MatrixType = 1, // Used only in FS for explicitly sampled FPs
kGeneral_MatrixType = 2, kNoPersp_MatrixType = 2,
kGeneral_MatrixType = 3,
}; };
GrPrimitiveProcessor::GrPrimitiveProcessor(ClassID classID) : GrProcessor(classID) {} GrPrimitiveProcessor::GrPrimitiveProcessor(ClassID classID) : GrProcessor(classID) {}
@ -35,13 +38,15 @@ uint32_t GrPrimitiveProcessor::computeCoordTransformsKey(const GrFragmentProcess
const GrCoordTransform& coordTransform = fp.coordTransform(t); const GrCoordTransform& coordTransform = fp.coordTransform(t);
if (fp.isSampledWithExplicitCoords() && coordTransform.isNoOp()) { if (fp.isSampledWithExplicitCoords() && coordTransform.isNoOp()) {
key = kNone_MatrixType; key = kNone_MatrixType;
} else if (coordTransform.matrix().hasPerspective()) { } else if (fp.isSampledWithExplicitCoords() && coordTransform.matrix().isScaleTranslate()) {
key = kScaleTranslate_MatrixType;
} else if (!coordTransform.matrix().hasPerspective()) {
key = kNoPersp_MatrixType;
} else {
// Note that we can also have homogeneous varyings as a result of a GP local matrix or // Note that we can also have homogeneous varyings as a result of a GP local matrix or
// homogeneous local coords generated by GP. We're relying on the GP to include any // homogeneous local coords generated by GP. We're relying on the GP to include any
// variability in those in its key. // variability in those in its key.
key = kGeneral_MatrixType; key = kGeneral_MatrixType;
} else {
key = kNoPersp_MatrixType;
} }
key <<= 2*t; key <<= 2*t;
SkASSERT(0 == (totalKey & key)); // keys for each transform ought not to overlap SkASSERT(0 == (totalKey & key)); // keys for each transform ought not to overlap

View File

@ -29,7 +29,7 @@ public:
}; };
/** /**
* Values for array count that have special meaning. We allow 1-sized arrays.git * Values for array count that have special meaning. We allow 1-sized arrays.
*/ */
enum { enum {
kNonArray = 0, // not an array kNonArray = 0, // not an array
@ -37,63 +37,50 @@ public:
}; };
/** /**
* Defaults to a non-arry half with no type modifier or layout qualifier. * Defaults to a void with no type modifier or layout qualifier.
*/ */
GrShaderVar() GrShaderVar()
: fType(kHalf_GrSLType) : fType(kVoid_GrSLType)
, fTypeModifier(kNone_TypeModifier) , fTypeModifier(kNone_TypeModifier)
, fCount(kNonArray) , fCount(kNonArray)
, fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) { , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) {}
}
GrShaderVar(const SkString& name, GrSLType type, int arrayCount = kNonArray) GrShaderVar(const SkString& name, GrSLType type, int arrayCount = kNonArray)
: fType(type) : fType(type)
, fTypeModifier(kNone_TypeModifier) , fTypeModifier(kNone_TypeModifier)
, fCount(arrayCount) , fCount(arrayCount)
, fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS)
, fName(name) { , fName(name) {}
SkASSERT(kVoid_GrSLType != type);
fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS;
}
GrShaderVar(const char* name, GrSLType type, int arrayCount = kNonArray) GrShaderVar(const char* name, GrSLType type, int arrayCount = kNonArray)
: fType(type) : fType(type)
, fTypeModifier(kNone_TypeModifier) , fTypeModifier(kNone_TypeModifier)
, fCount(arrayCount) , fCount(arrayCount)
, fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS)
, fName(name) { , fName(name) {}
SkASSERT(kVoid_GrSLType != type);
fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS;
}
GrShaderVar(const char* name, GrSLType type, TypeModifier typeModifier) GrShaderVar(const char* name, GrSLType type, TypeModifier typeModifier)
: fType(type) : fType(type)
, fTypeModifier(typeModifier) , fTypeModifier(typeModifier)
, fCount(kNonArray) , fCount(kNonArray)
, fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS)
, fName(name) { , fName(name) {}
SkASSERT(kVoid_GrSLType != type);
}
GrShaderVar(const char* name, GrSLType type, TypeModifier typeModifier, int arrayCount) GrShaderVar(const char* name, GrSLType type, TypeModifier typeModifier, int arrayCount)
: fType(type) : fType(type)
, fTypeModifier(typeModifier) , fTypeModifier(typeModifier)
, fCount(arrayCount) , fCount(arrayCount)
, fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS)
, fName(name) { , fName(name) {}
SkASSERT(kVoid_GrSLType != type);
}
GrShaderVar(const GrShaderVar& that) GrShaderVar(const GrShaderVar& that)
: fType(that.fType) : fType(that.fType)
, fTypeModifier(that.fTypeModifier) , fTypeModifier(that.fTypeModifier)
, fCount(that.fCount) , fCount(that.fCount)
, fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS)
, fName(that.fName) , fName(that.fName)
, fLayoutQualifier(that.fLayoutQualifier) , fLayoutQualifier(that.fLayoutQualifier)
, fExtraModifiers(that.fExtraModifiers) { , fExtraModifiers(that.fExtraModifiers) {}
SkASSERT(kVoid_GrSLType != that.getType());
}
/** /**
* Sets as a non-array. * Sets as a non-array.

View File

@ -166,9 +166,18 @@ SkString GrGLSLFPFragmentBuilder::writeProcessorFunction(GrGLSLFragmentProcessor
if (args.fFp.isSampledWithExplicitCoords() && args.fTransformedCoords.count() > 0) { if (args.fFp.isSampledWithExplicitCoords() && args.fTransformedCoords.count() > 0) {
// we currently only support overriding a single coordinate pair // we currently only support overriding a single coordinate pair
SkASSERT(args.fTransformedCoords.count() == 1); SkASSERT(args.fTransformedCoords.count() == 1);
if (args.fTransformedCoords[0].fUniformMatrix.isValid()) { const GrShaderVar& transform = args.fTransformedCoords[0].fTransform;
this->codeAppendf("_coords = (%s * float3(_coords, 1)).xy;\n", switch (transform.getType()) {
args.fTransformedCoords[0].fMatrixCode.c_str()); case kFloat4_GrSLType:
this->codeAppendf("_coords = _coords * %s.xz + %s.yw;\n", transform.c_str(),
transform.c_str());
break;
case kFloat3x3_GrSLType:
this->codeAppendf("_coords = (%s * float3(_coords, 1)).xy;\n", transform.c_str());
break;
default:
SkASSERT(transform.getType() == kVoid_GrSLType);
break;
} }
} }
this->codeAppendf("half4 %s;\n", args.fOutputColor); this->codeAppendf("half4 %s;\n", args.fOutputColor);

View File

@ -80,6 +80,7 @@ void GrGLSLGeometryProcessor::emitTransforms(GrGLSLVertexBuilder* vb,
return std::make_tuple(localCoords, localCoordLength); return std::make_tuple(localCoords, localCoordLength);
}; };
GrShaderVar transformVar;
for (int i = 0; *handler; ++*handler, ++i) { for (int i = 0; *handler; ++*handler, ++i) {
auto [coordTransform, fp] = handler->get(); auto [coordTransform, fp] = handler->get();
// Add uniform for coord transform matrix. // Add uniform for coord transform matrix.
@ -89,10 +90,16 @@ void GrGLSLGeometryProcessor::emitTransforms(GrGLSLVertexBuilder* vb,
strUniName.printf("CoordTransformMatrix_%d", i); strUniName.printf("CoordTransformMatrix_%d", i);
auto flag = fp.isSampledWithExplicitCoords() ? kFragment_GrShaderFlag auto flag = fp.isSampledWithExplicitCoords() ? kFragment_GrShaderFlag
: kVertex_GrShaderFlag; : kVertex_GrShaderFlag;
fInstalledTransforms.push_back().fHandle = auto& uni = fInstalledTransforms.push_back();
uniformHandler if (fp.isSampledWithExplicitCoords() && coordTransform.matrix().isScaleTranslate() &&
->addUniform(flag, kFloat3x3_GrSLType, strUniName.c_str(), &matrixName) localMatrix.isScaleTranslate()) {
.toIndex(); uni.fType = kFloat4_GrSLType;
} else {
uni.fType = kFloat3x3_GrSLType;
}
uni.fHandle =
uniformHandler->addUniform(flag, uni.fType, strUniName.c_str(), &matrixName);
transformVar = uniformHandler->getUniformVariable(uni.fHandle);
} else { } else {
// Install a coord transform that will be skipped. // Install a coord transform that will be skipped.
fInstalledTransforms.push_back(); fInstalledTransforms.push_back();
@ -100,6 +107,7 @@ void GrGLSLGeometryProcessor::emitTransforms(GrGLSLVertexBuilder* vb,
continue; continue;
} }
GrShaderVar fsVar;
// Add varying if required and register varying and matrix uniform. // Add varying if required and register varying and matrix uniform.
if (!fp.isSampledWithExplicitCoords()) { if (!fp.isSampledWithExplicitCoords()) {
auto [localCoordsStr, localCoordLength] = getLocalCoords(); auto [localCoordsStr, localCoordLength] = getLocalCoords();
@ -112,19 +120,16 @@ void GrGLSLGeometryProcessor::emitTransforms(GrGLSLVertexBuilder* vb,
strVaryingName.printf("TransformedCoords_%d", i); strVaryingName.printf("TransformedCoords_%d", i);
varyingHandler->addVarying(strVaryingName.c_str(), &v); varyingHandler->addVarying(strVaryingName.c_str(), &v);
SkASSERT(fInstalledTransforms.back().fType == kFloat3x3_GrSLType);
if (v.type() == kFloat2_GrSLType) { if (v.type() == kFloat2_GrSLType) {
vb->codeAppendf("%s = (%s * %s).xy;", v.vsOut(), matrixName, vb->codeAppendf("%s = (%s * %s).xy;", v.vsOut(), matrixName,
localCoordsStr.c_str()); localCoordsStr.c_str());
} else { } else {
vb->codeAppendf("%s = %s * %s;", v.vsOut(), matrixName, localCoordsStr.c_str()); vb->codeAppendf("%s = %s * %s;", v.vsOut(), matrixName, localCoordsStr.c_str());
} }
GrShaderVar fsVar(SkString(v.fsIn()), v.type(), GrShaderVar::kIn_TypeModifier); fsVar = GrShaderVar(SkString(v.fsIn()), v.type(), GrShaderVar::kIn_TypeModifier);
handler->specifyCoordsForCurrCoordTransform(SkString(matrixName),
fInstalledTransforms.back().fHandle, fsVar);
} else {
handler->specifyCoordsForCurrCoordTransform(SkString(matrixName),
fInstalledTransforms.back().fHandle);
} }
handler->specifyCoordsForCurrCoordTransform(transformVar, fsVar);
} }
} }
@ -141,7 +146,14 @@ void GrGLSLGeometryProcessor::setTransformDataHelper(const SkMatrix& localMatrix
m = GetTransformMatrix(transform, localMatrix); m = GetTransformMatrix(transform, localMatrix);
} }
if (!SkMatrixPriv::CheapEqual(fInstalledTransforms[i].fCurrentValue, m)) { if (!SkMatrixPriv::CheapEqual(fInstalledTransforms[i].fCurrentValue, m)) {
pdman.setSkMatrix(fInstalledTransforms[i].fHandle.toIndex(), m); if (fInstalledTransforms[i].fType == kFloat4_GrSLType) {
float values[4] = {m.getScaleX(), m.getTranslateX(),
m.getScaleY(), m.getTranslateY()};
pdman.set4fv(fInstalledTransforms[i].fHandle.toIndex(), 1, values);
} else {
SkASSERT(fInstalledTransforms[i].fType == kFloat3x3_GrSLType);
pdman.setSkMatrix(fInstalledTransforms[i].fHandle.toIndex(), m);
}
fInstalledTransforms[i].fCurrentValue = m; fInstalledTransforms[i].fCurrentValue = m;
} }
} }

View File

@ -84,6 +84,7 @@ private:
struct TransformUniform { struct TransformUniform {
UniformHandle fHandle; UniformHandle fHandle;
GrSLType fType = kVoid_GrSLType;
SkMatrix fCurrentValue = SkMatrix::InvalidMatrix(); SkMatrix fCurrentValue = SkMatrix::InvalidMatrix();
}; };

View File

@ -28,21 +28,12 @@ public:
using CoordTransformRange = GrFragmentProcessor::PipelineCoordTransformRange; using CoordTransformRange = GrFragmentProcessor::PipelineCoordTransformRange;
struct TransformVar { struct TransformVar {
TransformVar() = default; // The transform as a variable. This may be a kFloat3x3 matrix or a kFloat4 representing
// {scaleX, transX, scaleY, transY}. For explicitly sampled FPs this is visible in the
TransformVar(SkString matrixCode, // FS. This is not available for NV_path_rendering with non-explicitly sampled FPs.
UniformHandle uniformMatrix, GrShaderVar fTransform;
GrShaderVar varyingPoint = {}) // The transformed coordinate output by the vertex shader and consumed by the fragment
: fMatrixCode(std::move(matrixCode)) // shader. Only valid for non-explicitly sampled FPs.
, fUniformMatrix(uniformMatrix)
, fVaryingPoint(varyingPoint) {}
// a string of SkSL code which resolves to the transformation matrix
SkString fMatrixCode;
// the variable containing the matrix, if any, otherwise an invalid handle
UniformHandle fUniformMatrix;
// the transformed coordinate output by the vertex shader and consumed by the fragment
// shader
GrShaderVar fVaryingPoint; GrShaderVar fVaryingPoint;
}; };
@ -69,10 +60,9 @@ public:
FPCoordTransformHandler& operator++(); FPCoordTransformHandler& operator++();
// 'args' are constructor params to GrShaderVar. // 'args' are constructor params to GrShaderVar.
template<typename... Args> void specifyCoordsForCurrCoordTransform(GrShaderVar transformVar, GrShaderVar varyingVar) {
void specifyCoordsForCurrCoordTransform(Args&&... args) {
SkASSERT(!fAddedCoord); SkASSERT(!fAddedCoord);
fTransformedCoordVars->emplace_back(std::forward<Args>(args)...); fTransformedCoordVars->push_back({transformVar, varyingVar});
SkDEBUGCODE(fAddedCoord = true;) SkDEBUGCODE(fAddedCoord = true;)
} }