Make GrGLProgramDesc's key variable length by compacting the effect key array
R=robertphillips@google.com Review URL: https://codereview.chromium.org/15252004 git-svn-id: http://skia.googlecode.com/svn/trunk@9239 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
881b10b023
commit
2db3ded335
@ -96,7 +96,7 @@ void GrGLProgram::abandon() {
|
||||
|
||||
void GrGLProgram::overrideBlend(GrBlendCoeff* srcCoeff,
|
||||
GrBlendCoeff* dstCoeff) const {
|
||||
switch (fDesc.fCoverageOutput) {
|
||||
switch (fDesc.getHeader().fCoverageOutput) {
|
||||
case GrGLProgramDesc::kModulate_CoverageOutput:
|
||||
break;
|
||||
// The prog will write a coverage value to the secondary
|
||||
@ -221,7 +221,7 @@ void add_color_filter(GrGLShaderBuilder* builder,
|
||||
}
|
||||
|
||||
GrSLConstantVec GrGLProgram::genInputColor(GrGLShaderBuilder* builder, SkString* inColor) {
|
||||
switch (fDesc.fColorInput) {
|
||||
switch (fDesc.getHeader().fColorInput) {
|
||||
case GrGLProgramDesc::kAttribute_ColorInput: {
|
||||
builder->addAttribute(kVec4f_GrSLType, COL_ATTR_NAME);
|
||||
const char *vsName, *fsName;
|
||||
@ -250,7 +250,7 @@ GrSLConstantVec GrGLProgram::genInputColor(GrGLShaderBuilder* builder, SkString*
|
||||
}
|
||||
|
||||
GrSLConstantVec GrGLProgram::genInputCoverage(GrGLShaderBuilder* builder, SkString* inCoverage) {
|
||||
switch (fDesc.fCoverageInput) {
|
||||
switch (fDesc.getHeader().fCoverageInput) {
|
||||
case GrGLProgramDesc::kAttribute_ColorInput: {
|
||||
builder->addAttribute(kVec4f_GrSLType, COV_ATTR_NAME);
|
||||
const char *vsName, *fsName;
|
||||
@ -282,13 +282,13 @@ GrSLConstantVec GrGLProgram::genInputCoverage(GrGLShaderBuilder* builder, SkStri
|
||||
void GrGLProgram::genGeometryShader(GrGLShaderBuilder* builder) const {
|
||||
#if GR_GL_EXPERIMENTAL_GS
|
||||
// TODO: The builder should add all this glue code.
|
||||
if (fDesc.fExperimentalGS) {
|
||||
if (fDesc.getHeader().fExperimentalGS) {
|
||||
GrAssert(fContext.info().glslGeneration() >= k150_GrGLSLGeneration);
|
||||
builder->fGSHeader.append("layout(triangles) in;\n"
|
||||
"layout(triangle_strip, max_vertices = 6) out;\n");
|
||||
builder->gsCodeAppend("\tfor (int i = 0; i < 3; ++i) {\n"
|
||||
"\t\tgl_Position = gl_in[i].gl_Position;\n");
|
||||
if (fDesc.fEmitsPointSize) {
|
||||
if (fDesc.getHeader().fEmitsPointSize) {
|
||||
builder->gsCodeAppend("\t\tgl_PointSize = 1.0;\n");
|
||||
}
|
||||
GrAssert(builder->fGSInputs.count() == builder->fGSOutputs.count());
|
||||
@ -309,7 +309,7 @@ const char* GrGLProgram::adjustInColor(const SkString& inColor) const {
|
||||
if (inColor.size()) {
|
||||
return inColor.c_str();
|
||||
} else {
|
||||
if (GrGLProgramDesc::kSolidWhite_ColorInput == fDesc.fColorInput) {
|
||||
if (GrGLProgramDesc::kSolidWhite_ColorInput == fDesc.getHeader().fColorInput) {
|
||||
return GrGLSLOnesVecf(4);
|
||||
} else {
|
||||
return GrGLSLZerosVecf(4);
|
||||
@ -412,7 +412,7 @@ bool GrGLProgram::compileShaders(const GrGLShaderBuilder& builder) {
|
||||
|
||||
fGShaderID = 0;
|
||||
#if GR_GL_EXPERIMENTAL_GS
|
||||
if (fDesc.fExperimentalGS) {
|
||||
if (fDesc.getHeader().fExperimentalGS) {
|
||||
builder.getShader(GrGLShaderBuilder::kGeometry_ShaderType, &shader);
|
||||
if (c_PrintShaders) {
|
||||
GrPrintf(shader.c_str());
|
||||
@ -439,6 +439,8 @@ bool GrGLProgram::compileShaders(const GrGLShaderBuilder& builder) {
|
||||
bool GrGLProgram::genProgram(const GrEffectStage* stages[]) {
|
||||
GrAssert(0 == fProgramID);
|
||||
|
||||
const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
|
||||
|
||||
GrGLShaderBuilder builder(fContext.info(), fUniformManager, fDesc);
|
||||
|
||||
// the dual source output has no canonical var name, have to
|
||||
@ -467,9 +469,9 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) {
|
||||
GrSLConstantVec knownColorValue = this->genInputColor(&builder, &inColor);
|
||||
|
||||
// we output point size in the GS if present
|
||||
if (fDesc.fEmitsPointSize
|
||||
if (header.fEmitsPointSize
|
||||
#if GR_GL_EXPERIMENTAL_GS
|
||||
&& !fDesc.fExperimentalGS
|
||||
&& !header.fExperimentalGS
|
||||
#endif
|
||||
) {
|
||||
builder.vsCodeAppend("\tgl_PointSize = 1.0;\n");
|
||||
@ -479,7 +481,7 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) {
|
||||
SkXfermode::Coeff colorCoeff;
|
||||
SkXfermode::Coeff filterColorCoeff;
|
||||
SkAssertResult(
|
||||
SkXfermode::ModeAsCoeff(static_cast<SkXfermode::Mode>(fDesc.fColorFilterXfermode),
|
||||
SkXfermode::ModeAsCoeff(static_cast<SkXfermode::Mode>(header.fColorFilterXfermode),
|
||||
&filterColorCoeff,
|
||||
&colorCoeff));
|
||||
bool needColor, needFilterColor;
|
||||
@ -489,13 +491,13 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) {
|
||||
SkTArray<GrGLUniformManager::UniformHandle, true>* stageUniformArrays[GrDrawState::kNumStages];
|
||||
|
||||
if (needColor) {
|
||||
for (int s = 0; s < fDesc.fFirstCoverageStage; ++s) {
|
||||
for (int s = 0; s < fDesc.numColorEffects(); ++s) {
|
||||
stageUniformArrays[s] = &fUniformHandles.fEffectSamplerUnis[s];
|
||||
}
|
||||
|
||||
builder.emitEffects(stages,
|
||||
fDesc.fEffectKeys,
|
||||
fDesc.fFirstCoverageStage,
|
||||
fDesc.effectKeys(),
|
||||
fDesc.numColorEffects(),
|
||||
&inColor,
|
||||
&knownColorValue,
|
||||
stageUniformArrays,
|
||||
@ -503,7 +505,7 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) {
|
||||
}
|
||||
|
||||
// Insert the color filter. This will soon be replaced by a color effect.
|
||||
if (SkXfermode::kDst_Mode != fDesc.fColorFilterXfermode) {
|
||||
if (SkXfermode::kDst_Mode != header.fColorFilterXfermode) {
|
||||
const char* colorFilterColorUniName = NULL;
|
||||
fUniformHandles.fColorFilterUni = builder.addUniform(GrGLShaderBuilder::kFragment_ShaderType,
|
||||
kVec4f_GrSLType, "FilterColor",
|
||||
@ -529,20 +531,20 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) {
|
||||
SkString inCoverage;
|
||||
GrSLConstantVec knownCoverageValue = this->genInputCoverage(&builder, &inCoverage);
|
||||
|
||||
for (int s = fDesc.fFirstCoverageStage, i = 0; s < GrDrawState::kNumStages; ++s, ++i) {
|
||||
stageUniformArrays[i] = &fUniformHandles.fEffectSamplerUnis[s];
|
||||
for (int s = 0; s < fDesc.numCoverageEffects(); ++s) {
|
||||
stageUniformArrays[s] = &fUniformHandles.fEffectSamplerUnis[s + fDesc.numColorEffects()];
|
||||
}
|
||||
|
||||
builder.emitEffects(stages + fDesc.fFirstCoverageStage,
|
||||
fDesc.fEffectKeys + fDesc.fFirstCoverageStage,
|
||||
GrDrawState::kNumStages - fDesc.fFirstCoverageStage,
|
||||
builder.emitEffects(stages + fDesc.numColorEffects(),
|
||||
fDesc.getEffectKeys() + fDesc.numColorEffects(),
|
||||
fDesc.numCoverageEffects(),
|
||||
&inCoverage,
|
||||
&knownCoverageValue,
|
||||
stageUniformArrays,
|
||||
fEffects + fDesc.fFirstCoverageStage);
|
||||
fEffects + fDesc.numColorEffects());
|
||||
|
||||
// discard if coverage is zero
|
||||
if (fDesc.fDiscardIfZeroCoverage && kOnes_GrSLConstantVec != knownCoverageValue) {
|
||||
if (header.fDiscardIfZeroCoverage && kOnes_GrSLConstantVec != knownCoverageValue) {
|
||||
if (kZeros_GrSLConstantVec == knownCoverageValue) {
|
||||
// This is unfortunate.
|
||||
builder.fsCodeAppend("\tdiscard;\n");
|
||||
@ -553,7 +555,7 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) {
|
||||
}
|
||||
|
||||
GrGLProgramDesc::CoverageOutput coverageOutput =
|
||||
static_cast<GrGLProgramDesc::CoverageOutput>(fDesc.fCoverageOutput);
|
||||
static_cast<GrGLProgramDesc::CoverageOutput>(header.fCoverageOutput);
|
||||
if (GrGLProgramDesc::CoverageOutputUsesSecondaryOutput(coverageOutput)) {
|
||||
builder.fFSOutputs.push_back().set(kVec4f_GrSLType,
|
||||
GrGLShaderVar::kOut_TypeModifier,
|
||||
@ -561,7 +563,7 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) {
|
||||
// default coeff to ones for kCoverage_DualSrcOutput
|
||||
SkString coeff;
|
||||
GrSLConstantVec knownCoeffValue = kOnes_GrSLConstantVec;
|
||||
if (GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput == fDesc.fCoverageOutput) {
|
||||
if (GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput == header.fCoverageOutput) {
|
||||
// Get (1-A) into coeff
|
||||
SkString inColorAlpha;
|
||||
GrGLSLGetComponent4f(&inColorAlpha,
|
||||
@ -687,20 +689,22 @@ bool GrGLProgram::bindOutputsAttribsAndLinkProgram(const GrGLShaderBuilder& buil
|
||||
GL_CALL(BindFragDataLocationIndexed(fProgramID, 0, 1, dual_source_output_name()));
|
||||
}
|
||||
|
||||
const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
|
||||
|
||||
// Bind the attrib locations to same values for all shaders
|
||||
GL_CALL(BindAttribLocation(fProgramID,
|
||||
fDesc.fPositionAttributeIndex,
|
||||
header.fPositionAttributeIndex,
|
||||
builder.positionAttribute().c_str()));
|
||||
if (-1 != fDesc.fLocalCoordAttributeIndex) {
|
||||
if (-1 != header.fLocalCoordAttributeIndex) {
|
||||
GL_CALL(BindAttribLocation(fProgramID,
|
||||
fDesc.fLocalCoordAttributeIndex,
|
||||
header.fLocalCoordAttributeIndex,
|
||||
builder.localCoordsAttribute().c_str()));
|
||||
}
|
||||
if (-1 != fDesc.fColorAttributeIndex) {
|
||||
GL_CALL(BindAttribLocation(fProgramID, fDesc.fColorAttributeIndex, COL_ATTR_NAME));
|
||||
if (-1 != header.fColorAttributeIndex) {
|
||||
GL_CALL(BindAttribLocation(fProgramID, header.fColorAttributeIndex, COL_ATTR_NAME));
|
||||
}
|
||||
if (-1 != fDesc.fCoverageAttributeIndex) {
|
||||
GL_CALL(BindAttribLocation(fProgramID, fDesc.fCoverageAttributeIndex, COV_ATTR_NAME));
|
||||
if (-1 != header.fCoverageAttributeIndex) {
|
||||
GL_CALL(BindAttribLocation(fProgramID, header.fCoverageAttributeIndex, COV_ATTR_NAME));
|
||||
}
|
||||
|
||||
const GrGLShaderBuilder::AttributePair* attribEnd = builder.getEffectAttributes().end();
|
||||
@ -761,12 +765,25 @@ void GrGLProgram::initSamplerUniforms() {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void GrGLProgram::setData(GrGpuGL* gpu,
|
||||
GrColor color,
|
||||
GrColor coverage,
|
||||
GrDrawState::BlendOptFlags blendOpts,
|
||||
const GrEffectStage* stages[],
|
||||
const GrDeviceCoordTexture* dstCopy,
|
||||
SharedGLState* sharedState) {
|
||||
const GrDrawState& drawState = gpu->getDrawState();
|
||||
|
||||
GrColor color;
|
||||
GrColor coverage;
|
||||
if (blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag) {
|
||||
color = 0;
|
||||
coverage = 0;
|
||||
} else if (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) {
|
||||
color = 0xffffffff;
|
||||
coverage = drawState.getCoverage();
|
||||
} else {
|
||||
color = drawState.getColor();
|
||||
coverage = drawState.getCoverage();
|
||||
}
|
||||
|
||||
this->setColor(drawState, color, sharedState);
|
||||
this->setCoverage(drawState, coverage, sharedState);
|
||||
this->setMatrixAndRenderTargetHeight(drawState);
|
||||
@ -803,26 +820,25 @@ void GrGLProgram::setData(GrGpuGL* gpu,
|
||||
fUniformHandles.fDstCopySamplerUni);
|
||||
}
|
||||
} else {
|
||||
GrAssert(GrGLUniformManager::kInvalidUniformHandle ==
|
||||
fUniformHandles.fDstCopyTopLeftUni);
|
||||
GrAssert(GrGLUniformManager::kInvalidUniformHandle ==
|
||||
fUniformHandles.fDstCopyScaleUni);
|
||||
GrAssert(GrGLUniformManager::kInvalidUniformHandle ==
|
||||
fUniformHandles.fDstCopySamplerUni);
|
||||
GrAssert(GrGLUniformManager::kInvalidUniformHandle == fUniformHandles.fDstCopyTopLeftUni);
|
||||
GrAssert(GrGLUniformManager::kInvalidUniformHandle == fUniformHandles.fDstCopyScaleUni);
|
||||
GrAssert(GrGLUniformManager::kInvalidUniformHandle == fUniformHandles.fDstCopySamplerUni);
|
||||
}
|
||||
for (int s = 0; s < GrDrawState::kNumStages; ++s) {
|
||||
if (NULL != fEffects[s]) {
|
||||
const GrEffectStage& stage = drawState.getStage(s);
|
||||
GrAssert(NULL != stage.getEffect());
|
||||
|
||||
bool explicitLocalCoords = -1 != fDesc.fLocalCoordAttributeIndex;
|
||||
GrDrawEffect drawEffect(stage, explicitLocalCoords);
|
||||
fEffects[s]->setData(fUniformManager, drawEffect);
|
||||
int numSamplers = fUniformHandles.fEffectSamplerUnis[s].count();
|
||||
int numEffects = fDesc.numTotalEffects();
|
||||
for (int e = 0; e < numEffects; ++e) {
|
||||
GrAssert(NULL != stages[e]);
|
||||
// We may have omitted the GrGLEffect because of the color filter logic in genProgram.
|
||||
// This can be removed when the color filter is an effect.
|
||||
if (NULL != fEffects[e]) {
|
||||
bool explicitLocalCoords = -1 != fDesc.getHeader().fLocalCoordAttributeIndex;
|
||||
GrDrawEffect drawEffect(*stages[e], explicitLocalCoords);
|
||||
fEffects[e]->setData(fUniformManager, drawEffect);
|
||||
int numSamplers = fUniformHandles.fEffectSamplerUnis[e].count();
|
||||
for (int u = 0; u < numSamplers; ++u) {
|
||||
UniformHandle handle = fUniformHandles.fEffectSamplerUnis[s][u];
|
||||
UniformHandle handle = fUniformHandles.fEffectSamplerUnis[e][u];
|
||||
if (GrGLUniformManager::kInvalidUniformHandle != handle) {
|
||||
const GrTextureAccess& access = (*stage.getEffect())->textureAccess(u);
|
||||
const GrTextureAccess& access = (*stages[e]->getEffect())->textureAccess(u);
|
||||
GrGLTexture* texture = static_cast<GrGLTexture*>(access.getTexture());
|
||||
gpu->bindTexture(texUnitIdx, access.getParams(), texture);
|
||||
++texUnitIdx;
|
||||
@ -835,18 +851,19 @@ void GrGLProgram::setData(GrGpuGL* gpu,
|
||||
void GrGLProgram::setColor(const GrDrawState& drawState,
|
||||
GrColor color,
|
||||
SharedGLState* sharedState) {
|
||||
const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
|
||||
if (!drawState.hasColorVertexAttribute()) {
|
||||
switch (fDesc.fColorInput) {
|
||||
switch (header.fColorInput) {
|
||||
case GrGLProgramDesc::kAttribute_ColorInput:
|
||||
GrAssert(-1 != fDesc.fColorAttributeIndex);
|
||||
GrAssert(-1 != header.fColorAttributeIndex);
|
||||
if (sharedState->fConstAttribColor != color ||
|
||||
sharedState->fConstAttribColorIndex != fDesc.fColorAttributeIndex) {
|
||||
sharedState->fConstAttribColorIndex != header.fColorAttributeIndex) {
|
||||
// OpenGL ES only supports the float varieties of glVertexAttrib
|
||||
GrGLfloat c[4];
|
||||
GrColorToRGBAFloat(color, c);
|
||||
GL_CALL(VertexAttrib4fv(fDesc.fColorAttributeIndex, c));
|
||||
GL_CALL(VertexAttrib4fv(header.fColorAttributeIndex, c));
|
||||
sharedState->fConstAttribColor = color;
|
||||
sharedState->fConstAttribColorIndex = fDesc.fColorAttributeIndex;
|
||||
sharedState->fConstAttribColorIndex = header.fColorAttributeIndex;
|
||||
}
|
||||
break;
|
||||
case GrGLProgramDesc::kUniform_ColorInput:
|
||||
@ -876,17 +893,18 @@ void GrGLProgram::setColor(const GrDrawState& drawState,
|
||||
void GrGLProgram::setCoverage(const GrDrawState& drawState,
|
||||
GrColor coverage,
|
||||
SharedGLState* sharedState) {
|
||||
const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
|
||||
if (!drawState.hasCoverageVertexAttribute()) {
|
||||
switch (fDesc.fCoverageInput) {
|
||||
switch (header.fCoverageInput) {
|
||||
case GrGLProgramDesc::kAttribute_ColorInput:
|
||||
if (sharedState->fConstAttribCoverage != coverage ||
|
||||
sharedState->fConstAttribCoverageIndex != fDesc.fCoverageAttributeIndex) {
|
||||
sharedState->fConstAttribCoverageIndex != header.fCoverageAttributeIndex) {
|
||||
// OpenGL ES only supports the float varieties of glVertexAttrib
|
||||
GrGLfloat c[4];
|
||||
GrColorToRGBAFloat(coverage, c);
|
||||
GL_CALL(VertexAttrib4fv(fDesc.fCoverageAttributeIndex, c));
|
||||
GL_CALL(VertexAttrib4fv(header.fCoverageAttributeIndex, c));
|
||||
sharedState->fConstAttribCoverage = coverage;
|
||||
sharedState->fConstAttribCoverageIndex = fDesc.fCoverageAttributeIndex;
|
||||
sharedState->fConstAttribCoverageIndex = header.fCoverageAttributeIndex;
|
||||
}
|
||||
break;
|
||||
case GrGLProgramDesc::kUniform_ColorInput:
|
||||
|
@ -48,7 +48,7 @@ public:
|
||||
void abandon();
|
||||
|
||||
/**
|
||||
* The shader may modify the blend coefficients. Params are in/out
|
||||
* The shader may modify the blend coefficients. Params are in/out.
|
||||
*/
|
||||
void overrideBlend(GrBlendCoeff* srcCoeff, GrBlendCoeff* dstCoeff) const;
|
||||
|
||||
@ -104,12 +104,10 @@ public:
|
||||
* This function uploads uniforms and calls each GrGLEffect's setData. It is called before a
|
||||
* draw occurs using the program after the program has already been bound. It also uses the
|
||||
* GrGpuGL object to bind the textures required by the GrGLEffects.
|
||||
*
|
||||
* The color and coverage params override the GrDrawState's getColor() and getCoverage() values.
|
||||
*/
|
||||
void setData(GrGpuGL*,
|
||||
GrColor color,
|
||||
GrColor coverage,
|
||||
GrDrawState::BlendOptFlags,
|
||||
const GrEffectStage* stages[], // output of GrGLProgramDesc:Build()
|
||||
const GrDeviceCoordTexture* dstCopy, // can be NULL
|
||||
SharedGLState*);
|
||||
|
||||
@ -121,7 +119,9 @@ private:
|
||||
bool succeeded() const { return 0 != fProgramID; }
|
||||
|
||||
/**
|
||||
* This is the heavy initialization routine for building a GLProgram.
|
||||
* This is the heavy initialization routine for building a GLProgram. stages is all the enabled
|
||||
* color stages followed by all the enabled coverage stages as output by
|
||||
* GrGLProgramDesc::Build()
|
||||
*/
|
||||
bool genProgram(const GrEffectStage* stages[]);
|
||||
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include "GrGLShaderBuilder.h"
|
||||
#include "GrGpuGL.h"
|
||||
|
||||
#include "SkChecksum.h"
|
||||
|
||||
void GrGLProgramDesc::Build(const GrDrawState& drawState,
|
||||
bool isPoints,
|
||||
GrDrawState::BlendOptFlags blendOpts,
|
||||
@ -19,8 +21,8 @@ void GrGLProgramDesc::Build(const GrDrawState& drawState,
|
||||
GrBlendCoeff dstCoeff,
|
||||
const GrGpuGL* gpu,
|
||||
const GrDeviceCoordTexture* dstCopy,
|
||||
const GrEffectStage* stages[],
|
||||
GrGLProgramDesc* desc) {
|
||||
|
||||
// This should already have been caught
|
||||
GrAssert(!(GrDrawState::kSkipDraw_BlendOptFlag & blendOpts));
|
||||
|
||||
@ -34,131 +36,169 @@ void GrGLProgramDesc::Build(const GrDrawState& drawState,
|
||||
// bindings in use or other descriptor field settings) it should be set
|
||||
// to a canonical value to avoid duplicate programs with different keys.
|
||||
|
||||
|
||||
desc->fEmitsPointSize = isPoints;
|
||||
|
||||
bool requiresColorAttrib = !skipColor && drawState.hasColorVertexAttribute();
|
||||
bool requiresCoverageAttrib = !skipCoverage && drawState.hasCoverageVertexAttribute();
|
||||
// we only need the local coords if we're actually going to generate effect code
|
||||
bool requiresLocalCoordAttrib = !(skipCoverage && skipColor) &&
|
||||
drawState.hasLocalCoordAttribute();
|
||||
|
||||
// fColorInput/fCoverageInput records how colors are specified for the program so we strip the
|
||||
// bits from the bindings to avoid false negatives when searching for an existing program in the
|
||||
// cache.
|
||||
|
||||
desc->fColorFilterXfermode = skipColor ? SkXfermode::kDst_Mode : drawState.getColorFilterMode();
|
||||
|
||||
|
||||
bool colorIsTransBlack = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
|
||||
bool colorIsSolidWhite = (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) ||
|
||||
(!requiresColorAttrib && 0xffffffff == drawState.getColor());
|
||||
if (colorIsTransBlack) {
|
||||
desc->fColorInput = kTransBlack_ColorInput;
|
||||
} else if (colorIsSolidWhite) {
|
||||
desc->fColorInput = kSolidWhite_ColorInput;
|
||||
} else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresColorAttrib) {
|
||||
desc->fColorInput = kUniform_ColorInput;
|
||||
} else {
|
||||
desc->fColorInput = kAttribute_ColorInput;
|
||||
|
||||
// Do an initial loop over the stages to count them. We count the color and coverage effects
|
||||
// separately here. Later we may decide the distinction doesn't matter and will count all
|
||||
// effects as color in desc. Two things will allow simplication of this mess: GrDrawState will
|
||||
// have tight lists of color and coverage stages rather than a fixed size array with NULLS and
|
||||
// the xfermode-color filter will be removed.
|
||||
int colorEffectCnt = 0;
|
||||
int coverageEffectCnt = 0;
|
||||
if (!skipColor) {
|
||||
for (int s = 0; s < drawState.getFirstCoverageStage(); ++s) {
|
||||
if (drawState.isStageEnabled(s)) {
|
||||
stages[colorEffectCnt] = &drawState.getStage(s);
|
||||
++colorEffectCnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!skipCoverage) {
|
||||
for (int s = drawState.getFirstCoverageStage(); s < GrDrawState::kNumStages; ++s) {
|
||||
if (drawState.isStageEnabled(s)) {
|
||||
stages[colorEffectCnt + coverageEffectCnt] = &drawState.getStage(s);
|
||||
++coverageEffectCnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == drawState.getCoverage();
|
||||
|
||||
if (skipCoverage) {
|
||||
desc->fCoverageInput = kTransBlack_ColorInput;
|
||||
} else if (covIsSolidWhite) {
|
||||
desc->fCoverageInput = kSolidWhite_ColorInput;
|
||||
} else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresCoverageAttrib) {
|
||||
desc->fCoverageInput = kUniform_ColorInput;
|
||||
} else {
|
||||
desc->fCoverageInput = kAttribute_ColorInput;
|
||||
size_t newKeyLength = KeyLength(colorEffectCnt + coverageEffectCnt);
|
||||
bool allocChanged;
|
||||
desc->fKey.reset(newKeyLength, SkAutoMalloc::kAlloc_OnShrink, &allocChanged);
|
||||
if (allocChanged || !desc->fInitialized) {
|
||||
// make sure any padding in the header is zero if we we haven't used this allocation before.
|
||||
memset(desc->header(), 0, kHeaderSize);
|
||||
}
|
||||
// write the key length
|
||||
*desc->atOffset<uint32_t, kLengthOffset>() = newKeyLength;
|
||||
|
||||
KeyHeader* header = desc->header();
|
||||
EffectKey* effectKeys = desc->effectKeys();
|
||||
|
||||
int currEffectKey = 0;
|
||||
bool readsDst = false;
|
||||
bool readFragPosition = false;
|
||||
int lastEnabledStage = -1;
|
||||
|
||||
for (int s = 0; s < GrDrawState::kNumStages; ++s) {
|
||||
|
||||
bool skip = s < drawState.getFirstCoverageStage() ? skipColor : skipCoverage;
|
||||
if (!skip && drawState.isStageEnabled(s)) {
|
||||
lastEnabledStage = s;
|
||||
const GrEffectRef& effect = *drawState.getStage(s).getEffect();
|
||||
const GrBackendEffectFactory& factory = effect->getFactory();
|
||||
GrDrawEffect drawEffect(drawState.getStage(s), requiresLocalCoordAttrib);
|
||||
desc->fEffectKeys[s] = factory.glEffectKey(drawEffect, gpu->glCaps());
|
||||
effectKeys[currEffectKey] = factory.glEffectKey(drawEffect, gpu->glCaps());
|
||||
++currEffectKey;
|
||||
if (effect->willReadDstColor()) {
|
||||
readsDst = true;
|
||||
}
|
||||
if (effect->willReadFragmentPosition()) {
|
||||
readFragPosition = true;
|
||||
}
|
||||
} else {
|
||||
desc->fEffectKeys[s] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
header->fEmitsPointSize = isPoints;
|
||||
header->fColorFilterXfermode = skipColor ? SkXfermode::kDst_Mode : drawState.getColorFilterMode();
|
||||
|
||||
// Currently the experimental GS will only work with triangle prims (and it doesn't do anything
|
||||
// other than pass through values from the VS to the FS anyway).
|
||||
#if GR_GL_EXPERIMENTAL_GS
|
||||
#if 0
|
||||
header->fExperimentalGS = gpu->caps().geometryShaderSupport();
|
||||
#else
|
||||
header->fExperimentalGS = false;
|
||||
#endif
|
||||
#endif
|
||||
if (colorIsTransBlack) {
|
||||
header->fColorInput = kTransBlack_ColorInput;
|
||||
} else if (colorIsSolidWhite) {
|
||||
header->fColorInput = kSolidWhite_ColorInput;
|
||||
} else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresColorAttrib) {
|
||||
header->fColorInput = kUniform_ColorInput;
|
||||
} else {
|
||||
header->fColorInput = kAttribute_ColorInput;
|
||||
}
|
||||
|
||||
bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == drawState.getCoverage();
|
||||
|
||||
if (skipCoverage) {
|
||||
header->fCoverageInput = kTransBlack_ColorInput;
|
||||
} else if (covIsSolidWhite) {
|
||||
header->fCoverageInput = kSolidWhite_ColorInput;
|
||||
} else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresCoverageAttrib) {
|
||||
header->fCoverageInput = kUniform_ColorInput;
|
||||
} else {
|
||||
header->fCoverageInput = kAttribute_ColorInput;
|
||||
}
|
||||
|
||||
if (readsDst) {
|
||||
GrAssert(NULL != dstCopy || gpu->caps()->dstReadInShaderSupport());
|
||||
const GrTexture* dstCopyTexture = NULL;
|
||||
if (NULL != dstCopy) {
|
||||
dstCopyTexture = dstCopy->texture();
|
||||
}
|
||||
desc->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps());
|
||||
GrAssert(0 != desc->fDstReadKey);
|
||||
header->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps());
|
||||
GrAssert(0 != header->fDstReadKey);
|
||||
} else {
|
||||
desc->fDstReadKey = 0;
|
||||
header->fDstReadKey = 0;
|
||||
}
|
||||
|
||||
if (readFragPosition) {
|
||||
desc->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(drawState.getRenderTarget(),
|
||||
header->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(drawState.getRenderTarget(),
|
||||
gpu->glCaps());
|
||||
} else {
|
||||
desc->fFragPosKey = 0;
|
||||
header->fFragPosKey = 0;
|
||||
}
|
||||
|
||||
desc->fCoverageOutput = kModulate_CoverageOutput;
|
||||
|
||||
// Currently the experimental GS will only work with triangle prims (and it doesn't do anything
|
||||
// other than pass through values from the VS to the FS anyway).
|
||||
#if GR_GL_EXPERIMENTAL_GS
|
||||
#if 0
|
||||
desc->fExperimentalGS = gpu->caps().geometryShaderSupport();
|
||||
#else
|
||||
desc->fExperimentalGS = false;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// We leave this set to kNumStages until we discover that the coverage/color distinction is
|
||||
// material to the generated program. We do this to avoid distinct keys that generate equivalent
|
||||
// programs.
|
||||
desc->fFirstCoverageStage = GrDrawState::kNumStages;
|
||||
// This tracks the actual first coverage stage.
|
||||
int firstCoverageStage = GrDrawState::kNumStages;
|
||||
desc->fDiscardIfZeroCoverage = false; // Enabled below if stenciling and there is coverage.
|
||||
bool hasCoverage = false;
|
||||
// If we're rendering coverage-as-color then it's as though there are no coverage stages.
|
||||
if (!drawState.isCoverageDrawing()) {
|
||||
// We can have coverage either through a stage or coverage vertex attributes.
|
||||
if (drawState.getFirstCoverageStage() <= lastEnabledStage) {
|
||||
firstCoverageStage = drawState.getFirstCoverageStage();
|
||||
hasCoverage = true;
|
||||
} else {
|
||||
hasCoverage = requiresCoverageAttrib;
|
||||
}
|
||||
// Record attribute indices
|
||||
header->fPositionAttributeIndex = drawState.positionAttributeIndex();
|
||||
header->fLocalCoordAttributeIndex = drawState.localCoordAttributeIndex();
|
||||
|
||||
// For constant color and coverage we need an attribute with an index beyond those already set
|
||||
int availableAttributeIndex = drawState.getVertexAttribCount();
|
||||
if (requiresColorAttrib) {
|
||||
header->fColorAttributeIndex = drawState.colorVertexAttributeIndex();
|
||||
} else if (GrGLProgramDesc::kAttribute_ColorInput == header->fColorInput) {
|
||||
GrAssert(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
|
||||
header->fColorAttributeIndex = availableAttributeIndex;
|
||||
availableAttributeIndex++;
|
||||
} else {
|
||||
header->fColorAttributeIndex = -1;
|
||||
}
|
||||
|
||||
if (requiresCoverageAttrib) {
|
||||
header->fCoverageAttributeIndex = drawState.coverageVertexAttributeIndex();
|
||||
} else if (GrGLProgramDesc::kAttribute_ColorInput == header->fCoverageInput) {
|
||||
GrAssert(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
|
||||
header->fCoverageAttributeIndex = availableAttributeIndex;
|
||||
} else {
|
||||
header->fCoverageAttributeIndex = -1;
|
||||
}
|
||||
|
||||
if (hasCoverage) {
|
||||
// Here we deal with whether/how we handle color and coverage separately.
|
||||
|
||||
// Set these defaults and then possibly change our mind if there is coverage.
|
||||
header->fDiscardIfZeroCoverage = false;
|
||||
header->fCoverageOutput = kModulate_CoverageOutput;
|
||||
|
||||
// If we do have coverage determine whether it matters.
|
||||
bool separateCoverageFromColor = false;
|
||||
if (!drawState.isCoverageDrawing() && (coverageEffectCnt > 0 || requiresCoverageAttrib)) {
|
||||
// color filter is applied between color/coverage computation
|
||||
if (SkXfermode::kDst_Mode != desc->fColorFilterXfermode) {
|
||||
desc->fFirstCoverageStage = firstCoverageStage;
|
||||
if (SkXfermode::kDst_Mode != header->fColorFilterXfermode) {
|
||||
separateCoverageFromColor = true;
|
||||
}
|
||||
|
||||
// If we're stenciling then we want to discard samples that have zero coverage
|
||||
if (drawState.getStencil().doesWrite()) {
|
||||
desc->fDiscardIfZeroCoverage = true;
|
||||
desc->fFirstCoverageStage = firstCoverageStage;
|
||||
header->fDiscardIfZeroCoverage = true;
|
||||
separateCoverageFromColor = true;
|
||||
}
|
||||
|
||||
if (gpu->caps()->dualSourceBlendingSupport() &&
|
||||
@ -166,46 +206,45 @@ void GrGLProgramDesc::Build(const GrDrawState& drawState,
|
||||
GrDrawState::kCoverageAsAlpha_BlendOptFlag))) {
|
||||
if (kZero_GrBlendCoeff == dstCoeff) {
|
||||
// write the coverage value to second color
|
||||
desc->fCoverageOutput = kSecondaryCoverage_CoverageOutput;
|
||||
desc->fFirstCoverageStage = firstCoverageStage;
|
||||
header->fCoverageOutput = kSecondaryCoverage_CoverageOutput;
|
||||
separateCoverageFromColor = true;
|
||||
} else if (kSA_GrBlendCoeff == dstCoeff) {
|
||||
// SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
|
||||
desc->fCoverageOutput = kSecondaryCoverageISA_CoverageOutput;
|
||||
desc->fFirstCoverageStage = firstCoverageStage;
|
||||
header->fCoverageOutput = kSecondaryCoverageISA_CoverageOutput;
|
||||
separateCoverageFromColor = true;
|
||||
} else if (kSC_GrBlendCoeff == dstCoeff) {
|
||||
// SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
|
||||
desc->fCoverageOutput = kSecondaryCoverageISC_CoverageOutput;
|
||||
desc->fFirstCoverageStage = firstCoverageStage;
|
||||
header->fCoverageOutput = kSecondaryCoverageISC_CoverageOutput;
|
||||
separateCoverageFromColor = true;
|
||||
}
|
||||
} else if (readsDst &&
|
||||
kOne_GrBlendCoeff == srcCoeff &&
|
||||
kZero_GrBlendCoeff == dstCoeff) {
|
||||
desc->fCoverageOutput = kCombineWithDst_CoverageOutput;
|
||||
desc->fFirstCoverageStage = firstCoverageStage;
|
||||
header->fCoverageOutput = kCombineWithDst_CoverageOutput;
|
||||
separateCoverageFromColor = true;
|
||||
}
|
||||
}
|
||||
|
||||
desc->fPositionAttributeIndex = drawState.positionAttributeIndex();
|
||||
desc->fLocalCoordAttributeIndex = drawState.localCoordAttributeIndex();
|
||||
|
||||
// For constant color and coverage we need an attribute with an index beyond those already set
|
||||
int availableAttributeIndex = drawState.getVertexAttribCount();
|
||||
if (requiresColorAttrib) {
|
||||
desc->fColorAttributeIndex = drawState.colorVertexAttributeIndex();
|
||||
} else if (GrGLProgramDesc::kAttribute_ColorInput == desc->fColorInput) {
|
||||
GrAssert(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
|
||||
desc->fColorAttributeIndex = availableAttributeIndex;
|
||||
availableAttributeIndex++;
|
||||
if (separateCoverageFromColor) {
|
||||
header->fColorEffectCnt = colorEffectCnt;
|
||||
header->fCoverageEffectCnt = coverageEffectCnt;
|
||||
} else {
|
||||
desc->fColorAttributeIndex = -1;
|
||||
header->fColorEffectCnt = colorEffectCnt + coverageEffectCnt;
|
||||
header->fCoverageEffectCnt = 0;
|
||||
}
|
||||
|
||||
if (requiresCoverageAttrib) {
|
||||
desc->fCoverageAttributeIndex = drawState.coverageVertexAttributeIndex();
|
||||
} else if (GrGLProgramDesc::kAttribute_ColorInput == desc->fCoverageInput) {
|
||||
GrAssert(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
|
||||
desc->fCoverageAttributeIndex = availableAttributeIndex;
|
||||
} else {
|
||||
desc->fCoverageAttributeIndex = -1;
|
||||
}
|
||||
*desc->checksum() = 0;
|
||||
*desc->checksum() = SkChecksum::Compute(reinterpret_cast<uint32_t*>(desc->fKey.get()),
|
||||
newKeyLength);
|
||||
desc->fInitialized = true;
|
||||
}
|
||||
|
||||
GrGLProgramDesc& GrGLProgramDesc::operator= (const GrGLProgramDesc& other) {
|
||||
fInitialized = other.fInitialized;
|
||||
if (fInitialized) {
|
||||
size_t keyLength = other.keyLength();
|
||||
fKey.reset(keyLength);
|
||||
memcpy(fKey.get(), other.fKey.get(), keyLength);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -25,26 +25,37 @@ class GrGpuGL;
|
||||
to be API-neutral then so could this class. */
|
||||
class GrGLProgramDesc {
|
||||
public:
|
||||
GrGLProgramDesc() {
|
||||
// since we use this as part of a key we can't have any uninitialized padding
|
||||
memset(this, 0, sizeof(GrGLProgramDesc));
|
||||
GrGLProgramDesc() : fInitialized(false) {}
|
||||
GrGLProgramDesc(const GrGLProgramDesc& desc) { *this = desc; }
|
||||
|
||||
// Returns this as a uint32_t array to be used as a key in the program cache.
|
||||
const uint32_t* asKey() const {
|
||||
GrAssert(fInitialized);
|
||||
return reinterpret_cast<const uint32_t*>(fKey.get());
|
||||
}
|
||||
|
||||
// Returns this as a uint32_t array to be used as a key in the program cache
|
||||
const uint32_t* asKey() const {
|
||||
return reinterpret_cast<const uint32_t*>(this);
|
||||
}
|
||||
// Gets the number of bytes in asKey(). It will be a 4-byte aligned value. When comparing two
|
||||
// keys the size of either key can be used with memcmp() since the lengths themselves begin the
|
||||
// keys and thus the memcmp will exit early if the keys are of different lengths.
|
||||
uint32_t keyLength() const { return *this->atOffset<uint32_t, kLengthOffset>(); }
|
||||
|
||||
// Gets the a checksum of the key. Can be used as a hash value for a fast lookup in a cache.
|
||||
uint32_t getChecksum() const { return *this->atOffset<uint32_t, kChecksumOffset>(); }
|
||||
|
||||
// For unit testing.
|
||||
void setRandom(SkMWCRandom*,
|
||||
const GrGpuGL* gpu,
|
||||
const GrTexture* dummyDstTexture,
|
||||
const GrEffectStage* stages[GrDrawState::kNumStages],
|
||||
const GrRenderTarget* dummyDstRenderTarget,
|
||||
const GrTexture* dummyDstCopyTexture,
|
||||
const GrEffectStage* stages[],
|
||||
int numColorStages,
|
||||
int numCoverageStages,
|
||||
int currAttribIndex);
|
||||
|
||||
/**
|
||||
* Builds a program descriptor from a GrDrawState. Whether the primitive type is points, the
|
||||
* output of GrDrawState::getBlendOpts, and the caps of the GrGpuGL are also inputs.
|
||||
* output of GrDrawState::getBlendOpts, and the caps of the GrGpuGL are also inputs. It also
|
||||
* writes a tightly packed array of GrEffectStage* from the drawState.
|
||||
*/
|
||||
static void Build(const GrDrawState&,
|
||||
bool isPoints,
|
||||
@ -53,8 +64,37 @@ public:
|
||||
GrBlendCoeff dstCoeff,
|
||||
const GrGpuGL* gpu,
|
||||
const GrDeviceCoordTexture* dstCopy,
|
||||
const GrEffectStage* outStages[GrDrawState::kNumStages],
|
||||
GrGLProgramDesc* outDesc);
|
||||
|
||||
int numColorEffects() const {
|
||||
GrAssert(fInitialized);
|
||||
return this->getHeader().fColorEffectCnt;
|
||||
}
|
||||
|
||||
int numCoverageEffects() const {
|
||||
GrAssert(fInitialized);
|
||||
return this->getHeader().fCoverageEffectCnt;
|
||||
}
|
||||
|
||||
int numTotalEffects() const { return this->numColorEffects() + this->numCoverageEffects(); }
|
||||
|
||||
GrGLProgramDesc& operator= (const GrGLProgramDesc& other);
|
||||
|
||||
bool operator== (const GrGLProgramDesc& other) const {
|
||||
GrAssert(fInitialized && other.fInitialized);
|
||||
// The length is masked as a hint to the compiler that the address will be 4 byte aligned.
|
||||
return 0 == memcmp(this->asKey(), other.asKey(), this->keyLength() & ~0x3);
|
||||
}
|
||||
|
||||
bool operator!= (const GrGLProgramDesc& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
static bool Less(const GrGLProgramDesc& a, const GrGLProgramDesc& b) {
|
||||
return memcmp(a.asKey(), b.asKey(), a.keyLength() & ~0x3) < 0;
|
||||
}
|
||||
|
||||
private:
|
||||
// Specifies where the initial color comes from before the stages are applied.
|
||||
enum ColorInput {
|
||||
@ -96,37 +136,78 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
/** Non-zero if this stage has an effect */
|
||||
GrGLEffect::EffectKey fEffectKeys[GrDrawState::kNumStages];
|
||||
|
||||
// To enable experimental geometry shader code (not for use in
|
||||
// production)
|
||||
#if GR_GL_EXPERIMENTAL_GS
|
||||
bool fExperimentalGS;
|
||||
#endif
|
||||
|
||||
GrGLShaderBuilder::DstReadKey fDstReadKey; // set by GrGLShaderBuilder if there
|
||||
struct KeyHeader {
|
||||
GrGLShaderBuilder::DstReadKey fDstReadKey; // set by GrGLShaderBuilder if there
|
||||
// are effects that must read the dst.
|
||||
// Otherwise, 0.
|
||||
GrGLShaderBuilder::FragPosKey fFragPosKey; // set by GrGLShaderBuilder if there are
|
||||
GrGLShaderBuilder::FragPosKey fFragPosKey; // set by GrGLShaderBuilder if there are
|
||||
// effects that read the fragment position.
|
||||
// Otherwise, 0.
|
||||
|
||||
// should the FS discard if the coverage is zero (to avoid stencil manipulation)
|
||||
SkBool8 fDiscardIfZeroCoverage;
|
||||
// should the FS discard if the coverage is zero (to avoid stencil manipulation)
|
||||
SkBool8 fDiscardIfZeroCoverage;
|
||||
|
||||
uint8_t fColorInput; // casts to enum ColorInput
|
||||
uint8_t fCoverageInput; // casts to enum ColorInput
|
||||
uint8_t fCoverageOutput; // casts to enum CoverageOutput
|
||||
uint8_t fColorInput; // casts to enum ColorInput
|
||||
uint8_t fCoverageInput; // casts to enum ColorInput
|
||||
uint8_t fCoverageOutput; // casts to enum CoverageOutput
|
||||
|
||||
int8_t fFirstCoverageStage;
|
||||
SkBool8 fEmitsPointSize;
|
||||
uint8_t fColorFilterXfermode; // casts to enum SkXfermode::Mode
|
||||
SkBool8 fEmitsPointSize;
|
||||
uint8_t fColorFilterXfermode; // casts to enum SkXfermode::Mode
|
||||
|
||||
int8_t fPositionAttributeIndex;
|
||||
int8_t fLocalCoordAttributeIndex;
|
||||
int8_t fColorAttributeIndex;
|
||||
int8_t fCoverageAttributeIndex;
|
||||
// To enable experimental geometry shader code (not for use in
|
||||
// production)
|
||||
#if GR_GL_EXPERIMENTAL_GS
|
||||
SkBool8 fExperimentalGS;
|
||||
#endif
|
||||
|
||||
int8_t fPositionAttributeIndex;
|
||||
int8_t fLocalCoordAttributeIndex;
|
||||
int8_t fColorAttributeIndex;
|
||||
int8_t fCoverageAttributeIndex;
|
||||
|
||||
int8_t fColorEffectCnt;
|
||||
int8_t fCoverageEffectCnt;
|
||||
};
|
||||
|
||||
// The key is 1 uint32_t for the length, followed another for the checksum, the header, and then
|
||||
// the effect keys. Everything is fixed length except the effect key array.
|
||||
enum {
|
||||
kLengthOffset = 0,
|
||||
kChecksumOffset = kLengthOffset + sizeof(uint32_t),
|
||||
kHeaderOffset = kChecksumOffset + sizeof(uint32_t),
|
||||
kHeaderSize = SkAlign4(sizeof(KeyHeader)),
|
||||
kEffectKeyOffset = kHeaderOffset + kHeaderSize,
|
||||
};
|
||||
|
||||
template<typename T, size_t OFFSET> T* atOffset() {
|
||||
return reinterpret_cast<T*>(reinterpret_cast<intptr_t>(fKey.get()) + OFFSET);
|
||||
}
|
||||
|
||||
template<typename T, size_t OFFSET> const T* atOffset() const {
|
||||
return reinterpret_cast<const T*>(reinterpret_cast<intptr_t>(fKey.get()) + OFFSET);
|
||||
}
|
||||
|
||||
typedef GrGLEffect::EffectKey EffectKey;
|
||||
|
||||
uint32_t* checksum() { return this->atOffset<uint32_t, kChecksumOffset>(); }
|
||||
KeyHeader* header() { return this->atOffset<KeyHeader, kHeaderOffset>(); }
|
||||
EffectKey* effectKeys() { return this->atOffset<EffectKey, kEffectKeyOffset>(); }
|
||||
|
||||
const KeyHeader& getHeader() const { return *this->atOffset<KeyHeader, kHeaderOffset>(); }
|
||||
const EffectKey* getEffectKeys() const { return this->atOffset<EffectKey, kEffectKeyOffset>(); }
|
||||
|
||||
static size_t KeyLength(int effectCnt) {
|
||||
GR_STATIC_ASSERT(!(sizeof(EffectKey) & 0x3));
|
||||
return kEffectKeyOffset + effectCnt * sizeof(EffectKey);
|
||||
}
|
||||
|
||||
enum {
|
||||
kMaxPreallocEffects = 16,
|
||||
kPreAllocSize = kEffectKeyOffset + kMaxPreallocEffects * sizeof(EffectKey),
|
||||
};
|
||||
|
||||
SkAutoSMalloc<kPreAllocSize> fKey;
|
||||
bool fInitialized;
|
||||
|
||||
// GrGLProgram and GrGLShaderBuilder read the private fields to generate code. TODO: Move all
|
||||
// code generation to GrGLShaderBuilder (and maybe add getters rather than friending).
|
||||
|
@ -105,7 +105,7 @@ GrGLShaderBuilder::GrGLShaderBuilder(const GrGLContextInfo& ctxInfo,
|
||||
, fUniformManager(uniformManager)
|
||||
, fFSFeaturesAddedMask(0)
|
||||
#if GR_GL_EXPERIMENTAL_GS
|
||||
, fUsesGS(desc.fExperimentalGS)
|
||||
, fUsesGS(SkToBool(desc.getHeader().fExperimentalGS))
|
||||
#else
|
||||
, fUsesGS(false)
|
||||
#endif
|
||||
@ -113,11 +113,13 @@ GrGLShaderBuilder::GrGLShaderBuilder(const GrGLContextInfo& ctxInfo,
|
||||
, fRTHeightUniform(GrGLUniformManager::kInvalidUniformHandle)
|
||||
, fDstCopyTopLeftUniform (GrGLUniformManager::kInvalidUniformHandle)
|
||||
, fDstCopyScaleUniform (GrGLUniformManager::kInvalidUniformHandle)
|
||||
, fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.fFragPosKey) {
|
||||
, fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFragPosKey) {
|
||||
|
||||
const GrGLProgramDesc::KeyHeader& header = desc.getHeader();
|
||||
|
||||
fPositionVar = &fVSAttrs.push_back();
|
||||
fPositionVar->set(kVec2f_GrSLType, GrGLShaderVar::kAttribute_TypeModifier, "aPosition");
|
||||
if (-1 != desc.fLocalCoordAttributeIndex) {
|
||||
if (-1 != header.fLocalCoordAttributeIndex) {
|
||||
fLocalCoordsVar = &fVSAttrs.push_back();
|
||||
fLocalCoordsVar->set(kVec2f_GrSLType,
|
||||
GrGLShaderVar::kAttribute_TypeModifier,
|
||||
@ -126,13 +128,13 @@ GrGLShaderBuilder::GrGLShaderBuilder(const GrGLContextInfo& ctxInfo,
|
||||
fLocalCoordsVar = fPositionVar;
|
||||
}
|
||||
// Emit code to read the dst copy textue if necessary.
|
||||
if (kNoDstRead_DstReadKey != desc.fDstReadKey &&
|
||||
if (kNoDstRead_DstReadKey != header.fDstReadKey &&
|
||||
GrGLCaps::kNone_FBFetchType == ctxInfo.caps()->fbFetchType()) {
|
||||
bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & desc.fDstReadKey);
|
||||
bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & header.fDstReadKey);
|
||||
const char* dstCopyTopLeftName;
|
||||
const char* dstCopyCoordScaleName;
|
||||
uint32_t configMask;
|
||||
if (SkToBool(kUseAlphaConfig_DstReadKeyBit & desc.fDstReadKey)) {
|
||||
if (SkToBool(kUseAlphaConfig_DstReadKeyBit & header.fDstReadKey)) {
|
||||
configMask = kA_GrColorComponentFlag;
|
||||
} else {
|
||||
configMask = kRGBA_GrColorComponentFlags;
|
||||
@ -656,11 +658,7 @@ void GrGLShaderBuilder::emitEffects(
|
||||
SkString outColor;
|
||||
|
||||
for (int e = 0; e < effectCnt; ++e) {
|
||||
if (NULL == effectStages[e] || GrGLEffect::kNoEffectKey == effectKeys[e]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
GrAssert(NULL != effectStages[e]->getEffect());
|
||||
GrAssert(NULL != effectStages[e] && NULL != effectStages[e]->getEffect());
|
||||
const GrEffectStage& stage = *effectStages[e];
|
||||
const GrEffectRef& effect = *stage.getEffect();
|
||||
|
||||
|
@ -177,47 +177,36 @@ private:
|
||||
|
||||
void abandon();
|
||||
GrGLProgram* getProgram(const GrGLProgramDesc& desc, const GrEffectStage* stages[]);
|
||||
|
||||
private:
|
||||
enum {
|
||||
kKeySize = sizeof(GrGLProgramDesc),
|
||||
// We may actually have kMaxEntries+1 shaders in the GL context because we create a new
|
||||
// shader before evicting from the cache.
|
||||
kMaxEntries = 32
|
||||
kMaxEntries = 32,
|
||||
kHashBits = 6,
|
||||
};
|
||||
|
||||
class Entry;
|
||||
// The value of the hash key is based on the ProgramDesc.
|
||||
typedef GrTBinHashKey<Entry, kKeySize> ProgramHashKey;
|
||||
struct Entry;
|
||||
|
||||
class Entry : public ::GrNoncopyable {
|
||||
public:
|
||||
Entry() : fProgram(NULL), fLRUStamp(0) {}
|
||||
Entry& operator = (const Entry& entry) {
|
||||
GrSafeRef(entry.fProgram.get());
|
||||
fProgram.reset(entry.fProgram.get());
|
||||
fKey = entry.fKey;
|
||||
fLRUStamp = entry.fLRUStamp;
|
||||
return *this;
|
||||
}
|
||||
int compare(const ProgramHashKey& key) const {
|
||||
return fKey.compare(key);
|
||||
}
|
||||
struct ProgDescLess;
|
||||
|
||||
public:
|
||||
SkAutoTUnref<GrGLProgram> fProgram;
|
||||
ProgramHashKey fKey;
|
||||
unsigned int fLRUStamp; // Move outside entry?
|
||||
};
|
||||
// binary search for entry matching desc. returns index into fEntries that matches desc or ~
|
||||
// of the index of where it should be inserted.
|
||||
int search(const GrGLProgramDesc& desc) const;
|
||||
|
||||
GrTHashTable<Entry, ProgramHashKey, 8> fHashCache;
|
||||
// sorted array of all the entries
|
||||
Entry* fEntries[kMaxEntries];
|
||||
// hash table based on lowest kHashBits bits of the program key. Used to avoid binary
|
||||
// searching fEntries.
|
||||
Entry* fHashTable[1 << kHashBits];
|
||||
|
||||
Entry fEntries[kMaxEntries];
|
||||
int fCount;
|
||||
unsigned int fCurrLRUStamp;
|
||||
const GrGLContext& fGL;
|
||||
#ifdef PROGRAM_CACHE_STATS
|
||||
int fTotalRequests;
|
||||
int fCacheMisses;
|
||||
int fHashMisses; // cache hit but hash table missed
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -9,12 +9,32 @@
|
||||
|
||||
#include "GrEffect.h"
|
||||
#include "GrGLEffect.h"
|
||||
#include "SkTSearch.h"
|
||||
|
||||
typedef GrGLUniformManager::UniformHandle UniformHandle;
|
||||
static const UniformHandle kInvalidUniformHandle = GrGLUniformManager::kInvalidUniformHandle;
|
||||
|
||||
#define SKIP_CACHE_CHECK true
|
||||
#define GR_UINT32_MAX static_cast<uint32_t>(-1)
|
||||
struct GrGpuGL::ProgramCache::Entry {
|
||||
SK_DECLARE_INST_COUNT_ROOT(Entry);
|
||||
Entry() : fProgram(NULL), fLRUStamp(0) {}
|
||||
|
||||
SkAutoTUnref<GrGLProgram> fProgram;
|
||||
unsigned int fLRUStamp;
|
||||
};
|
||||
|
||||
SK_DEFINE_INST_COUNT(GrGpuGL::ProgramCache::Entry);
|
||||
|
||||
struct GrGpuGL::ProgramCache::ProgDescLess {
|
||||
bool operator() (const GrGLProgramDesc& desc, const Entry* entry) {
|
||||
GrAssert(NULL != entry->fProgram.get());
|
||||
return GrGLProgramDesc::Less(desc, entry->fProgram->getDesc());
|
||||
}
|
||||
|
||||
bool operator() (const Entry* entry, const GrGLProgramDesc& desc) {
|
||||
GrAssert(NULL != entry->fProgram.get());
|
||||
return GrGLProgramDesc::Less(entry->fProgram->getDesc(), desc);
|
||||
}
|
||||
};
|
||||
|
||||
GrGpuGL::ProgramCache::ProgramCache(const GrGLContext& gl)
|
||||
: fCount(0)
|
||||
@ -23,70 +43,147 @@ GrGpuGL::ProgramCache::ProgramCache(const GrGLContext& gl)
|
||||
#ifdef PROGRAM_CACHE_STATS
|
||||
, fTotalRequests(0)
|
||||
, fCacheMisses(0)
|
||||
, fHashMisses(0)
|
||||
#endif
|
||||
{
|
||||
for (int i = 0; i < 1 << kHashBits; ++i) {
|
||||
fHashTable[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
GrGpuGL::ProgramCache::~ProgramCache() {
|
||||
for (int i = 0; i < fCount; ++i){
|
||||
SkDELETE(fEntries[i]);
|
||||
}
|
||||
// dump stats
|
||||
#ifdef PROGRAM_CACHE_STATS
|
||||
SkDebugf("--- Program Cache ---\n");
|
||||
SkDebugf("Total requests: %d\n", fTotalRequests);
|
||||
SkDebugf("Cache misses: %d\n", fCacheMisses);
|
||||
SkDebugf("Cache miss %%: %f\n", (fTotalRequests > 0)
|
||||
? (float)fCacheMisses/(float)fTotalRequests : 0.0f);
|
||||
SkDebugf("Cache miss %%: %f\n", (fTotalRequests > 0) ?
|
||||
100.f * fCacheMisses / fTotalRequests :
|
||||
0.f);
|
||||
int cacheHits = fTotalRequests - fCacheMisses;
|
||||
SkDebugf("Hash miss %%: %f\n", (cacheHits > 0) ? 100.f * fHashMisses / cacheHits : 0.f);
|
||||
SkDebugf("---------------------\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void GrGpuGL::ProgramCache::abandon() {
|
||||
for (int i = 0; i < fCount; ++i) {
|
||||
GrAssert(NULL != fEntries[i].fProgram.get());
|
||||
fEntries[i].fProgram->abandon();
|
||||
fEntries[i].fProgram.reset(NULL);
|
||||
GrAssert(NULL != fEntries[i]->fProgram.get());
|
||||
fEntries[i]->fProgram->abandon();
|
||||
fEntries[i]->fProgram.reset(NULL);
|
||||
}
|
||||
fCount = 0;
|
||||
}
|
||||
|
||||
int GrGpuGL::ProgramCache::search(const GrGLProgramDesc& desc) const {
|
||||
ProgDescLess less;
|
||||
return SkTSearch(fEntries, fCount, desc, sizeof(Entry*), less);
|
||||
}
|
||||
|
||||
GrGLProgram* GrGpuGL::ProgramCache::getProgram(const GrGLProgramDesc& desc,
|
||||
const GrEffectStage* stages[]) {
|
||||
Entry newEntry;
|
||||
newEntry.fKey.setKeyData(desc.asKey());
|
||||
#ifdef PROGRAM_CACHE_STATS
|
||||
++fTotalRequests;
|
||||
#endif
|
||||
|
||||
Entry* entry = fHashCache.find(newEntry.fKey);
|
||||
Entry* entry = NULL;
|
||||
|
||||
uint32_t hashIdx = desc.getChecksum();
|
||||
hashIdx ^= hashIdx >> 16;
|
||||
if (kHashBits <= 8) {
|
||||
hashIdx ^= hashIdx >> 8;
|
||||
}
|
||||
hashIdx &=((1 << kHashBits) - 1);
|
||||
Entry* hashedEntry = fHashTable[hashIdx];
|
||||
if (NULL != hashedEntry && hashedEntry->fProgram->getDesc() == desc) {
|
||||
GrAssert(NULL != hashedEntry->fProgram);
|
||||
entry = hashedEntry;
|
||||
}
|
||||
|
||||
int entryIdx;
|
||||
if (NULL == entry) {
|
||||
entryIdx = this->search(desc);
|
||||
if (entryIdx >= 0) {
|
||||
entry = fEntries[entryIdx];
|
||||
#ifdef PROGRAM_CACHE_STATS
|
||||
++fHashMisses;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL == entry) {
|
||||
// We have a cache miss
|
||||
#ifdef PROGRAM_CACHE_STATS
|
||||
++fCacheMisses;
|
||||
#endif
|
||||
newEntry.fProgram.reset(GrGLProgram::Create(fGL, desc, stages));
|
||||
if (NULL == newEntry.fProgram.get()) {
|
||||
GrGLProgram* program = GrGLProgram::Create(fGL, desc, stages);
|
||||
if (NULL == program) {
|
||||
return NULL;
|
||||
}
|
||||
int purgeIdx = 0;
|
||||
if (fCount < kMaxEntries) {
|
||||
entry = fEntries + fCount;
|
||||
++fCount;
|
||||
entry = SkNEW(Entry);
|
||||
purgeIdx = fCount++;
|
||||
fEntries[purgeIdx] = entry;
|
||||
} else {
|
||||
GrAssert(kMaxEntries == fCount);
|
||||
entry = fEntries;
|
||||
GrAssert(fCount == kMaxEntries);
|
||||
purgeIdx = 0;
|
||||
for (int i = 1; i < kMaxEntries; ++i) {
|
||||
if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
|
||||
entry = fEntries + i;
|
||||
if (fEntries[i]->fLRUStamp < fEntries[purgeIdx]->fLRUStamp) {
|
||||
purgeIdx = i;
|
||||
}
|
||||
}
|
||||
fHashCache.remove(entry->fKey, entry);
|
||||
entry = fEntries[purgeIdx];
|
||||
int purgedHashIdx = entry->fProgram->getDesc().getChecksum() & ((1 << kHashBits) - 1);
|
||||
if (fHashTable[purgedHashIdx] == entry) {
|
||||
fHashTable[purgedHashIdx] = NULL;
|
||||
}
|
||||
}
|
||||
*entry = newEntry;
|
||||
fHashCache.insert(entry->fKey, entry);
|
||||
GrAssert(fEntries[purgeIdx] == entry);
|
||||
entry->fProgram.reset(program);
|
||||
// We need to shift fEntries around so that the entry currently at purgeIdx is placed
|
||||
// just before the entry at ~entryIdx (in order to keep fEntries sorted by descriptor).
|
||||
entryIdx = ~entryIdx;
|
||||
if (entryIdx < purgeIdx) {
|
||||
// Let E and P be the entries at index entryIdx and purgeIdx, respectively.
|
||||
// If the entries array looks like this:
|
||||
// aaaaEbbbbbPccccc
|
||||
// we rearrange it to look like this:
|
||||
// aaaaPEbbbbbccccc
|
||||
size_t copySize = (purgeIdx - entryIdx) * sizeof(Entry*);
|
||||
memmove(fEntries + entryIdx + 1, fEntries + entryIdx, copySize);
|
||||
fEntries[entryIdx] = entry;
|
||||
} else if (purgeIdx < entryIdx) {
|
||||
// If the entries array looks like this:
|
||||
// aaaaPbbbbbEccccc
|
||||
// we rearrange it to look like this:
|
||||
// aaaabbbbbPEccccc
|
||||
size_t copySize = (entryIdx - purgeIdx - 1) * sizeof(Entry*);
|
||||
memmove(fEntries + purgeIdx, fEntries + purgeIdx + 1, copySize);
|
||||
fEntries[entryIdx - 1] = entry;
|
||||
}
|
||||
#if GR_DEBUG
|
||||
GrAssert(NULL != fEntries[0]->fProgram.get());
|
||||
for (int i = 0; i < fCount - 1; ++i) {
|
||||
GrAssert(NULL != fEntries[i + 1]->fProgram.get());
|
||||
const GrGLProgramDesc& a = fEntries[i]->fProgram->getDesc();
|
||||
const GrGLProgramDesc& b = fEntries[i + 1]->fProgram->getDesc();
|
||||
GrAssert(GrGLProgramDesc::Less(a, b));
|
||||
GrAssert(!GrGLProgramDesc::Less(b, a));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
fHashTable[hashIdx] = entry;
|
||||
entry->fLRUStamp = fCurrLRUStamp;
|
||||
if (GR_UINT32_MAX == fCurrLRUStamp) {
|
||||
|
||||
if (SK_MaxU32 == fCurrLRUStamp) {
|
||||
// wrap around! just trash our LRU, one time hit.
|
||||
for (int i = 0; i < fCount; ++i) {
|
||||
fEntries[i].fLRUStamp = 0;
|
||||
fEntries[i]->fLRUStamp = 0;
|
||||
}
|
||||
}
|
||||
++fCurrLRUStamp;
|
||||
@ -177,9 +274,6 @@ bool GrGpuGL::flushGraphicsState(DrawType type, const GrDeviceCoordTexture* dstC
|
||||
}
|
||||
|
||||
const GrEffectStage* stages[GrDrawState::kNumStages];
|
||||
for (int i = 0; i < GrDrawState::kNumStages; ++i) {
|
||||
stages[i] = drawState.isStageEnabled(i) ? &drawState.getStage(i) : NULL;
|
||||
}
|
||||
GrGLProgramDesc desc;
|
||||
GrGLProgramDesc::Build(this->getDrawState(),
|
||||
kDrawPoints_DrawType == type,
|
||||
@ -188,6 +282,7 @@ bool GrGpuGL::flushGraphicsState(DrawType type, const GrDeviceCoordTexture* dstC
|
||||
dstCoeff,
|
||||
this,
|
||||
dstCopy,
|
||||
stages,
|
||||
&desc);
|
||||
|
||||
fCurrentProgram.reset(fProgramCache->getProgram(desc, stages));
|
||||
@ -206,19 +301,7 @@ bool GrGpuGL::flushGraphicsState(DrawType type, const GrDeviceCoordTexture* dstC
|
||||
fCurrentProgram->overrideBlend(&srcCoeff, &dstCoeff);
|
||||
this->flushBlend(kDrawLines_DrawType == type, srcCoeff, dstCoeff);
|
||||
|
||||
GrColor color;
|
||||
GrColor coverage;
|
||||
if (blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag) {
|
||||
color = 0;
|
||||
coverage = 0;
|
||||
} else if (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) {
|
||||
color = 0xffffffff;
|
||||
coverage = drawState.getCoverage();
|
||||
} else {
|
||||
color = drawState.getColor();
|
||||
coverage = drawState.getCoverage();
|
||||
}
|
||||
fCurrentProgram->setData(this, color, coverage, dstCopy, &fSharedGLProgramState);
|
||||
fCurrentProgram->setData(this, blendOpts, stages, dstCopy, &fSharedGLProgramState);
|
||||
}
|
||||
this->flushStencil(type);
|
||||
this->flushScissor();
|
||||
|
@ -18,59 +18,86 @@
|
||||
#include "GrDrawEffect.h"
|
||||
#include "effects/GrConfigConversionEffect.h"
|
||||
|
||||
#include "SkChecksum.h"
|
||||
#include "SkRandom.h"
|
||||
#include "Test.h"
|
||||
|
||||
void GrGLProgramDesc::setRandom(SkMWCRandom* random,
|
||||
const GrGpuGL* gpu,
|
||||
const GrTexture* dstTexture,
|
||||
const GrEffectStage* stages[GrDrawState::kNumStages],
|
||||
const GrRenderTarget* dstRenderTarget,
|
||||
const GrTexture* dstCopyTexture,
|
||||
const GrEffectStage* stages[],
|
||||
int numColorStages,
|
||||
int numCoverageStages,
|
||||
int currAttribIndex) {
|
||||
fEmitsPointSize = random->nextBool();
|
||||
int numEffects = numColorStages + numCoverageStages;
|
||||
size_t keyLength = KeyLength(numEffects);
|
||||
fKey.reset(keyLength);
|
||||
*this->atOffset<uint32_t, kLengthOffset>() = static_cast<uint32_t>(keyLength);
|
||||
memset(this->header(), 0, kHeaderSize);
|
||||
|
||||
fPositionAttributeIndex = 0;
|
||||
KeyHeader* header = this->header();
|
||||
header->fEmitsPointSize = random->nextBool();
|
||||
|
||||
header->fPositionAttributeIndex = 0;
|
||||
|
||||
// if the effects have used up all off the available attributes,
|
||||
// don't try to use color or coverage attributes as input
|
||||
do {
|
||||
fColorInput = random->nextULessThan(kColorInputCnt);
|
||||
header->fColorInput = random->nextULessThan(kColorInputCnt);
|
||||
} while (GrDrawState::kMaxVertexAttribCnt <= currAttribIndex &&
|
||||
kAttribute_ColorInput == fColorInput);
|
||||
fColorAttributeIndex = (fColorInput == kAttribute_ColorInput) ? currAttribIndex++ : -1;
|
||||
kAttribute_ColorInput == header->fColorInput);
|
||||
header->fColorAttributeIndex = (header->fColorInput == kAttribute_ColorInput) ?
|
||||
currAttribIndex++ :
|
||||
-1;
|
||||
|
||||
do {
|
||||
fCoverageInput = random->nextULessThan(kColorInputCnt);
|
||||
header->fCoverageInput = random->nextULessThan(kColorInputCnt);
|
||||
} while (GrDrawState::kMaxVertexAttribCnt <= currAttribIndex &&
|
||||
kAttribute_ColorInput == fCoverageInput);
|
||||
fCoverageAttributeIndex = (fCoverageInput == kAttribute_ColorInput) ? currAttribIndex++ : -1;
|
||||
kAttribute_ColorInput == header->fCoverageInput);
|
||||
header->fCoverageAttributeIndex = (header->fCoverageInput == kAttribute_ColorInput) ?
|
||||
currAttribIndex++ :
|
||||
-1;
|
||||
|
||||
fColorFilterXfermode = random->nextULessThan(SkXfermode::kLastCoeffMode + 1);
|
||||
|
||||
fFirstCoverageStage = random->nextULessThan(GrDrawState::kNumStages);
|
||||
header->fColorFilterXfermode = random->nextULessThan(SkXfermode::kLastCoeffMode + 1);
|
||||
|
||||
#if GR_GL_EXPERIMENTAL_GS
|
||||
fExperimentalGS = gpu->caps()->geometryShaderSupport() && random->nextBool();
|
||||
header->fExperimentalGS = gpu->caps()->geometryShaderSupport() && random->nextBool();
|
||||
#endif
|
||||
|
||||
fDiscardIfZeroCoverage = random->nextBool();
|
||||
header->fDiscardIfZeroCoverage = random->nextBool();
|
||||
|
||||
bool useLocalCoords = random->nextBool() && currAttribIndex < GrDrawState::kMaxVertexAttribCnt;
|
||||
fLocalCoordAttributeIndex = useLocalCoords ? currAttribIndex++ : -1;
|
||||
header->fLocalCoordAttributeIndex = useLocalCoords ? currAttribIndex++ : -1;
|
||||
|
||||
header->fColorEffectCnt = numColorStages;
|
||||
header->fCoverageEffectCnt = numCoverageStages;
|
||||
|
||||
bool dstRead = false;
|
||||
for (int s = 0; s < GrDrawState::kNumStages; ++s) {
|
||||
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())->willReadDstColor()) {
|
||||
dstRead = true;
|
||||
}
|
||||
bool fragPos = false;
|
||||
int numStages = numColorStages + numCoverageStages;
|
||||
for (int s = 0; s < numStages; ++s) {
|
||||
const GrBackendEffectFactory& factory = (*stages[s]->getEffect())->getFactory();
|
||||
GrDrawEffect drawEffect(*stages[s], useLocalCoords);
|
||||
this->effectKeys()[s] = factory.glEffectKey(drawEffect, gpu->glCaps());
|
||||
if ((*stages[s]->getEffect())->willReadDstColor()) {
|
||||
dstRead = true;
|
||||
}
|
||||
if ((*stages[s]->getEffect())->willReadFragmentPosition()) {
|
||||
fragPos = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (dstRead) {
|
||||
this->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstTexture, gpu->glCaps());
|
||||
header->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps());
|
||||
} else {
|
||||
header->fDstReadKey = 0;
|
||||
}
|
||||
if (fragPos) {
|
||||
header->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(dstRenderTarget,
|
||||
gpu->glCaps());
|
||||
} else {
|
||||
header->fFragPosKey = 0;
|
||||
}
|
||||
|
||||
CoverageOutput coverageOutput;
|
||||
@ -82,7 +109,11 @@ void GrGLProgramDesc::setRandom(SkMWCRandom* random,
|
||||
(!dstRead && kCombineWithDst_CoverageOutput == coverageOutput);
|
||||
} while (illegalCoverageOutput);
|
||||
|
||||
fCoverageOutput = coverageOutput;
|
||||
header->fCoverageOutput = coverageOutput;
|
||||
|
||||
*this->checksum() = 0;
|
||||
*this->checksum() = SkChecksum::Compute(reinterpret_cast<uint32_t*>(fKey.get()), keyLength);
|
||||
fInitialized = true;
|
||||
}
|
||||
|
||||
bool GrGpuGL::programUnitTest(int maxStages) {
|
||||
@ -90,10 +121,12 @@ bool GrGpuGL::programUnitTest(int maxStages) {
|
||||
maxStages = GrMin(maxStages, (int)GrDrawState::kNumStages);
|
||||
|
||||
GrTextureDesc dummyDesc;
|
||||
dummyDesc.fFlags = kRenderTarget_GrTextureFlagBit;
|
||||
dummyDesc.fConfig = kSkia8888_GrPixelConfig;
|
||||
dummyDesc.fWidth = 34;
|
||||
dummyDesc.fHeight = 18;
|
||||
SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0));
|
||||
dummyDesc.fFlags = kNone_GrTextureFlags;
|
||||
dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
|
||||
dummyDesc.fWidth = 16;
|
||||
dummyDesc.fHeight = 22;
|
||||
@ -113,43 +146,52 @@ bool GrGpuGL::programUnitTest(int maxStages) {
|
||||
#endif
|
||||
|
||||
GrGLProgramDesc pdesc;
|
||||
const GrEffectStage* stages[GrDrawState::kNumStages];
|
||||
memset(stages, 0, sizeof(stages));
|
||||
|
||||
int currAttribIndex = 1; // we need to always leave room for position
|
||||
int attribIndices[2];
|
||||
GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
|
||||
for (int s = 0; s < maxStages; ++s) {
|
||||
// enable the stage?
|
||||
if (random.nextBool()) {
|
||||
SkAutoTUnref<const GrEffectRef> effect(GrEffectTestFactory::CreateStage(
|
||||
&random,
|
||||
this->getContext(),
|
||||
*this->caps(),
|
||||
dummyTextures));
|
||||
int numAttribs = (*effect)->numVertexAttribs();
|
||||
|
||||
// If adding this effect would exceed the max attrib count then generate a
|
||||
// new random effect.
|
||||
if (currAttribIndex + numAttribs > GrDrawState::kMaxVertexAttribCnt) {
|
||||
--s;
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < numAttribs; ++i) {
|
||||
attribIndices[i] = currAttribIndex++;
|
||||
}
|
||||
GrEffectStage* stage = SkNEW(GrEffectStage);
|
||||
stage->setEffect(effect.get(), attribIndices[0], attribIndices[1]);
|
||||
stages[s] = stage;
|
||||
int numStages = random.nextULessThan(maxStages + 1);
|
||||
int numColorStages = random.nextULessThan(numStages + 1);
|
||||
int numCoverageStages = numStages - numColorStages;
|
||||
|
||||
SkAutoSTMalloc<8, const GrEffectStage*> stages(numStages);
|
||||
|
||||
for (int s = 0; s < numStages; ++s) {
|
||||
SkAutoTUnref<const GrEffectRef> effect(GrEffectTestFactory::CreateStage(
|
||||
&random,
|
||||
this->getContext(),
|
||||
*this->caps(),
|
||||
dummyTextures));
|
||||
int numAttribs = (*effect)->numVertexAttribs();
|
||||
|
||||
// If adding this effect would exceed the max attrib count then generate a
|
||||
// new random effect.
|
||||
if (currAttribIndex + numAttribs > GrDrawState::kMaxVertexAttribCnt) {
|
||||
--s;
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < numAttribs; ++i) {
|
||||
attribIndices[i] = currAttribIndex++;
|
||||
}
|
||||
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);
|
||||
pdesc.setRandom(&random,
|
||||
this,
|
||||
dummyTextures[0]->asRenderTarget(),
|
||||
dstTexture,
|
||||
stages.get(),
|
||||
numColorStages,
|
||||
numCoverageStages,
|
||||
currAttribIndex);
|
||||
|
||||
SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this->glContext(),
|
||||
pdesc,
|
||||
stages));
|
||||
for (int s = 0; s < maxStages; ++s) {
|
||||
stages.get()));
|
||||
for (int s = 0; s < numStages; ++s) {
|
||||
SkDELETE(stages[s]);
|
||||
}
|
||||
if (NULL == program.get()) {
|
||||
|
Loading…
Reference in New Issue
Block a user