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

View File

@ -11,12 +11,15 @@
#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 {
kNone_MatrixType = 0,
kNoPersp_MatrixType = 1,
kGeneral_MatrixType = 2,
kNone_MatrixType = 0, // Used only in FS for explicitly sampled FPs
kScaleTranslate_MatrixType = 1, // Used only in FS for explicitly sampled FPs
kNoPersp_MatrixType = 2,
kGeneral_MatrixType = 3,
};
GrPrimitiveProcessor::GrPrimitiveProcessor(ClassID classID) : GrProcessor(classID) {}
@ -35,13 +38,15 @@ uint32_t GrPrimitiveProcessor::computeCoordTransformsKey(const GrFragmentProcess
const GrCoordTransform& coordTransform = fp.coordTransform(t);
if (fp.isSampledWithExplicitCoords() && coordTransform.isNoOp()) {
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
// homogeneous local coords generated by GP. We're relying on the GP to include any
// variability in those in its key.
key = kGeneral_MatrixType;
} else {
key = kNoPersp_MatrixType;
}
key <<= 2*t;
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 {
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()
: fType(kHalf_GrSLType)
, fTypeModifier(kNone_TypeModifier)
, fCount(kNonArray)
, fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) {
}
: fType(kVoid_GrSLType)
, fTypeModifier(kNone_TypeModifier)
, fCount(kNonArray)
, fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) {}
GrShaderVar(const SkString& name, GrSLType type, int arrayCount = kNonArray)
: fType(type)
, fTypeModifier(kNone_TypeModifier)
, fCount(arrayCount)
, fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS)
, fName(name) {
SkASSERT(kVoid_GrSLType != type);
fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS;
}
: fType(type)
, fTypeModifier(kNone_TypeModifier)
, fCount(arrayCount)
, fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS)
, fName(name) {}
GrShaderVar(const char* name, GrSLType type, int arrayCount = kNonArray)
: fType(type)
, fTypeModifier(kNone_TypeModifier)
, fCount(arrayCount)
, fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS)
, fName(name) {
SkASSERT(kVoid_GrSLType != type);
fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS;
}
: fType(type)
, fTypeModifier(kNone_TypeModifier)
, fCount(arrayCount)
, fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS)
, fName(name) {}
GrShaderVar(const char* name, GrSLType type, TypeModifier typeModifier)
: fType(type)
, fTypeModifier(typeModifier)
, fCount(kNonArray)
, fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS)
, fName(name) {
SkASSERT(kVoid_GrSLType != type);
}
: fType(type)
, fTypeModifier(typeModifier)
, fCount(kNonArray)
, fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS)
, fName(name) {}
GrShaderVar(const char* name, GrSLType type, TypeModifier typeModifier, int arrayCount)
: fType(type)
, fTypeModifier(typeModifier)
, fCount(arrayCount)
, fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS)
, fName(name) {
SkASSERT(kVoid_GrSLType != type);
}
: fType(type)
, fTypeModifier(typeModifier)
, fCount(arrayCount)
, fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS)
, fName(name) {}
GrShaderVar(const GrShaderVar& that)
: fType(that.fType)
, fTypeModifier(that.fTypeModifier)
, fCount(that.fCount)
, fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS)
, fName(that.fName)
, fLayoutQualifier(that.fLayoutQualifier)
, fExtraModifiers(that.fExtraModifiers) {
SkASSERT(kVoid_GrSLType != that.getType());
}
: fType(that.fType)
, fTypeModifier(that.fTypeModifier)
, fCount(that.fCount)
, fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS)
, fName(that.fName)
, fLayoutQualifier(that.fLayoutQualifier)
, fExtraModifiers(that.fExtraModifiers) {}
/**
* Sets as a non-array.

View File

@ -166,9 +166,18 @@ SkString GrGLSLFPFragmentBuilder::writeProcessorFunction(GrGLSLFragmentProcessor
if (args.fFp.isSampledWithExplicitCoords() && args.fTransformedCoords.count() > 0) {
// we currently only support overriding a single coordinate pair
SkASSERT(args.fTransformedCoords.count() == 1);
if (args.fTransformedCoords[0].fUniformMatrix.isValid()) {
this->codeAppendf("_coords = (%s * float3(_coords, 1)).xy;\n",
args.fTransformedCoords[0].fMatrixCode.c_str());
const GrShaderVar& transform = args.fTransformedCoords[0].fTransform;
switch (transform.getType()) {
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);

View File

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

View File

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

View File

@ -28,21 +28,12 @@ public:
using CoordTransformRange = GrFragmentProcessor::PipelineCoordTransformRange;
struct TransformVar {
TransformVar() = default;
TransformVar(SkString matrixCode,
UniformHandle uniformMatrix,
GrShaderVar varyingPoint = {})
: fMatrixCode(std::move(matrixCode))
, 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
// 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
// FS. This is not available for NV_path_rendering with non-explicitly sampled FPs.
GrShaderVar fTransform;
// The transformed coordinate output by the vertex shader and consumed by the fragment
// shader. Only valid for non-explicitly sampled FPs.
GrShaderVar fVaryingPoint;
};
@ -69,10 +60,9 @@ public:
FPCoordTransformHandler& operator++();
// 'args' are constructor params to GrShaderVar.
template<typename... Args>
void specifyCoordsForCurrCoordTransform(Args&&... args) {
void specifyCoordsForCurrCoordTransform(GrShaderVar transformVar, GrShaderVar varyingVar) {
SkASSERT(!fAddedCoord);
fTransformedCoordVars->emplace_back(std::forward<Args>(args)...);
fTransformedCoordVars->push_back({transformVar, varyingVar});
SkDEBUGCODE(fAddedCoord = true;)
}