Move loops that chain together effects into GrGLShaderBuilder from GrGLProgram.

R=robertphillips@google.com

Review URL: https://codereview.chromium.org/14925010

git-svn-id: http://skia.googlecode.com/svn/trunk@9073 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
bsalomon@google.com 2013-05-09 13:45:02 +00:00
parent be21431872
commit 504976ef6f
6 changed files with 211 additions and 150 deletions

View File

@ -87,7 +87,7 @@ GrSLType GrGLEffectMatrix::emitCode(GrGLShaderBuilder* builder,
&uniName);
}
const char* varyingName = "StageCoord";
const char* varyingName = "MatrixCoord";
SkString suffixedVaryingName;
if (NULL != suffix) {
suffixedVaryingName.append(varyingName);

View File

@ -485,35 +485,21 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) {
bool needColor, needFilterColor;
need_blend_inputs(filterColorCoeff, colorCoeff, &needFilterColor, &needColor);
if (needColor) {
///////////////////////////////////////////////////////////////////////////
// compute the color
// if we have color stages string them together, feeding the output color
// of each to the next and generating code for each stage.
SkString outColor;
for (int s = 0; s < fDesc.fFirstCoverageStage; ++s) {
if (GrGLEffect::kNoEffectKey != fDesc.fEffectKeys[s]) {
if (kZeros_GrSLConstantVec == knownColorValue) {
// Effects have no way to communicate zeros, they treat an empty string as ones.
inColor = "initialColor";
builder.fsCodeAppendf("\tvec4 %s = %s;\n", inColor.c_str(), GrGLSLZerosVecf(4));
}
// create var to hold stage result
outColor = "color";
outColor.appendS32(s);
builder.fsCodeAppendf("\tvec4 %s;\n", outColor.c_str());
// used in order for builder to return the per-stage uniform handles.
SkTArray<GrGLUniformManager::UniformHandle, true>* stageUniformArrays[GrDrawState::kNumStages];
builder.setCurrentStage(s);
fEffects[s] = builder.createAndEmitGLEffect(*stages[s],
fDesc.fEffectKeys[s],
inColor.size() ? inColor.c_str() : NULL,
outColor.c_str(),
&fUniformHandles.fEffectSamplerUnis[s]);
builder.setNonStage();
inColor = outColor;
knownColorValue = kNone_GrSLConstantVec;
}
if (needColor) {
for (int s = 0; s < fDesc.fFirstCoverageStage; ++s) {
stageUniformArrays[s] = &fUniformHandles.fEffectSamplerUnis[s];
}
builder.emitEffects(stages,
fDesc.fEffectKeys,
fDesc.fFirstCoverageStage,
&inColor,
&knownColorValue,
stageUniformArrays,
fEffects);
}
// Insert the color filter. This will soon be replaced by a color effect.
@ -540,37 +526,21 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) {
///////////////////////////////////////////////////////////////////////////
// compute the partial coverage
// incoming coverage to current stage being processed.
SkString inCoverage;
GrSLConstantVec knownCoverageValue = this->genInputCoverage(&builder, &inCoverage);
SkString outCoverage;
for (int s = fDesc.fFirstCoverageStage; s < GrDrawState::kNumStages; ++s) {
if (fDesc.fEffectKeys[s]) {
if (kZeros_GrSLConstantVec == knownCoverageValue) {
// Effects have no way to communicate zeros, they treat an empty string as ones.
inCoverage = "initialCoverage";
builder.fsCodeAppendf("\tvec4 %s = %s;\n", inCoverage.c_str(), GrGLSLZerosVecf(4));
}
// create var to hold stage output
outCoverage = "coverage";
outCoverage.appendS32(s);
builder.fsCodeAppendf("\tvec4 %s;\n", outCoverage.c_str());
builder.setCurrentStage(s);
fEffects[s] = builder.createAndEmitGLEffect(
*stages[s],
fDesc.fEffectKeys[s],
inCoverage.size() ? inCoverage.c_str() : NULL,
outCoverage.c_str(),
&fUniformHandles.fEffectSamplerUnis[s]);
builder.setNonStage();
inCoverage = outCoverage;
knownCoverageValue = kNone_GrSLConstantVec;
}
for (int s = fDesc.fFirstCoverageStage, i = 0; s < GrDrawState::kNumStages; ++s, ++i) {
stageUniformArrays[i] = &fUniformHandles.fEffectSamplerUnis[s];
}
builder.emitEffects(stages + fDesc.fFirstCoverageStage,
fDesc.fEffectKeys + fDesc.fFirstCoverageStage,
GrDrawState::kNumStages - fDesc.fFirstCoverageStage,
&inCoverage,
&knownCoverageValue,
stageUniformArrays,
fEffects + fDesc.fFirstCoverageStage);
// discard if coverage is zero
if (fDesc.fDiscardIfZeroCoverage && kOnes_GrSLConstantVec != knownCoverageValue) {
if (kZeros_GrSLConstantVec == knownCoverageValue) {

View File

@ -39,7 +39,7 @@ public:
void setRandom(SkMWCRandom*,
const GrGpuGL* gpu,
const GrTexture* dummyDstTexture,
const GrEffectStage stages[GrDrawState::kNumStages],
const GrEffectStage* stages[GrDrawState::kNumStages],
int currAttribIndex);
/**

View File

@ -103,7 +103,6 @@ GrGLShaderBuilder::GrGLShaderBuilder(const GrGLContextInfo& ctxInfo,
, fFSOutputs(kMaxFSOutputs)
, fCtxInfo(ctxInfo)
, fUniformManager(uniformManager)
, fCurrentStageIdx(kNonStageIdx)
, fFSFeaturesAddedMask(0)
#if GR_GL_EXPERIMENTAL_GS
, fUsesGS(desc.fExperimentalGS)
@ -215,6 +214,21 @@ void GrGLShaderBuilder::addFSFeature(uint32_t featureBit, const char* extensionN
}
}
void GrGLShaderBuilder::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());
}
}
const char* GrGLShaderBuilder::dstColor() {
static const char kFBFetchColorName[] = "gl_LastFragData[0]";
GrGLCaps::FBFetchType fetchType = fCtxInfo.caps()->fbFetchType();
@ -364,12 +378,7 @@ GrGLUniformManager::UniformHandle GrGLShaderBuilder::addUniformArray(uint32_t vi
GrAssert(h2 == h);
uni.fVariable.setType(type);
uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
SkString* uniName = uni.fVariable.accessName();
if (kNonStageIdx == fCurrentStageIdx) {
uniName->printf("u%s", name);
} else {
uniName->printf("u%s%d", name, fCurrentStageIdx);
}
this->nameVariable(uni.fVariable.accessName(), 'u', name);
uni.fVariable.setArrayCount(count);
uni.fVisibility = visibility;
@ -415,11 +424,8 @@ void GrGLShaderBuilder::addVarying(GrSLType type,
fVSOutputs.push_back();
fVSOutputs.back().setType(type);
fVSOutputs.back().setTypeModifier(GrGLShaderVar::kVaryingOut_TypeModifier);
if (kNonStageIdx == fCurrentStageIdx) {
fVSOutputs.back().accessName()->printf("v%s", name);
} else {
fVSOutputs.back().accessName()->printf("v%s%d", name, fCurrentStageIdx);
}
this->nameVariable(fVSOutputs.back().accessName(), 'v', name);
if (vsOutName) {
*vsOutName = fVSOutputs.back().getName().c_str();
}
@ -436,11 +442,7 @@ void GrGLShaderBuilder::addVarying(GrSLType type,
fGSOutputs.push_back();
fGSOutputs.back().setType(type);
fGSOutputs.back().setTypeModifier(GrGLShaderVar::kVaryingOut_TypeModifier);
if (kNonStageIdx == fCurrentStageIdx) {
fGSOutputs.back().accessName()->printf("g%s", name);
} else {
fGSOutputs.back().accessName()->printf("g%s%d", name, fCurrentStageIdx);
}
this->nameVariable(fGSOutputs.back().accessName(), 'g', name);
fsName = fGSOutputs.back().accessName();
} else {
fsName = fVSOutputs.back().accessName();
@ -470,18 +472,16 @@ const char* GrGLShaderBuilder::fragmentPosition() {
} else {
static const char* kCoordName = "fragCoordYDown";
if (!fSetupFragPosition) {
// temporarily change the stage index because we're inserting non-stage code.
CodeStage::AutoStageRestore csar(&fCodeStage, NULL);
GrAssert(GrGLUniformManager::kInvalidUniformHandle == fRTHeightUniform);
const char* rtHeightName;
// temporarily change the stage index because we're inserting a uniform whose name
// shouldn't be mangled to be stage-specific.
int oldStageIdx = fCurrentStageIdx;
fCurrentStageIdx = kNonStageIdx;
fRTHeightUniform = this->addUniform(kFragment_ShaderType,
kFloat_GrSLType,
"RTHeight",
&rtHeightName);
fCurrentStageIdx = oldStageIdx;
this->fFSCode.prependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoord.y, gl_FragCoord.zw);\n",
kCoordName, rtHeightName);
@ -514,11 +514,7 @@ void GrGLShaderBuilder::emitFunction(ShaderType shader,
SkString* outName) {
GrAssert(kFragment_ShaderType == shader);
fFSFunctions.append(GrGLSLTypeString(returnType));
if (kNonStageIdx != fCurrentStageIdx) {
outName->printf("%s_%d", name, fCurrentStageIdx);
} else {
*outName = name;
}
this->nameVariable(outName, '\0', name);
fFSFunctions.appendf(" %s", outName->c_str());
fFSFunctions.append("(");
for (int i = 0; i < argCnt; ++i) {
@ -623,52 +619,86 @@ void GrGLShaderBuilder::finished(GrGLuint programID) {
fUniformManager.getUniformLocations(programID, fUniforms);
}
GrGLEffect* GrGLShaderBuilder::createAndEmitGLEffect(
const GrEffectStage& stage,
GrGLEffect::EffectKey key,
const char* fsInColor,
const char* fsOutColor,
SkTArray<GrGLUniformManager::UniformHandle, true>* samplerHandles) {
GrAssert(NULL != stage.getEffect());
void GrGLShaderBuilder::emitEffects(
const GrEffectStage* effectStages[],
const GrBackendEffectFactory::EffectKey effectKeys[],
int effectCnt,
SkString* fsInOutColor,
GrSLConstantVec* fsInOutColorKnownValue,
SkTArray<GrGLUniformManager::UniformHandle, true>* effectSamplerHandles[],
GrGLEffect* glEffects[]) {
bool effectEmitted = false;
const GrEffectRef& effect = *stage.getEffect();
int numTextures = effect->numTextures();
SkSTArray<8, GrGLShaderBuilder::TextureSampler> textureSamplers;
textureSamplers.push_back_n(numTextures);
for (int i = 0; i < numTextures; ++i) {
textureSamplers[i].init(this, &effect->textureAccess(i), i);
samplerHandles->push_back(textureSamplers[i].fSamplerUniform);
}
GrDrawEffect drawEffect(stage, this->hasExplicitLocalCoords());
SkString inColor = *fsInOutColor;
SkString outColor;
int numAttributes = stage.getVertexAttribIndexCount();
const int* attributeIndices = stage.getVertexAttribIndices();
SkSTArray<GrEffect::kMaxVertexAttribs, SkString> attributeNames;
for (int i = 0; i < numAttributes; ++i) {
SkString attributeName("aAttr");
attributeName.appendS32(attributeIndices[i]);
if (this->addAttribute(effect->vertexAttribType(i), attributeName.c_str())) {
fEffectAttributes.push_back().set(attributeIndices[i], attributeName);
for (int e = 0; e < effectCnt; ++e) {
if (NULL == effectStages[e] || GrGLEffect::kNoEffectKey == effectKeys[e]) {
continue;
}
GrAssert(NULL != effectStages[e]->getEffect());
const GrEffectStage& stage = *effectStages[e];
const GrEffectRef& effect = *stage.getEffect();
CodeStage::AutoStageRestore csar(&fCodeStage, &stage);
int numTextures = effect->numTextures();
SkSTArray<8, GrGLShaderBuilder::TextureSampler> textureSamplers;
textureSamplers.push_back_n(numTextures);
for (int t = 0; t < numTextures; ++t) {
textureSamplers[t].init(this, &effect->textureAccess(t), t);
effectSamplerHandles[e]->push_back(textureSamplers[t].fSamplerUniform);
}
GrDrawEffect drawEffect(stage, this->hasExplicitLocalCoords());
int numAttributes = stage.getVertexAttribIndexCount();
const int* attributeIndices = stage.getVertexAttribIndices();
SkSTArray<GrEffect::kMaxVertexAttribs, SkString> attributeNames;
for (int a = 0; a < numAttributes; ++a) {
// TODO: Make addAttribute mangle the name.
SkString attributeName("aAttr");
attributeName.appendS32(attributeIndices[a]);
if (this->addAttribute(effect->vertexAttribType(a), attributeName.c_str())) {
fEffectAttributes.push_back().set(attributeIndices[a], attributeName);
}
}
glEffects[e] = effect->getFactory().createGLInstance(drawEffect);
if (kZeros_GrSLConstantVec == *fsInOutColorKnownValue) {
// Effects have no way to communicate zeros, they treat an empty string as ones.
this->nameVariable(&inColor, '\0', "input");
this->fsCodeAppendf("\tvec4 %s = %s;\n", inColor.c_str(), GrGLSLZerosVecf(4));
}
// create var to hold stage result
this->nameVariable(&outColor, '\0', "output");
this->fsCodeAppendf("\tvec4 %s;\n", outColor.c_str());
// Enclose custom code in a block to avoid namespace conflicts
SkString openBrace;
openBrace.printf("\t{ // Stage %d: %s\n", fCodeStage.stageIndex(), glEffects[e]->name());
this->fVSCode.append(openBrace);
this->fFSCode.append(openBrace);
glEffects[e]->emitCode(this,
drawEffect,
effectKeys[e],
outColor.c_str(),
inColor.isEmpty() ? NULL : inColor.c_str(),
textureSamplers);
this->fVSCode.append("\t}\n");
this->fFSCode.append("\t}\n");
inColor = outColor;
*fsInOutColorKnownValue = kNone_GrSLConstantVec;
effectEmitted = true;
}
GrGLEffect* glEffect = effect->getFactory().createGLInstance(drawEffect);
// Enclose custom code in a block to avoid namespace conflicts
this->fVSCode.appendf("\t{ // %s\n", glEffect->name());
this->fFSCode.appendf("\t{ // %s \n", glEffect->name());
glEffect->emitCode(this,
drawEffect,
key,
fsOutColor,
fsInColor,
textureSamplers);
this->fVSCode.appendf("\t}\n");
this->fFSCode.appendf("\t}\n");
return glEffect;
if (effectEmitted) {
*fsInOutColor = outColor;
}
}
const SkString* GrGLShaderBuilder::getEffectAttributeName(int attributeIndex) const {

View File

@ -71,7 +71,7 @@ public:
GrAssert(NULL != builder);
SkString name;
name.printf("Sampler%d_", idx);
name.printf("Sampler%d", idx);
fSamplerUniform = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
kSampler2D_GrSLType,
name.c_str());
@ -275,16 +275,24 @@ public:
/** Called after building is complete to get the final shader string. */
void getShader(ShaderType, SkString*) const;
void setCurrentStage(int stageIdx) { fCurrentStageIdx = stageIdx; }
void setNonStage() { fCurrentStageIdx = kNonStageIdx; }
// TODO: move remainder of shader code generation to this class and call this privately
// Handles of sampler uniforms generated for the effect are appended to samplerHandles.
GrGLEffect* createAndEmitGLEffect(
const GrEffectStage& stage,
GrBackendEffectFactory::EffectKey key,
const char* fsInColor, // NULL means no incoming color
const char* fsOutColor,
SkTArray<GrGLUniformManager::UniformHandle, true>* samplerHandles);
/**
* Adds code for effects. effectStages contains the effects to add. effectKeys[i] is the key
* generated from effectStages[i]. An entry in effectStages can be NULL, in which case it is
* skipped. Moreover, if the corresponding key is GrGLEffect::NoEffectKey then it is skipped.
* inOutFSColor specifies the input color to the first stage and is updated to be the
* output color of the last stage. fsInOutColorKnownValue specifies whether the input color
* has a known constant value and is updated to refer to the status of the output color.
* The handles to texture samplers for effectStage[i] are added to effectSamplerHandles[i]. The
* glEffects array is updated to contain the GrGLEffect generated for each entry in
* effectStages.
*/
void emitEffects(const GrEffectStage* effectStages[],
const GrBackendEffectFactory::EffectKey effectKeys[],
int effectCnt,
SkString* inOutFSColor,
GrSLConstantVec* fsInOutColorKnownValue,
SkTArray<GrGLUniformManager::UniformHandle, true>* effectSamplerHandles[],
GrGLEffect* glEffects[]);
GrGLUniformManager::UniformHandle getRTHeightUniform() const { return fRTHeightUniform; }
GrGLUniformManager::UniformHandle getDstCopyTopLeftUniform() const {
@ -338,9 +346,56 @@ public:
VarArray fFSOutputs;
private:
enum {
kNonStageIdx = -1,
};
class CodeStage : GrNoncopyable {
public:
CodeStage() : fNextIndex(0), fCurrentIndex(-1), fEffectStage(NULL) {}
bool inStageCode() const {
this->validate();
return NULL != fEffectStage;
}
const GrEffectStage* effectStage() const {
this->validate();
return fEffectStage;
}
int stageIndex() const {
this->validate();
return fCurrentIndex;
}
class AutoStageRestore : GrNoncopyable {
public:
AutoStageRestore(CodeStage* codeStage, const GrEffectStage* newStage) {
GrAssert(NULL != codeStage);
fSavedIndex = codeStage->fCurrentIndex;
fSavedEffectStage = codeStage->fEffectStage;
if (NULL == newStage) {
codeStage->fCurrentIndex = -1;
} else {
codeStage->fCurrentIndex = codeStage->fNextIndex++;
}
codeStage->fEffectStage = newStage;
fCodeStage = codeStage;
}
~AutoStageRestore() {
fCodeStage->fCurrentIndex = fSavedIndex;
fCodeStage->fEffectStage = fSavedEffectStage;
}
private:
CodeStage* fCodeStage;
int fSavedIndex;
const GrEffectStage* fSavedEffectStage;
};
private:
void validate() const { GrAssert((NULL == fEffectStage) == (-1 == fCurrentIndex)); }
int fNextIndex;
int fCurrentIndex;
const GrEffectStage* fEffectStage;
} fCodeStage;
/**
* Features that should only be enabled by GrGLShaderBuilder itself.
@ -356,6 +411,11 @@ private:
// the enables separately for each shader.
void addFSFeature(uint32_t featureBit, const char* extensionName);
// Generates a name for a variable. The generated string will be name prefixed by the prefix
// char (unless the prefix is '\0'). It also mangles the name to be stage-specific if we're
// generating stage code.
void nameVariable(SkString* out, char prefix, const char* name);
// Interpretation of DstReadKey when generating code
enum {
kNoDstRead_DstReadKey = 0,
@ -366,7 +426,6 @@ private:
const GrGLContextInfo& fCtxInfo;
GrGLUniformManager& fUniformManager;
int fCurrentStageIdx;
uint32_t fFSFeaturesAddedMask;
SkString fFSFunctions;
SkString fFSExtensions;

View File

@ -24,7 +24,7 @@
void GrGLProgramDesc::setRandom(SkMWCRandom* random,
const GrGpuGL* gpu,
const GrTexture* dstTexture,
const GrEffectStage stages[GrDrawState::kNumStages],
const GrEffectStage* stages[GrDrawState::kNumStages],
int currAttribIndex) {
fEmitsPointSize = random->nextBool();
@ -59,11 +59,11 @@ void GrGLProgramDesc::setRandom(SkMWCRandom* random,
bool dstRead = false;
for (int s = 0; s < GrDrawState::kNumStages; ++s) {
if (NULL != stages[s].getEffect()) {
const GrBackendEffectFactory& factory = (*stages[s].getEffect())->getFactory();
GrDrawEffect drawEffect(stages[s], useLocalCoords);
if (NULL != stages[s]) {
const GrBackendEffectFactory& factory = (*stages[s]->getEffect())->getFactory();
GrDrawEffect drawEffect(*stages[s], useLocalCoords);
fEffectKeys[s] = factory.glEffectKey(drawEffect, gpu->glCaps());
if ((*stages[s].getEffect())->willReadDst()) {
if ((*stages[s]->getEffect())->willReadDst()) {
dstRead = true;
}
}
@ -113,7 +113,8 @@ bool GrGpuGL::programUnitTest(int maxStages) {
#endif
GrGLProgramDesc pdesc;
GrEffectStage stages[GrDrawState::kNumStages];
const GrEffectStage* stages[GrDrawState::kNumStages];
memset(stages, 0, sizeof(stages));
int currAttribIndex = 1; // we need to always leave room for position
int attribIndices[2];
@ -137,19 +138,20 @@ bool GrGpuGL::programUnitTest(int maxStages) {
for (int i = 0; i < numAttribs; ++i) {
attribIndices[i] = currAttribIndex++;
}
stages[s].setEffect(effect.get(), attribIndices[0], attribIndices[1]);
GrEffectStage* stage = SkNEW(GrEffectStage);
stage->setEffect(effect.get(), attribIndices[0], attribIndices[1]);
stages[s] = stage;
}
}
const GrTexture* dstTexture = random.nextBool() ? dummyTextures[0] : dummyTextures[1];
pdesc.setRandom(&random, this, dstTexture, stages, currAttribIndex);
const GrEffectStage* stagePtrs[GrDrawState::kNumStages];
for (int s = 0; s < GrDrawState::kNumStages; ++s) {
stagePtrs[s] = &stages[s];
}
SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this->glContext(),
pdesc,
stagePtrs));
stages));
for (int s = 0; s < maxStages; ++s) {
SkDELETE(stages[s]);
}
if (NULL == program.get()) {
return false;
}