* found in the LICENSE file.
*/
+#include "GrGLProgramBuilder.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,
+ GrGpu::DrawType drawType,
+ 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(optState,
+ drawType,
+ optState.hasGeometryProcessor(),
+ gpu));
+
+ GrGLProgramBuilder* pb = builder.get();
+ const GrGLProgramDescBuilder::GLKeyHeader& header = GrGLProgramDescBuilder::GetHeader(pb->desc());
+
+ // 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;
- GrGLSLExpr4 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);
+ GrGLSLExpr1 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.fUseNvpr &&
+ gpu->glPathRendering()->texturingMode() ==
+ GrGLPathRendering::FixedFunction_TexturingMode);
+ if (hasVertexShader) {
+ pb->fVS.setupLocalCoords();
+ pb->fVS.transformGLToSkiaCoords();
+ if (header.fEmitsPointSize) {
+ pb->fVS.codeAppend("gl_PointSize = 1.0;");
+ }
+ if (GrProgramDesc::kAttribute_ColorInput == header.fColorInput) {
+ pb->fVS.setupBuiltinVertexAttribute("Color", &inputColor);
+ }
+ if (GrProgramDesc::kAttribute_ColorInput == header.fCoverageInput) {
+ pb->fVS.setupBuiltinVertexAttribute("Coverage", &inputCoverage);
+ }
}
- 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);
- }
+ // TODO: Once all stages can handle taking a float or vec4 and correctly handling them we can
+ // remove this cast to a vec4.
+ GrGLSLExpr4 inputCoverageVec4 = GrGLSLExpr4::VectorCast(inputCoverage);
- // Subclasses drive effect emitting
- this->createAndEmitEffects(geometryProcessor, colorStages, coverageStages, &inputColor,
- &inputCoverage);
+ pb->emitAndInstallProcs(optState, &inputColor, &inputCoverageVec4);
- fFS.emitCodeAfterEffects(inputColor, inputCoverage);
+ if (hasVertexShader) {
+ pb->fVS.transformSkiaToGLCoords();
+ }
- if (!this->finish()) {
- return false;
+ // write the secondary color output if necessary
+ if (GrProgramDesc::kNone_SecondaryOutputType != header.fSecondaryOutputType) {
+ pb->fFS.enableSecondaryOutput(inputColor, inputCoverageVec4);
}
- return true;
+ pb->fFS.combineColorAndCoverage(inputColor, inputCoverageVec4);
+
+ return pb->finalize();
}
-//////////////////////////////////////////////////////////////////////////////
+GrGLProgramBuilder*
+GrGLProgramBuilder::CreateProgramBuilder(const GrOptDrawState& optState,
+ GrGpu::DrawType drawType,
+ bool hasGeometryProcessor,
+ GrGpuGL* gpu) {
+ const GrProgramDesc& desc = optState.programDesc();
+ if (GrGLProgramDescBuilder::GetHeader(desc).fUseNvpr) {
+ SkASSERT(gpu->glCaps().pathRenderingSupport());
+ SkASSERT(GrProgramDesc::kAttribute_ColorInput != desc.header().fColorInput);
+ SkASSERT(GrProgramDesc::kAttribute_ColorInput != desc.header().fCoverageInput);
+ SkASSERT(!hasGeometryProcessor);
+ if (gpu->glPathRendering()->texturingMode() ==
+ GrGLPathRendering::FixedFunction_TexturingMode) {
+ return SkNEW_ARGS(GrGLLegacyNvprProgramBuilder, (gpu, optState));
+ } else {
+ return SkNEW_ARGS(GrGLNvprProgramBuilder, (gpu, optState));
+ }
+ } else {
+ return SkNEW_ARGS(GrGLProgramBuilder, (gpu, optState));
+ }
+}
-GrGLProgramBuilder::GrGLProgramBuilder(GrGpuGL* gpu,
- const GrGLProgramDesc& desc)
- : fEffectEmitter(NULL)
- , fFragOnly(SkToBool(desc.getHeader().fUseFragShaderOnly))
- , fTexCoordSetCnt(0)
- , fProgramID(0)
- , fFS(this, desc)
- , fSeparableVaryingInfos(kVarsPerBlock)
- , fGrProcessorEmitter(this)
- , fDesc(desc)
+/////////////////////////////////////////////////////////////////////////////
+
+GrGLProgramBuilder::GrGLProgramBuilder(GrGpuGL* gpu, const GrOptDrawState& optState)
+ : fVS(this)
+ , fGS(this)
+ , fFS(this, optState.programDesc().header().fFragPosKey)
+ , fOutOfStage(true)
+ , fStageIndex(-1)
+ , fGeometryProcessor(NULL)
+ , fOptState(optState)
+ , fDesc(optState.programDesc())
, fGpu(gpu)
, fUniforms(kVarsPerBlock) {
}
+void GrGLProgramBuilder::addVarying(const char* name,
+ GrGLVarying* varying,
+ GrGLShaderVar::Precision fsPrecision) {
+ SkASSERT(varying);
+ if (varying->vsVarying()) {
+ fVS.addVarying(name, varying);
+ }
+ if (fOptState.hasGeometryProcessor() && fOptState.getGeometryProcessor()->willUseGeoShader()) {
+ fGS.addVarying(name, varying);
+ }
+ if (varying->fsVarying()) {
+ fFS.addVarying(varying, 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);
}
}
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) {
}
}
-void GrGLProgramBuilder::createAndEmitEffects(const GrFragmentStage* effectStages[],
- int effectCnt,
- const GrGLProgramDesc::EffectKeyProvider& keyProvider,
- GrGLSLExpr4* fsInOutColor) {
- 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);
- effectEmitted = true;
+const GrGLContextInfo& GrGLProgramBuilder::ctxInfo() const {
+ return fGpu->ctxInfo();
+}
+
+void GrGLProgramBuilder::setupUniformColorAndCoverageIfNeeded(GrGLSLExpr4* inputColor,
+ GrGLSLExpr1* inputCoverage) {
+ const GrProgramDesc::KeyHeader& header = this->header();
+ if (GrProgramDesc::kUniform_ColorInput == header.fColorInput) {
+ const char* name;
+ fUniformHandles.fColorUni =
+ this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
+ kVec4f_GrSLType,
+ "Color",
+ &name);
+ *inputColor = GrGLSLExpr4(name);
+ } else if (GrProgramDesc::kAllOnes_ColorInput == header.fColorInput) {
+ *inputColor = GrGLSLExpr4(1);
}
+ if (GrProgramDesc::kUniform_ColorInput == header.fCoverageInput) {
+ const char* name;
+ fUniformHandles.fCoverageUni =
+ this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
+ kFloat_GrSLType,
+ "Coverage",
+ &name);
+ *inputCoverage = GrGLSLExpr1(name);
+ } else if (GrProgramDesc::kAllOnes_ColorInput == header.fCoverageInput) {
+ *inputCoverage = GrGLSLExpr1(1);
+ }
+}
- if (effectEmitted) {
- *fsInOutColor = outColor;
+void GrGLProgramBuilder::emitAndInstallProcs(const GrOptDrawState& optState,
+ GrGLSLExpr4* inputColor,
+ GrGLSLExpr4* inputCoverage) {
+ fFragmentProcessors.reset(SkNEW(GrGLInstalledFragProcs));
+ int numProcs = optState.numFragmentStages();
+ this->emitAndInstallFragProcs(0, optState.numColorStages(), inputColor);
+ if (optState.hasGeometryProcessor()) {
+ const GrGeometryProcessor& gp = *optState.getGeometryProcessor();
+ fVS.emitAttributes(gp);
+ ProcKeyProvider keyProvider(&fDesc,
+ ProcKeyProvider::kGeometry_ProcessorType,
+ GrGLProgramDescBuilder::kProcessorKeyOffsetsAndLengthOffset);
+ GrGLSLExpr4 output;
+ this->emitAndInstallProc<GrGeometryProcessor>(gp, 0, keyProvider, *inputCoverage, &output);
+ *inputCoverage = output;
}
+ this->emitAndInstallFragProcs(optState.numColorStages(), numProcs, inputCoverage);
}
-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;
+void GrGLProgramBuilder::emitAndInstallFragProcs(int procOffset, int numProcs, GrGLSLExpr4* inOut) {
+ ProcKeyProvider keyProvider(&fDesc,
+ ProcKeyProvider::kFragment_ProcessorType,
+ GrGLProgramDescBuilder::kProcessorKeyOffsetsAndLengthOffset);
+ for (int e = procOffset; e < numProcs; ++e) {
+ GrGLSLExpr4 output;
+ const GrFragmentStage& stage = fOptState.getFragmentStage(e);
+ this->emitAndInstallProc<GrFragmentStage>(stage, e, keyProvider, *inOut, &output);
+ *inOut = output;
}
+}
+
+// TODO Processors cannot output zeros because an empty string is all 1s
+// the fix is to allow effects to take the GrGLSLExpr4 directly
+template <class Proc>
+void GrGLProgramBuilder::emitAndInstallProc(const Proc& proc,
+ int index,
+ const ProcKeyProvider& keyProvider,
+ const GrGLSLExpr4& input,
+ GrGLSLExpr4* output) {
+ // Program builders have a bit of state we need to clear with each effect
+ AutoStageAdvance adv(this);
// create var to hold stage result
SkString outColorName;
this->nameVariable(&outColorName, '\0', "output");
- fFS.codeAppendf("\tvec4 %s;\n", outColorName.c_str());
- *outColor = outColorName;
+ fFS.codeAppendf("vec4 %s;", outColorName.c_str());
+ *output = outColorName;
- this->emitEffect(effectStage, keyProvider.get(effectIndex), outColor->c_str(),
- inColor->isOnes() ? NULL : inColor->c_str(), fCodeStage.stageIndex());
+ // Enclose custom code in a block to avoid namespace conflicts
+ SkString openBrace;
+ openBrace.printf("{ // Stage %d\n", fStageIndex);
+ fFS.codeAppend(openBrace.c_str());
- *inColor = *outColor;
+ this->emitAndInstallProc(proc, keyProvider.get(index), output->c_str(),
+ input.isOnes() ? NULL : input.c_str());
+
+ fFS.codeAppend("}");
}
-void GrGLProgramBuilder::emitSamplers(const GrProcessor& effect,
- GrGLProcessor::TextureSamplerArray* outSamplers) {
- SkTArray<GrGLProgramEffects::Sampler, true>& samplers =
- this->getProgramEffects()->addSamplers();
- int numTextures = effect.numTextures();
- samplers.push_back_n(numTextures);
+void GrGLProgramBuilder::emitAndInstallProc(const GrFragmentStage& fs,
+ const GrProcessorKey& key,
+ const char* outColor,
+ const char* inColor) {
+ GrGLInstalledFragProc* ifp = SkNEW_ARGS(GrGLInstalledFragProc, (fVS.hasLocalCoords()));
+
+ const GrFragmentProcessor& fp = *fs.getProcessor();
+ ifp->fGLProc.reset(fp.getFactory().createGLInstance(fp));
+
+ SkSTArray<4, GrGLProcessor::TextureSampler> samplers(fp.numTextures());
+ this->emitSamplers(fp, &samplers, ifp);
+
+ // Fragment processors can have coord transforms
+ SkSTArray<2, GrGLProcessor::TransformedCoords> coords(fp.numTransforms());
+ this->emitTransforms(fs, &coords, ifp);
+
+ ifp->fGLProc->emitCode(this, fp, key, outColor, inColor, 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(fp);
+ fFragmentProcessors->fProcs.push_back(ifp);
+}
+
+void GrGLProgramBuilder::emitAndInstallProc(const GrGeometryProcessor& gp,
+ const GrProcessorKey& key,
+ const char* outColor,
+ const char* inColor) {
+ SkASSERT(!fGeometryProcessor);
+ fGeometryProcessor = SkNEW(GrGLInstalledGeoProc);
+
+ fGeometryProcessor->fGLProc.reset(gp.getFactory().createGLInstance(gp));
+
+ SkSTArray<4, GrGLProcessor::TextureSampler> samplers(gp.numTextures());
+ this->emitSamplers(gp, &samplers, fGeometryProcessor);
+
+ GrGLGeometryProcessor::EmitArgs args(this, gp, key, outColor, inColor, samplers);
+ fGeometryProcessor->fGLProc->emitCode(args);
+
+ // 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(gp);
+}
+
+void GrGLProgramBuilder::verify(const GrGeometryProcessor& gp) {
+ SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition());
+}
+
+void GrGLProgramBuilder::verify(const GrFragmentProcessor& fp) {
+ SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition());
+ SkASSERT(fFS.hasReadDstColor() == fp.willReadDstColor());
+}
+
+void GrGLProgramBuilder::emitTransforms(const GrFragmentStage& effectStage,
+ GrGLProcessor::TransformedCoordsArray* outCoords,
+ GrGLInstalledFragProc* ifp) {
+ const GrFragmentProcessor* effect = effectStage.getProcessor();
+ int numTransforms = effect->numTransforms();
+ ifp->fTransforms.push_back_n(numTransforms);
+
+ for (int t = 0; t < numTransforms; t++) {
+ const char* uniName = "StageMatrix";
+ GrSLType varyingType =
+ effectStage.isPerspectiveCoordTransform(t, fVS.hasLocalCoords()) ?
+ kVec3f_GrSLType :
+ kVec2f_GrSLType;
+
+ SkString suffixedUniName;
+ if (0 != t) {
+ suffixedUniName.append(uniName);
+ suffixedUniName.appendf("_%i", t);
+ uniName = suffixedUniName.c_str();
+ }
+ ifp->fTransforms[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();
+ }
+ GrGLVertToFrag v(varyingType);
+ this->addVarying(varyingName, &v);
+
+ 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;",
+ v.vsOut(), uniName, coords.c_str());
+ } else {
+ fVS.codeAppendf("%s = %s * vec3(%s, 1);",
+ v.vsOut(), uniName, coords.c_str());
+ }
+ SkNEW_APPEND_TO_TARRAY(outCoords, GrGLProcessor::TransformedCoords,
+ (SkString(v.fsIn()), varyingType));
+ }
+}
+
+void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor,
+ GrGLProcessor::TextureSamplerArray* outSamplers,
+ GrGLInstalledProc* ip) {
+ int numTextures = processor.numTextures();
+ ip->fSamplers.push_back_n(numTextures);
SkString name;
for (int t = 0; t < numTextures; ++t) {
name.printf("Sampler%d", t);
- samplers[t].fUniform = this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
- kSampler2D_GrSLType,
- name.c_str());
+ ip->fSamplers[t].fUniform = this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
+ kSampler2D_GrSLType,
+ name.c_str());
SkNEW_APPEND_TO_TARRAY(outSamplers, GrGLProcessor::TextureSampler,
- (samplers[t].fUniform, effect.textureAccess(t)));
+ (ip->fSamplers[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 (!(GrGLProgramDescBuilder::GetHeader(fDesc).fUseNvpr &&
+ fGpu->glPathRendering()->texturingMode() ==
+ GrGLPathRendering::FixedFunction_TexturingMode)) {
+ 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();
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()));
+ SkDebugf((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, fFragmentProcessors.get()));
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+GrGLInstalledFragProcs::~GrGLInstalledFragProcs() {
+ int numProcs = fProcs.count();
+ for (int e = 0; e < numProcs; ++e) {
+ SkDELETE(fProcs[e]);
+ }
}