diff options
-rw-r--r-- | src/gpu/gl/GrGLProgram.cpp | 106 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgram.h | 9 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgramDesc.h | 1 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgramEffects.cpp | 452 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgramEffects.h | 174 | ||||
-rw-r--r-- | src/gpu/gl/GrGLShaderBuilder.cpp | 33 | ||||
-rw-r--r-- | src/gpu/gl/GrGLShaderBuilder.h | 22 | ||||
-rw-r--r-- | src/gpu/gl/GrGpuGL.cpp | 125 | ||||
-rw-r--r-- | src/gpu/gl/GrGpuGL.h | 24 | ||||
-rw-r--r-- | src/gpu/gl/GrGpuGL_program.cpp | 81 | ||||
-rw-r--r-- | tests/GLProgramsTest.cpp | 9 |
11 files changed, 767 insertions, 269 deletions
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp index 4fe7a2b7c9..1ca61e3748 100644 --- a/src/gpu/gl/GrGLProgram.cpp +++ b/src/gpu/gl/GrGLProgram.cpp @@ -39,7 +39,9 @@ GrGLProgram::GrGLProgram(GrGpuGL* gpu, const GrEffectStage* colorStages[], const GrEffectStage* coverageStages[]) : fGpu(gpu) -, fUniformManager(gpu) { +, fUniformManager(gpu) +, fHasVertexShader(false) +, fNumTexCoordSets(0) { fDesc = desc; fProgramID = 0; @@ -48,7 +50,21 @@ GrGLProgram::GrGLProgram(GrGpuGL* gpu, fColor = GrColor_ILLEGAL; fColorFilterColor = GrColor_ILLEGAL; - this->genProgram(colorStages, coverageStages); + if (fDesc.getHeader().fHasVertexCode || + !fGpu->glCaps().fixedFunctionSupport() || + !fGpu->glCaps().pathStencilingSupport()) { + + GrGLFullShaderBuilder fullBuilder(fGpu, fUniformManager, fDesc); + if (this->genProgram(&fullBuilder, colorStages, coverageStages)) { + fUniformHandles.fViewMatrixUni = fullBuilder.getViewMatrixUniform(); + fHasVertexShader = true; + } + } else { + GrGLFragmentOnlyShaderBuilder fragmentOnlyBuilder(fGpu, fUniformManager, fDesc); + if (this->genProgram(&fragmentOnlyBuilder, colorStages, coverageStages)) { + fNumTexCoordSets = fragmentOnlyBuilder.getNumTexCoordSets(); + } + } } GrGLProgram::~GrGLProgram() { @@ -205,18 +221,16 @@ void expand_known_value4f(SkString* string, GrSLConstantVec vec) { } -bool GrGLProgram::genProgram(const GrEffectStage* colorStages[], +bool GrGLProgram::genProgram(GrGLShaderBuilder* builder, + const GrEffectStage* colorStages[], const GrEffectStage* coverageStages[]) { SkASSERT(0 == fProgramID); const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader(); - GrGLFullShaderBuilder builder(fGpu, fUniformManager, fDesc); - fUniformHandles.fViewMatrixUni = builder.getViewMatrixUniform(); - // incoming color to current stage being processed. - SkString inColor = builder.getInputColor(); - GrSLConstantVec knownColorValue = builder.getKnownColorValue(); + SkString inColor = builder->getInputColor(); + GrSLConstantVec knownColorValue = builder->getKnownColorValue(); // Get the coeffs for the Mode-based color filter, determine if color is needed. SkXfermode::Coeff colorCoeff; @@ -229,20 +243,20 @@ bool GrGLProgram::genProgram(const GrEffectStage* colorStages[], need_blend_inputs(filterColorCoeff, colorCoeff, &needFilterColor, &needColor); fColorEffects.reset( - builder.createAndEmitEffects(colorStages, - fDesc.effectKeys(), - needColor ? fDesc.numColorEffects() : 0, - &inColor, - &knownColorValue)); + builder->createAndEmitEffects(colorStages, + fDesc.effectKeys(), + needColor ? fDesc.numColorEffects() : 0, + &inColor, + &knownColorValue)); // Insert the color filter. This will soon be replaced by a color effect. if (SkXfermode::kDst_Mode != header.fColorFilterXfermode) { const char* colorFilterColorUniName = NULL; - fUniformHandles.fColorFilterUni = builder.addUniform(GrGLShaderBuilder::kFragment_Visibility, - kVec4f_GrSLType, "FilterColor", - &colorFilterColorUniName); + fUniformHandles.fColorFilterUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, + kVec4f_GrSLType, "FilterColor", + &colorFilterColorUniName); - builder.fsCodeAppend("\tvec4 filteredColor;\n"); + builder->fsCodeAppend("\tvec4 filteredColor;\n"); const char* color; // add_color_filter requires a real input string. if (knownColorValue == kOnes_GrSLConstantVec) { @@ -252,36 +266,36 @@ bool GrGLProgram::genProgram(const GrEffectStage* colorStages[], } else { color = inColor.c_str(); } - add_color_filter(&builder, "filteredColor", filterColorCoeff, + add_color_filter(builder, "filteredColor", filterColorCoeff, colorCoeff, colorFilterColorUniName, color); inColor = "filteredColor"; } /////////////////////////////////////////////////////////////////////////// // compute the partial coverage - SkString inCoverage = builder.getInputCoverage(); - GrSLConstantVec knownCoverageValue = builder.getKnownCoverageValue(); + SkString inCoverage = builder->getInputCoverage(); + GrSLConstantVec knownCoverageValue = builder->getKnownCoverageValue(); fCoverageEffects.reset( - builder.createAndEmitEffects(coverageStages, - fDesc.getEffectKeys() + fDesc.numColorEffects(), - fDesc.numCoverageEffects(), - &inCoverage, - &knownCoverageValue)); + builder->createAndEmitEffects(coverageStages, + fDesc.getEffectKeys() + fDesc.numColorEffects(), + fDesc.numCoverageEffects(), + &inCoverage, + &knownCoverageValue)); // discard if coverage is zero if (header.fDiscardIfZeroCoverage && kOnes_GrSLConstantVec != knownCoverageValue) { if (kZeros_GrSLConstantVec == knownCoverageValue) { // This is unfortunate. - builder.fsCodeAppend("\tdiscard;\n"); + builder->fsCodeAppend("\tdiscard;\n"); } else { - builder.fsCodeAppendf("\tif (all(lessThanEqual(%s, vec4(0.0)))) {\n\t\tdiscard;\n\t}\n", - inCoverage.c_str()); + builder->fsCodeAppendf("\tif (all(lessThanEqual(%s, vec4(0.0)))) {\n\t\tdiscard;\n\t}\n", + inCoverage.c_str()); } } if (GrGLProgramDesc::CoverageOutputUsesSecondaryOutput(header.fCoverageOutput)) { - const char* secondaryOutputName = builder.enableSecondaryOutput(); + const char* secondaryOutputName = builder->enableSecondaryOutput(); // default coeff to ones for kCoverage_DualSrcOutput SkString coeff; @@ -317,7 +331,7 @@ bool GrGLProgram::genProgram(const GrEffectStage* colorStages[], knownCoeffValue, knownCoverageValue, false); - builder.fsCodeAppendf("\t%s = %s;\n", secondaryOutputName, modulate.c_str()); + builder->fsCodeAppendf("\t%s = %s;\n", secondaryOutputName, modulate.c_str()); } /////////////////////////////////////////////////////////////////////////// @@ -343,7 +357,7 @@ bool GrGLProgram::genProgram(const GrEffectStage* colorStages[], SkString dstContribution; GrSLConstantVec knownDstContributionValue = GrGLSLModulatef<4>(&dstContribution, dstCoeff.c_str(), - builder.dstColor(), + builder->dstColor(), knownDstCoeffValue, kNone_GrSLConstantVec, true); @@ -358,18 +372,18 @@ bool GrGLProgram::genProgram(const GrEffectStage* colorStages[], } else { expand_known_value4f(&fragColor, knownFragColorValue); } - builder.fsCodeAppendf("\t%s = %s;\n", builder.getColorOutputName(), fragColor.c_str()); + builder->fsCodeAppendf("\t%s = %s;\n", builder->getColorOutputName(), fragColor.c_str()); - if (!builder.finish(&fProgramID)) { + if (!builder->finish(&fProgramID)) { return false; } - fUniformHandles.fRTHeightUni = builder.getRTHeightUniform(); - fUniformHandles.fDstCopyTopLeftUni = builder.getDstCopyTopLeftUniform(); - fUniformHandles.fDstCopyScaleUni = builder.getDstCopyScaleUniform(); - fUniformHandles.fColorUni = builder.getColorUniform(); - fUniformHandles.fCoverageUni = builder.getCoverageUniform(); - fUniformHandles.fDstCopySamplerUni = builder.getDstCopySamplerUniform(); + fUniformHandles.fRTHeightUni = builder->getRTHeightUniform(); + fUniformHandles.fDstCopyTopLeftUni = builder->getDstCopyTopLeftUniform(); + fUniformHandles.fDstCopyScaleUni = builder->getDstCopyScaleUniform(); + fUniformHandles.fColorUni = builder->getColorUniform(); + fUniformHandles.fCoverageUni = builder->getCoverageUniform(); + fUniformHandles.fDstCopySamplerUni = builder->getDstCopySamplerUniform(); // This must be called after we set fDstCopySamplerUni above. this->initSamplerUniforms(); @@ -445,6 +459,10 @@ void GrGLProgram::setData(GrDrawState::BlendOptFlags blendOpts, fColorEffects->setData(fGpu, fUniformManager, colorStages); fCoverageEffects->setData(fGpu, fUniformManager, coverageStages); + + if (!fHasVertexShader) { + fGpu->disableUnusedTexGen(fNumTexCoordSets); + } } void GrGLProgram::setColor(const GrDrawState& drawState, @@ -537,9 +555,13 @@ void GrGLProgram::setMatrixAndRenderTargetHeight(const GrDrawState& drawState) { fUniformManager.set1f(fUniformHandles.fRTHeightUni, SkIntToScalar(size.fHeight)); } - if (fMatrixState.fRenderTargetOrigin != rt->origin() || - !fMatrixState.fViewMatrix.cheapEqualTo(drawState.getViewMatrix()) || - fMatrixState.fRenderTargetSize != size) { + if (!fHasVertexShader) { + SkASSERT(!fUniformHandles.fViewMatrixUni.isValid()); + fGpu->setProjectionMatrix(drawState.getViewMatrix(), size, rt->origin()); + } else if (fMatrixState.fRenderTargetOrigin != rt->origin() || + fMatrixState.fRenderTargetSize != size || + !fMatrixState.fViewMatrix.cheapEqualTo(drawState.getViewMatrix())) { + SkASSERT(fUniformHandles.fViewMatrixUni.isValid()); fMatrixState.fViewMatrix = drawState.getViewMatrix(); fMatrixState.fRenderTargetSize = size; diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h index c8bcbf479e..23ed45602a 100644 --- a/src/gpu/gl/GrGLProgram.h +++ b/src/gpu/gl/GrGLProgram.h @@ -62,6 +62,8 @@ public: */ GrGLuint programID() const { return fProgramID; } + bool hasVertexShader() const { return fHasVertexShader; } + /** * Some GL state that is relevant to programs is not stored per-program. In particular color * and coverage attributes can be global state. This struct is read and updated by @@ -160,7 +162,9 @@ private: * This is the heavy initialization routine for building a GLProgram. colorStages and * coverageStages correspond to the output of GrGLProgramDesc::Build(). */ - bool genProgram(const GrEffectStage* colorStages[], const GrEffectStage* coverageStages[]); + bool genProgram(GrGLShaderBuilder* builder, + const GrEffectStage* colorStages[], + const GrEffectStage* coverageStages[]); // Sets the texture units for samplers void initSamplerUniforms(); @@ -195,6 +199,9 @@ private: GrGLUniformManager fUniformManager; UniformHandles fUniformHandles; + bool fHasVertexShader; + int fNumTexCoordSets; + typedef SkRefCnt INHERITED; }; diff --git a/src/gpu/gl/GrGLProgramDesc.h b/src/gpu/gl/GrGLProgramDesc.h index 0c7c8cf629..46eed09739 100644 --- a/src/gpu/gl/GrGLProgramDesc.h +++ b/src/gpu/gl/GrGLProgramDesc.h @@ -233,6 +233,7 @@ private: friend class GrGLProgram; friend class GrGLShaderBuilder; friend class GrGLFullShaderBuilder; + friend class GrGLFragmentOnlyShaderBuilder; }; #endif diff --git a/src/gpu/gl/GrGLProgramEffects.cpp b/src/gpu/gl/GrGLProgramEffects.cpp index d5826abe30..17c666a015 100644 --- a/src/gpu/gl/GrGLProgramEffects.cpp +++ b/src/gpu/gl/GrGLProgramEffects.cpp @@ -37,7 +37,6 @@ enum { kMatrixTypeKeyMask = (1 << kMatrixTypeKeyBits) - 1, kPositionCoords_Flag = (1 << kMatrixTypeKeyBits), kTransformKeyBits = kMatrixTypeKeyBits + 1, - kTransformKeyMask = (1 << kTransformKeyBits) - 1, }; namespace { @@ -69,8 +68,78 @@ inline bool swizzle_requires_alpha_remapping(const GrGLCaps& caps, return false; } +/** + * Retrieves the matrix type from transformKey for the transform at transformIdx. + */ +MatrixType get_matrix_type(EffectKey transformKey, int transformIdx) { + return static_cast<MatrixType>( + (transformKey >> (kTransformKeyBits * transformIdx)) & kMatrixTypeKeyMask); +} + +/** + * Retrieves the source coords from transformKey for the transform at transformIdx. It may not be + * the same coordinate set as the original GrCoordTransform if the position and local coords are + * identical for this program. + */ +GrCoordSet get_source_coords(EffectKey transformKey, int transformIdx) { + return (transformKey >> (kTransformKeyBits * transformIdx)) & kPositionCoords_Flag ? + kPosition_GrCoordSet : + kLocal_GrCoordSet; +} + +/** + * Retrieves the final translation that a transform needs to apply to its source coords (and + * verifies that a translation is all it needs). + */ +void get_transform_translation(const GrDrawEffect& drawEffect, + int transformIdx, + GrGLfloat* tx, + GrGLfloat* ty) { + const GrCoordTransform& coordTransform = (*drawEffect.effect())->coordTransform(transformIdx); + SkASSERT(!coordTransform.reverseY()); + const SkMatrix& matrix = coordTransform.getMatrix(); + if (kLocal_GrCoordSet == coordTransform.sourceCoords() && + !drawEffect.programHasExplicitLocalCoords()) { + const SkMatrix& coordChangeMatrix = drawEffect.getCoordChangeMatrix(); + SkASSERT(SkMatrix::kTranslate_Mask == (matrix.getType() | coordChangeMatrix.getType())); + *tx = SkScalarToFloat(matrix[SkMatrix::kMTransX] + coordChangeMatrix[SkMatrix::kMTransX]); + *ty = SkScalarToFloat(matrix[SkMatrix::kMTransY] + coordChangeMatrix[SkMatrix::kMTransY]); + } else { + SkASSERT(SkMatrix::kTranslate_Mask == matrix.getType()); + *tx = SkScalarToFloat(matrix[SkMatrix::kMTransX]); + *ty = SkScalarToFloat(matrix[SkMatrix::kMTransY]); + } } +/** + * Retrieves the final matrix that a transform needs to apply to its source coords. + */ +SkMatrix get_transform_matrix(const GrDrawEffect& drawEffect, int transformIdx) { + const GrCoordTransform& coordTransform = (*drawEffect.effect())->coordTransform(transformIdx); + SkMatrix combined; + if (kLocal_GrCoordSet == coordTransform.sourceCoords() && + !drawEffect.programHasExplicitLocalCoords()) { + combined.setConcat(coordTransform.getMatrix(), drawEffect.getCoordChangeMatrix()); + } else { + combined = coordTransform.getMatrix(); + } + if (coordTransform.reverseY()) { + // combined.postScale(1,-1); + // combined.postTranslate(0,1); + combined.set(SkMatrix::kMSkewY, + combined[SkMatrix::kMPersp0] - combined[SkMatrix::kMSkewY]); + combined.set(SkMatrix::kMScaleY, + combined[SkMatrix::kMPersp1] - combined[SkMatrix::kMScaleY]); + combined.set(SkMatrix::kMTransY, + combined[SkMatrix::kMPersp2] - combined[SkMatrix::kMTransY]); + } + return combined; +} + +} + +//////////////////////////////////////////////////////////////////////////////// + EffectKey GrGLProgramEffects::GenAttribKey(const GrDrawEffect& drawEffect) { EffectKey key = 0; int numAttributes = drawEffect.getVertexAttribIndexCount(); @@ -144,6 +213,23 @@ GrGLProgramEffects::~GrGLProgramEffects() { } } +void GrGLProgramEffects::emitSamplers(GrGLShaderBuilder* builder, + const GrEffectRef& effect, + TextureSamplerArray* outSamplers) { + SkTArray<Sampler, true>& samplers = fSamplers.push_back(); + int numTextures = effect->numTextures(); + samplers.push_back_n(numTextures); + SkString name; + for (int t = 0; t < numTextures; ++t) { + name.printf("Sampler%d", t); + samplers[t].fUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, + kSampler2D_GrSLType, + name.c_str()); + SkNEW_APPEND_TO_TARRAY(outSamplers, TextureSampler, + (samplers[t].fUniform, effect->textureAccess(t))); + } +} + void GrGLProgramEffects::initSamplers(const GrGLUniformManager& uniformManager, int* texUnitIdx) { int numEffects = fGLEffects.count(); SkASSERT(numEffects == fSamplers.count()); @@ -158,77 +244,6 @@ void GrGLProgramEffects::initSamplers(const GrGLUniformManager& uniformManager, } } -void GrGLVertexProgramEffects::setData(GrGpuGL* gpu, - const GrGLUniformManager& uniformManager, - const GrEffectStage* effectStages[]) { - int numEffects = fGLEffects.count(); - SkASSERT(numEffects == fTransforms.count()); - SkASSERT(numEffects == fSamplers.count()); - for (int e = 0; e < numEffects; ++e) { - GrDrawEffect drawEffect(*effectStages[e], fHasExplicitLocalCoords); - fGLEffects[e]->setData(uniformManager, drawEffect); - this->setTransformData(uniformManager, drawEffect, e); - this->bindTextures(gpu, *drawEffect.effect(), e); - } -} - -void GrGLVertexProgramEffects::setTransformData(const GrGLUniformManager& uniformManager, - const GrDrawEffect& drawEffect, - int effectIdx) { - SkTArray<Transform, true>& transforms = fTransforms[effectIdx]; - int numTransforms = transforms.count(); - SkASSERT(numTransforms == (*drawEffect.effect())->numTransforms()); - for (int t = 0; t < numTransforms; ++t) { - const GrCoordTransform& coordTransform = (*drawEffect.effect())->coordTransform(t); - const SkMatrix& matrix = coordTransform.getMatrix(); - const SkMatrix& coordChangeMatrix = kLocal_GrCoordSet == coordTransform.sourceCoords() ? - drawEffect.getCoordChangeMatrix() : - SkMatrix::I(); - SkASSERT(transforms[t].fHandle.isValid() != (kVoid_GrSLType == transforms[t].fType)); - switch (transforms[t].fType) { - case kVoid_GrSLType: - SkASSERT(matrix.isIdentity()); - SkASSERT(coordChangeMatrix.isIdentity()); - SkASSERT(!coordTransform.reverseY()); - return; - case kVec2f_GrSLType: { - SkASSERT(SkMatrix::kTranslate_Mask == (matrix.getType() | coordChangeMatrix.getType())); - SkASSERT(!coordTransform.reverseY()); - SkScalar tx = matrix[SkMatrix::kMTransX] + (coordChangeMatrix)[SkMatrix::kMTransX]; - SkScalar ty = matrix[SkMatrix::kMTransY] + (coordChangeMatrix)[SkMatrix::kMTransY]; - if (transforms[t].fCurrentValue.get(SkMatrix::kMTransX) != tx || - transforms[t].fCurrentValue.get(SkMatrix::kMTransY) != ty) { - uniformManager.set2f(transforms[t].fHandle, tx, ty); - transforms[t].fCurrentValue.set(SkMatrix::kMTransX, tx); - transforms[t].fCurrentValue.set(SkMatrix::kMTransY, ty); - } - break; - } - case kMat33f_GrSLType: { - SkMatrix combined; - combined.setConcat(matrix, coordChangeMatrix); - if (coordTransform.reverseY()) { - // combined.postScale(1,-1); - // combined.postTranslate(0,1); - combined.set(SkMatrix::kMSkewY, - combined[SkMatrix::kMPersp0] - combined[SkMatrix::kMSkewY]); - combined.set(SkMatrix::kMScaleY, - combined[SkMatrix::kMPersp1] - combined[SkMatrix::kMScaleY]); - combined.set(SkMatrix::kMTransY, - combined[SkMatrix::kMPersp2] - combined[SkMatrix::kMTransY]); - } - if (!transforms[t].fCurrentValue.cheapEqualTo(combined)) { - uniformManager.setSkMatrix(transforms[t].fHandle, combined); - transforms[t].fCurrentValue = combined; - } - break; - } - default: - GrCrash("Unexpected uniform type."); - } - } -} - void GrGLProgramEffects::bindTextures(GrGpuGL* gpu, const GrEffectRef& effect, int effectIdx) { const SkTArray<Sampler, true>& samplers = fSamplers[effectIdx]; int numSamplers = samplers.count(); @@ -244,75 +259,67 @@ void GrGLProgramEffects::bindTextures(GrGpuGL* gpu, const GrEffectRef& effect, i //////////////////////////////////////////////////////////////////////////////// -GrGLVertexProgramEffectsBuilder::GrGLVertexProgramEffectsBuilder(GrGLFullShaderBuilder* builder, - int reserveCount) - : fBuilder(builder) - , fProgramEffects(SkNEW_ARGS(GrGLVertexProgramEffects, - (reserveCount, fBuilder->hasExplicitLocalCoords()))) { -} - -void GrGLVertexProgramEffectsBuilder::emitEffect(const GrEffectStage& stage, - EffectKey key, - const char* outColor, - const char* inColor, - int stageIndex) { - SkASSERT(NULL != fProgramEffects.get()); - - GrDrawEffect drawEffect(stage, fProgramEffects->fHasExplicitLocalCoords); +void GrGLVertexProgramEffects::emitEffect(GrGLFullShaderBuilder* builder, + const GrEffectStage& stage, + EffectKey key, + const char* outColor, + const char* inColor, + int stageIndex) { + GrDrawEffect drawEffect(stage, fHasExplicitLocalCoords); const GrEffectRef& effect = *stage.getEffect(); SkSTArray<2, TransformedCoords> coords(effect->numTransforms()); SkSTArray<4, TextureSampler> samplers(effect->numTextures()); - this->emitAttributes(stage); - this->emitTransforms(effect, key, &coords); - INHERITED::emitSamplers(fBuilder, fProgramEffects.get(), effect, &samplers); + this->emitAttributes(builder, stage); + this->emitTransforms(builder, effect, key, &coords); + this->emitSamplers(builder, effect, &samplers); GrGLEffect* glEffect = effect->getFactory().createGLInstance(drawEffect); - fProgramEffects->fGLEffects.push_back(glEffect); + fGLEffects.push_back(glEffect); // Enclose custom code in a block to avoid namespace conflicts SkString openBrace; openBrace.printf("\t{ // Stage %d: %s\n", stageIndex, glEffect->name()); - fBuilder->vsCodeAppend(openBrace.c_str()); - fBuilder->fsCodeAppend(openBrace.c_str()); + builder->vsCodeAppend(openBrace.c_str()); + builder->fsCodeAppend(openBrace.c_str()); if (glEffect->isVertexEffect()) { GrGLVertexEffect* vertexEffect = static_cast<GrGLVertexEffect*>(glEffect); - vertexEffect->emitCode(fBuilder, drawEffect, key, outColor, inColor, coords, samplers); + vertexEffect->emitCode(builder, drawEffect, key, outColor, inColor, coords, samplers); } else { - glEffect->emitCode(fBuilder, drawEffect, key, outColor, inColor, coords, samplers); + glEffect->emitCode(builder, drawEffect, key, outColor, inColor, coords, samplers); } - fBuilder->vsCodeAppend("\t}\n"); - fBuilder->fsCodeAppend("\t}\n"); + builder->vsCodeAppend("\t}\n"); + builder->fsCodeAppend("\t}\n"); } -void GrGLVertexProgramEffectsBuilder::emitAttributes(const GrEffectStage& stage) { +void GrGLVertexProgramEffects::emitAttributes(GrGLFullShaderBuilder* builder, + const GrEffectStage& stage) { int numAttributes = stage.getVertexAttribIndexCount(); const int* attributeIndices = stage.getVertexAttribIndices(); for (int a = 0; a < numAttributes; ++a) { // TODO: Make addAttribute mangle the name. SkString attributeName("aAttr"); attributeName.appendS32(attributeIndices[a]); - fBuilder->addEffectAttribute(attributeIndices[a], - (*stage.getEffect())->vertexAttribType(a), - attributeName); + builder->addEffectAttribute(attributeIndices[a], + (*stage.getEffect())->vertexAttribType(a), + attributeName); } } -void GrGLVertexProgramEffectsBuilder::emitTransforms(const GrEffectRef& effect, - EffectKey effectKey, - TransformedCoordsArray* outCoords) { - typedef GrGLVertexProgramEffects::Transform Transform; - SkTArray<Transform, true>& transforms = fProgramEffects->fTransforms.push_back(); +void GrGLVertexProgramEffects::emitTransforms(GrGLFullShaderBuilder* builder, + const GrEffectRef& effect, + EffectKey effectKey, + TransformedCoordsArray* outCoords) { + SkTArray<Transform, true>& transforms = fTransforms.push_back(); EffectKey totalKey = GrBackendEffectFactory::GetTransformKey(effectKey); int numTransforms = effect->numTransforms(); transforms.push_back_n(numTransforms); for (int t = 0; t < numTransforms; t++) { - EffectKey key = (totalKey >> (kTransformKeyBits * t)) & kTransformKeyMask; GrSLType varyingType = kVoid_GrSLType; const char* uniName; - switch (key & kMatrixTypeKeyMask) { + switch (get_matrix_type(totalKey, t)) { case kIdentity_MatrixType: transforms[t].fType = kVoid_GrSLType; uniName = NULL; @@ -343,10 +350,10 @@ void GrGLVertexProgramEffectsBuilder::emitTransforms(const GrEffectRef& effect, suffixedUniName.appendf("_%i", t); uniName = suffixedUniName.c_str(); } - transforms[t].fHandle = fBuilder->addUniform(GrGLShaderBuilder::kVertex_Visibility, - transforms[t].fType, - uniName, - &uniName); + transforms[t].fHandle = builder->addUniform(GrGLShaderBuilder::kVertex_Visibility, + transforms[t].fType, + uniName, + &uniName); } const char* varyingName = "MatrixCoord"; @@ -358,55 +365,222 @@ void GrGLVertexProgramEffectsBuilder::emitTransforms(const GrEffectRef& effect, } const char* vsVaryingName; const char* fsVaryingName; - fBuilder->addVarying(varyingType, varyingName, &vsVaryingName, &fsVaryingName); + builder->addVarying(varyingType, varyingName, &vsVaryingName, &fsVaryingName); - const GrGLShaderVar& coords = (kPositionCoords_Flag & key) ? - fBuilder->positionAttribute() : - fBuilder->localCoordsAttribute(); + const GrGLShaderVar& coords = kPosition_GrCoordSet == get_source_coords(totalKey, t) ? + builder->positionAttribute() : + builder->localCoordsAttribute(); // varying = matrix * coords (logically) switch (transforms[t].fType) { case kVoid_GrSLType: SkASSERT(kVec2f_GrSLType == varyingType); - fBuilder->vsCodeAppendf("\t%s = %s;\n", vsVaryingName, coords.c_str()); + builder->vsCodeAppendf("\t%s = %s;\n", vsVaryingName, coords.c_str()); break; case kVec2f_GrSLType: SkASSERT(kVec2f_GrSLType == varyingType); - fBuilder->vsCodeAppendf("\t%s = %s + %s;\n", - vsVaryingName, uniName, coords.c_str()); + builder->vsCodeAppendf("\t%s = %s + %s;\n", + vsVaryingName, uniName, coords.c_str()); break; case kMat33f_GrSLType: { SkASSERT(kVec2f_GrSLType == varyingType || kVec3f_GrSLType == varyingType); if (kVec2f_GrSLType == varyingType) { - fBuilder->vsCodeAppendf("\t%s = (%s * vec3(%s, 1)).xy;\n", - vsVaryingName, uniName, coords.c_str()); + builder->vsCodeAppendf("\t%s = (%s * vec3(%s, 1)).xy;\n", + vsVaryingName, uniName, coords.c_str()); } else { - fBuilder->vsCodeAppendf("\t%s = %s * vec3(%s, 1);\n", - vsVaryingName, uniName, coords.c_str()); + builder->vsCodeAppendf("\t%s = %s * vec3(%s, 1);\n", + vsVaryingName, uniName, coords.c_str()); } break; } default: GrCrash("Unexpected uniform type."); } - SkNEW_APPEND_TO_TARRAY(outCoords, TransformedCoords, (fsVaryingName, varyingType)); + SkNEW_APPEND_TO_TARRAY(outCoords, TransformedCoords, + (SkString(fsVaryingName), varyingType)); } } -void GrGLProgramEffectsBuilder::emitSamplers(GrGLShaderBuilder* builder, - GrGLProgramEffects* programEffects, - const GrEffectRef& effect, - TextureSamplerArray* outSamplers) { - typedef GrGLProgramEffects::Sampler Sampler; - SkTArray<Sampler, true>& samplers = programEffects->fSamplers.push_back(); - int numTextures = effect->numTextures(); - samplers.push_back_n(numTextures); +void GrGLVertexProgramEffects::setData(GrGpuGL* gpu, + const GrGLUniformManager& uniformManager, + const GrEffectStage* effectStages[]) { + int numEffects = fGLEffects.count(); + SkASSERT(numEffects == fTransforms.count()); + SkASSERT(numEffects == fSamplers.count()); + for (int e = 0; e < numEffects; ++e) { + GrDrawEffect drawEffect(*effectStages[e], fHasExplicitLocalCoords); + fGLEffects[e]->setData(uniformManager, drawEffect); + this->setTransformData(uniformManager, drawEffect, e); + this->bindTextures(gpu, *drawEffect.effect(), e); + } +} + +void GrGLVertexProgramEffects::setTransformData(const GrGLUniformManager& uniformManager, + const GrDrawEffect& drawEffect, + int effectIdx) { + SkTArray<Transform, true>& transforms = fTransforms[effectIdx]; + int numTransforms = transforms.count(); + SkASSERT(numTransforms == (*drawEffect.effect())->numTransforms()); + for (int t = 0; t < numTransforms; ++t) { + SkASSERT(transforms[t].fHandle.isValid() != (kVoid_GrSLType == transforms[t].fType)); + switch (transforms[t].fType) { + case kVoid_GrSLType: + SkASSERT(get_transform_matrix(drawEffect, t).isIdentity()); + return; + case kVec2f_GrSLType: { + GrGLfloat tx, ty; + get_transform_translation(drawEffect, t, &tx, &ty); + if (transforms[t].fCurrentValue.get(SkMatrix::kMTransX) != tx || + transforms[t].fCurrentValue.get(SkMatrix::kMTransY) != ty) { + uniformManager.set2f(transforms[t].fHandle, tx, ty); + transforms[t].fCurrentValue.set(SkMatrix::kMTransX, tx); + transforms[t].fCurrentValue.set(SkMatrix::kMTransY, ty); + } + break; + } + case kMat33f_GrSLType: { + const SkMatrix& matrix = get_transform_matrix(drawEffect, t); + if (!transforms[t].fCurrentValue.cheapEqualTo(matrix)) { + uniformManager.setSkMatrix(transforms[t].fHandle, matrix); + transforms[t].fCurrentValue = matrix; + } + break; + } + default: + GrCrash("Unexpected uniform type."); + } + } +} + +GrGLVertexProgramEffectsBuilder::GrGLVertexProgramEffectsBuilder(GrGLFullShaderBuilder* builder, + int reserveCount) + : fBuilder(builder) + , fProgramEffects(SkNEW_ARGS(GrGLVertexProgramEffects, + (reserveCount, fBuilder->hasExplicitLocalCoords()))) { +} + +void GrGLVertexProgramEffectsBuilder::emitEffect(const GrEffectStage& stage, + GrGLProgramEffects::EffectKey key, + const char* outColor, + const char* inColor, + int stageIndex) { + SkASSERT(NULL != fProgramEffects.get()); + fProgramEffects->emitEffect(fBuilder, stage, key, outColor, inColor, stageIndex); +} + +//////////////////////////////////////////////////////////////////////////////// + +void GrGLTexGenProgramEffects::emitEffect(GrGLFragmentOnlyShaderBuilder* builder, + const GrEffectStage& stage, + EffectKey key, + const char* outColor, + const char* inColor, + int stageIndex) { + GrDrawEffect drawEffect(stage, false); + const GrEffectRef& effect = *stage.getEffect(); + SkSTArray<2, TransformedCoords> coords(effect->numTransforms()); + SkSTArray<4, TextureSampler> samplers(effect->numTextures()); + + SkASSERT(0 == stage.getVertexAttribIndexCount()); + this->setupTexGen(builder, effect, key, &coords); + this->emitSamplers(builder, effect, &samplers); + + GrGLEffect* glEffect = effect->getFactory().createGLInstance(drawEffect); + fGLEffects.push_back(glEffect); + + // Enclose custom code in a block to avoid namespace conflicts + SkString openBrace; + openBrace.printf("\t{ // Stage %d: %s\n", stageIndex, glEffect->name()); + builder->fsCodeAppend(openBrace.c_str()); + + SkASSERT(!glEffect->isVertexEffect()); + glEffect->emitCode(builder, drawEffect, key, outColor, inColor, coords, samplers); + + builder->fsCodeAppend("\t}\n"); +} + +void GrGLTexGenProgramEffects::setupTexGen(GrGLFragmentOnlyShaderBuilder* builder, + const GrEffectRef& effect, + EffectKey effectKey, + TransformedCoordsArray* outCoords) { + int numTransforms = effect->numTransforms(); + EffectKey totalKey = GrBackendEffectFactory::GetTransformKey(effectKey); + int texCoordIndex = builder->addTexCoordSets(numTransforms); + SkNEW_APPEND_TO_TARRAY(&fTransforms, Transforms, (totalKey, texCoordIndex)); SkString name; - for (int t = 0; t < numTextures; ++t) { - name.printf("Sampler%d", t); - samplers[t].fUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, - kSampler2D_GrSLType, - name.c_str()); - SkNEW_APPEND_TO_TARRAY(outSamplers, TextureSampler, - (samplers[t].fUniform, effect->textureAccess(t))); + for (int t = 0; t < numTransforms; ++t) { + GrSLType type = kGeneral_MatrixType == get_matrix_type(totalKey, t) ? + kVec3f_GrSLType : + kVec2f_GrSLType; + name.printf("%s(gl_TexCoord[%i])", GrGLSLTypeString(type), texCoordIndex++); + SkNEW_APPEND_TO_TARRAY(outCoords, TransformedCoords, (name, type)); + } +} + +void GrGLTexGenProgramEffects::setData(GrGpuGL* gpu, + const GrGLUniformManager& uniformManager, + const GrEffectStage* effectStages[]) { + int numEffects = fGLEffects.count(); + SkASSERT(numEffects == fTransforms.count()); + SkASSERT(numEffects == fSamplers.count()); + for (int e = 0; e < numEffects; ++e) { + GrDrawEffect drawEffect(*effectStages[e], false); + fGLEffects[e]->setData(uniformManager, drawEffect); + this->setTexGenState(gpu, drawEffect, e); + this->bindTextures(gpu, *drawEffect.effect(), e); } } + +void GrGLTexGenProgramEffects::setTexGenState(GrGpuGL* gpu, + const GrDrawEffect& drawEffect, + int effectIdx) { + EffectKey totalKey = fTransforms[effectIdx].fTransformKey; + int texCoordIndex = fTransforms[effectIdx].fTexCoordIndex; + int numTransforms = (*drawEffect.effect())->numTransforms(); + for (int t = 0; t < numTransforms; ++t) { + switch (get_matrix_type(totalKey, t)) { + case kIdentity_MatrixType: { + SkASSERT(get_transform_matrix(drawEffect, t).isIdentity()); + GrGLfloat identity[] = {1, 0, 0, + 0, 1, 0}; + gpu->enableTexGen(texCoordIndex++, GrGpuGL::kST_TexGenComponents, identity); + break; + } + case kTrans_MatrixType: { + GrGLfloat tx, ty; + get_transform_translation(drawEffect, t, &tx, &ty); + GrGLfloat translate[] = {1, 0, tx, + 0, 1, ty}; + gpu->enableTexGen(texCoordIndex++, GrGpuGL::kST_TexGenComponents, translate); + break; + } + case kNoPersp_MatrixType: { + const SkMatrix& transform = get_transform_matrix(drawEffect, t); + gpu->enableTexGen(texCoordIndex++, GrGpuGL::kST_TexGenComponents, transform); + break; + } + case kGeneral_MatrixType: { + const SkMatrix& transform = get_transform_matrix(drawEffect, t); + gpu->enableTexGen(texCoordIndex++, GrGpuGL::kSTR_TexGenComponents, transform); + break; + } + default: + GrCrash("Unexpected matrixs type."); + } + } +} + +GrGLTexGenProgramEffectsBuilder::GrGLTexGenProgramEffectsBuilder( + GrGLFragmentOnlyShaderBuilder* builder, + int reserveCount) + : fBuilder(builder) + , fProgramEffects(SkNEW_ARGS(GrGLTexGenProgramEffects, (reserveCount))) { +} + +void GrGLTexGenProgramEffectsBuilder::emitEffect(const GrEffectStage& stage, + GrGLProgramEffects::EffectKey key, + const char* outColor, + const char* inColor, + int stageIndex) { + SkASSERT(NULL != fProgramEffects.get()); + fProgramEffects->emitEffect(fBuilder, stage, key, outColor, inColor, stageIndex); +} diff --git a/src/gpu/gl/GrGLProgramEffects.h b/src/gpu/gl/GrGLProgramEffects.h index f6f975ae4e..4572a4250d 100644 --- a/src/gpu/gl/GrGLProgramEffects.h +++ b/src/gpu/gl/GrGLProgramEffects.h @@ -14,10 +14,10 @@ #include "GrGLUniformManager.h" class GrEffectStage; -class GrGLProgramEffectsBuilder; class GrGLVertexProgramEffectsBuilder; class GrGLShaderBuilder; class GrGLFullShaderBuilder; +class GrGLFragmentOnlyShaderBuilder; /** * This class encapsulates an array of GrGLEffects and their supporting data (coord transforms @@ -56,7 +56,7 @@ public: */ class TransformedCoords { public: - TransformedCoords(const char* name, GrSLType type) + TransformedCoords(const SkString& name, GrSLType type) : fName(name), fType(type) { } @@ -97,14 +97,19 @@ public: typedef SkTArray<TextureSampler> TextureSamplerArray; protected: - friend class GrGLProgramEffectsBuilder; - GrGLProgramEffects(int reserveCount) : fGLEffects(reserveCount) , fSamplers(reserveCount) { } /** + * Helper for emitEffect() in a subclasses. Emits uniforms for an effect's texture accesses and + * appends the necessary data to the TextureSamplerArray* object so effects can add texture + * lookups to their code. This method is only meant to be called during the construction phase. + */ + void emitSamplers(GrGLShaderBuilder*, const GrEffectRef&, TextureSamplerArray*); + + /** * Helper for setData(). Binds all the textures for an effect. */ void bindTextures(GrGpuGL*, const GrEffectRef&, int effectIdx); @@ -120,6 +125,23 @@ protected: }; /** + * This is an abstract base class for constructing different types of GrGLProgramEffects objects. + */ +class GrGLProgramEffectsBuilder { +public: + /** + * Emits the effect's shader code, and stores the necessary uniforms internally. + */ + virtual void emitEffect(const GrEffectStage&, + GrGLProgramEffects::EffectKey, + const char* outColor, + const char* inColor, + int stageIndex) = 0; +}; + +//////////////////////////////////////////////////////////////////////////////// + +/** * This is a GrGLProgramEffects implementation that does coord transforms with the vertex shader. */ class GrGLVertexProgramEffects : public GrGLProgramEffects { @@ -138,6 +160,34 @@ private: } /** + * Helper for GrGLProgramEffectsBuilder::emitEfffect(). This method is meant to only be called + * during the construction phase. + */ + void emitEffect(GrGLFullShaderBuilder*, + const GrEffectStage&, + GrGLProgramEffects::EffectKey, + const char* outColor, + const char* inColor, + int stageIndex); + + /** + * Helper for emitEffect(). Emits any attributes an effect may have. + */ + void emitAttributes(GrGLFullShaderBuilder*, const GrEffectStage&); + + /** + * Helper for emitEffect(). Emits code to implement an effect's coord transforms in the VS. + * Varyings are added as an outputs of the VS and inputs to the FS. The varyings may be either a + * vec2f or vec3f depending upon whether perspective interpolation is required or not. The names + * of the varyings in the VS and FS as well their types are appended to the + * TransformedCoordsArray* object, which is in turn passed to the effect's emitCode() function. + */ + void emitTransforms(GrGLFullShaderBuilder*, + const GrEffectRef&, + EffectKey, + TransformedCoordsArray*); + + /** * Helper for setData(). Sets all the transform matrices for an effect. */ void setTransformData(const GrGLUniformManager&, const GrDrawEffect&, int effectIdx); @@ -155,39 +205,99 @@ private: typedef GrGLProgramEffects INHERITED; }; -//////////////////////////////////////////////////////////////////////////////// - /** - * This is an abstract base class for constructing different types of GrGLProgramEffects objects. + * This class is used to construct a GrGLVertexProgramEffects* object. */ -class GrGLProgramEffectsBuilder { +class GrGLVertexProgramEffectsBuilder : public GrGLProgramEffectsBuilder { public: - /** - * Emits the effect's shader code, and stores the necessary uniforms internally. - */ + GrGLVertexProgramEffectsBuilder(GrGLFullShaderBuilder*, int reserveCount); + virtual void emitEffect(const GrEffectStage&, GrGLProgramEffects::EffectKey, const char* outColor, const char* inColor, - int stageIndex) = 0; + int stageIndex) SK_OVERRIDE; -protected: /** - * Helper for emitEffect(). Emits uniforms for an effect's texture accesses and appends the - * necessary data to the TextureSamplerArray* object so effects can add texture lookups. + * Finalizes the building process and returns the effect array. After this call, the builder + * becomes invalid. */ - static void emitSamplers(GrGLShaderBuilder*, - GrGLProgramEffects*, - const GrEffectRef&, - GrGLProgramEffects::TextureSamplerArray*); + GrGLProgramEffects* finish() { return fProgramEffects.detach(); } + +private: + GrGLFullShaderBuilder* fBuilder; + SkAutoTDelete<GrGLVertexProgramEffects> fProgramEffects; + + typedef GrGLProgramEffectsBuilder INHERITED; }; +//////////////////////////////////////////////////////////////////////////////// + /** - * This class is used to construct a GrGLVertexProgramEffects object. + * This is a GrGLProgramEffects implementation that does coord transforms with the the built-in GL + * TexGen functionality. */ -class GrGLVertexProgramEffectsBuilder : public GrGLProgramEffectsBuilder { +class GrGLTexGenProgramEffects : public GrGLProgramEffects { public: - GrGLVertexProgramEffectsBuilder(GrGLFullShaderBuilder*, int reserveCount); + virtual void setData(GrGpuGL*, + const GrGLUniformManager&, + const GrEffectStage* effectStages[]) SK_OVERRIDE; + +private: + friend class GrGLTexGenProgramEffectsBuilder; + + GrGLTexGenProgramEffects(int reserveCount) + : INHERITED(reserveCount) + , fTransforms(reserveCount) { + } + + /** + * Helper for GrGLProgramEffectsBuilder::emitEfffect(). This method is meant to only be called + * during the construction phase. + */ + void emitEffect(GrGLFragmentOnlyShaderBuilder*, + const GrEffectStage&, + GrGLProgramEffects::EffectKey, + const char* outColor, + const char* inColor, + int stageIndex); + + /** + * Helper for emitEffect(). Allocates texture units from the builder for each transform in an + * effect. The transforms all use adjacent texture units. They either use two or three of the + * coordinates at a given texture unit, depending on if they need perspective interpolation. + * The expressions to access the transformed coords (i.e. 'vec2(gl_TexCoord[0])') as well as the + * types are appended to the TransformedCoordsArray* object, which is in turn passed to the + * effect's emitCode() function. + */ + void setupTexGen(GrGLFragmentOnlyShaderBuilder*, + const GrEffectRef&, + EffectKey, + TransformedCoordsArray*); + + /** + * Helper for setData(). Sets the TexGen state for each transform in an effect. + */ + void setTexGenState(GrGpuGL*, const GrDrawEffect&, int effectIdx); + + struct Transforms { + Transforms(EffectKey transformKey, int texCoordIndex) + : fTransformKey(transformKey), fTexCoordIndex(texCoordIndex) {} + EffectKey fTransformKey; + int fTexCoordIndex; + }; + + SkTArray<Transforms> fTransforms; + + typedef GrGLProgramEffects INHERITED; +}; + +/** + * This class is used to construct a GrGLTexGenProgramEffects* object. + */ +class GrGLTexGenProgramEffectsBuilder : public GrGLProgramEffectsBuilder { +public: + GrGLTexGenProgramEffectsBuilder(GrGLFragmentOnlyShaderBuilder*, int reserveCount); virtual void emitEffect(const GrEffectStage&, GrGLProgramEffects::EffectKey, @@ -202,24 +312,8 @@ public: GrGLProgramEffects* finish() { return fProgramEffects.detach(); } private: - /** - * Helper for emitEffect(). Emits any attributes an effect might have. - */ - void emitAttributes(const GrEffectStage&); - - /** - * Helper for emitEffect(). Emits code to implement an effect's coord transforms in the VS. - * Varyings are added as an outputs of the VS and inputs to the FS. The varyings may be either a - * vec2f or vec3f depending upon whether perspective interpolation is required or not. The names - * of the varyings in the VS and FS as well their types are appended to the - * TransformedCoordsArray* object, which is in turn passed to the effect's emitCode() function. - */ - void emitTransforms(const GrEffectRef&, - GrGLProgramEffects::EffectKey, - GrGLProgramEffects::TransformedCoordsArray*); - - GrGLFullShaderBuilder* fBuilder; - SkAutoTDelete<GrGLVertexProgramEffects> fProgramEffects; + GrGLFragmentOnlyShaderBuilder* fBuilder; + SkAutoTDelete<GrGLTexGenProgramEffects> fProgramEffects; typedef GrGLProgramEffectsBuilder INHERITED; }; diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp index 089ece7c07..00fefe1305 100644 --- a/src/gpu/gl/GrGLShaderBuilder.cpp +++ b/src/gpu/gl/GrGLShaderBuilder.cpp @@ -441,7 +441,6 @@ const char* GrGLShaderBuilder::fragmentPosition() { } } - void GrGLShaderBuilder::fsEmitFunction(GrSLType returnType, const char* name, int argCnt, @@ -920,3 +919,35 @@ void GrGLFullShaderBuilder::bindProgramLocations(GrGLuint programId) const { GL_CALL(BindAttribLocation(programId, attrib->fIndex, attrib->fName.c_str())); } } + +//////////////////////////////////////////////////////////////////////////////// + +GrGLFragmentOnlyShaderBuilder::GrGLFragmentOnlyShaderBuilder(GrGpuGL* gpu, + GrGLUniformManager& uniformManager, + const GrGLProgramDesc& desc) + : INHERITED(gpu, uniformManager, desc) + , fNumTexCoordSets(0) { + + SkASSERT(!desc.getHeader().fHasVertexCode); + SkASSERT(gpu->glCaps().fixedFunctionSupport()); + SkASSERT(gpu->glCaps().pathStencilingSupport()); + SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fColorInput); + SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fCoverageInput); +} + +GrGLProgramEffects* GrGLFragmentOnlyShaderBuilder::createAndEmitEffects( + const GrEffectStage* effectStages[], + const EffectKey effectKeys[], + int effectCnt, + SkString* inOutFSColor, + GrSLConstantVec* fsInOutColorKnownValue) { + + GrGLTexGenProgramEffectsBuilder texGenEffectsBuilder(this, effectCnt); + this->INHERITED::createAndEmitEffects(&texGenEffectsBuilder, + effectStages, + effectKeys, + effectCnt, + inOutFSColor, + fsInOutColorKnownValue); + return texGenEffectsBuilder.finish(); +} diff --git a/src/gpu/gl/GrGLShaderBuilder.h b/src/gpu/gl/GrGLShaderBuilder.h index 4c43fc36c3..208c61060b 100644 --- a/src/gpu/gl/GrGLShaderBuilder.h +++ b/src/gpu/gl/GrGLShaderBuilder.h @@ -450,4 +450,26 @@ private: typedef GrGLShaderBuilder INHERITED; }; +//////////////////////////////////////////////////////////////////////////////// + +class GrGLFragmentOnlyShaderBuilder : public GrGLShaderBuilder { +public: + GrGLFragmentOnlyShaderBuilder(GrGpuGL*, GrGLUniformManager&, const GrGLProgramDesc&); + + int getNumTexCoordSets() const { return fNumTexCoordSets; } + int addTexCoordSets(int count) { return (fNumTexCoordSets += count) - count; } + + virtual GrGLProgramEffects* createAndEmitEffects( + const GrEffectStage* effectStages[], + const EffectKey effectKeys[], + int effectCnt, + SkString* inOutFSColor, + GrSLConstantVec* fsInOutColorKnownValue) SK_OVERRIDE; + +private: + int fNumTexCoordSets; + + typedef GrGLShaderBuilder INHERITED; +}; + #endif diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp index 50d2a1f517..18165d9ca3 100644 --- a/src/gpu/gl/GrGpuGL.cpp +++ b/src/gpu/gl/GrGpuGL.cpp @@ -124,6 +124,7 @@ GrGpuGL::GrGpuGL(const GrGLContext& ctx, GrContext* context) fCaps.reset(SkRef(ctx.info().caps())); fHWBoundTextures.reset(ctx.info().caps()->maxFragmentTextureUnits()); + fHWTexGenSettings.reset(ctx.info().caps()->maxFixedFunctionTextureCoords()); fillInConfigRenderableTable(); @@ -377,7 +378,13 @@ void GrGpuGL::onResetContext(uint32_t resetBits) { GL_CALL(Disable(GR_GL_TEXTURE_GEN_T)); GL_CALL(Disable(GR_GL_TEXTURE_GEN_Q)); GL_CALL(Disable(GR_GL_TEXTURE_GEN_R)); + if (this->caps()->pathStencilingSupport()) { + GL_CALL(PathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL)); + } + fHWTexGenSettings[i].fMode = GR_GL_NONE; + fHWTexGenSettings[i].fNumComponents = 0; } + fHWActiveTexGenSets = 0; } // we assume these values @@ -2114,6 +2121,124 @@ void GrGpuGL::bindTexture(int unitIdx, const GrTextureParams& params, GrGLTextur texture->setCachedTexParams(newTexParams, this->getResetTimestamp()); } +void GrGpuGL::setProjectionMatrix(const SkMatrix& matrix, + const SkISize& renderTargetSize, + GrSurfaceOrigin renderTargetOrigin) { + + SkASSERT(this->glCaps().fixedFunctionSupport()); + + if (renderTargetOrigin == fHWProjectionMatrixState.fRenderTargetOrigin && + renderTargetSize == fHWProjectionMatrixState.fRenderTargetSize && + matrix.cheapEqualTo(fHWProjectionMatrixState.fViewMatrix)) { + return; + } + + fHWProjectionMatrixState.fViewMatrix = matrix; + fHWProjectionMatrixState.fRenderTargetSize = renderTargetSize; + fHWProjectionMatrixState.fRenderTargetOrigin = renderTargetOrigin; + + GrGLfloat glMatrix[4 * 4]; + fHWProjectionMatrixState.getGLMatrix<4>(glMatrix); + GL_CALL(MatrixMode(GR_GL_PROJECTION)); + GL_CALL(LoadMatrixf(glMatrix)); +} + +void GrGpuGL::enableTexGen(int unitIdx, + TexGenComponents components, + const GrGLfloat* coefficients) { + + SkASSERT(this->glCaps().fixedFunctionSupport()); + SkASSERT(this->caps()->pathStencilingSupport()); + SkASSERT(components >= kS_TexGenComponents && components <= kSTR_TexGenComponents); + + if (GR_GL_OBJECT_LINEAR == fHWTexGenSettings[unitIdx].fMode && + components == fHWTexGenSettings[unitIdx].fNumComponents && + !memcmp(coefficients, fHWTexGenSettings[unitIdx].fCoefficients, + 3 * components * sizeof(GrGLfloat))) { + return; + } + + this->setTextureUnit(unitIdx); + + if (GR_GL_OBJECT_LINEAR != fHWTexGenSettings[unitIdx].fMode) { + for (int i = 0; i < 4; i++) { + GL_CALL(TexGeni(GR_GL_S + i, GR_GL_TEXTURE_GEN_MODE, GR_GL_OBJECT_LINEAR)); + } + fHWTexGenSettings[unitIdx].fMode = GR_GL_OBJECT_LINEAR; + } + + for (int i = fHWTexGenSettings[unitIdx].fNumComponents; i < components; i++) { + GL_CALL(Enable(GR_GL_TEXTURE_GEN_S + i)); + } + for (int i = components; i < fHWTexGenSettings[unitIdx].fNumComponents; i++) { + GL_CALL(Disable(GR_GL_TEXTURE_GEN_S + i)); + } + fHWTexGenSettings[unitIdx].fNumComponents = components; + + for (int i = 0; i < components; i++) { + GrGLfloat plane[] = {coefficients[0 + 3 * i], + coefficients[1 + 3 * i], + 0, + coefficients[2 + 3 * i]}; + GL_CALL(TexGenfv(GR_GL_S + i, GR_GL_OBJECT_PLANE, plane)); + } + + GL_CALL(PathTexGen(GR_GL_TEXTURE0 + unitIdx, + GR_GL_OBJECT_LINEAR, + components, + coefficients)); + + memcpy(fHWTexGenSettings[unitIdx].fCoefficients, coefficients, + 3 * components * sizeof(GrGLfloat)); + + fHWActiveTexGenSets = SkTMax(fHWActiveTexGenSets, unitIdx); +} + +void GrGpuGL::enableTexGen(int unitIdx, TexGenComponents components, const SkMatrix& matrix) { + + GrGLfloat coefficients[3 * 3]; + SkASSERT(this->glCaps().fixedFunctionSupport()); + SkASSERT(components >= kS_TexGenComponents && components <= kSTR_TexGenComponents); + + coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]); + coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]); + coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]); + + if (components >= kST_TexGenComponents) { + coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]); + coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]); + coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]); + } + + if (components >= kSTR_TexGenComponents) { + coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]); + coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]); + coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]); + } + + enableTexGen(unitIdx, components, coefficients); +} + +void GrGpuGL::disableUnusedTexGen(int numUsedTexCoordSets) { + + SkASSERT(this->glCaps().fixedFunctionSupport()); + + for (int i = numUsedTexCoordSets; i < fHWActiveTexGenSets; i++) { + if (0 == fHWTexGenSettings[i].fNumComponents) { + continue; + } + + this->setTextureUnit(i); + for (int j = 0; j < fHWTexGenSettings[i].fNumComponents; j++) { + GL_CALL(Disable(GR_GL_TEXTURE_GEN_S + j)); + } + GL_CALL(PathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL)); + fHWTexGenSettings[i].fNumComponents = 0; + } + + fHWActiveTexGenSets = SkTMin(fHWActiveTexGenSets, numUsedTexCoordSets); +} + void GrGpuGL::flushMiscFixedFunctionState() { const GrDrawState& drawState = this->getDrawState(); diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h index b0195bbaed..a59654a0f8 100644 --- a/src/gpu/gl/GrGpuGL.h +++ b/src/gpu/gl/GrGpuGL.h @@ -37,8 +37,19 @@ public: GrGLVersion glVersion() const { return fGLContext.info().version(); } GrGLSLGeneration glslGeneration() const { return fGLContext.info().glslGeneration(); } - // Used by GrGLProgram to bind necessary textures for GrGLEffects. + // Used by GrGLProgram and GrGLTexGenProgramEffects to configure OpenGL state. void bindTexture(int unitIdx, const GrTextureParams& params, GrGLTexture* texture); + void setProjectionMatrix(const SkMatrix& matrix, + const SkISize& renderTargetSize, + GrSurfaceOrigin renderTargetOrigin); + enum TexGenComponents { + kS_TexGenComponents = 1, + kST_TexGenComponents = 2, + kSTR_TexGenComponents = 3 + }; + void enableTexGen(int unitIdx, TexGenComponents, const GrGLfloat* coefficients); + void enableTexGen(int unitIdx, TexGenComponents, const SkMatrix& matrix); + void disableUnusedTexGen(int numUsedTexCoordSets); bool programUnitTest(int maxStages); @@ -213,9 +224,6 @@ private: #endif }; - // sets the matrix for path stenciling (uses the GL fixed pipe matrices) - void flushPathStencilMatrix(); - // flushes dithering, color-mask, and face culling stat void flushMiscFixedFunctionState(); @@ -432,6 +440,14 @@ private: TriState fHWDitherEnabled; GrRenderTarget* fHWBoundRenderTarget; SkTArray<GrTexture*, true> fHWBoundTextures; + + struct TexGenData { + GrGLenum fMode; + GrGLint fNumComponents; + GrGLfloat fCoefficients[3 * 3]; + }; + int fHWActiveTexGenSets; + SkTArray<TexGenData, true> fHWTexGenSettings; ///@} // we record what stencil format worked last time to hopefully exit early diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp index 8a3444e508..92eed8d9bb 100644 --- a/src/gpu/gl/GrGpuGL_program.cpp +++ b/src/gpu/gl/GrGpuGL_program.cpp @@ -210,28 +210,6 @@ void GrGpuGL::abandonResources(){ #define GL_CALL(X) GR_GL_CALL(this->glInterface(), X) -void GrGpuGL::flushPathStencilMatrix() { - const SkMatrix& viewMatrix = this->getDrawState().getViewMatrix(); - const GrRenderTarget* rt = this->getDrawState().getRenderTarget(); - SkISize size; - size.set(rt->width(), rt->height()); - const SkMatrix& vm = this->getDrawState().getViewMatrix(); - - if (fHWProjectionMatrixState.fRenderTargetOrigin != rt->origin() || - !fHWProjectionMatrixState.fViewMatrix.cheapEqualTo(viewMatrix) || - fHWProjectionMatrixState.fRenderTargetSize!= size) { - - fHWProjectionMatrixState.fViewMatrix = vm; - fHWProjectionMatrixState.fRenderTargetSize = size; - fHWProjectionMatrixState.fRenderTargetOrigin = rt->origin(); - - GrGLfloat projectionMatrix[4 * 4]; - fHWProjectionMatrixState.getGLMatrix<4>(projectionMatrix); - GL_CALL(MatrixMode(GR_GL_PROJECTION)); - GL_CALL(LoadMatrixf(projectionMatrix)); - } -} - bool GrGpuGL::flushGraphicsState(DrawType type, const GrDeviceCoordTexture* dstCopy) { const GrDrawState& drawState = this->getDrawState(); @@ -239,7 +217,10 @@ bool GrGpuGL::flushGraphicsState(DrawType type, const GrDeviceCoordTexture* dstC SkASSERT(NULL != drawState.getRenderTarget()); if (kStencilPath_DrawType == type) { - this->flushPathStencilMatrix(); + const GrRenderTarget* rt = this->getDrawState().getRenderTarget(); + SkISize size; + size.set(rt->width(), rt->height()); + this->setProjectionMatrix(drawState.getViewMatrix(), size, rt->origin()); } else { this->flushMiscFixedFunctionState(); @@ -360,24 +341,40 @@ void GrGpuGL::setupGeometry(const DrawInfo& info, size_t* indexOffsetInBytes) { GrGLAttribArrayState* attribState = fHWGeometryState.bindArrayAndBuffersToDraw(this, vbuf, ibuf); - uint32_t usedAttribArraysMask = 0; - const GrVertexAttrib* vertexAttrib = this->getDrawState().getVertexAttribs(); - int vertexAttribCount = this->getDrawState().getVertexAttribCount(); - for (int vertexAttribIndex = 0; vertexAttribIndex < vertexAttribCount; - ++vertexAttribIndex, ++vertexAttrib) { - - usedAttribArraysMask |= (1 << vertexAttribIndex); - GrVertexAttribType attribType = vertexAttrib->fType; - attribState->set(this, - vertexAttribIndex, - vbuf, - GrGLAttribTypeToLayout(attribType).fCount, - GrGLAttribTypeToLayout(attribType).fType, - GrGLAttribTypeToLayout(attribType).fNormalized, - stride, - reinterpret_cast<GrGLvoid*>( - vertexOffsetInBytes + vertexAttrib->fOffset)); - } + if (!fCurrentProgram->hasVertexShader()) { + int posIdx = this->getDrawState().positionAttributeIndex(); + const GrVertexAttrib* vertexArray = this->getDrawState().getVertexAttribs() + posIdx; + GrVertexAttribType vertexArrayType = vertexArray->fType; + SkASSERT(!GrGLAttribTypeToLayout(vertexArrayType).fNormalized); + SkASSERT(GrGLAttribTypeToLayout(vertexArrayType).fCount == 2); + attribState->setFixedFunctionVertexArray(this, + vbuf, + 2, + GrGLAttribTypeToLayout(vertexArrayType).fType, + stride, + reinterpret_cast<GrGLvoid*>( + vertexOffsetInBytes + vertexArray->fOffset)); + attribState->disableUnusedArrays(this, 0, true); + } else { + uint32_t usedAttribArraysMask = 0; + const GrVertexAttrib* vertexAttrib = this->getDrawState().getVertexAttribs(); + int vertexAttribCount = this->getDrawState().getVertexAttribCount(); + for (int vertexAttribIndex = 0; vertexAttribIndex < vertexAttribCount; + ++vertexAttribIndex, ++vertexAttrib) { + + usedAttribArraysMask |= (1 << vertexAttribIndex); + GrVertexAttribType attribType = vertexAttrib->fType; + attribState->set(this, + vertexAttribIndex, + vbuf, + GrGLAttribTypeToLayout(attribType).fCount, + GrGLAttribTypeToLayout(attribType).fType, + GrGLAttribTypeToLayout(attribType).fNormalized, + stride, + reinterpret_cast<GrGLvoid*>( + vertexOffsetInBytes + vertexAttrib->fOffset)); + } - attribState->disableUnusedArrays(this, usedAttribArraysMask, false); + attribState->disableUnusedArrays(this, usedAttribArraysMask, false); + } } diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp index fe17f88945..13d0d2ee5b 100644 --- a/tests/GLProgramsTest.cpp +++ b/tests/GLProgramsTest.cpp @@ -78,6 +78,7 @@ void GrGLProgramDesc::setRandom(SkRandom* random, bool dstRead = false; bool fragPos = false; + bool vertexCode = false; int numStages = numColorStages + numCoverageStages; for (int s = 0; s < numStages; ++s) { const GrBackendEffectFactory& factory = (*stages[s]->getEffect())->getFactory(); @@ -89,6 +90,9 @@ void GrGLProgramDesc::setRandom(SkRandom* random, if ((*stages[s]->getEffect())->willReadFragmentPosition()) { fragPos = true; } + if ((*stages[s]->getEffect())->hasVertexCode()) { + vertexCode = true; + } } if (dstRead) { @@ -103,6 +107,11 @@ void GrGLProgramDesc::setRandom(SkRandom* random, header->fFragPosKey = 0; } + header->fHasVertexCode = vertexCode || + useLocalCoords || + kAttribute_ColorInput == header->fColorInput || + kAttribute_ColorInput == header->fCoverageInput; + CoverageOutput coverageOutput; bool illegalCoverageOutput; do { |