Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(326)

Unified Diff: src/gpu/gl/builders/GrGLProgramBuilder.cpp

Issue 491673002: Initial refactor of shaderbuilder (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/gpu/gl/builders/GrGLProgramBuilder.h ('k') | src/gpu/gl/builders/GrGLSLPrettyPrint.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/gpu/gl/builders/GrGLProgramBuilder.cpp
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f4ee32b48db2579ff4b3ff9259c63d7829020690
--- /dev/null
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -0,0 +1,409 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gl/GrGLProgram.h"
+#include "gl/GrGLSLPrettyPrint.h"
+#include "gl/GrGLUniformHandle.h"
+#include "GrCoordTransform.h"
+#include "GrDrawEffect.h"
+#include "../GrGpuGL.h"
+#include "GrGLFragmentShaderBuilder.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 GrEffectStage* colorStages[],
+ const GrEffectStage* coverageStages[]) {
+ const GrGLProgramDesc::KeyHeader& header = this->desc().getHeader();
+
+ fFS.emitCodeBeforeEffects();
+
+ ///////////////////////////////////////////////////////////////////////////
+ // 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);
+ }
+
+ 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::kSolidWhite_ColorInput == header.fCoverageInput) {
+ inputCoverage = GrGLSLExpr4(1);
+ }
+
+ this->emitCodeBeforeEffects(&inputColor, &inputCoverage);
+
+ ///////////////////////////////////////////////////////////////////////////
+ // emit the per-effect code for both color and coverage effects
+
+ GrGLProgramDesc::EffectKeyProvider colorKeyProvider(
+ &this->desc(), GrGLProgramDesc::EffectKeyProvider::kColor_EffectType);
+ fColorEffects.reset(this->createAndEmitEffects(colorStages,
+ this->desc().numColorEffects(),
+ colorKeyProvider,
+ &inputColor));
+
+ GrGLProgramDesc::EffectKeyProvider coverageKeyProvider(
+ &this->desc(), GrGLProgramDesc::EffectKeyProvider::kCoverage_EffectType);
+ fCoverageEffects.reset(this->createAndEmitEffects(coverageStages,
+ this->desc().numCoverageEffects(),
+ coverageKeyProvider,
+ &inputCoverage));
+
+ this->emitCodeAfterEffects();
+
+ fFS.emitCodeAfterEffects(inputColor, inputCoverage);
+
+ if (!this->finish()) {
+ return false;
+ }
+
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+GrGLProgramBuilder::GrGLProgramBuilder(GrGpuGL* gpu,
+ const GrGLProgramDesc& desc)
+ : fFragOnly(!desc.getHeader().fHasVertexCode && gpu->shouldUseFixedFunctionTexturing())
+ , fTexCoordSetCnt(0)
+ , fProgramID(0)
+ , fFS(this, desc)
+ , fDesc(desc)
+ , fGpu(gpu)
+ , fUniforms(kVarsPerBlock) {
+}
+
+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 (out->endsWith('_')) {
+ // Names containing "__" are reserved.
+ out->append("x");
+ }
+ out->appendf("_Stage%d", fCodeStage.stageIndex());
+ }
+}
+
+GrGLProgramDataManager::UniformHandle GrGLProgramBuilder::addUniformArray(uint32_t visibility,
+ GrSLType type,
+ const char* name,
+ int count,
+ const char** outName) {
+ SkASSERT(name && strlen(name));
+ SkDEBUGCODE(static const uint32_t kVisibilityMask = kVertex_Visibility | kFragment_Visibility);
+ SkASSERT(0 == (~kVisibilityMask & visibility));
+ SkASSERT(0 != visibility);
+
+ UniformInfo& uni = fUniforms.push_back();
+ uni.fVariable.setType(type);
+ uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
+ this->nameVariable(uni.fVariable.accessName(), 'u', name);
+ uni.fVariable.setArrayCount(count);
+ uni.fVisibility = visibility;
+
+ // If it is visible in both the VS and FS, the precision must match.
+ // We declare a default FS precision, but not a default VS. So set the var
+ // to use the default FS precision.
+ if ((kVertex_Visibility | kFragment_Visibility) == visibility) {
+ // the fragment and vertex precisions must match
+ uni.fVariable.setPrecision(kDefaultFragmentPrecision);
+ }
+
+ if (NULL != outName) {
+ *outName = uni.fVariable.c_str();
+ }
+ 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) {
+ if (fUniforms[i].fVisibility & visibility) {
+ fUniforms[i].fVariable.appendDecl(this->ctxInfo(), out);
+ out->append(";\n");
+ }
+ }
+}
+
+void GrGLProgramBuilder::createAndEmitEffects(GrGLProgramEffectsBuilder* programEffectsBuilder,
+ const GrEffectStage* effectStages[],
+ int effectCnt,
+ const GrGLProgramDesc::EffectKeyProvider& keyProvider,
+ GrGLSLExpr4* fsInOutColor) {
+ bool effectEmitted = false;
+
+ GrGLSLExpr4 inColor = *fsInOutColor;
+ GrGLSLExpr4 outColor;
+
+ for (int e = 0; e < effectCnt; ++e) {
+ SkASSERT(NULL != effectStages[e] && NULL != effectStages[e]->getEffect());
+ const GrEffectStage& stage = *effectStages[e];
+
+ CodeStage::AutoStageRestore csar(&fCodeStage, &stage);
+
+ 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;
+
+
+ programEffectsBuilder->emitEffect(stage,
+ keyProvider.get(e),
+ outColor.c_str(),
+ inColor.isOnes() ? NULL : inColor.c_str(),
+ fCodeStage.stageIndex());
+
+ inColor = outColor;
+ effectEmitted = true;
+ }
+
+ if (effectEmitted) {
+ *fsInOutColor = outColor;
+ }
+}
+
+bool GrGLProgramBuilder::finish() {
+ SkASSERT(0 == fProgramID);
+ GL_CALL_RET(fProgramID, CreateProgram());
+ if (!fProgramID) {
+ return false;
+ }
+
+ SkTDArray<GrGLuint> shadersToDelete;
+
+ if (!this->compileAndAttachShaders(fProgramID, &shadersToDelete)) {
+ GL_CALL(DeleteProgram(fProgramID));
+ return false;
+ }
+
+ this->bindProgramLocations(fProgramID);
+
+ GL_CALL(LinkProgram(fProgramID));
+
+ // Calling GetProgramiv is expensive in Chromium. Assume success in release builds.
+ bool checkLinked = !fGpu->ctxInfo().isChromium();
+#ifdef SK_DEBUG
+ 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;
+ }
+ }
+
+ this->resolveProgramLocations(fProgramID);
+
+ for (int i = 0; i < shadersToDelete.count(); ++i) {
+ GL_CALL(DeleteShader(shadersToDelete[i]));
+ }
+
+ return true;
+}
+
+bool GrGLProgramBuilder::compileAndAttachShaders(GrGLuint programId,
+ SkTDArray<GrGLuint>* shaderIds) const {
+ return fFS.compileAndAttachShaders(programId, shaderIds);
+}
+
+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::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;
+ }
+ }
+}
+
+const GrGLContextInfo& GrGLProgramBuilder::ctxInfo() const {
+ return fGpu->ctxInfo();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+GrGLFullProgramBuilder::GrGLFullProgramBuilder(GrGpuGL* gpu,
+ const GrGLProgramDesc& desc)
+ : INHERITED(gpu, desc)
+ , fGS(this)
+ , fVS(this) {
+}
+
+void GrGLFullProgramBuilder::emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) {
+ fVS.emitCodeBeforeEffects(color, coverage);
+}
+
+void GrGLFullProgramBuilder::emitCodeAfterEffects() {
+ fVS.emitCodeAfterEffects();
+}
+
+void GrGLFullProgramBuilder::addVarying(GrSLType type,
+ const char* name,
+ const char** vsOutName,
+ const char** fsInName) {
+ fVS.addVarying(type, name, vsOutName);
+
+ SkString* fsInputName = fVS.fOutputs.back().accessName();
+
+#if GR_GL_EXPERIMENTAL_GS
+ if (desc().getHeader().fExperimentalGS) {
+ // TODO let the caller use these names
+ fGS.addVarying(type, fsInputName->c_str(), NULL);
+ fsInputName = fGS.fOutputs.back().accessName();
+ }
+#endif
+ fFS.addVarying(type, fsInputName->c_str(), fsInName);
+}
+
+GrGLProgramEffects* GrGLFullProgramBuilder::createAndEmitEffects(
+ const GrEffectStage* effectStages[],
+ int effectCnt,
+ const GrGLProgramDesc::EffectKeyProvider& keyProvider,
+ GrGLSLExpr4* inOutFSColor) {
+
+ GrGLVertexProgramEffectsBuilder programEffectsBuilder(this, effectCnt);
+ this->INHERITED::createAndEmitEffects(&programEffectsBuilder,
+ effectStages,
+ effectCnt,
+ keyProvider,
+ inOutFSColor);
+ return programEffectsBuilder.finish();
+}
+
+bool GrGLFullProgramBuilder::compileAndAttachShaders(GrGLuint programId,
+ SkTDArray<GrGLuint>* shaderIds) const {
+ return INHERITED::compileAndAttachShaders(programId, shaderIds)
+ && fVS.compileAndAttachShaders(programId, shaderIds)
+#if GR_GL_EXPERIMENTAL_GS
+ && (!desc().getHeader().fExperimentalGS
+ || fGS.compileAndAttachShaders(programId, shaderIds))
+#endif
+ ;
+}
+
+void GrGLFullProgramBuilder::bindProgramLocations(GrGLuint programId) {
+ fVS.bindProgramLocations(programId);
+ INHERITED::bindProgramLocations(programId);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+GrGLFragmentOnlyProgramBuilder::GrGLFragmentOnlyProgramBuilder(GrGpuGL* gpu,
+ const GrGLProgramDesc& desc)
+ : INHERITED(gpu, desc) {
+ SkASSERT(!desc.getHeader().fHasVertexCode);
+ SkASSERT(gpu->glCaps().pathRenderingSupport());
+ SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fColorInput);
+ SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fCoverageInput);
+}
+
+int GrGLFragmentOnlyProgramBuilder::addTexCoordSets(int count) {
+ int firstFreeCoordSet = fTexCoordSetCnt;
+ fTexCoordSetCnt += count;
+ SkASSERT(gpu()->glCaps().maxFixedFunctionTextureCoords() >= fTexCoordSetCnt);
+ return firstFreeCoordSet;
+}
+
+GrGLProgramEffects* GrGLFragmentOnlyProgramBuilder::createAndEmitEffects(
+ const GrEffectStage* effectStages[], int effectCnt,
+ const GrGLProgramDesc::EffectKeyProvider& keyProvider, GrGLSLExpr4* inOutFSColor) {
+
+ GrGLPathTexGenProgramEffectsBuilder pathTexGenEffectsBuilder(this,
+ effectCnt);
+ this->INHERITED::createAndEmitEffects(&pathTexGenEffectsBuilder,
+ effectStages,
+ effectCnt,
+ keyProvider,
+ inOutFSColor);
+ return pathTexGenEffectsBuilder.finish();
+}
« no previous file with comments | « src/gpu/gl/builders/GrGLProgramBuilder.h ('k') | src/gpu/gl/builders/GrGLSLPrettyPrint.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698