| Index: src/gpu/gl/builders/GrGLProgramBuilder.cpp
|
| diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
|
| index de08ec4ad06502b45a9ffb2a5794c4e0a745c839..fbf78d763464a3b0175fff9d60474c5db0beaa7f 100644
|
| --- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
|
| +++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
|
| @@ -5,110 +5,151 @@
|
| * found in the LICENSE file.
|
| */
|
|
|
| +#include "GrGLProgramBuilder.h"
|
| +#include "gl/GrGLGeometryProcessor.h"
|
| #include "gl/GrGLProgram.h"
|
| #include "gl/GrGLSLPrettyPrint.h"
|
| #include "gl/GrGLUniformHandle.h"
|
| -#include "GrCoordTransform.h"
|
| #include "../GrGpuGL.h"
|
| -#include "GrGLFragmentShaderBuilder.h"
|
| +#include "GrCoordTransform.h"
|
| +#include "GrGLLegacyNvprProgramBuilder.h"
|
| +#include "GrGLNvprProgramBuilder.h"
|
| #include "GrGLProgramBuilder.h"
|
| #include "GrTexture.h"
|
| -#include "GrGLVertexShaderBuilder.h"
|
| #include "SkRTConf.h"
|
| #include "SkTraceEvent.h"
|
|
|
| -namespace {
|
| #define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X)
|
| #define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X)
|
|
|
| -// number of each input/output type in a single allocation block
|
| -static const int kVarsPerBlock = 8;
|
| -
|
| // ES2 FS only guarantees mediump and lowp support
|
| static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar::kMedium_Precision;
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
| -bool GrGLProgramBuilder::genProgram(const GrGeometryStage* geometryProcessor,
|
| - const GrFragmentStage* colorStages[],
|
| - const GrFragmentStage* coverageStages[]) {
|
| - const GrGLProgramDesc::KeyHeader& header = this->desc().getHeader();
|
| +//////////////////////////////////////////////////////////////////////////////
|
|
|
| - fFS.emitCodeBeforeEffects();
|
| +const int GrGLProgramBuilder::kVarsPerBlock = 8;
|
| +
|
| +GrGLProgram* GrGLProgramBuilder::CreateProgram(const GrOptDrawState& optState,
|
| + const GrGLProgramDesc& desc,
|
| + GrGpu::DrawType drawType,
|
| + const GrGeometryStage* geometryProcessor,
|
| + const GrFragmentStage* colorStages[],
|
| + const GrFragmentStage* coverageStages[],
|
| + GrGpuGL* gpu) {
|
| + // create a builder. This will be handed off to effects so they can use it to add
|
| + // uniforms, varyings, textures, etc
|
| + SkAutoTDelete<GrGLProgramBuilder> builder(CreateProgramBuilder(desc,
|
| + optState,
|
| + drawType,
|
| + SkToBool(geometryProcessor),
|
| + gpu));
|
| +
|
| + GrGLProgramBuilder* pb = builder.get();
|
| + const GrGLProgramDesc::KeyHeader& header = pb->header();
|
| +
|
| + // emit code to read the dst copy texture, if necessary
|
| + if (GrGLFragmentShaderBuilder::kNoDstRead_DstReadKey != header.fDstReadKey
|
| + && !gpu->glCaps().fbFetchSupport()) {
|
| + pb->fFS.emitCodeToReadDstTexture();
|
| + }
|
|
|
| - ///////////////////////////////////////////////////////////////////////////
|
| // get the initial color and coverage to feed into the first effect in each effect chain
|
| + GrGLSLExpr4 inputColor, inputCoverage;
|
| + pb->setupUniformColorAndCoverageIfNeeded(&inputColor, &inputCoverage);
|
| +
|
| + // if we have a vertex shader(we don't only if we are using NVPR or NVPR ES), then we may have
|
| + // to setup a few more things like builtin vertex attributes
|
| + bool hasVertexShader = !header.fUseFragShaderOnly;
|
| + if (hasVertexShader) {
|
| + pb->fVS.setupLocalCoords();
|
| + pb->fVS.transformGLToSkiaCoords();
|
| + if (header.fEmitsPointSize) {
|
| + pb->fVS.codeAppend("gl_PointSize = 1.0;");
|
| + }
|
| + if (GrGLProgramDesc::kAttribute_ColorInput == header.fColorInput) {
|
| + pb->fVS.setupBuiltinVertexAttribute("Color", &inputColor);
|
| + }
|
| + if (GrGLProgramDesc::kAttribute_ColorInput == header.fCoverageInput) {
|
| + pb->fVS.setupBuiltinVertexAttribute("Coverage", &inputCoverage);
|
| + }
|
| + }
|
|
|
| - GrGLSLExpr4 inputColor;
|
| - GrGLSLExpr4 inputCoverage;
|
| + pb->createAndEmitProcessors(geometryProcessor, colorStages, coverageStages, &inputColor,
|
| + &inputCoverage);
|
|
|
| - if (GrGLProgramDesc::kUniform_ColorInput == header.fColorInput) {
|
| - const char* name;
|
| - fUniformHandles.fColorUni =
|
| - this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
|
| - kVec4f_GrSLType,
|
| - "Color",
|
| - &name);
|
| - inputColor = GrGLSLExpr4(name);
|
| - } else if (GrGLProgramDesc::kAllOnes_ColorInput == header.fColorInput) {
|
| - inputColor = GrGLSLExpr4(1);
|
| + if (hasVertexShader) {
|
| + pb->fVS.transformSkiaToGLCoords();
|
| }
|
|
|
| - if (GrGLProgramDesc::kUniform_ColorInput == header.fCoverageInput) {
|
| - const char* name;
|
| - fUniformHandles.fCoverageUni =
|
| - this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
|
| - kVec4f_GrSLType,
|
| - "Coverage",
|
| - &name);
|
| - inputCoverage = GrGLSLExpr4(name);
|
| - } else if (GrGLProgramDesc::kAllOnes_ColorInput == header.fCoverageInput) {
|
| - inputCoverage = GrGLSLExpr4(1);
|
| + // write the secondary color output if necessary
|
| + if (GrOptDrawState::kNone_SecondaryOutputType != header.fSecondaryOutputType) {
|
| + pb->fFS.enableSecondaryOutput(inputColor, inputCoverage);
|
| }
|
|
|
| - // Subclasses drive effect emitting
|
| - this->createAndEmitEffects(geometryProcessor, colorStages, coverageStages, &inputColor,
|
| - &inputCoverage);
|
| + pb->fFS.combineColorAndCoverage(inputColor, inputCoverage);
|
|
|
| - fFS.emitCodeAfterEffects(inputColor, inputCoverage);
|
| + return pb->finalize();
|
| +}
|
|
|
| - if (!this->finish()) {
|
| - return false;
|
| +GrGLProgramBuilder*
|
| +GrGLProgramBuilder::CreateProgramBuilder(const GrGLProgramDesc& desc,
|
| + const GrOptDrawState& optState,
|
| + GrGpu::DrawType drawType,
|
| + bool hasGeometryProcessor,
|
| + GrGpuGL* gpu) {
|
| + if (desc.getHeader().fUseFragShaderOnly) {
|
| + SkASSERT(gpu->glCaps().pathRenderingSupport());
|
| + SkASSERT(gpu->glPathRendering()->texturingMode() ==
|
| + GrGLPathRendering::FixedFunction_TexturingMode);
|
| + SkASSERT(!hasGeometryProcessor);
|
| + return SkNEW_ARGS(GrGLLegacyNvprProgramBuilder, (gpu, optState, desc));
|
| + } else if (GrGpu::IsPathRenderingDrawType(drawType)) {
|
| + SkASSERT(gpu->glCaps().pathRenderingSupport());
|
| + SkASSERT(gpu->glPathRendering()->texturingMode() ==
|
| + GrGLPathRendering::SeparableShaders_TexturingMode);
|
| + SkASSERT(!hasGeometryProcessor);
|
| + return SkNEW_ARGS(GrGLNvprProgramBuilder, (gpu, optState, desc));
|
| + } else {
|
| + return SkNEW_ARGS(GrGLProgramBuilder, (gpu, optState, desc));
|
| }
|
| -
|
| - return true;
|
| }
|
|
|
| -//////////////////////////////////////////////////////////////////////////////
|
| +/////////////////////////////////////////////////////////////////////////////
|
|
|
| GrGLProgramBuilder::GrGLProgramBuilder(GrGpuGL* gpu, const GrOptDrawState& optState,
|
| const GrGLProgramDesc& desc)
|
| - : fEffectEmitter(NULL)
|
| - , fFragOnly(SkToBool(desc.getHeader().fUseFragShaderOnly))
|
| - , fTexCoordSetCnt(0)
|
| - , fProgramID(0)
|
| + : fVS(this)
|
| + , fGS(this)
|
| , fFS(this, desc)
|
| - , fSeparableVaryingInfos(kVarsPerBlock)
|
| - , fGrProcessorEmitter(this)
|
| + , fOutOfStage(true)
|
| + , fStageIndex(-1)
|
| , fOptState(optState)
|
| , fDesc(desc)
|
| , fGpu(gpu)
|
| , fUniforms(kVarsPerBlock) {
|
| }
|
|
|
| +void GrGLProgramBuilder::addVarying(GrSLType type,
|
| + const char* name,
|
| + const char** vsOutName,
|
| + const char** fsInName,
|
| + GrGLShaderVar::Precision fsPrecision) {
|
| + SkString* fsInputName = fVS.addVarying(type, name, vsOutName);
|
| + fFS.addVarying(type, fsInputName->c_str(), fsInName, fsPrecision);
|
| +}
|
| +
|
| void GrGLProgramBuilder::nameVariable(SkString* out, char prefix, const char* name) {
|
| if ('\0' == prefix) {
|
| *out = name;
|
| } else {
|
| out->printf("%c%s", prefix, name);
|
| }
|
| - if (fCodeStage.inStageCode()) {
|
| + if (!fOutOfStage) {
|
| if (out->endsWith('_')) {
|
| // Names containing "__" are reserved.
|
| out->append("x");
|
| }
|
| - out->appendf("_Stage%d", fCodeStage.stageIndex());
|
| + out->appendf("_Stage%d", fStageIndex);
|
| }
|
| }
|
|
|
| @@ -143,13 +184,6 @@ GrGLProgramDataManager::UniformHandle GrGLProgramBuilder::addUniformArray(uint32
|
| return GrGLProgramDataManager::UniformHandle::CreateFromUniformIndex(fUniforms.count() - 1);
|
| }
|
|
|
| -void GrGLProgramBuilder::appendDecls(const VarArray& vars, SkString* out) const {
|
| - for (int i = 0; i < vars.count(); ++i) {
|
| - vars[i].appendDecl(this->ctxInfo(), out);
|
| - out->append(";\n");
|
| - }
|
| -}
|
| -
|
| void GrGLProgramBuilder::appendUniformDecls(ShaderVisibility visibility,
|
| SkString* out) const {
|
| for (int i = 0; i < fUniforms.count(); ++i) {
|
| @@ -160,20 +194,129 @@ void GrGLProgramBuilder::appendUniformDecls(ShaderVisibility visibility,
|
| }
|
| }
|
|
|
| -void GrGLProgramBuilder::createAndEmitEffects(const GrFragmentStage* effectStages[],
|
| - int effectCnt,
|
| - const GrGLProgramDesc::EffectKeyProvider& keyProvider,
|
| - GrGLSLExpr4* fsInOutColor) {
|
| +const GrGLContextInfo& GrGLProgramBuilder::ctxInfo() const {
|
| + return fGpu->ctxInfo();
|
| +}
|
| +
|
| +void GrGLProgramBuilder::setupUniformColorAndCoverageIfNeeded(GrGLSLExpr4* inputColor,
|
| + GrGLSLExpr4* inputCoverage) {
|
| + const GrGLProgramDesc::KeyHeader& header = this->header();
|
| + if (GrGLProgramDesc::kUniform_ColorInput == header.fColorInput) {
|
| + const char* name;
|
| + fUniformHandles.fColorUni =
|
| + this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
|
| + kVec4f_GrSLType,
|
| + "Color",
|
| + &name);
|
| + *inputColor = GrGLSLExpr4(name);
|
| + } else if (GrGLProgramDesc::kAllOnes_ColorInput == header.fColorInput) {
|
| + *inputColor = GrGLSLExpr4(1);
|
| + }
|
| + if (GrGLProgramDesc::kUniform_ColorInput == header.fCoverageInput) {
|
| + const char* name;
|
| + fUniformHandles.fCoverageUni =
|
| + this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
|
| + kVec4f_GrSLType,
|
| + "Coverage",
|
| + &name);
|
| + *inputCoverage = GrGLSLExpr4(name);
|
| + } else if (GrGLProgramDesc::kAllOnes_ColorInput == header.fCoverageInput) {
|
| + *inputCoverage = GrGLSLExpr4(1);
|
| + }
|
| +}
|
| +
|
| +void GrGLProgramBuilder::createAndEmitProcessors(const GrGeometryStage* geometryProcessor,
|
| + const GrFragmentStage* colorStages[],
|
| + const GrFragmentStage* coverageStages[],
|
| + GrGLSLExpr4* inputColor,
|
| + GrGLSLExpr4* inputCoverage) {
|
| + bool useLocalCoords = fVS.hasExplicitLocalCoords();
|
| +
|
| + EffectKeyProvider colorKeyProvider(&fDesc, EffectKeyProvider::kColor_EffectType);
|
| + int numColorEffects = fDesc.numColorEffects();
|
| + GrGLInstalledProcessors* ip = SkNEW_ARGS(GrGLInstalledProcessors, (numColorEffects,
|
| + useLocalCoords));
|
| + this->createAndEmitProcessors<GrFragmentStage>(colorStages, numColorEffects, colorKeyProvider,
|
| + inputColor, ip);
|
| + fColorEffects.reset(ip);
|
| +
|
| + if (geometryProcessor) {
|
| + fVS.emitAttributes(*geometryProcessor->getProcessor());
|
| + EffectKeyProvider gpKeyProvider(&fDesc, EffectKeyProvider::kGeometryProcessor_EffectType);
|
| + ip = SkNEW_ARGS(GrGLInstalledProcessors, (1, useLocalCoords));
|
| + this->createAndEmitProcessors<GrGeometryStage>(&geometryProcessor, 1, gpKeyProvider,
|
| + inputCoverage, ip);
|
| + fGeometryProcessor.reset(ip);
|
| + }
|
| +
|
| + EffectKeyProvider coverageKeyProvider(&fDesc, EffectKeyProvider::kCoverage_EffectType);
|
| + int numCoverageEffects = fDesc.numCoverageEffects();
|
| + ip = SkNEW_ARGS(GrGLInstalledProcessors, (numCoverageEffects, useLocalCoords));
|
| + this->createAndEmitProcessors<GrFragmentStage>(coverageStages, numCoverageEffects,
|
| + coverageKeyProvider, inputCoverage, ip);
|
| + fCoverageEffects.reset(ip);
|
| +}
|
| +
|
| +template <class ProcessorStage>
|
| +void GrGLProgramBuilder::createAndEmitProcessors(const ProcessorStage* processStages[],
|
| + int effectCnt,
|
| + const EffectKeyProvider& keyProvider,
|
| + GrGLSLExpr4* fsInOutColor,
|
| + GrGLInstalledProcessors* installedProcessors) {
|
| bool effectEmitted = false;
|
|
|
| GrGLSLExpr4 inColor = *fsInOutColor;
|
| GrGLSLExpr4 outColor;
|
|
|
| for (int e = 0; e < effectCnt; ++e) {
|
| - fGrProcessorEmitter.set(effectStages[e]->getFragmentProcessor());
|
| - fEffectEmitter = &fGrProcessorEmitter;
|
| - // calls into the subclass to emit the actual effect into the program effect object
|
| - this->emitEffect(*effectStages[e], e, keyProvider, &inColor, &outColor);
|
| + // Program builders have a bit of state we need to clear with each effect
|
| + AutoStageAdvance adv(this);
|
| + const ProcessorStage& stage = *processStages[e];
|
| + SkASSERT(stage.getProcessor());
|
| +
|
| + if (inColor.isZeros()) {
|
| + SkString inColorName;
|
| +
|
| + // Effects have no way to communicate zeros, they treat an empty string as ones.
|
| + this->nameVariable(&inColorName, '\0', "input");
|
| + fFS.codeAppendf("vec4 %s = %s;", inColorName.c_str(), inColor.c_str());
|
| + inColor = inColorName;
|
| + }
|
| +
|
| + // create var to hold stage result
|
| + SkString outColorName;
|
| + this->nameVariable(&outColorName, '\0', "output");
|
| + fFS.codeAppendf("vec4 %s;", outColorName.c_str());
|
| + outColor = outColorName;
|
| +
|
| + SkASSERT(installedProcessors);
|
| + const typename ProcessorStage::Processor& processor = *stage.getProcessor();
|
| + SkSTArray<2, GrGLProcessor::TransformedCoords> coords(processor.numTransforms());
|
| + SkSTArray<4, GrGLProcessor::TextureSampler> samplers(processor.numTextures());
|
| +
|
| + this->emitTransforms(stage, &coords, installedProcessors);
|
| + this->emitSamplers(processor, &samplers, installedProcessors);
|
| +
|
| + typename ProcessorStage::GLProcessor* glEffect =
|
| + processor.getFactory().createGLInstance(processor);
|
| + installedProcessors->addEffect(glEffect);
|
| +
|
| + // Enclose custom code in a block to avoid namespace conflicts
|
| + SkString openBrace;
|
| + openBrace.printf("{ // Stage %d: %s\n", fStageIndex, glEffect->name());
|
| + fFS.codeAppend(openBrace.c_str());
|
| + fVS.codeAppend(openBrace.c_str());
|
| +
|
| + glEffect->emitCode(this, processor, keyProvider.get(e), outColor.c_str(),
|
| + inColor.isOnes() ? NULL : inColor.c_str(), coords, samplers);
|
| +
|
| + // We have to check that effects and the code they emit are consistent, ie if an effect
|
| + // asks for dst color, then the emit code needs to follow suit
|
| + verify(processor);
|
| + fFS.codeAppend("}");
|
| + fVS.codeAppend("}");
|
| +
|
| + inColor = outColor;
|
| effectEmitted = true;
|
| }
|
|
|
| @@ -182,40 +325,77 @@ void GrGLProgramBuilder::createAndEmitEffects(const GrFragmentStage* effectStage
|
| }
|
| }
|
|
|
| -void GrGLProgramBuilder::emitEffect(const GrProcessorStage& effectStage,
|
| - int effectIndex,
|
| - const GrGLProgramDesc::EffectKeyProvider& keyProvider,
|
| - GrGLSLExpr4* inColor,
|
| - GrGLSLExpr4* outColor) {
|
| - SkASSERT(effectStage.getProcessor());
|
| - CodeStage::AutoStageRestore csar(&fCodeStage, &effectStage);
|
| -
|
| - if (inColor->isZeros()) {
|
| - SkString inColorName;
|
| -
|
| - // Effects have no way to communicate zeros, they treat an empty string as ones.
|
| - this->nameVariable(&inColorName, '\0', "input");
|
| - fFS.codeAppendf("\tvec4 %s = %s;\n", inColorName.c_str(), inColor->c_str());
|
| - *inColor = inColorName;
|
| - }
|
| -
|
| - // create var to hold stage result
|
| - SkString outColorName;
|
| - this->nameVariable(&outColorName, '\0', "output");
|
| - fFS.codeAppendf("\tvec4 %s;\n", outColorName.c_str());
|
| - *outColor = outColorName;
|
| +void GrGLProgramBuilder::verify(const GrGeometryProcessor& gp) {
|
| + SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition());
|
| +}
|
|
|
| - this->emitEffect(effectStage, keyProvider.get(effectIndex), outColor->c_str(),
|
| - inColor->isOnes() ? NULL : inColor->c_str(), fCodeStage.stageIndex());
|
| +void GrGLProgramBuilder::verify(const GrFragmentProcessor& fp) {
|
| + SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition());
|
| + SkASSERT(fFS.hasReadDstColor() == fp.willReadDstColor());
|
| +}
|
|
|
| - *inColor = *outColor;
|
| +void GrGLProgramBuilder::emitTransforms(const GrProcessorStage& effectStage,
|
| + GrGLProcessor::TransformedCoordsArray* outCoords,
|
| + GrGLInstalledProcessors* installedProcessors) {
|
| + SkTArray<GrGLInstalledProcessors::Transform, true>& transforms =
|
| + installedProcessors->addTransforms();
|
| + const GrProcessor* effect = effectStage.getProcessor();
|
| + int numTransforms = effect->numTransforms();
|
| + transforms.push_back_n(numTransforms);
|
| +
|
| + for (int t = 0; t < numTransforms; t++) {
|
| + const char* uniName = "StageMatrix";
|
| + GrSLType varyingType =
|
| + effectStage.isPerspectiveCoordTransform(t, fVS.hasExplicitLocalCoords()) ?
|
| + kVec3f_GrSLType :
|
| + kVec2f_GrSLType;
|
| +
|
| + SkString suffixedUniName;
|
| + if (0 != t) {
|
| + suffixedUniName.append(uniName);
|
| + suffixedUniName.appendf("_%i", t);
|
| + uniName = suffixedUniName.c_str();
|
| + }
|
| + transforms[t].fHandle = this->addUniform(GrGLProgramBuilder::kVertex_Visibility,
|
| + kMat33f_GrSLType,
|
| + uniName,
|
| + &uniName).toShaderBuilderIndex();
|
| +
|
| + const char* varyingName = "MatrixCoord";
|
| + SkString suffixedVaryingName;
|
| + if (0 != t) {
|
| + suffixedVaryingName.append(varyingName);
|
| + suffixedVaryingName.appendf("_%i", t);
|
| + varyingName = suffixedVaryingName.c_str();
|
| + }
|
| + const char* vsVaryingName;
|
| + const char* fsVaryingName;
|
| + this->addVarying(varyingType, varyingName, &vsVaryingName, &fsVaryingName);
|
| +
|
| + const GrGLShaderVar& coords =
|
| + kPosition_GrCoordSet == effect->coordTransform(t).sourceCoords() ?
|
| + fVS.positionAttribute() :
|
| + fVS.localCoordsAttribute();
|
| +
|
| + // varying = matrix * coords (logically)
|
| + SkASSERT(kVec2f_GrSLType == varyingType || kVec3f_GrSLType == varyingType);
|
| + if (kVec2f_GrSLType == varyingType) {
|
| + fVS.codeAppendf("%s = (%s * vec3(%s, 1)).xy;",
|
| + vsVaryingName, uniName, coords.c_str());
|
| + } else {
|
| + fVS.codeAppendf("%s = %s * vec3(%s, 1);",
|
| + vsVaryingName, uniName, coords.c_str());
|
| + }
|
| + SkNEW_APPEND_TO_TARRAY(outCoords, GrGLProcessor::TransformedCoords,
|
| + (SkString(fsVaryingName), varyingType));
|
| + }
|
| }
|
|
|
| -void GrGLProgramBuilder::emitSamplers(const GrProcessor& effect,
|
| - GrGLProcessor::TextureSamplerArray* outSamplers) {
|
| - SkTArray<GrGLProgramEffects::Sampler, true>& samplers =
|
| - this->getProgramEffects()->addSamplers();
|
| - int numTextures = effect.numTextures();
|
| +void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor,
|
| + GrGLProcessor::TextureSamplerArray* outSamplers,
|
| + GrGLInstalledProcessors* installedProcessors) {
|
| + SkTArray<GrGLInstalledProcessors::Sampler, true>& samplers = installedProcessors->addSamplers();
|
| + int numTextures = processor.numTextures();
|
| samplers.push_back_n(numTextures);
|
| SkString name;
|
| for (int t = 0; t < numTextures; ++t) {
|
| @@ -224,27 +404,37 @@ void GrGLProgramBuilder::emitSamplers(const GrProcessor& effect,
|
| kSampler2D_GrSLType,
|
| name.c_str());
|
| SkNEW_APPEND_TO_TARRAY(outSamplers, GrGLProcessor::TextureSampler,
|
| - (samplers[t].fUniform, effect.textureAccess(t)));
|
| + (samplers[t].fUniform, processor.textureAccess(t)));
|
| }
|
| }
|
|
|
| -bool GrGLProgramBuilder::finish() {
|
| - SkASSERT(0 == fProgramID);
|
| - GL_CALL_RET(fProgramID, CreateProgram());
|
| - if (!fProgramID) {
|
| - return false;
|
| +GrGLProgram* GrGLProgramBuilder::finalize() {
|
| + // verify we can get a program id
|
| + GrGLuint programID;
|
| + GL_CALL_RET(programID, CreateProgram());
|
| + if (0 == programID) {
|
| + return NULL;
|
| }
|
|
|
| + // compile shaders and bind attributes / uniforms
|
| SkTDArray<GrGLuint> shadersToDelete;
|
| -
|
| - if (!this->compileAndAttachShaders(fProgramID, &shadersToDelete)) {
|
| - GL_CALL(DeleteProgram(fProgramID));
|
| - return false;
|
| + if (!fFS.compileAndAttachShaders(programID, &shadersToDelete)) {
|
| + this->cleanupProgram(programID, shadersToDelete);
|
| + return NULL;
|
| }
|
| -
|
| - this->bindProgramLocations(fProgramID);
|
| -
|
| - GL_CALL(LinkProgram(fProgramID));
|
| + if (!this->header().fUseFragShaderOnly) {
|
| + if (!fVS.compileAndAttachShaders(programID, &shadersToDelete)) {
|
| + this->cleanupProgram(programID, shadersToDelete);
|
| + return NULL;
|
| + }
|
| + fVS.bindVertexAttributes(programID);
|
| + }
|
| + bool usingBindUniform = fGpu->glInterface()->fFunctions.fBindUniformLocation != NULL;
|
| + if (usingBindUniform) {
|
| + this->bindUniformLocations(programID);
|
| + }
|
| + fFS.bindFragmentShaderLocations(programID);
|
| + GL_CALL(LinkProgram(programID));
|
|
|
| // Calling GetProgramiv is expensive in Chromium. Assume success in release builds.
|
| bool checkLinked = !fGpu->ctxInfo().isChromium();
|
| @@ -252,80 +442,78 @@ bool GrGLProgramBuilder::finish() {
|
| checkLinked = true;
|
| #endif
|
| if (checkLinked) {
|
| - GrGLint linked = GR_GL_INIT_ZERO;
|
| - GL_CALL(GetProgramiv(fProgramID, GR_GL_LINK_STATUS, &linked));
|
| - if (!linked) {
|
| - GrGLint infoLen = GR_GL_INIT_ZERO;
|
| - GL_CALL(GetProgramiv(fProgramID, GR_GL_INFO_LOG_LENGTH, &infoLen));
|
| - SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
|
| - if (infoLen > 0) {
|
| - // retrieve length even though we don't need it to workaround
|
| - // bug in chrome cmd buffer param validation.
|
| - GrGLsizei length = GR_GL_INIT_ZERO;
|
| - GL_CALL(GetProgramInfoLog(fProgramID,
|
| - infoLen+1,
|
| - &length,
|
| - (char*)log.get()));
|
| - GrPrintf((char*)log.get());
|
| - }
|
| - SkDEBUGFAIL("Error linking program");
|
| - GL_CALL(DeleteProgram(fProgramID));
|
| - fProgramID = 0;
|
| - return false;
|
| - }
|
| + checkLinkStatus(programID);
|
| }
|
| -
|
| - this->resolveProgramLocations(fProgramID);
|
| -
|
| - for (int i = 0; i < shadersToDelete.count(); ++i) {
|
| - GL_CALL(DeleteShader(shadersToDelete[i]));
|
| + if (!usingBindUniform) {
|
| + this->resolveUniformLocations(programID);
|
| }
|
|
|
| - return true;
|
| -}
|
| + this->cleanupShaders(shadersToDelete);
|
|
|
| -bool GrGLProgramBuilder::compileAndAttachShaders(GrGLuint programId,
|
| - SkTDArray<GrGLuint>* shaderIds) const {
|
| - return fFS.compileAndAttachShaders(programId, shaderIds);
|
| + return this->createProgram(programID);
|
| }
|
|
|
| -void GrGLProgramBuilder::bindProgramLocations(GrGLuint programId) {
|
| - fFS.bindProgramLocations(programId);
|
| -
|
| - // skbug.com/2056
|
| - bool usingBindUniform = fGpu->glInterface()->fFunctions.fBindUniformLocation != NULL;
|
| - if (usingBindUniform) {
|
| - int count = fUniforms.count();
|
| - for (int i = 0; i < count; ++i) {
|
| - GL_CALL(BindUniformLocation(programId, i, fUniforms[i].fVariable.c_str()));
|
| - fUniforms[i].fLocation = i;
|
| - }
|
| +void GrGLProgramBuilder::bindUniformLocations(GrGLuint programID) {
|
| + int count = fUniforms.count();
|
| + for (int i = 0; i < count; ++i) {
|
| + GL_CALL(BindUniformLocation(programID, i, fUniforms[i].fVariable.c_str()));
|
| + fUniforms[i].fLocation = i;
|
| }
|
| }
|
|
|
| -void GrGLProgramBuilder::resolveProgramLocations(GrGLuint programId) {
|
| - bool usingBindUniform = fGpu->glInterface()->fFunctions.fBindUniformLocation != NULL;
|
| - if (!usingBindUniform) {
|
| - int count = fUniforms.count();
|
| - for (int i = 0; i < count; ++i) {
|
| - GrGLint location;
|
| - GL_CALL_RET(location,
|
| - GetUniformLocation(programId, fUniforms[i].fVariable.c_str()));
|
| - fUniforms[i].fLocation = location;
|
| +bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID) {
|
| + GrGLint linked = GR_GL_INIT_ZERO;
|
| + GL_CALL(GetProgramiv(programID, GR_GL_LINK_STATUS, &linked));
|
| + if (!linked) {
|
| + GrGLint infoLen = GR_GL_INIT_ZERO;
|
| + GL_CALL(GetProgramiv(programID, GR_GL_INFO_LOG_LENGTH, &infoLen));
|
| + SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
|
| + if (infoLen > 0) {
|
| + // retrieve length even though we don't need it to workaround
|
| + // bug in chrome cmd buffer param validation.
|
| + GrGLsizei length = GR_GL_INIT_ZERO;
|
| + GL_CALL(GetProgramInfoLog(programID,
|
| + infoLen+1,
|
| + &length,
|
| + (char*)log.get()));
|
| + GrPrintf((char*)log.get());
|
| }
|
| + SkDEBUGFAIL("Error linking program");
|
| + GL_CALL(DeleteProgram(programID));
|
| + programID = 0;
|
| }
|
| + return SkToBool(linked);
|
| +}
|
|
|
| - int count = fSeparableVaryingInfos.count();
|
| +void GrGLProgramBuilder::resolveUniformLocations(GrGLuint programID) {
|
| + int count = fUniforms.count();
|
| for (int i = 0; i < count; ++i) {
|
| GrGLint location;
|
| - GL_CALL_RET(location,
|
| - GetProgramResourceLocation(programId,
|
| - GR_GL_FRAGMENT_INPUT,
|
| - fSeparableVaryingInfos[i].fVariable.c_str()));
|
| - fSeparableVaryingInfos[i].fLocation = location;
|
| + GL_CALL_RET(location, GetUniformLocation(programID, fUniforms[i].fVariable.c_str()));
|
| + fUniforms[i].fLocation = location;
|
| }
|
| }
|
|
|
| -const GrGLContextInfo& GrGLProgramBuilder::ctxInfo() const {
|
| - return fGpu->ctxInfo();
|
| +void GrGLProgramBuilder::cleanupProgram(GrGLuint programID, const SkTDArray<GrGLuint>& shaderIDs) {
|
| + GL_CALL(DeleteProgram(programID));
|
| + cleanupShaders(shaderIDs);
|
| +}
|
| +void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs) {
|
| + for (int i = 0; i < shaderIDs.count(); ++i) {
|
| + GL_CALL(DeleteShader(shaderIDs[i]));
|
| + }
|
| +}
|
| +
|
| +GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) {
|
| + return SkNEW_ARGS(GrGLProgram, (fGpu, fDesc, fUniformHandles, programID, fUniforms,
|
| + fGeometryProcessor, fColorEffects, fCoverageEffects));
|
| +}
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +
|
| +GrGLInstalledProcessors::~GrGLInstalledProcessors() {
|
| + int numEffects = fGLProcessors.count();
|
| + for (int e = 0; e < numEffects; ++e) {
|
| + SkDELETE(fGLProcessors[e]);
|
| + }
|
| }
|
|
|