aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar cdalton <cdalton@nvidia.com>2016-02-12 12:14:06 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2016-02-12 12:14:06 -0800
commitc08f196648463d44eb85e17c5815dbf8f709a42a (patch)
treec6207815ec240c521636248118372ef3a88d4a73 /src
parent083617b9a7247dd4c52f8dfd195fa34a083e6f1d (diff)
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
Diffstat (limited to 'src')
-rw-r--r--src/gpu/GrPathProcessor.cpp7
-rw-r--r--src/gpu/batches/GrPLSPathRenderer.cpp4
-rw-r--r--src/gpu/gl/GrGLCaps.cpp18
-rw-r--r--src/gpu/gl/GrGLGpu.cpp68
-rw-r--r--src/gpu/gl/GrGLVaryingHandler.cpp10
-rw-r--r--src/gpu/gl/GrGLVaryingHandler.h7
-rwxr-xr-xsrc/gpu/glsl/GrGLSLCaps.cpp6
-rwxr-xr-xsrc/gpu/glsl/GrGLSLCaps.h12
-rw-r--r--src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp2
-rw-r--r--src/gpu/glsl/GrGLSLFragmentShaderBuilder.h16
-rw-r--r--src/gpu/glsl/GrGLSLGeometryProcessor.cpp3
-rw-r--r--src/gpu/glsl/GrGLSLShaderBuilder.h14
-rw-r--r--src/gpu/glsl/GrGLSLShaderVar.h36
-rw-r--r--src/gpu/glsl/GrGLSLVarying.cpp128
-rw-r--r--src/gpu/glsl/GrGLSLVarying.h82
15 files changed, 286 insertions, 127 deletions
diff --git a/src/gpu/GrPathProcessor.cpp b/src/gpu/GrPathProcessor.cpp
index cb33010f7e..1d70dea289 100644
--- a/src/gpu/GrPathProcessor.cpp
+++ b/src/gpu/GrPathProcessor.cpp
@@ -22,13 +22,18 @@ public:
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 b4f6ce4210..faadd6d49b 100644
--- a/src/gpu/batches/GrPLSPathRenderer.cpp
+++ b/src/gpu/batches/GrPLSPathRenderer.cpp
@@ -328,7 +328,7 @@ public:
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 @@ public:
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 79bb22efac..6dc5ee8c4f 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -596,6 +596,24 @@ void GrGLCaps::initGLSL(const GrGLContextInfo& ctxInfo) {
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 b9a5ee9837..be315dab1e 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -285,7 +285,8 @@ GrGLGpu::~GrGLGpu() {
}
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 @@ void GrGLGpu::createPLSSetupProgram() {
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 @@ void GrGLGpu::createPLSSetupProgram() {
);
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 @@ void GrGLGpu::createCopyPrograms() {
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 @@ void GrGLGpu::createCopyPrograms() {
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 @@ void GrGLGpu::createCopyPrograms() {
);
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 b27a9960ec..a2d4e9d1b9 100644
--- a/src/gpu/gl/GrGLVaryingHandler.cpp
+++ b/src/gpu/gl/GrGLVaryingHandler.cpp
@@ -24,8 +24,14 @@ GrGLSLVaryingHandler::VaryingHandle GrGLVaryingHandler::addPathProcessingVarying
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 fe8c3dca69..c4e5ba457e 100644
--- a/src/gpu/gl/GrGLVaryingHandler.h
+++ b/src/gpu/gl/GrGLVaryingHandler.h
@@ -24,12 +24,9 @@ public:
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 c82d8333df..ba99be57e2 100755
--- a/src/gpu/glsl/GrGLSLCaps.cpp
+++ b/src/gpu/glsl/GrGLSLCaps.cpp
@@ -23,11 +23,14 @@ GrGLSLCaps::GrGLSLCaps(const GrContextOptions& options) {
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 @@ SkString GrGLSLCaps::dump() const {
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 060539645e..2f87f66850 100755
--- a/src/gpu/glsl/GrGLSLCaps.h
+++ b/src/gpu/glsl/GrGLSLCaps.h
@@ -54,6 +54,10 @@ public:
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 @@ public:
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 @@ private:
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 @@ private:
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 7ec18a23e8..8651827841 100644
--- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
@@ -176,7 +176,7 @@ const char* GrGLSLFragmentShaderBuilder::dstColor() {
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 e998458158..a437a194ca 100644
--- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
+++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
@@ -32,9 +32,8 @@ public:
* 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 @@ private:
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 b8951be551..f7dba820a0 100644
--- a/src/gpu/glsl/GrGLSLGeometryProcessor.cpp
+++ b/src/gpu/glsl/GrGLSLGeometryProcessor.cpp
@@ -19,6 +19,9 @@ void GrGLSLGeometryProcessor::emitCode(EmitArgs& args) {
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 5c3408e704..bc3b4ca717 100644
--- a/src/gpu/glsl/GrGLSLShaderBuilder.h
+++ b/src/gpu/glsl/GrGLSLShaderBuilder.h
@@ -142,6 +142,19 @@ protected:
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 @@ protected:
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 e26a75c096..bdd36f3763 100644
--- a/src/gpu/glsl/GrGLSLShaderVar.h
+++ b/src/gpu/glsl/GrGLSLShaderVar.h
@@ -51,7 +51,9 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ private:
/// 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 ea52fbe7ab..99bfe7e18f 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,62 +37,33 @@ void GrGLSLVaryingHandler::addPassThroughAttribute(const GrGeometryProcessor::At
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);
- }
-}
-
-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;
+ varying->fFsIn = (willUseGeoShader ? v.fGsOut : v.fVsOut).c_str();
+ v.fVisibility |= kFragment_GrShaderFlag;
}
-
- 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) {
@@ -105,7 +90,46 @@ void GrGLSLVaryingHandler::addAttribute(const GrShaderVar& var) {
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 22431978c8..5867361ce4 100644
--- a/src/gpu/glsl/GrGLSLVarying.h
+++ b/src/gpu/glsl/GrGLSLVarying.h
@@ -71,18 +71,25 @@ static const int kVaryingsPerBlock = 8;
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 @@ public:
* 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*/);
+ }
+
+ /*
+ * 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*/);
+ }
/*
- * 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
+ * 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 @@ public:
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 @@ private:
// helper function for get*Decls
void appendDecls(const VarArray& vars, SkString* out) const;
+ const char* fDefaultInterpolationModifier;
+
friend class GrGLSLProgramBuilder;
};