Use noperspective interpolation for 2D draws
Adds a mechanism to notify GrGLSLVaryingHandler that a shader will not
emit geometry in perspective. This gives it a chance to use the
noperspective keyword if it is supported.
Updates the existing processors to notify the varying handler when
there is no perspective.
Begins using the noperspective keyword in GrGLGpu internal shaders.
Web scenes with observable benefit (Pixel C, gpu config):
tabl_nofolo.skp 4.62 -> 3.33 ms 28%
desk_tigersvg.skp 26.5 -> 24 ms 9%
desk_pokemonwiki.skp 16.1 -> 14.9 ms 7%
tabl_deviantart.skp 3.97 -> 3.7 ms 7%
desk_gws.skp 3.85 -> 3.65 ms 5%
Also adds new methods for creating varyings with flat interpolation.
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1673093002
Review URL: https://codereview.chromium.org/1673093002
diff --git a/src/gpu/GrPathProcessor.cpp b/src/gpu/GrPathProcessor.cpp
index cb33010..1d70dea 100644
--- a/src/gpu/GrPathProcessor.cpp
+++ b/src/gpu/GrPathProcessor.cpp
@@ -22,13 +22,18 @@
const GrGLSLCaps&,
GrProcessorKeyBuilder* b) {
b->add32(SkToInt(pathProc.overrides().readsColor()) |
- SkToInt(pathProc.overrides().readsCoverage()) << 16);
+ (SkToInt(pathProc.overrides().readsCoverage()) << 1) |
+ (SkToInt(pathProc.viewMatrix().hasPerspective()) << 2));
}
void emitCode(EmitArgs& args) override {
GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
const GrPathProcessor& pathProc = args.fGP.cast<GrPathProcessor>();
+ if (!pathProc.viewMatrix().hasPerspective()) {
+ args.fVaryingHandler->setNoPerspective();
+ }
+
// emit transforms
this->emitTransforms(args.fVaryingHandler, args.fTransformsIn, args.fTransformsOut);
diff --git a/src/gpu/batches/GrPLSPathRenderer.cpp b/src/gpu/batches/GrPLSPathRenderer.cpp
index b4f6ce4..faadd6d 100644
--- a/src/gpu/batches/GrPLSPathRenderer.cpp
+++ b/src/gpu/batches/GrPLSPathRenderer.cpp
@@ -328,7 +328,7 @@
delta3.vsOut(), v3.vsOut(), v1.vsOut(), v1.vsOut(), v3.vsOut());
GrGLSLVertToFrag windings(kInt_GrSLType);
- varyingHandler->addVarying("windings", &windings, kLow_GrSLPrecision);
+ varyingHandler->addFlatVarying("windings", &windings, kLow_GrSLPrecision);
vsBuilder->codeAppendf("%s = %s;",
windings.vsOut(), te.inWindings()->fName);
@@ -513,7 +513,7 @@
ep1.vsOut());
GrGLSLVertToFrag windings(kInt_GrSLType);
- varyingHandler->addVarying("windings", &windings, kLow_GrSLPrecision);
+ varyingHandler->addFlatVarying("windings", &windings, kLow_GrSLPrecision);
vsBuilder->codeAppendf("%s = %s;",
windings.vsOut(), qe.inWindings()->fName);
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 79bb22e..6dc5ee8 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -596,6 +596,24 @@
glslCaps->fBindlessTextureSupport = ctxInfo.hasExtension("GL_NV_bindless_texture");
+ if (kGL_GrGLStandard == standard) {
+ glslCaps->fFlatInterpolationSupport = ctxInfo.glslGeneration() >= k130_GrGLSLGeneration;
+ } else {
+ glslCaps->fFlatInterpolationSupport =
+ ctxInfo.glslGeneration() >= k330_GrGLSLGeneration; // This is the value for GLSL ES 3.0.
+ }
+
+ if (kGL_GrGLStandard == standard) {
+ glslCaps->fNoPerspectiveInterpolationSupport =
+ ctxInfo.glslGeneration() >= k130_GrGLSLGeneration;
+ } else {
+ if (ctxInfo.hasExtension("GL_NV_shader_noperspective_interpolation")) {
+ glslCaps->fNoPerspectiveInterpolationSupport = true;
+ glslCaps->fNoPerspectiveInterpolationExtensionString =
+ "GL_NV_shader_noperspective_interpolation";
+ }
+ }
+
// Adreno GPUs have a tendency to drop tiles when there is a divide-by-zero in a shader
glslCaps->fDropsTileOnZeroDivide = kQualcomm_GrGLVendor == ctxInfo.vendor();
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index b9a5ee9..be315da 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -285,7 +285,8 @@
}
void GrGLGpu::createPLSSetupProgram() {
- const char* version = this->glCaps().glslCaps()->versionDeclString();
+ const GrGLSLCaps* glslCaps = this->glCaps().glslCaps();
+ const char* version = glslCaps->versionDeclString();
GrGLSLShaderVar aVertex("a_vertex", kVec2f_GrSLType, GrShaderVar::kAttribute_TypeModifier);
GrGLSLShaderVar uTexCoordXform("u_texCoordXform", kVec4f_GrSLType,
@@ -295,13 +296,19 @@
GrGLSLShaderVar vTexCoord("v_texCoord", kVec2f_GrSLType, GrShaderVar::kVaryingOut_TypeModifier);
SkString vshaderTxt(version);
- aVertex.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
+ if (glslCaps->noperspectiveInterpolationSupport()) {
+ if (const char* extension = glslCaps->noperspectiveInterpolationExtensionString()) {
+ vshaderTxt.appendf("#extension %s : require\n", extension);
+ }
+ vTexCoord.addModifier("noperspective");
+ }
+ aVertex.appendDecl(glslCaps, &vshaderTxt);
vshaderTxt.append(";");
- uTexCoordXform.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
+ uTexCoordXform.appendDecl(glslCaps, &vshaderTxt);
vshaderTxt.append(";");
- uPosXform.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
+ uPosXform.appendDecl(glslCaps, &vshaderTxt);
vshaderTxt.append(";");
- vTexCoord.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
+ vTexCoord.appendDecl(glslCaps, &vshaderTxt);
vshaderTxt.append(";");
vshaderTxt.append(
@@ -313,17 +320,20 @@
);
SkString fshaderTxt(version);
+ if (glslCaps->noperspectiveInterpolationSupport()) {
+ if (const char* extension = glslCaps->noperspectiveInterpolationExtensionString()) {
+ fshaderTxt.appendf("#extension %s : require\n", extension);
+ }
+ }
fshaderTxt.append("#extension ");
- fshaderTxt.append(this->glCaps().glslCaps()->fbFetchExtensionString());
+ fshaderTxt.append(glslCaps->fbFetchExtensionString());
fshaderTxt.append(" : require\n");
fshaderTxt.append("#extension GL_EXT_shader_pixel_local_storage : require\n");
- GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision,
- *this->glCaps().glslCaps(),
- &fshaderTxt);
+ GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, *glslCaps, &fshaderTxt);
vTexCoord.setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier);
- vTexCoord.appendDecl(this->glCaps().glslCaps(), &fshaderTxt);
+ vTexCoord.appendDecl(glslCaps, &fshaderTxt);
fshaderTxt.append(";");
- uTexture.appendDecl(this->glCaps().glslCaps(), &fshaderTxt);
+ uTexture.appendDecl(glslCaps, &fshaderTxt);
fshaderTxt.append(";");
fshaderTxt.appendf(
@@ -3300,7 +3310,8 @@
for (size_t i = 0; i < SK_ARRAY_COUNT(fCopyPrograms); ++i) {
fCopyPrograms[i].fProgram = 0;
}
- const char* version = this->glCaps().glslCaps()->versionDeclString();
+ const GrGLSLCaps* glslCaps = this->glCaps().glslCaps();
+ const char* version = glslCaps->versionDeclString();
static const GrSLType kSamplerTypes[3] = { kSampler2D_GrSLType, kSamplerExternal_GrSLType,
kSampler2DRect_GrSLType };
SkASSERT(3 == SK_ARRAY_COUNT(fCopyPrograms));
@@ -3326,13 +3337,20 @@
GrShaderVar::kOut_TypeModifier);
SkString vshaderTxt(version);
- aVertex.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
+ if (glslCaps->noperspectiveInterpolationSupport()) {
+ if (const char* extension = glslCaps->noperspectiveInterpolationExtensionString()) {
+ vshaderTxt.appendf("#extension %s : require\n", extension);
+ }
+ vTexCoord.addModifier("noperspective");
+ }
+
+ aVertex.appendDecl(glslCaps, &vshaderTxt);
vshaderTxt.append(";");
- uTexCoordXform.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
+ uTexCoordXform.appendDecl(glslCaps, &vshaderTxt);
vshaderTxt.append(";");
- uPosXform.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
+ uPosXform.appendDecl(glslCaps, &vshaderTxt);
vshaderTxt.append(";");
- vTexCoord.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
+ vTexCoord.appendDecl(glslCaps, &vshaderTxt);
vshaderTxt.append(";");
vshaderTxt.append(
@@ -3345,21 +3363,25 @@
);
SkString fshaderTxt(version);
+ if (glslCaps->noperspectiveInterpolationSupport()) {
+ if (const char* extension = glslCaps->noperspectiveInterpolationExtensionString()) {
+ fshaderTxt.appendf("#extension %s : require\n", extension);
+ }
+ }
if (kSamplerTypes[i] == kSamplerExternal_GrSLType) {
fshaderTxt.appendf("#extension %s : require\n",
- this->glCaps().glslCaps()->externalTextureExtensionString());
+ glslCaps->externalTextureExtensionString());
}
- GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision,
- *this->glCaps().glslCaps(),
+ GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, *glslCaps,
&fshaderTxt);
vTexCoord.setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier);
- vTexCoord.appendDecl(this->glCaps().glslCaps(), &fshaderTxt);
+ vTexCoord.appendDecl(glslCaps, &fshaderTxt);
fshaderTxt.append(";");
- uTexture.appendDecl(this->glCaps().glslCaps(), &fshaderTxt);
+ uTexture.appendDecl(glslCaps, &fshaderTxt);
fshaderTxt.append(";");
const char* fsOutName;
- if (this->glCaps().glslCaps()->mustDeclareFragmentShaderOutput()) {
- oFragColor.appendDecl(this->glCaps().glslCaps(), &fshaderTxt);
+ if (glslCaps->mustDeclareFragmentShaderOutput()) {
+ oFragColor.appendDecl(glslCaps, &fshaderTxt);
fshaderTxt.append(";");
fsOutName = oFragColor.c_str();
} else {
diff --git a/src/gpu/gl/GrGLVaryingHandler.cpp b/src/gpu/gl/GrGLVaryingHandler.cpp
index b27a996..a2d4e9d 100644
--- a/src/gpu/gl/GrGLVaryingHandler.cpp
+++ b/src/gpu/gl/GrGLVaryingHandler.cpp
@@ -24,8 +24,14 @@
glPB->fArgs.fPrimitiveProcessor->numAttribs() == 0);
#endif
this->addVarying(name, v, fsPrecision);
- VaryingInfo& varyingInfo = fPathProcVaryingInfos.push_back();
- varyingInfo.fVariable = fFragInputs.back();
+ auto varyingInfo = fPathProcVaryingInfos.push_back();
varyingInfo.fLocation = fPathProcVaryingInfos.count() - 1;
return VaryingHandle(varyingInfo.fLocation);
}
+
+void GrGLVaryingHandler::onFinalize() {
+ SkASSERT(fPathProcVaryingInfos.empty() || fPathProcVaryingInfos.count() == fFragInputs.count());
+ for (int i = 0; i < fPathProcVaryingInfos.count(); ++i) {
+ fPathProcVaryingInfos[i].fVariable = fFragInputs[i];
+ }
+}
diff --git a/src/gpu/gl/GrGLVaryingHandler.h b/src/gpu/gl/GrGLVaryingHandler.h
index fe8c3dc..c4e5ba4 100644
--- a/src/gpu/gl/GrGLVaryingHandler.h
+++ b/src/gpu/gl/GrGLVaryingHandler.h
@@ -24,12 +24,9 @@
GrSLPrecision fsPrecision = kDefault_GrSLPrecision);
private:
- void onFinalize() override {}
+ void onFinalize() override;
- typedef GrGLProgramDataManager::VaryingInfo VaryingInfo;
- typedef GrGLProgramDataManager::VaryingInfoArray VaryingInfoArray;
-
- VaryingInfoArray fPathProcVaryingInfos;
+ GrGLProgramDataManager::VaryingInfoArray fPathProcVaryingInfos;
friend class GrGLProgramBuilder;
diff --git a/src/gpu/glsl/GrGLSLCaps.cpp b/src/gpu/glsl/GrGLSLCaps.cpp
index c82d833..ba99be5 100755
--- a/src/gpu/glsl/GrGLSLCaps.cpp
+++ b/src/gpu/glsl/GrGLSLCaps.cpp
@@ -23,11 +23,14 @@
fCanUseAnyFunctionInShader = true;
fCanUseMinAndAbsTogether = true;
fMustForceNegatedAtanParamToFloat = false;
+ fFlatInterpolationSupport = false;
+ fNoPerspectiveInterpolationSupport = false;
fVersionDeclString = nullptr;
fShaderDerivativeExtensionString = nullptr;
fFragCoordConventionsExtensionString = nullptr;
fSecondaryOutputExtensionString = nullptr;
fExternalTextureExtensionString = nullptr;
+ fNoPerspectiveInterpolationExtensionString = nullptr;
fFBFetchColorName = nullptr;
fFBFetchExtensionString = nullptr;
fAdvBlendEqInteraction = kNotSupported_AdvBlendEqInteraction;
@@ -58,6 +61,9 @@
r.appendf("Can use min() and abs() together: %s\n", (fCanUseMinAndAbsTogether ? "YES" : "NO"));
r.appendf("Must force negated atan param to float: %s\n", (fMustForceNegatedAtanParamToFloat ?
"YES" : "NO"));
+ r.appendf("Flat interpolation support: %s\n", (fFlatInterpolationSupport ? "YES" : "NO"));
+ r.appendf("No perspective interpolation support: %s\n", (fNoPerspectiveInterpolationSupport ?
+ "YES" : "NO"));
r.appendf("Advanced blend equation interaction: %s\n",
kAdvBlendEqInteractionStr[fAdvBlendEqInteraction]);
return r;
diff --git a/src/gpu/glsl/GrGLSLCaps.h b/src/gpu/glsl/GrGLSLCaps.h
index 0605396..2f87f66 100755
--- a/src/gpu/glsl/GrGLSLCaps.h
+++ b/src/gpu/glsl/GrGLSLCaps.h
@@ -54,6 +54,10 @@
bool dropsTileOnZeroDivide() const { return fDropsTileOnZeroDivide; }
+ bool flatInterpolationSupport() const { return fFlatInterpolationSupport; }
+
+ bool noperspectiveInterpolationSupport() const { return fNoPerspectiveInterpolationSupport; }
+
AdvBlendEqInteraction advBlendEqInteraction() const { return fAdvBlendEqInteraction; }
bool mustEnableAdvBlendEqs() const {
@@ -105,6 +109,11 @@
return fExternalTextureExtensionString;
}
+ const char* noperspectiveInterpolationExtensionString() const {
+ SkASSERT(this->noperspectiveInterpolationSupport());
+ return fNoPerspectiveInterpolationExtensionString;
+ }
+
/**
* Given a texture's config, this determines what swizzle must be appended to accesses to the
* texture in generated shader code. Swizzling may be implemented in texture parameters or a
@@ -137,6 +146,8 @@
bool fBindlessTextureSupport : 1;
bool fUsesPrecisionModifiers : 1;
bool fCanUseAnyFunctionInShader : 1;
+ bool fFlatInterpolationSupport : 1;
+ bool fNoPerspectiveInterpolationSupport : 1;
// Used for specific driver bug work arounds
bool fCanUseMinAndAbsTogether : 1;
@@ -148,6 +159,7 @@
const char* fFragCoordConventionsExtensionString;
const char* fSecondaryOutputExtensionString;
const char* fExternalTextureExtensionString;
+ const char* fNoPerspectiveInterpolationExtensionString;
const char* fFBFetchColorName;
const char* fFBFetchExtensionString;
diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
index 7ec18a2..8651827 100644
--- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
@@ -176,7 +176,7 @@
const GrGLSLCaps* glslCaps = fProgramBuilder->glslCaps();
if (glslCaps->fbFetchSupport()) {
- this->addFeature(1 << (GrGLSLFragmentShaderBuilder::kLastGLSLPrivateFeature + 1),
+ this->addFeature(1 << kFramebufferFetch_GLSLPrivateFeature,
glslCaps->fbFetchExtensionString());
// Some versions of this extension string require declaring custom color output on ES 3.0+
diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
index e998458..a437a19 100644
--- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
+++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
@@ -32,9 +32,8 @@
* if code is added that uses one of these features without calling enableFeature()
*/
enum GLSLFeature {
- kStandardDerivatives_GLSLFeature = 0,
- kPixelLocalStorage_GLSLFeature = 1,
- kLastGLSLFeature = kPixelLocalStorage_GLSLFeature
+ kStandardDerivatives_GLSLFeature = kLastGLSLPrivateFeature + 1,
+ kPixelLocalStorage_GLSLFeature
};
/**
@@ -168,17 +167,6 @@
void onFinalize() override;
- /**
- * Features that should only be enabled by GrGLSLFragmentShaderBuilder itself.
- */
- enum GLSLPrivateFeature {
- kFragCoordConventions_GLSLPrivateFeature = kLastGLSLFeature + 1,
- kBlendEquationAdvanced_GLSLPrivateFeature,
- kBlendFuncExtended_GLSLPrivateFeature,
- kExternalTexture_GLSLPrivateFeature,
- kLastGLSLPrivateFeature = kBlendFuncExtended_GLSLPrivateFeature
- };
-
// Interpretation of FragPosKey when generating code
enum {
kNoFragPosRead_FragPosKey = 0, // The fragment positition will not be needed.
diff --git a/src/gpu/glsl/GrGLSLGeometryProcessor.cpp b/src/gpu/glsl/GrGLSLGeometryProcessor.cpp
index b8951be..f7dba82 100644
--- a/src/gpu/glsl/GrGLSLGeometryProcessor.cpp
+++ b/src/gpu/glsl/GrGLSLGeometryProcessor.cpp
@@ -19,6 +19,9 @@
GrGPArgs gpArgs;
this->onEmitCode(args, &gpArgs);
vBuilder->transformToNormalizedDeviceSpace(gpArgs.fPositionVar);
+ if (kVec2f_GrSLType == gpArgs.fPositionVar.getType()) {
+ args.fVaryingHandler->setNoPerspective();
+ }
}
void GrGLSLGeometryProcessor::emitTransforms(GrGLSLVertexBuilder* vb,
diff --git a/src/gpu/glsl/GrGLSLShaderBuilder.h b/src/gpu/glsl/GrGLSLShaderBuilder.h
index 5c3408e..bc3b4ca 100644
--- a/src/gpu/glsl/GrGLSLShaderBuilder.h
+++ b/src/gpu/glsl/GrGLSLShaderBuilder.h
@@ -142,6 +142,19 @@
typedef GrTAllocator<GrGLSLShaderVar> VarArray;
void appendDecls(const VarArray& vars, SkString* out) const;
+ /**
+ * Features that should only be enabled internally by the builders.
+ */
+ enum GLSLPrivateFeature {
+ kFragCoordConventions_GLSLPrivateFeature,
+ kBlendEquationAdvanced_GLSLPrivateFeature,
+ kBlendFuncExtended_GLSLPrivateFeature,
+ kExternalTexture_GLSLPrivateFeature,
+ kFramebufferFetch_GLSLPrivateFeature,
+ kNoPerspectiveInterpolation_GLSLPrivateFeature,
+ kLastGLSLPrivateFeature = kNoPerspectiveInterpolation_GLSLPrivateFeature
+ };
+
/*
* A general function which enables an extension in a shader if the feature bit is not present
*/
@@ -215,6 +228,7 @@
friend class GrGLSLProgramBuilder;
friend class GrGLProgramBuilder;
+ friend class GrGLSLVaryingHandler; // to access noperspective interpolation feature.
friend class GrGLPathProgramBuilder; // to access fInputs.
friend class GrVkProgramBuilder;
};
diff --git a/src/gpu/glsl/GrGLSLShaderVar.h b/src/gpu/glsl/GrGLSLShaderVar.h
index e26a75c..bdd36f3 100644
--- a/src/gpu/glsl/GrGLSLShaderVar.h
+++ b/src/gpu/glsl/GrGLSLShaderVar.h
@@ -51,7 +51,9 @@
GrGLSLShaderVar(const GrGLSLShaderVar& var)
: GrShaderVar(var.c_str(), var.getType(), var.getTypeModifier(),
var.getArrayCount(), var.getPrecision())
- , fUseUniformFloatArrays(var.fUseUniformFloatArrays) {
+ , fUseUniformFloatArrays(var.fUseUniformFloatArrays)
+ , fLayoutQualifier(var.fLayoutQualifier)
+ , fExtraModifiers(var.fExtraModifiers) {
SkASSERT(kVoid_GrSLType != var.getType());
}
@@ -71,11 +73,15 @@
const SkString& name,
GrSLPrecision precision = kDefault_GrSLPrecision,
const char* layoutQualifier = nullptr,
+ const char* extraModifiers = nullptr,
bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
SkASSERT(kVoid_GrSLType != type);
SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsNumeric(type));
INHERITED::set(type, name, typeModifier, precision);
fLayoutQualifier = layoutQualifier;
+ if (extraModifiers) {
+ fExtraModifiers.printf("%s ", extraModifiers);
+ }
fUseUniformFloatArrays = useUniformFloatArrays;
}
@@ -87,11 +93,15 @@
const char* name,
GrSLPrecision precision = kDefault_GrSLPrecision,
const char* layoutQualifier = nullptr,
+ const char* extraModifiers = nullptr,
bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
SkASSERT(kVoid_GrSLType != type);
SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsNumeric(type));
INHERITED::set(type, name, typeModifier, precision);
fLayoutQualifier = layoutQualifier;
+ if (extraModifiers) {
+ fExtraModifiers.printf("%s ", extraModifiers);
+ }
fUseUniformFloatArrays = useUniformFloatArrays;
}
@@ -104,11 +114,15 @@
int count,
GrSLPrecision precision = kDefault_GrSLPrecision,
const char* layoutQualifier = nullptr,
+ const char* extraModifiers = nullptr,
bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
SkASSERT(kVoid_GrSLType != type);
SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsNumeric(type));
INHERITED::set(type, name, typeModifier, precision, count);
fLayoutQualifier = layoutQualifier;
+ if (extraModifiers) {
+ fExtraModifiers.printf("%s ", extraModifiers);
+ }
fUseUniformFloatArrays = useUniformFloatArrays;
}
@@ -121,11 +135,15 @@
int count,
GrSLPrecision precision = kDefault_GrSLPrecision,
const char* layoutQualifier = nullptr,
+ const char* extraModifiers = nullptr,
bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
SkASSERT(kVoid_GrSLType != type);
SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsNumeric(type));
INHERITED::set(type, name, typeModifier, precision, count);
fLayoutQualifier = layoutQualifier;
+ if (extraModifiers) {
+ fExtraModifiers.printf("%s ", extraModifiers);
+ }
fUseUniformFloatArrays = useUniformFloatArrays;
}
@@ -136,6 +154,12 @@
fLayoutQualifier = layoutQualifier;
}
+ void addModifier(const char* modifier) {
+ if (modifier) {
+ fExtraModifiers.appendf("%s ", modifier);
+ }
+ }
+
/**
* Write a declaration of this variable to out.
*/
@@ -144,11 +168,8 @@
if (!fLayoutQualifier.isEmpty()) {
out->appendf("layout(%s) ", fLayoutQualifier.c_str());
}
+ out->append(fExtraModifiers);
if (this->getTypeModifier() != kNone_TypeModifier) {
- if (GrSLTypeIsIntType(fType) && (this->getTypeModifier() == kVaryingIn_TypeModifier ||
- this->getTypeModifier() == kVaryingOut_TypeModifier)) {
- out->append("flat ");
- }
out->append(TypeModifierString(glslCaps, this->getTypeModifier()));
out->append(" ");
}
@@ -234,9 +255,10 @@
/// Work around driver bugs on some hardware that don't correctly
/// support uniform float []
- bool fUseUniformFloatArrays;
+ bool fUseUniformFloatArrays;
- SkString fLayoutQualifier;
+ SkString fLayoutQualifier;
+ SkString fExtraModifiers;
typedef GrShaderVar INHERITED;
};
diff --git a/src/gpu/glsl/GrGLSLVarying.cpp b/src/gpu/glsl/GrGLSLVarying.cpp
index ea52fbe..99bfe7e 100644
--- a/src/gpu/glsl/GrGLSLVarying.cpp
+++ b/src/gpu/glsl/GrGLSLVarying.cpp
@@ -10,10 +10,24 @@
#include "glsl/GrGLSLProgramBuilder.h"
void GrGLSLVaryingHandler::addPassThroughAttribute(const GrGeometryProcessor::Attribute* input,
- const char* output) {
+ const char* output, GrSLPrecision precision) {
GrSLType type = GrVertexAttribTypeToSLType(input->fType);
GrGLSLVertToFrag v(type);
- this->addVarying(input->fName, &v);
+ this->addVarying(input->fName, &v, precision);
+ this->writePassThroughAttribute(input, output, v);
+}
+
+void GrGLSLVaryingHandler::addFlatPassThroughAttribute(const GrGeometryProcessor::Attribute* input,
+ const char* output,
+ GrSLPrecision precision) {
+ GrSLType type = GrVertexAttribTypeToSLType(input->fType);
+ GrGLSLVertToFrag v(type);
+ this->addFlatVarying(input->fName, &v, precision);
+ this->writePassThroughAttribute(input, output, v);
+}
+
+void GrGLSLVaryingHandler::writePassThroughAttribute(const GrGeometryProcessor::Attribute* input,
+ const char* output, const GrGLSLVarying& v) {
fProgramBuilder->fVS.codeAppendf("%s = %s;", v.vsOut(), input->fName);
if (fProgramBuilder->primitiveProcessor().willUseGeoShader()) {
@@ -23,64 +37,35 @@
fProgramBuilder->fFS.codeAppendf("%s = %s;", output, v.fsIn());
}
-void GrGLSLVaryingHandler::addVarying(const char* name,
- GrGLSLVarying* varying,
- GrSLPrecision precision) {
+void GrGLSLVaryingHandler::internalAddVarying(const char* name,
+ GrGLSLVarying* varying,
+ GrSLPrecision precision,
+ bool flat) {
+ bool willUseGeoShader = fProgramBuilder->primitiveProcessor().willUseGeoShader();
+ VaryingInfo& v = fVaryings.push_back();
+
SkASSERT(varying);
+ v.fType = varying->fType;
+ v.fPrecision = precision;
+ v.fIsFlat = flat;
+ fProgramBuilder->nameVariable(&v.fVsOut, 'v', name);
+ v.fVisibility = kNone_GrShaderFlags;
if (varying->vsVarying()) {
- this->addVertexVarying(name, precision, varying);
+ varying->fVsOut = v.fVsOut.c_str();
+ v.fVisibility |= kVertex_GrShaderFlag;
}
- if (fProgramBuilder->primitiveProcessor().willUseGeoShader()) {
- this->addGeomVarying(name, precision, varying);
+ if (willUseGeoShader) {
+ fProgramBuilder->nameVariable(&v.fGsOut, 'g', name);
+ varying->fGsIn = v.fVsOut.c_str();
+ varying->fGsOut = v.fGsOut.c_str();
+ v.fVisibility |= kGeometry_GrShaderFlag;
}
if (varying->fsVarying()) {
- this->addFragVarying(precision, varying);
+ varying->fFsIn = (willUseGeoShader ? v.fGsOut : v.fVsOut).c_str();
+ v.fVisibility |= kFragment_GrShaderFlag;
}
}
-void GrGLSLVaryingHandler::addVertexVarying(const char* name,
- GrSLPrecision precision,
- GrGLSLVarying* v) {
- fVertexOutputs.push_back();
- fVertexOutputs.back().setType(v->fType);
- fVertexOutputs.back().setTypeModifier(GrGLSLShaderVar::kVaryingOut_TypeModifier);
- fVertexOutputs.back().setPrecision(precision);
- fProgramBuilder->nameVariable(fVertexOutputs.back().accessName(), 'v', name);
- v->fVsOut = fVertexOutputs.back().getName().c_str();
-}
-void GrGLSLVaryingHandler::addGeomVarying(const char* name,
- GrSLPrecision precision,
- GrGLSLVarying* v) {
- // if we have a GS take each varying in as an array
- // and output as non-array.
- if (v->vsVarying()) {
- fGeomInputs.push_back();
- fGeomInputs.back().setType(v->fType);
- fGeomInputs.back().setTypeModifier(GrGLSLShaderVar::kVaryingIn_TypeModifier);
- fGeomInputs.back().setPrecision(precision);
- fGeomInputs.back().setUnsizedArray();
- *fGeomInputs.back().accessName() = v->fVsOut;
- v->fGsIn = v->fVsOut;
- }
-
- if (v->fsVarying()) {
- fGeomOutputs.push_back();
- fGeomOutputs.back().setType(v->fType);
- fGeomOutputs.back().setTypeModifier(GrGLSLShaderVar::kVaryingOut_TypeModifier);
- fGeomOutputs.back().setPrecision(precision);
- fProgramBuilder->nameVariable(fGeomOutputs.back().accessName(), 'g', name);
- v->fGsOut = fGeomOutputs.back().getName().c_str();
- }
-}
-
-void GrGLSLVaryingHandler::addFragVarying(GrSLPrecision precision, GrGLSLVarying* v) {
- v->fFsIn = v->fGsOut ? v->fGsOut : v->fVsOut;
- fFragInputs.push_back().set(v->fType,
- GrGLSLShaderVar::kVaryingIn_TypeModifier,
- v->fFsIn,
- precision);
-}
-
void GrGLSLVaryingHandler::emitAttributes(const GrGeometryProcessor& gp) {
int vaCount = gp.numAttribs();
for (int i = 0; i < vaCount; i++) {
@@ -105,7 +90,46 @@
fVertexInputs.push_back(var);
}
+void GrGLSLVaryingHandler::setNoPerspective() {
+ const GrGLSLCaps& caps = *fProgramBuilder->glslCaps();
+ if (!caps.noperspectiveInterpolationSupport()) {
+ return;
+ }
+ if (const char* extension = caps.noperspectiveInterpolationExtensionString()) {
+ int bit = 1 << GrGLSLFragmentShaderBuilder::kNoPerspectiveInterpolation_GLSLPrivateFeature;
+ fProgramBuilder->fVS.addFeature(bit, extension);
+ if (fProgramBuilder->primitiveProcessor().willUseGeoShader()) {
+ fProgramBuilder->fGS.addFeature(bit, extension);
+ }
+ fProgramBuilder->fFS.addFeature(bit, extension);
+ }
+ fDefaultInterpolationModifier = "noperspective";
+}
+
void GrGLSLVaryingHandler::finalize() {
+ for (int i = 0; i < fVaryings.count(); ++i) {
+ const VaryingInfo& v = this->fVaryings[i];
+ const char* modifier = v.fIsFlat ? "flat" : fDefaultInterpolationModifier;
+ if (v.fVisibility & kVertex_GrShaderFlag) {
+ fVertexOutputs.push_back().set(v.fType, GrShaderVar::kVaryingOut_TypeModifier, v.fVsOut,
+ v.fPrecision, nullptr, modifier);
+ if (v.fVisibility & kGeometry_GrShaderFlag) {
+ fGeomInputs.push_back().set(v.fType, GrShaderVar::kVaryingIn_TypeModifier, v.fVsOut,
+ GrShaderVar::kUnsizedArray, v.fPrecision, nullptr,
+ modifier);
+ }
+ }
+ if (v.fVisibility & kFragment_GrShaderFlag) {
+ const char* fsIn = v.fVsOut.c_str();
+ if (v.fVisibility & kGeometry_GrShaderFlag) {
+ fGeomOutputs.push_back().set(v.fType, GrGLSLShaderVar::kVaryingOut_TypeModifier,
+ v.fGsOut, v.fPrecision, nullptr, modifier);
+ fsIn = v.fGsOut.c_str();
+ }
+ fFragInputs.push_back().set(v.fType, GrShaderVar::kVaryingIn_TypeModifier, fsIn,
+ v.fPrecision, nullptr, modifier);
+ }
+ }
this->onFinalize();
}
diff --git a/src/gpu/glsl/GrGLSLVarying.h b/src/gpu/glsl/GrGLSLVarying.h
index 2243197..5867361 100644
--- a/src/gpu/glsl/GrGLSLVarying.h
+++ b/src/gpu/glsl/GrGLSLVarying.h
@@ -71,18 +71,25 @@
class GrGLSLVaryingHandler {
public:
explicit GrGLSLVaryingHandler(GrGLSLProgramBuilder* program)
- : fVertexInputs(kVaryingsPerBlock)
+ : fVaryings(kVaryingsPerBlock)
+ , fVertexInputs(kVaryingsPerBlock)
, fVertexOutputs(kVaryingsPerBlock)
, fGeomInputs(kVaryingsPerBlock)
, fGeomOutputs(kVaryingsPerBlock)
, fFragInputs(kVaryingsPerBlock)
, fFragOutputs(kVaryingsPerBlock)
- , fProgramBuilder(program) {}
+ , fProgramBuilder(program)
+ , fDefaultInterpolationModifier(nullptr) {}
virtual ~GrGLSLVaryingHandler() {}
- typedef GrTAllocator<GrGLSLShaderVar> VarArray;
- typedef GrGLSLProgramDataManager::VaryingHandle VaryingHandle;
+ /*
+ * Notifies the varying handler that this shader will never emit geometry in perspective and
+ * therefore does not require perspective-correct interpolation. When supported, this allows
+ * varyings to use the "noperspective" keyword, which means the GPU can use cheaper math for
+ * interpolation.
+ */
+ void setNoPerspective();
/*
* addVarying allows fine grained control for setting up varyings between stages. Calling this
@@ -93,18 +100,36 @@
* TODO convert most uses of addVarying to addPassThroughAttribute
*/
void addVarying(const char* name,
- GrGLSLVarying*,
- GrSLPrecision precision = kDefault_GrSLPrecision);
+ GrGLSLVarying* varying,
+ GrSLPrecision precision = kDefault_GrSLPrecision) {
+ SkASSERT(GrSLTypeIsFloatType(varying->type())); // Integers must use addFlatVarying.
+ this->internalAddVarying(name, varying, precision, false /*flat*/);
+ }
/*
- * This call can be used by GP to pass an attribute through all shaders directly to 'output' in
- * the fragment shader. Though this call effects both the vertex shader and fragment shader,
- * it expects 'output' to be defined in the fragment shader before this call is made. If there
+ * addFlatVarying sets up a varying whose value is constant across every fragment. The graphics
+ * pipeline will pull its value from the final vertex of the draw primitive (provoking vertex).
+ * Flat interpolation is not always supported and the user must check the caps before using.
+ * TODO: Some platforms can change the provoking vertex. Should we be resetting this knob?
+ */
+ void addFlatVarying(const char* name,
+ GrGLSLVarying* varying,
+ GrSLPrecision precision = kDefault_GrSLPrecision) {
+ this->internalAddVarying(name, varying, precision, true /*flat*/);
+ }
+
+ /*
+ * The GP can use these calls to pass an attribute through all shaders directly to 'output' in
+ * the fragment shader. Though these calls affect both the vertex shader and fragment shader,
+ * they expect 'output' to be defined in the fragment shader before the call is made. If there
* is a geometry shader, we will simply take the value of the varying from the first vertex and
* that will be set as the output varying for all emitted vertices.
- * TODO it might be nicer behavior to have a flag to declare output inside this call
+ * TODO it might be nicer behavior to have a flag to declare output inside these calls
*/
- void addPassThroughAttribute(const GrGeometryProcessor::Attribute*, const char* output);
+ void addPassThroughAttribute(const GrGeometryProcessor::Attribute*, const char* output,
+ GrSLPrecision = kDefault_GrSLPrecision);
+ void addFlatPassThroughAttribute(const GrGeometryProcessor::Attribute*, const char* output,
+ GrSLPrecision = kDefault_GrSLPrecision);
void emitAttributes(const GrGeometryProcessor& gp);
@@ -115,21 +140,36 @@
void getVertexDecls(SkString* inputDecls, SkString* outputDecls) const;
void getGeomDecls(SkString* inputDecls, SkString* outputDecls) const;
void getFragDecls(SkString* inputDecls, SkString* outputDecls) const;
+
protected:
- VarArray fVertexInputs;
- VarArray fVertexOutputs;
- VarArray fGeomInputs;
- VarArray fGeomOutputs;
- VarArray fFragInputs;
- VarArray fFragOutputs;
+ struct VaryingInfo {
+ GrSLType fType;
+ GrSLPrecision fPrecision;
+ bool fIsFlat;
+ SkString fVsOut;
+ SkString fGsOut;
+ GrShaderFlags fVisibility;
+ };
+
+ typedef GrTAllocator<VaryingInfo> VaryingList;
+ typedef GrTAllocator<GrGLSLShaderVar> VarArray;
+ typedef GrGLSLProgramDataManager::VaryingHandle VaryingHandle;
+
+ VaryingList fVaryings;
+ VarArray fVertexInputs;
+ VarArray fVertexOutputs;
+ VarArray fGeomInputs;
+ VarArray fGeomOutputs;
+ VarArray fFragInputs;
+ VarArray fFragOutputs;
// This is not owned by the class
GrGLSLProgramBuilder* fProgramBuilder;
private:
- void addVertexVarying(const char* name, GrSLPrecision precision, GrGLSLVarying* v);
- void addGeomVarying(const char* name, GrSLPrecision precision, GrGLSLVarying* v);
- void addFragVarying(GrSLPrecision precision, GrGLSLVarying* v);
+ void internalAddVarying(const char* name, GrGLSLVarying*, GrSLPrecision, bool flat);
+ void writePassThroughAttribute(const GrGeometryProcessor::Attribute*, const char* output,
+ const GrGLSLVarying&);
void addAttribute(const GrShaderVar& var);
@@ -138,6 +178,8 @@
// helper function for get*Decls
void appendDecls(const VarArray& vars, SkString* out) const;
+ const char* fDefaultInterpolationModifier;
+
friend class GrGLSLProgramBuilder;
};