| Index: src/gpu/glsl/GrGLSLProgramBuilder.cpp
|
| diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
|
| index b9eaca4153214fcc07d35925140c12dd572dbb05..bc0208321cbc3e2ae1ad330b41342185f98975e5 100644
|
| --- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp
|
| +++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
|
| @@ -22,16 +22,33 @@ GrGLSLProgramBuilder::GrGLSLProgramBuilder(const DrawArgs& args)
|
| , fStageIndex(-1)
|
| , fArgs(args)
|
| , fGeometryProcessor(nullptr)
|
| - , fXferProcessor(nullptr) {
|
| + , fXferProcessor(nullptr)
|
| + , fSamplerUniforms(4)
|
| + , fNumVertexSamplers(0)
|
| + , fNumGeometrySamplers(0)
|
| + , fNumFragmentSamplers(0) {
|
| +}
|
| +
|
| +void GrGLSLProgramBuilder::addFeature(GrShaderFlags shaders,
|
| + uint32_t featureBit,
|
| + const char* extensionName) {
|
| + if (shaders & kVertex_GrShaderFlag) {
|
| + fVS.addFeature(featureBit, extensionName);
|
| + }
|
| + if (shaders & kGeometry_GrShaderFlag) {
|
| + SkASSERT(this->glslCaps()->geometryShaderSupport());
|
| + fGS.addFeature(featureBit, extensionName);
|
| + }
|
| + if (shaders & kFragment_GrShaderFlag) {
|
| + fFS.addFeature(featureBit, extensionName);
|
| + }
|
| }
|
|
|
| bool GrGLSLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor,
|
| - GrGLSLExpr4* inputCoverage,
|
| - int maxTextures) {
|
| + GrGLSLExpr4* inputCoverage) {
|
| // First we loop over all of the installed processors and collect coord transforms. These will
|
| // be sent to the GrGLSLPrimitiveProcessor in its emitCode function
|
| const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
|
| - int totalTextures = primProc.numTextures();
|
|
|
| for (int i = 0; i < this->pipeline().numFragmentProcessors(); i++) {
|
| const GrFragmentProcessor& processor = this->pipeline().getFragmentProcessor(i);
|
| @@ -40,12 +57,6 @@ bool GrGLSLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor,
|
| SkTArray<const GrCoordTransform*, true>& procCoords = fCoordTransforms.push_back();
|
| processor.gatherCoordTransforms(&procCoords);
|
| }
|
| -
|
| - totalTextures += processor.numTextures();
|
| - if (totalTextures >= maxTextures) {
|
| - GrCapsDebugf(this->caps(), "Program would use too many texture units\n");
|
| - return false;
|
| - }
|
| }
|
|
|
| this->emitAndInstallPrimProc(primProc, inputColor, inputCoverage);
|
| @@ -61,7 +72,8 @@ bool GrGLSLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor,
|
| primProc.getPixelLocalStorageState());
|
| this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOutput());
|
| }
|
| - return true;
|
| +
|
| + return this->checkSamplerCounts();
|
| }
|
|
|
| void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& proc,
|
| @@ -198,6 +210,42 @@ void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
|
| fFS.codeAppend("}");
|
| }
|
|
|
| +void GrGLSLProgramBuilder::emitSamplers(const GrProcessor& processor,
|
| + GrGLSLTextureSampler::TextureSamplerArray* outSamplers) {
|
| + int numTextures = processor.numTextures();
|
| + UniformHandle* localSamplerUniforms = fSamplerUniforms.push_back_n(numTextures);
|
| + SkString name;
|
| + for (int t = 0; t < numTextures; ++t) {
|
| + const GrTextureAccess& access = processor.textureAccess(t);
|
| + GrShaderFlags visibility = access.getVisibility();
|
| + if (visibility & kVertex_GrShaderFlag) {
|
| + ++fNumVertexSamplers;
|
| + }
|
| + if (visibility & kGeometry_GrShaderFlag) {
|
| + SkASSERT(this->primitiveProcessor().willUseGeoShader());
|
| + ++fNumGeometrySamplers;
|
| + }
|
| + if (visibility & kFragment_GrShaderFlag) {
|
| + ++fNumFragmentSamplers;
|
| + }
|
| + GrSLType samplerType = access.getTexture()->samplerType();
|
| + if (kSamplerExternal_GrSLType == samplerType) {
|
| + const char* externalFeatureString = this->glslCaps()->externalTextureExtensionString();
|
| + // We shouldn't ever create a GrGLTexture that requires external sampler type
|
| + SkASSERT(externalFeatureString);
|
| + this->addFeature(visibility,
|
| + 1 << GrGLSLShaderBuilder::kExternalTexture_GLSLPrivateFeature,
|
| + externalFeatureString);
|
| + }
|
| + name.printf("Sampler%d", t);
|
| + localSamplerUniforms[t] = this->uniformHandler()->addUniform(access.getVisibility(),
|
| + samplerType,
|
| + kDefault_GrSLPrecision,
|
| + name.c_str());
|
| + outSamplers->emplace_back(localSamplerUniforms[t], access);
|
| + }
|
| +}
|
| +
|
| void GrGLSLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) {
|
| // Swizzle the fragment shader outputs if necessary.
|
| GrSwizzle swizzle;
|
| @@ -214,6 +262,29 @@ void GrGLSLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) {
|
| }
|
| }
|
|
|
| +bool GrGLSLProgramBuilder::checkSamplerCounts() {
|
| + const GrGLSLCaps& glslCaps = *this->glslCaps();
|
| + if (fNumVertexSamplers > glslCaps.maxVertexSamplers()) {
|
| + GrCapsDebugf(this->caps(), "Program would use too many vertex samplers\n");
|
| + return false;
|
| + }
|
| + if (fNumGeometrySamplers > glslCaps.maxGeometrySamplers()) {
|
| + GrCapsDebugf(this->caps(), "Program would use too many geometry samplers\n");
|
| + return false;
|
| + }
|
| + if (fNumFragmentSamplers > glslCaps.maxFragmentSamplers()) {
|
| + GrCapsDebugf(this->caps(), "Program would use too many fragment samplers\n");
|
| + return false;
|
| + }
|
| + // If the same sampler is used in two different shaders, it counts as two combined samplers.
|
| + int numCombinedSamplers = fNumVertexSamplers + fNumGeometrySamplers + fNumFragmentSamplers;
|
| + if (numCombinedSamplers > glslCaps.maxCombinedSamplers()) {
|
| + GrCapsDebugf(this->caps(), "Program would use too many combined samplers\n");
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| #ifdef SK_DEBUG
|
| void GrGLSLProgramBuilder::verify(const GrPrimitiveProcessor& gp) {
|
| SkASSERT(fFS.usedProcessorFeatures() == gp.requiredFeatures());
|
|
|