diff options
25 files changed, 620 insertions, 402 deletions
diff --git a/include/gpu/GrProcessor.h b/include/gpu/GrProcessor.h index a5c834168b..c1755a8954 100644 --- a/include/gpu/GrProcessor.h +++ b/include/gpu/GrProcessor.h @@ -124,6 +124,12 @@ public: in generated shader code. */ const char* name() const; + int numTransforms() const { return fCoordTransforms.count(); } + + /** Returns the coordinate transformation at index. index must be valid according to + numTransforms(). */ + const GrCoordTransform& coordTransform(int index) const { return *fCoordTransforms[index]; } + int numTextures() const { return fTextureAccesses.count(); } /** Returns the access pattern for the texture at index. index must be valid according to @@ -153,6 +159,16 @@ public: protected: /** + * Subclasses call this from their constructor to register coordinate transformations. The + * effect subclass manages the lifetime of the transformations (this function only stores a + * pointer). The GrCoordTransform is typically a member field of the GrProcessor subclass. When + * the matrix has perspective, the transformed coordinates will have 3 components. Otherwise + * they'll have 2. This must only be called from the constructor because GrProcessors are + * immutable. + */ + void addCoordTransform(const GrCoordTransform* coordTransform); + + /** * Subclasses call this from their constructor to register GrTextureAccesses. The effect * subclass manages the lifetime of the accesses (this function only stores a pointer). The * GrTextureAccess is typically a member field of the GrProcessor subclass. This must only be @@ -182,7 +198,9 @@ private: * Subclass implements this to support getConstantColorComponents(...). */ virtual void onComputeInvariantOutput(InvariantOutput* inout) const = 0; + friend class GrGeometryProcessor; // to set fRequiresVertexShader and build fVertexAttribTypes. + SkSTArray<4, const GrCoordTransform*, true> fCoordTransforms; SkSTArray<4, const GrTextureAccess*, true> fTextureAccesses; bool fWillReadFragmentPosition; @@ -198,12 +216,6 @@ public: virtual const GrBackendFragmentProcessorFactory& getFactory() const = 0; - int numTransforms() const { return fCoordTransforms.count(); } - - /** Returns the coordinate transformation at index. index must be valid according to - numTransforms(). */ - const GrCoordTransform& coordTransform(int index) const { return *fCoordTransforms[index]; } - /** Will this effect read the destination pixel value? */ bool willReadDstColor() const { return fWillReadDstColor; } @@ -212,16 +224,6 @@ public: protected: /** - * Fragment Processor subclasses call this from their constructor to register coordinate - * transformations. The processor subclass manages the lifetime of the transformations (this - * function only stores a pointer). The GrCoordTransform is typically a member field of the - * GrProcessor subclass. When the matrix has perspective, the transformed coordinates will have - * 3 components. Otherwise they'll have 2. This must only be called from the constructor because - * GrProcessors are immutable. - */ - void addCoordTransform(const GrCoordTransform*); - - /** * If the effect subclass will read the destination pixel value then it must call this function * from its constructor. Otherwise, when its generated backend-specific effect class attempts * to generate code that reads the destination pixel it will fail. @@ -236,7 +238,6 @@ protected: void setWillNotUseInputColor() { fWillUseInputColor = false; } private: - SkSTArray<4, const GrCoordTransform*, true> fCoordTransforms; bool fWillReadDstColor; bool fWillUseInputColor; diff --git a/include/gpu/GrProcessorStage.h b/include/gpu/GrProcessorStage.h index c961572c1d..5cc06e78db 100644 --- a/include/gpu/GrProcessorStage.h +++ b/include/gpu/GrProcessorStage.h @@ -24,14 +24,16 @@ // is immutable, and only owns pending execution refs. This requries removing the common base // class from GrDrawState and GrOptDrawState called GrRODrawState and converting to GrOptDrawState // when draws are enqueued in the GrInOrderDrawBuffer. -class GrFragmentStage { +class GrProcessorStage { public: - explicit GrFragmentStage(const GrFragmentProcessor* proc) + explicit GrProcessorStage(const GrProcessor* proc) : fProc(SkRef(proc)) { fCoordChangeMatrixSet = false; } - GrFragmentStage(const GrFragmentStage& other) { + virtual ~GrProcessorStage() {} + + GrProcessorStage(const GrProcessorStage& other) { fCoordChangeMatrixSet = other.fCoordChangeMatrixSet; if (other.fCoordChangeMatrixSet) { fCoordChangeMatrix = other.fCoordChangeMatrix; @@ -39,7 +41,7 @@ public: fProc.initAndRef(other.fProc); } - static bool AreCompatible(const GrFragmentStage& a, const GrFragmentStage& b, + static bool AreCompatible(const GrProcessorStage& a, const GrProcessorStage& b, bool usingExplicitLocalCoords) { SkASSERT(a.fProc.get()); SkASSERT(b.fProc.get()); @@ -88,7 +90,7 @@ public: SkMatrix fCoordChangeMatrix; SkDEBUGCODE(mutable uint32_t fEffectUniqueID;) - friend class GrFragmentStage; + friend class GrProcessorStage; }; /** @@ -147,14 +149,38 @@ public: } } - const GrFragmentProcessor* getProcessor() const { return fProc.get(); } + virtual const GrProcessor* getProcessor() const = 0; void convertToPendingExec() { fProc.convertToPendingExec(); } protected: - bool fCoordChangeMatrixSet; - SkMatrix fCoordChangeMatrix; - GrProgramElementRef<const GrFragmentProcessor> fProc; + bool fCoordChangeMatrixSet; + SkMatrix fCoordChangeMatrix; + GrProgramElementRef<const GrProcessor> fProc; +}; + +class GrFragmentStage : public GrProcessorStage { +public: + GrFragmentStage(const GrFragmentProcessor* fp) : GrProcessorStage(fp) {} + + virtual const GrFragmentProcessor* getProcessor() const { + return static_cast<const GrFragmentProcessor*>(fProc.get()); + } + + typedef GrFragmentProcessor Processor; + typedef GrGLFragmentProcessor GLProcessor; +}; + +class GrGeometryStage : public GrProcessorStage { +public: + GrGeometryStage(const GrGeometryProcessor* gp) : GrProcessorStage(gp) {} + + virtual const GrGeometryProcessor* getProcessor() const { + return static_cast<const GrGeometryProcessor*>(fProc.get()); + } + + typedef GrGeometryProcessor Processor; + typedef GrGLGeometryProcessor GLProcessor; }; #endif diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h index b3ad6f4b34..d1ac77bc92 100644 --- a/src/effects/gradients/SkGradientShaderPriv.h +++ b/src/effects/gradients/SkGradientShaderPriv.h @@ -300,7 +300,7 @@ static inline int next_dither_toggle16(int toggle) { #include "GrCoordTransform.h" #include "gl/GrGLProcessor.h" -class GrFragmentStage; +class GrProcessorStage; class GrBackendProcessorFactory; /* diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp index e1fa6da877..288fa12730 100644 --- a/src/gpu/GrDrawState.cpp +++ b/src/gpu/GrDrawState.cpp @@ -43,7 +43,9 @@ bool GrDrawState::isEqual(const GrDrawState& that) const { if (this->hasGeometryProcessor()) { if (!that.hasGeometryProcessor()) { return false; - } else if (!this->getGeometryProcessor()->isEqual(*that.getGeometryProcessor())) { + } else if (!GrProcessorStage::AreCompatible(*this->getGeometryProcessor(), + *that.getGeometryProcessor(), + explicitLocalCoords)) { return false; } } else if (that.hasGeometryProcessor()) { @@ -51,13 +53,13 @@ bool GrDrawState::isEqual(const GrDrawState& that) const { } for (int i = 0; i < this->numColorStages(); i++) { - if (!GrFragmentStage::AreCompatible(this->getColorStage(i), that.getColorStage(i), + if (!GrProcessorStage::AreCompatible(this->getColorStage(i), that.getColorStage(i), explicitLocalCoords)) { return false; } } for (int i = 0; i < this->numCoverageStages(); i++) { - if (!GrFragmentStage::AreCompatible(this->getCoverageStage(i), that.getCoverageStage(i), + if (!GrProcessorStage::AreCompatible(this->getCoverageStage(i), that.getCoverageStage(i), explicitLocalCoords)) { return false; } @@ -114,6 +116,9 @@ GrDrawState::GrDrawState(const GrDrawState& state, const SkMatrix& preConcatMatr SkDEBUGCODE(fBlockEffectRemovalCnt = 0;) *this = state; if (!preConcatMatrix.isIdentity()) { + if (this->hasGeometryProcessor()) { + fGeometryProcessor->localCoordChange(preConcatMatrix); + } for (int i = 0; i < this->numColorStages(); ++i) { fColorStages[i].localCoordChange(preConcatMatrix); } @@ -142,7 +147,7 @@ GrDrawState& GrDrawState::operator=(const GrDrawState& that) { fCoverage = that.fCoverage; fDrawFace = that.fDrawFace; if (that.hasGeometryProcessor()) { - fGeometryProcessor.initAndRef(that.fGeometryProcessor); + fGeometryProcessor.reset(SkNEW_ARGS(GrGeometryStage, (*that.fGeometryProcessor.get()))); } else { fGeometryProcessor.reset(NULL); } @@ -197,6 +202,9 @@ bool GrDrawState::setIdentityViewMatrix() { // sad trombone sound return false; } + if (this->hasGeometryProcessor()) { + fGeometryProcessor->localCoordChange(invVM); + } for (int s = 0; s < this->numColorStages(); ++s) { fColorStages[s].localCoordChange(invVM); } @@ -257,7 +265,9 @@ bool GrDrawState::validateVertexAttribs() const { } if (this->hasGeometryProcessor()) { - const GrGeometryProcessor* gp = this->getGeometryProcessor(); + const GrGeometryStage& stage = *this->getGeometryProcessor(); + const GrGeometryProcessor* gp = stage.getProcessor(); + SkASSERT(gp); // make sure that any attribute indices have the correct binding type, that the attrib // type and effect's shader lang type are compatible, and that attributes shared by // multiple effects use the same shader lang type. @@ -400,7 +410,8 @@ bool GrDrawState::hasSolidCoverage() const { // Run through the coverage stages and see if the coverage will be all ones at the end. if (this->hasGeometryProcessor()) { - fGeometryProcessor->computeInvariantOutput(&inout); + const GrGeometryProcessor* gp = fGeometryProcessor->getProcessor(); + gp->computeInvariantOutput(&inout); } for (int s = 0; s < this->numCoverageStages(); ++s) { @@ -445,7 +456,7 @@ void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) { if (SK_InvalidUniqueID == fOriginalGPID) { fDrawState->fGeometryProcessor.reset(NULL); } else { - SkASSERT(fDrawState->getGeometryProcessor()->getUniqueID() == + SkASSERT(fDrawState->getGeometryProcessor()->getProcessor()->getUniqueID() == fOriginalGPID); fOriginalGPID = SK_InvalidUniqueID; } @@ -466,7 +477,7 @@ void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) { if (NULL != ds) { SkASSERT(SK_InvalidUniqueID == fOriginalGPID); if (NULL != ds->getGeometryProcessor()) { - fOriginalGPID = ds->getGeometryProcessor()->getUniqueID(); + fOriginalGPID = ds->getGeometryProcessor()->getProcessor()->getUniqueID(); } fColorEffectCnt = ds->numColorStages(); fCoverageEffectCnt = ds->numCoverageStages(); @@ -504,9 +515,14 @@ void GrDrawState::AutoViewMatrixRestore::restore() { fDrawState->fViewMatrix = fViewMatrix; SkASSERT(fDrawState->numColorStages() >= fNumColorStages); int numCoverageStages = fSavedCoordChanges.count() - fNumColorStages; + numCoverageStages -= fHasGeometryProcessor ? 1 : 0; SkASSERT(fDrawState->numCoverageStages() >= numCoverageStages); int i = 0; + if (fHasGeometryProcessor) { + SkASSERT(fDrawState->hasGeometryProcessor()); + fDrawState->fGeometryProcessor->restoreCoordChange(fSavedCoordChanges[i++]); + } for (int s = 0; s < fNumColorStages; ++s, ++i) { fDrawState->fColorStages[s].restoreCoordChange(fSavedCoordChanges[i]); } @@ -552,6 +568,7 @@ bool GrDrawState::AutoViewMatrixRestore::setIdentity(GrDrawState* drawState) { if (0 == drawState->numTotalStages()) { drawState->fViewMatrix.reset(); fDrawState = drawState; + fHasGeometryProcessor = false; fNumColorStages = 0; fSavedCoordChanges.reset(0); SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;) @@ -573,6 +590,13 @@ void GrDrawState::AutoViewMatrixRestore::doEffectCoordChanges(const SkMatrix& co fSavedCoordChanges.reset(fDrawState->numTotalStages()); int i = 0; + fHasGeometryProcessor = false; + if (fDrawState->hasGeometryProcessor()) { + fDrawState->fGeometryProcessor->saveCoordChange(&fSavedCoordChanges[i++]); + fDrawState->fGeometryProcessor->localCoordChange(coordChangeMatrix); + fHasGeometryProcessor = true; + } + fNumColorStages = fDrawState->numColorStages(); for (int s = 0; s < fNumColorStages; ++s, ++i) { fDrawState->getColorStage(s).saveCoordChange(&fSavedCoordChanges[i]); @@ -595,7 +619,7 @@ void GrDrawState::convertToPendingExec() { fColorStages[i].convertToPendingExec(); } if (fGeometryProcessor) { - fGeometryProcessor.convertToPendingExec(); + fGeometryProcessor->convertToPendingExec(); } for (int i = 0; i < fCoverageStages.count(); ++i) { fCoverageStages[i].convertToPendingExec(); diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h index d58d8c64e7..03af7b532f 100644 --- a/src/gpu/GrDrawState.h +++ b/src/gpu/GrDrawState.h @@ -221,7 +221,7 @@ public: const GrGeometryProcessor* setGeometryProcessor(const GrGeometryProcessor* geometryProcessor) { SkASSERT(geometryProcessor); SkASSERT(!this->hasGeometryProcessor()); - fGeometryProcessor.reset(SkRef(geometryProcessor)); + fGeometryProcessor.reset(new GrGeometryStage(geometryProcessor)); this->invalidateOptState(); return geometryProcessor; } @@ -254,7 +254,7 @@ public: } bool hasGeometryProcessor() const { return SkToBool(fGeometryProcessor.get()); } - const GrGeometryProcessor* getGeometryProcessor() const { return fGeometryProcessor.get(); } + const GrGeometryStage* getGeometryProcessor() const { return fGeometryProcessor.get(); } const GrFragmentStage& getColorStage(int idx) const { return fColorStages[idx]; } const GrFragmentStage& getCoverageStage(int idx) const { return fCoverageStages[idx]; } @@ -485,7 +485,8 @@ public: GrDrawState* fDrawState; SkMatrix fViewMatrix; int fNumColorStages; - SkAutoSTArray<8, GrFragmentStage::SavedCoordChange> fSavedCoordChanges; + bool fHasGeometryProcessor; + SkAutoSTArray<8, GrProcessorStage::SavedCoordChange> fSavedCoordChanges; }; /// @} @@ -809,11 +810,10 @@ private: GrBlendCoeff fSrcBlend; GrBlendCoeff fDstBlend; - typedef SkSTArray<4, GrFragmentStage> FragmentStageArray; - typedef GrProgramElementRef<const GrGeometryProcessor> ProgramGeometryProcessor; - ProgramGeometryProcessor fGeometryProcessor; - FragmentStageArray fColorStages; - FragmentStageArray fCoverageStages; + typedef SkSTArray<4, GrFragmentStage> FragmentStageArray; + SkAutoTDelete<GrGeometryStage> fGeometryProcessor; + FragmentStageArray fColorStages; + FragmentStageArray fCoverageStages; uint32_t fHints; diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp index b144caf63e..7265f4d23a 100644 --- a/src/gpu/GrDrawTarget.cpp +++ b/src/gpu/GrDrawTarget.cpp @@ -391,7 +391,7 @@ bool GrDrawTarget::checkDraw(GrPrimitiveType type, int startVertex, SkASSERT(drawState.getRenderTarget()); if (drawState.hasGeometryProcessor()) { - const GrGeometryProcessor* gp = drawState.getGeometryProcessor(); + const GrGeometryProcessor* gp = drawState.getGeometryProcessor()->getProcessor(); int numTextures = gp->numTextures(); for (int t = 0; t < numTextures; ++t) { GrTexture* texture = gp->texture(t); diff --git a/src/gpu/GrOptDrawState.cpp b/src/gpu/GrOptDrawState.cpp index 7c8710f7d6..b3d90f7310 100644 --- a/src/gpu/GrOptDrawState.cpp +++ b/src/gpu/GrOptDrawState.cpp @@ -54,7 +54,7 @@ GrOptDrawState::GrOptDrawState(const GrDrawState& drawState, // Copy GeometryProcesssor from DS or ODS if (drawState.hasGeometryProcessor()) { - fGeometryProcessor.initAndRef(drawState.fGeometryProcessor); + fGeometryProcessor.reset(SkNEW_ARGS(GrGeometryStage, (*drawState.getGeometryProcessor()))); } else { fGeometryProcessor.reset(NULL); } @@ -305,8 +305,8 @@ void GrOptDrawState::getStageStats(const GrDrawState& ds, int firstColorStageIdx get_stage_stats(stage, &fReadsDst, &fReadsFragPosition); } if (ds.hasGeometryProcessor()) { - const GrGeometryProcessor& gp = *ds.getGeometryProcessor(); - fReadsFragPosition = fReadsFragPosition || gp.willReadFragmentPosition(); + const GrGeometryStage& stage = *ds.getGeometryProcessor(); + fReadsFragPosition = fReadsFragPosition || stage.getProcessor()->willReadFragmentPosition(); } } @@ -354,7 +354,9 @@ bool GrOptDrawState::isEqual(const GrOptDrawState& that) const { if (this->hasGeometryProcessor()) { if (!that.hasGeometryProcessor()) { return false; - } else if (!this->getGeometryProcessor()->isEqual(*that.getGeometryProcessor())) { + } else if (!GrProcessorStage::AreCompatible(*this->getGeometryProcessor(), + *that.getGeometryProcessor(), + explicitLocalCoords)) { return false; } } else if (that.hasGeometryProcessor()) { @@ -362,8 +364,8 @@ bool GrOptDrawState::isEqual(const GrOptDrawState& that) const { } for (int i = 0; i < this->numFragmentStages(); i++) { - if (!GrFragmentStage::AreCompatible(this->getFragmentStage(i), that.getFragmentStage(i), - explicitLocalCoords)) { + if (!GrProcessorStage::AreCompatible(this->getFragmentStage(i), that.getFragmentStage(i), + explicitLocalCoords)) { return false; } } diff --git a/src/gpu/GrOptDrawState.h b/src/gpu/GrOptDrawState.h index f47913a41a..1c439bbff1 100644 --- a/src/gpu/GrOptDrawState.h +++ b/src/gpu/GrOptDrawState.h @@ -127,7 +127,7 @@ public: } bool hasGeometryProcessor() const { return SkToBool(fGeometryProcessor.get()); } - const GrGeometryProcessor* getGeometryProcessor() const { return fGeometryProcessor.get(); } + const GrGeometryStage* getGeometryProcessor() const { return fGeometryProcessor.get(); } const GrFragmentStage& getColorStage(int idx) const { SkASSERT(idx < this->numColorStages()); return fFragmentStages[idx]; @@ -441,12 +441,11 @@ private: GrBlendCoeff fDstBlend; typedef SkSTArray<8, GrFragmentStage> FragmentStageArray; - typedef GrProgramElementRef<const GrGeometryProcessor> ProgramGeometryProcessor; - ProgramGeometryProcessor fGeometryProcessor; - FragmentStageArray fFragmentStages; + SkAutoTDelete<GrGeometryStage> fGeometryProcessor; + FragmentStageArray fFragmentStages; // This function is equivalent to the offset into fFragmentStages where coverage stages begin. - int fNumColorStages; + int fNumColorStages; // This is simply a different representation of info in fVertexAttribs and thus does // not need to be compared in op==. diff --git a/src/gpu/GrProcessor.cpp b/src/gpu/GrProcessor.cpp index 1732e3a27a..71dfaae912 100644 --- a/src/gpu/GrProcessor.cpp +++ b/src/gpu/GrProcessor.cpp @@ -103,6 +103,11 @@ const char* GrProcessor::name() const { return this->getFactory().name(); } +void GrProcessor::addCoordTransform(const GrCoordTransform* transform) { + fCoordTransforms.push_back(transform); + SkDEBUGCODE(transform->setInEffect();) +} + void GrProcessor::addTextureAccess(const GrTextureAccess* access) { fTextureAccesses.push_back(access); this->addGpuResource(access->getProgramTexture()); @@ -118,6 +123,10 @@ void GrProcessor::operator delete(void* target) { #ifdef SK_DEBUG void GrProcessor::assertEquality(const GrProcessor& other) const { + SkASSERT(this->numTransforms() == other.numTransforms()); + for (int i = 0; i < this->numTransforms(); ++i) { + SkASSERT(this->coordTransform(i) == other.coordTransform(i)); + } SkASSERT(this->numTextures() == other.numTextures()); for (int i = 0; i < this->numTextures(); ++i) { SkASSERT(this->textureAccess(i) == other.textureAccess(i)); @@ -164,11 +173,5 @@ bool GrProcessor::InvariantOutput::validPreMulColor() const { } return true; } -#endif // end DEBUG - -/////////////////////////////////////////////////////////////////////////////////////////////////// +#endif -void GrFragmentProcessor::addCoordTransform(const GrCoordTransform* transform) { - fCoordTransforms.push_back(transform); - SkDEBUGCODE(transform->setInEffect();) -} diff --git a/src/gpu/effects/GrConfigConversionEffect.h b/src/gpu/effects/GrConfigConversionEffect.h index 8c65dce506..aa2c87482e 100644 --- a/src/gpu/effects/GrConfigConversionEffect.h +++ b/src/gpu/effects/GrConfigConversionEffect.h @@ -10,7 +10,7 @@ #include "GrSingleTextureEffect.h" -class GrFragmentStage; +class GrProcessorStage; class GrGLConfigConversionEffect; /** diff --git a/src/gpu/gl/GrGLProcessor.h b/src/gpu/gl/GrGLProcessor.h index 04870779a3..5f698325fb 100644 --- a/src/gpu/gl/GrGLProcessor.h +++ b/src/gpu/gl/GrGLProcessor.h @@ -114,7 +114,6 @@ public: @param samplers Contains one entry for each GrTextureAccess of the GrProcessor. These can be passed to the builder to emit texture reads in the generated code. - TODO this should take a struct */ virtual void emitCode(GrGLFPBuilder* builder, const GrFragmentProcessor& effect, diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp index 2216fb1c5a..e0d4939323 100644 --- a/src/gpu/gl/GrGLProgram.cpp +++ b/src/gpu/gl/GrGLProgram.cpp @@ -10,7 +10,6 @@ #include "GrAllocator.h" #include "GrProcessor.h" #include "GrCoordTransform.h" -#include "GrGLGeometryProcessor.h" #include "GrGLProcessor.h" #include "GrGpuGL.h" #include "GrGLPathRendering.h" @@ -25,7 +24,7 @@ /** * Retrieves the final matrix that a transform needs to apply to its source coords. */ -static SkMatrix get_transform_matrix(const GrFragmentStage& processorStage, +static SkMatrix get_transform_matrix(const GrProcessorStage& processorStage, bool useExplicitLocalCoords, int transformIdx) { const GrCoordTransform& coordTransform = @@ -60,15 +59,17 @@ GrGLProgram::GrGLProgram(GrGpuGL* gpu, const BuiltinUniformHandles& builtinUniforms, GrGLuint programID, const UniformInfoArray& uniforms, - GrGLInstalledGeoProc* geometryProcessor, - GrGLInstalledFragProcs* fragmentProcessors) + GrGLInstalledProcessors* geometryProcessor, + GrGLInstalledProcessors* colorProcessors, + GrGLInstalledProcessors* coverageProcessors) : fColor(GrColor_ILLEGAL) , fCoverage(GrColor_ILLEGAL) , fDstCopyTexUnit(-1) , fBuiltinUniformHandles(builtinUniforms) , fProgramID(programID) - , fGeometryProcessor(geometryProcessor) - , fFragmentProcessors(SkRef(fragmentProcessors)) + , fGeometryProcessor(SkSafeRef(geometryProcessor)) + , fColorEffects(SkRef(colorProcessors)) + , fCoverageEffects(SkRef(coverageProcessors)) , fDesc(desc) , fGpu(gpu) , fProgramDataManager(gpu, uniforms) { @@ -95,24 +96,28 @@ void GrGLProgram::initSamplerUniforms() { if (fGeometryProcessor.get()) { this->initSamplers(fGeometryProcessor.get(), &texUnitIdx); } - int numProcs = fFragmentProcessors->fProcs.count(); - for (int i = 0; i < numProcs; i++) { - this->initSamplers(fFragmentProcessors->fProcs[i], &texUnitIdx); - } + this->initSamplers(fColorEffects.get(), &texUnitIdx); + this->initSamplers(fCoverageEffects.get(), &texUnitIdx); } -void GrGLProgram::initSamplers(GrGLInstalledProc* ip, int* texUnitIdx) { - SkTArray<GrGLInstalledProc::Sampler, true>& samplers = ip->fSamplers; - int numSamplers = samplers.count(); - for (int s = 0; s < numSamplers; ++s) { - SkASSERT(samplers[s].fUniform.isValid()); - fProgramDataManager.setSampler(samplers[s].fUniform, *texUnitIdx); - samplers[s].fTextureUnit = (*texUnitIdx)++; +void GrGLProgram::initSamplers(GrGLInstalledProcessors* ip, int* texUnitIdx) { + int numEffects = ip->fGLProcessors.count(); + SkASSERT(numEffects == ip->fSamplers.count()); + for (int e = 0; e < numEffects; ++e) { + SkTArray<GrGLInstalledProcessors::Sampler, true>& samplers = ip->fSamplers[e]; + int numSamplers = samplers.count(); + for (int s = 0; s < numSamplers; ++s) { + SkASSERT(samplers[s].fUniform.isValid()); + fProgramDataManager.setSampler(samplers[s].fUniform, *texUnitIdx); + samplers[s].fTextureUnit = (*texUnitIdx)++; + } } } -void GrGLProgram::bindTextures(const GrGLInstalledProc* ip, const GrProcessor& processor) { - const SkTArray<GrGLInstalledProc::Sampler, true>& samplers = ip->fSamplers; +void GrGLProgram::bindTextures(const GrGLInstalledProcessors* ip, + const GrProcessor& processor, + int effectIdx) { + const SkTArray<GrGLInstalledProcessors::Sampler, true>& samplers = ip->fSamplers[effectIdx]; int numSamplers = samplers.count(); SkASSERT(numSamplers == processor.numTextures()); for (int s = 0; s < numSamplers; ++s) { @@ -129,6 +134,9 @@ void GrGLProgram::bindTextures(const GrGLInstalledProc* ip, const GrProcessor& p void GrGLProgram::setData(const GrOptDrawState& optState, GrGpu::DrawType drawType, + const GrGeometryStage* geometryProcessor, + const GrFragmentStage* colorStages[], + const GrFragmentStage* coverageStages[], const GrDeviceCoordTexture* dstCopy, SharedGLState* sharedState) { GrColor color = optState.getColor(); @@ -162,34 +170,25 @@ void GrGLProgram::setData(const GrOptDrawState& optState, // we set the textures, and uniforms for installed processors in a generic way, but subclasses // of GLProgram determine how to set coord transforms if (fGeometryProcessor.get()) { - SkASSERT(optState.hasGeometryProcessor()); - const GrGeometryProcessor& gp = *optState.getGeometryProcessor(); - fGeometryProcessor->fGLProc->setData(fProgramDataManager, gp); - this->bindTextures(fGeometryProcessor, gp); + SkASSERT(geometryProcessor); + this->setData<GrGeometryStage>(&geometryProcessor, fGeometryProcessor.get()); } - this->setFragmentData(optState); + this->setData<GrFragmentStage>(colorStages, fColorEffects.get()); + this->setData<GrFragmentStage>(coverageStages, fCoverageEffects.get()); // Some of GrGLProgram subclasses need to update state here this->didSetData(drawType); } -void GrGLProgram::setFragmentData(const GrOptDrawState& optState) { - int numProcessors = fFragmentProcessors->fProcs.count(); - for (int e = 0; e < numProcessors; ++e) { - const GrFragmentStage& stage = optState.getFragmentStage(e); - const GrProcessor& processor = *stage.getProcessor(); - fFragmentProcessors->fProcs[e]->fGLProc->setData(fProgramDataManager, processor); - this->setTransformData(stage, fFragmentProcessors->fProcs[e]); - this->bindTextures(fFragmentProcessors->fProcs[e], processor); - } -} -void GrGLProgram::setTransformData(const GrFragmentStage& processor, GrGLInstalledFragProc* ip) { - SkTArray<GrGLInstalledFragProc::Transform, true>& transforms = ip->fTransforms; +void GrGLProgram::setTransformData(const GrProcessorStage& processor, + int effectIdx, + GrGLInstalledProcessors* ip) { + SkTArray<GrGLInstalledProcessors::Transform, true>& transforms = ip->fTransforms[effectIdx]; int numTransforms = transforms.count(); SkASSERT(numTransforms == processor.getProcessor()->numTransforms()); for (int t = 0; t < numTransforms; ++t) { SkASSERT(transforms[t].fHandle.isValid()); - const SkMatrix& matrix = get_transform_matrix(processor, ip->fLocalCoordAttrib, t); + const SkMatrix& matrix = get_transform_matrix(processor, ip->fHasExplicitLocalCoords, t); if (!transforms[t].fCurrentValue.cheapEqualTo(matrix)) { fProgramDataManager.setSkMatrix(transforms[t].fHandle.convertToUniformHandle(), matrix); transforms[t].fCurrentValue = matrix; @@ -322,8 +321,10 @@ GrGLNvprProgramBase::GrGLNvprProgramBase(GrGpuGL* gpu, const BuiltinUniformHandles& builtinUniforms, GrGLuint programID, const UniformInfoArray& uniforms, - GrGLInstalledFragProcs* fragmentProcessors) - : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, NULL, fragmentProcessors) { + GrGLInstalledProcessors* colorProcessors, + GrGLInstalledProcessors* coverageProcessors) + : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, NULL, colorProcessors, + coverageProcessors) { } void GrGLNvprProgramBase::onSetMatrixAndRenderTargetHeight(GrGpu::DrawType drawType, @@ -342,9 +343,11 @@ GrGLNvprProgram::GrGLNvprProgram(GrGpuGL* gpu, const BuiltinUniformHandles& builtinUniforms, GrGLuint programID, const UniformInfoArray& uniforms, - GrGLInstalledFragProcs* fragmentProcessors, + GrGLInstalledProcessors* colorProcessors, + GrGLInstalledProcessors* coverageProcessors, const SeparableVaryingInfoArray& separableVaryings) - : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, fragmentProcessors) { + : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, colorProcessors, + coverageProcessors) { int count = separableVaryings.count(); fVaryings.push_back_n(count); for (int i = 0; i < count; i++) { @@ -362,13 +365,15 @@ void GrGLNvprProgram::didSetData(GrGpu::DrawType drawType) { SkASSERT(GrGpu::IsPathRenderingDrawType(drawType)); } -void GrGLNvprProgram::setTransformData(const GrFragmentStage& proc, GrGLInstalledFragProc* ip) { - SkTArray<GrGLInstalledFragProc::Transform, true>& transforms = ip->fTransforms; +void GrGLNvprProgram::setTransformData(const GrProcessorStage& processor, + int effectIdx, + GrGLInstalledProcessors* ip) { + SkTArray<GrGLInstalledProcessors::Transform, true>& transforms = ip->fTransforms[effectIdx]; int numTransforms = transforms.count(); - SkASSERT(numTransforms == proc.getProcessor()->numTransforms()); + SkASSERT(numTransforms == processor.getProcessor()->numTransforms()); for (int t = 0; t < numTransforms; ++t) { SkASSERT(transforms[t].fHandle.isValid()); - const SkMatrix& transform = get_transform_matrix(proc, ip->fLocalCoordAttrib, t); + const SkMatrix& transform = get_transform_matrix(processor, ip->fHasExplicitLocalCoords, t); if (transforms[t].fCurrentValue.cheapEqualTo(transform)) { continue; } @@ -387,13 +392,15 @@ void GrGLNvprProgram::setTransformData(const GrFragmentStage& proc, GrGLInstalle ////////////////////////////////////////////////////////////////////////////////////// GrGLLegacyNvprProgram::GrGLLegacyNvprProgram(GrGpuGL* gpu, - const GrGLProgramDesc& desc, - const BuiltinUniformHandles& builtinUniforms, - GrGLuint programID, - const UniformInfoArray& uniforms, - GrGLInstalledFragProcs* fps, - int texCoordSetCnt) - : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, fps) + const GrGLProgramDesc& desc, + const BuiltinUniformHandles& builtinUniforms, + GrGLuint programID, + const UniformInfoArray& uniforms, + GrGLInstalledProcessors* colorProcessors, + GrGLInstalledProcessors* coverageProcessors, + int texCoordSetCnt) + : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, colorProcessors, + coverageProcessors) , fTexCoordSetCnt(texCoordSetCnt) { } @@ -402,16 +409,17 @@ void GrGLLegacyNvprProgram::didSetData(GrGpu::DrawType drawType) { fGpu->glPathRendering()->flushPathTexGenSettings(fTexCoordSetCnt); } -void -GrGLLegacyNvprProgram::setTransformData(const GrFragmentStage& proc, GrGLInstalledFragProc* ip) { +void GrGLLegacyNvprProgram::setTransformData(const GrProcessorStage& processorStage, + int effectIdx, + GrGLInstalledProcessors* ip) { // We've hidden the texcoord index in the first entry of the transforms array for each effect - int texCoordIndex = ip->fTransforms[0].fHandle.handle(); - int numTransforms = proc.getProcessor()->numTransforms(); + int texCoordIndex = ip->fTransforms[effectIdx][0].fHandle.handle(); + int numTransforms = processorStage.getProcessor()->numTransforms(); for (int t = 0; t < numTransforms; ++t) { - const SkMatrix& transform = get_transform_matrix(proc, false, t); + const SkMatrix& transform = get_transform_matrix(processorStage, false, t); GrGLPathRendering::PathTexGenComponents components = GrGLPathRendering::kST_PathTexGenComponents; - if (proc.isPerspectiveCoordTransform(t, false)) { + if (processorStage.isPerspectiveCoordTransform(t, false)) { components = GrGLPathRendering::kSTR_PathTexGenComponents; } fGpu->glPathRendering()->enablePathTexGen(texCoordIndex++, components, transform); diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h index e8aef35f1d..fc441e5d76 100644 --- a/src/gpu/gl/GrGLProgram.h +++ b/src/gpu/gl/GrGLProgram.h @@ -152,6 +152,9 @@ public: */ void setData(const GrOptDrawState&, GrGpu::DrawType, + const GrGeometryStage* geometryProcessor, + const GrFragmentStage* colorStages[], + const GrFragmentStage* coverageStages[], const GrDeviceCoordTexture* dstCopy, // can be NULL SharedGLState*); @@ -164,12 +167,13 @@ protected: const BuiltinUniformHandles&, GrGLuint programID, const UniformInfoArray&, - GrGLInstalledGeoProc* geometryProcessor, - GrGLInstalledFragProcs* fragmentProcessors); + GrGLInstalledProcessors* geometryProcessor, + GrGLInstalledProcessors* colorProcessors, + GrGLInstalledProcessors* coverageProcessors); // Sets the texture units for samplers. void initSamplerUniforms(); - void initSamplers(GrGLInstalledProc*, int* texUnitIdx); + void initSamplers(GrGLInstalledProcessors* processors, int* texUnitIdx); // Helper for setData(). Makes GL calls to specify the initial color when there is not // per-vertex colors. @@ -180,9 +184,23 @@ protected: void setCoverage(const GrOptDrawState&, GrColor coverage, SharedGLState*); // A templated helper to loop over effects, set the transforms(via subclass) and bind textures - void setFragmentData(const GrOptDrawState&); - virtual void setTransformData(const GrFragmentStage& effectStage, GrGLInstalledFragProc* pe); - void bindTextures(const GrGLInstalledProc*, const GrProcessor&); + template <class ProcessorStage> + void setData(const ProcessorStage* effectStages[], + GrGLInstalledProcessors* installedProcessors) { + int numEffects = installedProcessors->fGLProcessors.count(); + SkASSERT(numEffects == installedProcessors->fTransforms.count()); + SkASSERT(numEffects == installedProcessors->fSamplers.count()); + for (int e = 0; e < numEffects; ++e) { + const GrProcessor& effect = *effectStages[e]->getProcessor(); + installedProcessors->fGLProcessors[e]->setData(fProgramDataManager, effect); + this->setTransformData(*effectStages[e], e, installedProcessors); + this->bindTextures(installedProcessors, effect, e); + } + } + virtual void setTransformData(const GrProcessorStage& effectStage, + int effectIdx, + GrGLInstalledProcessors* pe); + void bindTextures(const GrGLInstalledProcessors*, const GrProcessor&, int effectIdx); /* * Legacy NVPR needs a hook here to flush path tex gen settings. @@ -203,8 +221,9 @@ protected: GrGLuint fProgramID; // the installed effects - SkAutoTDelete<GrGLInstalledGeoProc> fGeometryProcessor; - SkAutoTUnref<GrGLInstalledFragProcs> fFragmentProcessors; + SkAutoTUnref<GrGLInstalledProcessors> fGeometryProcessor; + SkAutoTUnref<GrGLInstalledProcessors> fColorEffects; + SkAutoTUnref<GrGLInstalledProcessors> fCoverageEffects; GrGLProgramDesc fDesc; GrGpuGL* fGpu; @@ -229,7 +248,8 @@ protected: const BuiltinUniformHandles&, GrGLuint programID, const UniformInfoArray&, - GrGLInstalledFragProcs* fragmentProcessors); + GrGLInstalledProcessors* colorProcessors, + GrGLInstalledProcessors* coverageProcessors); virtual void onSetMatrixAndRenderTargetHeight(GrGpu::DrawType, const GrOptDrawState&); typedef GrGLProgram INHERITED; @@ -247,10 +267,13 @@ private: const BuiltinUniformHandles&, GrGLuint programID, const UniformInfoArray&, - GrGLInstalledFragProcs* fragmentProcessors, + GrGLInstalledProcessors* colorProcessors, + GrGLInstalledProcessors* coverageProcessors, const SeparableVaryingInfoArray& separableVaryings); virtual void didSetData(GrGpu::DrawType) SK_OVERRIDE; - virtual void setTransformData(const GrFragmentStage&, GrGLInstalledFragProc*) SK_OVERRIDE; + virtual void setTransformData(const GrProcessorStage&, + int effectIdx, + GrGLInstalledProcessors*) SK_OVERRIDE; struct Varying { GrGLint fLocation; @@ -275,10 +298,13 @@ private: const BuiltinUniformHandles&, GrGLuint programID, const UniformInfoArray&, - GrGLInstalledFragProcs* fragmentProcessors, + GrGLInstalledProcessors* colorProcessors, + GrGLInstalledProcessors* coverageProcessors, int texCoordSetCnt); virtual void didSetData(GrGpu::DrawType) SK_OVERRIDE; - virtual void setTransformData(const GrFragmentStage&, GrGLInstalledFragProc*) SK_OVERRIDE; + virtual void setTransformData(const GrProcessorStage&, + int effectIdx, + GrGLInstalledProcessors*) SK_OVERRIDE; int fTexCoordSetCnt; diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp index 224411e51c..0c85c99a8a 100644 --- a/src/gpu/gl/GrGLProgramDesc.cpp +++ b/src/gpu/gl/GrGLProgramDesc.cpp @@ -60,10 +60,10 @@ static bool swizzle_requires_alpha_remapping(const GrGLCaps& caps, return false; } -static uint32_t gen_attrib_key(const GrGeometryProcessor& proc) { +static uint32_t gen_attrib_key(const GrGeometryProcessor* effect) { uint32_t key = 0; - const GrGeometryProcessor::VertexAttribArray& vars = proc.getVertexAttribs(); + const GrGeometryProcessor::VertexAttribArray& vars = effect->getVertexAttribs(); int numAttributes = vars.count(); SkASSERT(numAttributes <= 2); for (int a = 0; a < numAttributes; ++a) { @@ -73,7 +73,7 @@ static uint32_t gen_attrib_key(const GrGeometryProcessor& proc) { return key; } -static uint32_t gen_transform_key(const GrFragmentStage& effectStage, +static uint32_t gen_transform_key(const GrProcessorStage& effectStage, bool useExplicitLocalCoords) { uint32_t totalKey = 0; int numTransforms = effectStage.getProcessor()->numTransforms(); @@ -96,11 +96,11 @@ static uint32_t gen_transform_key(const GrFragmentStage& effectStage, return totalKey; } -static uint32_t gen_texture_key(const GrProcessor& proc, const GrGLCaps& caps) { +static uint32_t gen_texture_key(const GrProcessor* effect, const GrGLCaps& caps) { uint32_t key = 0; - int numTextures = proc.numTextures(); + int numTextures = effect->numTextures(); for (int t = 0; t < numTextures; ++t) { - const GrTextureAccess& access = proc.textureAccess(t); + const GrTextureAccess& access = effect->textureAccess(t); uint32_t configComponentMask = GrPixelConfigComponentMask(access.getTexture()->config()); if (swizzle_requires_alpha_remapping(caps, configComponentMask, access.swizzleMask())) { key |= 1 << t; @@ -115,61 +115,101 @@ static uint32_t gen_texture_key(const GrProcessor& proc, const GrGLCaps& caps) { * in its key (e.g. the pixel format of textures used). So we create a meta-key for * every effect using this function. It is also responsible for inserting the effect's class ID * which must be different for every GrProcessor subclass. It can fail if an effect uses too many - * textures, transforms, etc, for the space allotted in the meta-key. NOTE, both FPs and GPs share - * this function because it is hairy, though FPs do not have attribs, and GPs do not have transforms + * textures, transforms, etc, for the space allotted in the meta-key. */ -static bool get_meta_key(const GrProcessor& proc, - const GrGLCaps& caps, - uint32_t transformKey, - uint32_t attribKey, - GrProcessorKeyBuilder* b, - uint16_t* processorKeySize) { - const GrBackendProcessorFactory& factory = proc.getFactory(); - factory.getGLProcessorKey(proc, caps, b); + +static uint32_t* get_processor_meta_key(const GrProcessorStage& processorStage, + bool useExplicitLocalCoords, + const GrGLCaps& caps, + GrProcessorKeyBuilder* b) { + + uint32_t textureKey = gen_texture_key(processorStage.getProcessor(), caps); + uint32_t transformKey = gen_transform_key(processorStage,useExplicitLocalCoords); + uint32_t classID = processorStage.getProcessor()->getFactory().effectClassID(); + + // Currently we allow 16 bits for each of the above portions of the meta-key. Fail if they + // don't fit. + static const uint32_t kMetaKeyInvalidMask = ~((uint32_t) SK_MaxU16); + if ((textureKey | transformKey | classID) & kMetaKeyInvalidMask) { + return NULL; + } + + uint32_t* key = b->add32n(2); + key[0] = (textureKey << 16 | transformKey); + key[1] = (classID << 16); + return key; +} + +static bool get_fp_key(const GrProcessorStage& stage, + const GrGLCaps& caps, + bool useExplicitLocalCoords, + GrProcessorKeyBuilder* b, + uint16_t* processorKeySize) { + const GrProcessor& effect = *stage.getProcessor(); + const GrBackendProcessorFactory& factory = effect.getFactory(); + factory.getGLProcessorKey(effect, caps, b); + size_t size = b->size(); + if (size > SK_MaxU16) { + *processorKeySize = 0; // suppresses a warning. + return false; + } + *processorKeySize = SkToU16(size); + if (NULL == get_processor_meta_key(stage, useExplicitLocalCoords, caps, b)) { + return false; + } + return true; +} + +static bool get_gp_key(const GrGeometryStage& stage, + const GrGLCaps& caps, + bool useExplicitLocalCoords, + GrProcessorKeyBuilder* b, + uint16_t* processorKeySize) { + const GrProcessor& effect = *stage.getProcessor(); + const GrBackendProcessorFactory& factory = effect.getFactory(); + factory.getGLProcessorKey(effect, caps, b); size_t size = b->size(); if (size > SK_MaxU16) { *processorKeySize = 0; // suppresses a warning. return false; } *processorKeySize = SkToU16(size); - uint32_t textureKey = gen_texture_key(proc, caps); - uint32_t classID = proc.getFactory().effectClassID(); + uint32_t* key = get_processor_meta_key(stage, useExplicitLocalCoords, caps, b); + if (NULL == key) { + return false; + } + uint32_t attribKey = gen_attrib_key(stage.getProcessor()); // Currently we allow 16 bits for each of the above portions of the meta-key. Fail if they // don't fit. static const uint32_t kMetaKeyInvalidMask = ~((uint32_t) SK_MaxU16); - if ((textureKey | transformKey | classID) & kMetaKeyInvalidMask) { - return false; + if ((attribKey) & kMetaKeyInvalidMask) { + return false; } - uint32_t* key = b->add32n(2); - key[0] = (textureKey << 16 | transformKey); - key[1] = (classID << 16); + key[1] |= attribKey; return true; } struct GeometryProcessorKeyBuilder { - typedef GrGeometryProcessor StagedProcessor; - static bool GetProcessorKey(const GrGeometryProcessor& gp, + typedef GrGeometryStage StagedProcessor; + static bool GetProcessorKey(const GrGeometryStage& gpStage, const GrGLCaps& caps, - bool, + bool requiresLocalCoordAttrib, GrProcessorKeyBuilder* b, - uint16_t* keySize) { - /* 0 because no transforms on a GP */ - return get_meta_key(gp, caps, 0, gen_attrib_key(gp), b, keySize); + uint16_t* processorKeySize) { + return get_gp_key(gpStage, caps, requiresLocalCoordAttrib, b, processorKeySize); } }; struct FragmentProcessorKeyBuilder { typedef GrFragmentStage StagedProcessor; - static bool GetProcessorKey(const GrFragmentStage& fps, + static bool GetProcessorKey(const GrFragmentStage& fpStage, const GrGLCaps& caps, - bool useLocalCoords, + bool requiresLocalCoordAttrib, GrProcessorKeyBuilder* b, - uint16_t* keySize) { - /* 0 because no attribs on a fP */ - return get_meta_key(*fps.getProcessor(), caps, gen_transform_key(fps, useLocalCoords), 0, - b, keySize); + uint16_t* processorKeySize) { + return get_fp_key(fpStage, caps, requiresLocalCoordAttrib, b, processorKeySize); } }; @@ -202,9 +242,17 @@ GrGLProgramDesc::BuildStagedProcessorKey(const typename ProcessorKeyBuilder::Sta bool GrGLProgramDesc::Build(const GrOptDrawState& optState, GrGpu::DrawType drawType, + GrBlendCoeff srcCoeff, + GrBlendCoeff dstCoeff, GrGpuGL* gpu, const GrDeviceCoordTexture* dstCopy, + const GrGeometryStage** geometryProcessor, + SkTArray<const GrFragmentStage*, true>* colorStages, + SkTArray<const GrFragmentStage*, true>* coverageStages, GrGLProgramDesc* desc) { + colorStages->reset(); + coverageStages->reset(); + bool inputColorIsUsed = optState.inputColorIsUsed(); bool inputCoverageIsUsed = optState.inputCoverageIsUsed(); @@ -226,17 +274,29 @@ bool GrGLProgramDesc::Build(const GrOptDrawState& optState, // We can only have one effect which touches the vertex shader if (optState.hasGeometryProcessor()) { - if (!BuildStagedProcessorKey<GeometryProcessorKeyBuilder>(*optState.getGeometryProcessor(), + const GrGeometryStage& gpStage = *optState.getGeometryProcessor(); + if (!BuildStagedProcessorKey<GeometryProcessorKeyBuilder>(gpStage, gpu->glCaps(), - false, + requiresLocalCoordAttrib, desc, &offsetAndSizeIndex)) { return false; } + *geometryProcessor = &gpStage; } - for (int s = 0; s < optState.numFragmentStages(); ++s) { - if (!BuildStagedProcessorKey<FragmentProcessorKeyBuilder>(optState.getFragmentStage(s), + for (int s = 0; s < optState.numColorStages(); ++s) { + if (!BuildStagedProcessorKey<FragmentProcessorKeyBuilder>(optState.getColorStage(s), + gpu->glCaps(), + requiresLocalCoordAttrib, + desc, + &offsetAndSizeIndex)) { + return false; + } + } + + for (int s = 0; s < optState.numCoverageStages(); ++s) { + if (!BuildStagedProcessorKey<FragmentProcessorKeyBuilder>(optState.getCoverageStage(s), gpu->glCaps(), requiresLocalCoordAttrib, desc, @@ -339,8 +399,15 @@ bool GrGLProgramDesc::Build(const GrOptDrawState& optState, header->fPrimaryOutputType = optState.getPrimaryOutputType(); header->fSecondaryOutputType = optState.getSecondaryOutputType(); - header->fColorEffectCnt = optState.numColorStages(); - header->fCoverageEffectCnt = optState.numCoverageStages(); + for (int s = 0; s < optState.numColorStages(); ++s) { + colorStages->push_back(&optState.getColorStage(s)); + } + for (int s = 0; s < optState.numCoverageStages(); ++s) { + coverageStages->push_back(&optState.getCoverageStage(s)); + } + + header->fColorEffectCnt = colorStages->count(); + header->fCoverageEffectCnt = coverageStages->count(); desc->finalize(); return true; } diff --git a/src/gpu/gl/GrGLProgramDesc.h b/src/gpu/gl/GrGLProgramDesc.h index 4e1be5b2f9..9bf7553b61 100644 --- a/src/gpu/gl/GrGLProgramDesc.h +++ b/src/gpu/gl/GrGLProgramDesc.h @@ -43,8 +43,13 @@ public: */ static bool Build(const GrOptDrawState&, GrGpu::DrawType, + GrBlendCoeff srcCoeff, + GrBlendCoeff dstCoeff, GrGpuGL*, - const GrDeviceCoordTexture*, + const GrDeviceCoordTexture* dstCopy, + const GrGeometryStage** geometryProcessor, + SkTArray<const GrFragmentStage*, true>* colorStages, + SkTArray<const GrFragmentStage*, true>* coverageStages, GrGLProgramDesc*); bool hasGeometryProcessor() const { @@ -155,23 +160,26 @@ private: const KeyHeader& getHeader() const { return *this->atOffset<KeyHeader, kHeaderOffset>(); } /** Used to provide effects' keys to their emitCode() function. */ - class ProcKeyProvider { + class EffectKeyProvider { public: - enum ProcessorType { - kGeometry_ProcessorType, - kFragment_ProcessorType, + enum EffectType { + kGeometryProcessor_EffectType, + kColor_EffectType, + kCoverage_EffectType, }; - ProcKeyProvider(const GrGLProgramDesc* desc, ProcessorType type) - : fDesc(desc), fBaseIndex(0) { + EffectKeyProvider(const GrGLProgramDesc* desc, EffectType type) : fDesc(desc) { switch (type) { - case kGeometry_ProcessorType: + case kGeometryProcessor_EffectType: // there can be only one fBaseIndex = 0; break; - case kFragment_ProcessorType: + case kColor_EffectType: fBaseIndex = desc->hasGeometryProcessor() ? 1 : 0; break; + case kCoverage_EffectType: + fBaseIndex = desc->numColorEffects() + (desc->hasGeometryProcessor() ? 1 : 0); + break; } } diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h index 24ab4ec14d..056f0935ec 100644 --- a/src/gpu/gl/GrGpuGL.h +++ b/src/gpu/gl/GrGpuGL.h @@ -181,7 +181,10 @@ private: void abandon(); GrGLProgram* getProgram(const GrOptDrawState&, const GrGLProgramDesc&, - DrawType); + DrawType, + const GrGeometryStage* geometryProcessor, + const GrFragmentStage* colorStages[], + const GrFragmentStage* coverageStages[]); private: enum { diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp index 6a09ebf64e..7dba5316a4 100644 --- a/src/gpu/gl/GrGpuGL_program.cpp +++ b/src/gpu/gl/GrGpuGL_program.cpp @@ -93,7 +93,10 @@ int GrGpuGL::ProgramCache::search(const GrGLProgramDesc& desc) const { GrGLProgram* GrGpuGL::ProgramCache::getProgram(const GrOptDrawState& optState, const GrGLProgramDesc& desc, - DrawType type) { + DrawType type, + const GrGeometryStage* geometryProcessor, + const GrFragmentStage* colorStages[], + const GrFragmentStage* coverageStages[]) { #ifdef PROGRAM_CACHE_STATS ++fTotalRequests; #endif @@ -128,7 +131,9 @@ GrGLProgram* GrGpuGL::ProgramCache::getProgram(const GrOptDrawState& optState, #ifdef PROGRAM_CACHE_STATS ++fCacheMisses; #endif - GrGLProgram* program = GrGLProgramBuilder::CreateProgram(optState, desc, type, fGpu); + GrGLProgram* program = GrGLProgramBuilder::CreateProgram(optState, desc, type, + geometryProcessor, colorStages, + coverageStages, fGpu); if (NULL == program) { return NULL; } @@ -232,13 +237,30 @@ bool GrGpuGL::flushGraphicsState(DrawType type, const GrDeviceCoordTexture* dstC return false; } + const GrGeometryStage* geometryProcessor = NULL; + SkSTArray<8, const GrFragmentStage*, true> colorStages; + SkSTArray<8, const GrFragmentStage*, true> coverageStages; GrGLProgramDesc desc; - if (!GrGLProgramDesc::Build(*optState.get(), type, this, dstCopy, &desc)) { + if (!GrGLProgramDesc::Build(*optState.get(), + type, + srcCoeff, + dstCoeff, + this, + dstCopy, + &geometryProcessor, + &colorStages, + &coverageStages, + &desc)) { SkDEBUGFAIL("Failed to generate GL program descriptor"); return false; } - fCurrentProgram.reset(fProgramCache->getProgram(*optState.get(), desc, type)); + fCurrentProgram.reset(fProgramCache->getProgram(*optState.get(), + desc, + type, + geometryProcessor, + colorStages.begin(), + coverageStages.begin())); if (NULL == fCurrentProgram.get()) { SkDEBUGFAIL("Failed to create program!"); return false; @@ -254,7 +276,13 @@ bool GrGpuGL::flushGraphicsState(DrawType type, const GrDeviceCoordTexture* dstC this->flushBlend(*optState.get(), kDrawLines_DrawType == type, srcCoeff, dstCoeff); - fCurrentProgram->setData(*optState.get(), type, dstCopy, &fSharedGLProgramState); + fCurrentProgram->setData(*optState.get(), + type, + geometryProcessor, + colorStages.begin(), + coverageStages.begin(), + dstCopy, + &fSharedGLProgramState); } GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(optState->getRenderTarget()); diff --git a/src/gpu/gl/builders/GrGLLegacyNvprProgramBuilder.cpp b/src/gpu/gl/builders/GrGLLegacyNvprProgramBuilder.cpp index 1c1cb42122..acb4af10be 100644 --- a/src/gpu/gl/builders/GrGLLegacyNvprProgramBuilder.cpp +++ b/src/gpu/gl/builders/GrGLLegacyNvprProgramBuilder.cpp @@ -24,17 +24,20 @@ int GrGLLegacyNvprProgramBuilder::addTexCoordSets(int count) { return firstFreeCoordSet; } -void GrGLLegacyNvprProgramBuilder::emitTransforms(const GrFragmentStage& processorStage, +void GrGLLegacyNvprProgramBuilder::emitTransforms(const GrProcessorStage& processorStage, GrGLProcessor::TransformedCoordsArray* outCoords, - GrGLInstalledFragProc* ifp) { + GrGLInstalledProcessors* installedProcessors) { int numTransforms = processorStage.getProcessor()->numTransforms(); int texCoordIndex = this->addTexCoordSets(numTransforms); + SkTArray<GrGLInstalledProcessors::Transform, true>& transforms = + installedProcessors->addTransforms(); + // Use the first uniform location as the texcoord index. This may seem a bit hacky but it // allows us to use one program effects object for all of our programs which really simplifies // the code overall - ifp->fTransforms.push_back_n(1); - ifp->fTransforms[0].fHandle = GrGLInstalledFragProc::ShaderVarHandle(texCoordIndex); + transforms.push_back_n(1); + transforms[0].fHandle = GrGLInstalledProcessors::ShaderVarHandle(texCoordIndex); SkString name; for (int t = 0; t < numTransforms; ++t) { @@ -48,5 +51,5 @@ void GrGLLegacyNvprProgramBuilder::emitTransforms(const GrFragmentStage& process GrGLProgram* GrGLLegacyNvprProgramBuilder::createProgram(GrGLuint programID) { return SkNEW_ARGS(GrGLLegacyNvprProgram, (fGpu, fDesc, fUniformHandles, programID, fUniforms, - fFragmentProcessors.get(), fTexCoordSetCnt)); + fColorEffects, fCoverageEffects, fTexCoordSetCnt)); } diff --git a/src/gpu/gl/builders/GrGLLegacyNvprProgramBuilder.h b/src/gpu/gl/builders/GrGLLegacyNvprProgramBuilder.h index dabec081b4..496fbd8726 100644 --- a/src/gpu/gl/builders/GrGLLegacyNvprProgramBuilder.h +++ b/src/gpu/gl/builders/GrGLLegacyNvprProgramBuilder.h @@ -18,9 +18,9 @@ public: private: int addTexCoordSets(int count); - void emitTransforms(const GrFragmentStage&, + void emitTransforms(const GrProcessorStage&, GrGLProcessor::TransformedCoordsArray* outCoords, - GrGLInstalledFragProc*); + GrGLInstalledProcessors*); int fTexCoordSetCnt; diff --git a/src/gpu/gl/builders/GrGLNvprProgramBuilder.cpp b/src/gpu/gl/builders/GrGLNvprProgramBuilder.cpp index a20b0d6b0d..e5eae9d884 100644 --- a/src/gpu/gl/builders/GrGLNvprProgramBuilder.cpp +++ b/src/gpu/gl/builders/GrGLNvprProgramBuilder.cpp @@ -18,13 +18,15 @@ GrGLNvprProgramBuilder::GrGLNvprProgramBuilder(GrGpuGL* gpu, , fSeparableVaryingInfos(kVarsPerBlock) { } -void GrGLNvprProgramBuilder::emitTransforms(const GrFragmentStage& processorStage, +void GrGLNvprProgramBuilder::emitTransforms(const GrProcessorStage& processorStage, GrGLProcessor::TransformedCoordsArray* outCoords, - GrGLInstalledFragProc* ifp) { - const GrFragmentProcessor* effect = processorStage.getProcessor(); + GrGLInstalledProcessors* installedProcessors) { + const GrProcessor* effect = processorStage.getProcessor(); int numTransforms = effect->numTransforms(); - ifp->fTransforms.push_back_n(numTransforms); + SkTArray<GrGLInstalledProcessors::Transform, true>& transforms = + installedProcessors->addTransforms(); + transforms.push_back_n(numTransforms); for (int t = 0; t < numTransforms; t++) { GrSLType varyingType = @@ -41,24 +43,24 @@ void GrGLNvprProgramBuilder::emitTransforms(const GrFragmentStage& processorStag } const char* vsVaryingName; const char* fsVaryingName; - ifp->fTransforms[t].fHandle = this->addSeparableVarying(varyingType, varyingName, - &vsVaryingName, &fsVaryingName); - ifp->fTransforms[t].fType = varyingType; + transforms[t].fHandle = this->addSeparableVarying(varyingType, varyingName, + &vsVaryingName, &fsVaryingName); + transforms[t].fType = varyingType; SkNEW_APPEND_TO_TARRAY(outCoords, GrGLProcessor::TransformedCoords, (SkString(fsVaryingName), varyingType)); } } -GrGLInstalledFragProc::ShaderVarHandle +GrGLInstalledProcessors::ShaderVarHandle GrGLNvprProgramBuilder::addSeparableVarying(GrSLType type, - const char* name, - const char** vsOutName, - const char** fsInName) { + const char* name, + const char** vsOutName, + const char** fsInName) { addVarying(type, name, vsOutName, fsInName); SeparableVaryingInfo& varying = fSeparableVaryingInfos.push_back(); varying.fVariable = fFS.fInputs.back(); - return GrGLInstalledFragProc::ShaderVarHandle(fSeparableVaryingInfos.count() - 1); + return GrGLInstalledProcessors::ShaderVarHandle(fSeparableVaryingInfos.count() - 1); } void GrGLNvprProgramBuilder::resolveSeparableVaryings(GrGLuint programId) { @@ -78,5 +80,5 @@ GrGLProgram* GrGLNvprProgramBuilder::createProgram(GrGLuint programID) { // building this->resolveSeparableVaryings(programID); return SkNEW_ARGS(GrGLNvprProgram, (fGpu, fDesc, fUniformHandles, programID, fUniforms, - fFragmentProcessors.get(), fSeparableVaryingInfos)); + fColorEffects, fCoverageEffects, fSeparableVaryingInfos)); } diff --git a/src/gpu/gl/builders/GrGLNvprProgramBuilder.h b/src/gpu/gl/builders/GrGLNvprProgramBuilder.h index 4bf7e02414..cb1337521d 100644 --- a/src/gpu/gl/builders/GrGLNvprProgramBuilder.h +++ b/src/gpu/gl/builders/GrGLNvprProgramBuilder.h @@ -28,11 +28,11 @@ public: virtual GrGLProgram* createProgram(GrGLuint programID); private: - virtual void emitTransforms(const GrFragmentStage&, + virtual void emitTransforms(const GrProcessorStage&, GrGLProcessor::TransformedCoordsArray* outCoords, - GrGLInstalledFragProc*) SK_OVERRIDE; + GrGLInstalledProcessors*) SK_OVERRIDE; - typedef GrGLInstalledFragProc::ShaderVarHandle ShaderVarHandle; + typedef GrGLInstalledProcessors::ShaderVarHandle ShaderVarHandle; /** * Add a separable varying input variable to the current program. diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp index 687c2fd4c9..fbf78d7634 100644 --- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp +++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp @@ -32,13 +32,16 @@ const int GrGLProgramBuilder::kVarsPerBlock = 8; GrGLProgram* GrGLProgramBuilder::CreateProgram(const GrOptDrawState& optState, const GrGLProgramDesc& desc, GrGpu::DrawType drawType, + const GrGeometryStage* geometryProcessor, + const GrFragmentStage* colorStages[], + const GrFragmentStage* coverageStages[], GrGpuGL* gpu) { // create a builder. This will be handed off to effects so they can use it to add // uniforms, varyings, textures, etc SkAutoTDelete<GrGLProgramBuilder> builder(CreateProgramBuilder(desc, optState, drawType, - optState.hasGeometryProcessor(), + SkToBool(geometryProcessor), gpu)); GrGLProgramBuilder* pb = builder.get(); @@ -71,7 +74,8 @@ GrGLProgram* GrGLProgramBuilder::CreateProgram(const GrOptDrawState& optState, } } - pb->emitAndInstallProcs(optState, &inputColor, &inputCoverage); + pb->createAndEmitProcessors(geometryProcessor, colorStages, coverageStages, &inputColor, + &inputCoverage); if (hasVertexShader) { pb->fVS.transformSkiaToGLCoords(); @@ -112,15 +116,13 @@ GrGLProgramBuilder::CreateProgramBuilder(const GrGLProgramDesc& desc, ///////////////////////////////////////////////////////////////////////////// -GrGLProgramBuilder::GrGLProgramBuilder(GrGpuGL* gpu, - const GrOptDrawState& optState, +GrGLProgramBuilder::GrGLProgramBuilder(GrGpuGL* gpu, const GrOptDrawState& optState, const GrGLProgramDesc& desc) : fVS(this) , fGS(this) , fFS(this, desc) , fOutOfStage(true) , fStageIndex(-1) - , fGeometryProcessor(NULL) , fOptState(optState) , fDesc(desc) , fGpu(gpu) @@ -223,106 +225,104 @@ void GrGLProgramBuilder::setupUniformColorAndCoverageIfNeeded(GrGLSLExpr4* input } } -void GrGLProgramBuilder::emitAndInstallProcs(const GrOptDrawState& optState, - GrGLSLExpr4* inputColor, - GrGLSLExpr4* inputCoverage) { - fFragmentProcessors.reset(SkNEW(GrGLInstalledFragProcs)); - int numProcs = optState.numFragmentStages(); - this->emitAndInstallFragProcs(0, optState.numColorStages(), inputColor); - if (optState.hasGeometryProcessor()) { - const GrGeometryProcessor& gp = *optState.getGeometryProcessor(); - fVS.emitAttributes(gp); - ProcKeyProvider keyProvider(&fDesc, ProcKeyProvider::kGeometry_ProcessorType); - GrGLSLExpr4 output; - this->emitAndInstallProc<GrGeometryProcessor>(gp, 0, keyProvider, *inputCoverage, &output); - *inputCoverage = output; +void GrGLProgramBuilder::createAndEmitProcessors(const GrGeometryStage* geometryProcessor, + const GrFragmentStage* colorStages[], + const GrFragmentStage* coverageStages[], + GrGLSLExpr4* inputColor, + GrGLSLExpr4* inputCoverage) { + bool useLocalCoords = fVS.hasExplicitLocalCoords(); + + EffectKeyProvider colorKeyProvider(&fDesc, EffectKeyProvider::kColor_EffectType); + int numColorEffects = fDesc.numColorEffects(); + GrGLInstalledProcessors* ip = SkNEW_ARGS(GrGLInstalledProcessors, (numColorEffects, + useLocalCoords)); + this->createAndEmitProcessors<GrFragmentStage>(colorStages, numColorEffects, colorKeyProvider, + inputColor, ip); + fColorEffects.reset(ip); + + if (geometryProcessor) { + fVS.emitAttributes(*geometryProcessor->getProcessor()); + EffectKeyProvider gpKeyProvider(&fDesc, EffectKeyProvider::kGeometryProcessor_EffectType); + ip = SkNEW_ARGS(GrGLInstalledProcessors, (1, useLocalCoords)); + this->createAndEmitProcessors<GrGeometryStage>(&geometryProcessor, 1, gpKeyProvider, + inputCoverage, ip); + fGeometryProcessor.reset(ip); } - this->emitAndInstallFragProcs(optState.numColorStages(), numProcs, inputCoverage); -} -void GrGLProgramBuilder::emitAndInstallFragProcs(int procOffset, int numProcs, GrGLSLExpr4* inOut) { - ProcKeyProvider keyProvider(&fDesc, ProcKeyProvider::kFragment_ProcessorType); - for (int e = procOffset; e < numProcs; ++e) { - GrGLSLExpr4 output; - const GrFragmentStage& stage = fOptState.getFragmentStage(e); - this->emitAndInstallProc<GrFragmentStage>(stage, e, keyProvider, *inOut, &output); - *inOut = output; - } + EffectKeyProvider coverageKeyProvider(&fDesc, EffectKeyProvider::kCoverage_EffectType); + int numCoverageEffects = fDesc.numCoverageEffects(); + ip = SkNEW_ARGS(GrGLInstalledProcessors, (numCoverageEffects, useLocalCoords)); + this->createAndEmitProcessors<GrFragmentStage>(coverageStages, numCoverageEffects, + coverageKeyProvider, inputCoverage, ip); + fCoverageEffects.reset(ip); } -// TODO Processors cannot output zeros because an empty string is all 1s -// the fix is to allow effects to take the GrGLSLExpr4 directly -template <class Proc> -void GrGLProgramBuilder::emitAndInstallProc(const Proc& proc, - int index, - const ProcKeyProvider keyProvider, - const GrGLSLExpr4& input, - GrGLSLExpr4* output) { - // Program builders have a bit of state we need to clear with each effect - AutoStageAdvance adv(this); - - // create var to hold stage result - SkString outColorName; - this->nameVariable(&outColorName, '\0', "output"); - fFS.codeAppendf("vec4 %s;", outColorName.c_str()); - *output = outColorName; - - // Enclose custom code in a block to avoid namespace conflicts - SkString openBrace; - openBrace.printf("{ // Stage %d\n", fStageIndex); - fFS.codeAppend(openBrace.c_str()); - - this->emitAndInstallProc(proc, keyProvider.get(index), output->c_str(), - input.isOnes() ? NULL : input.c_str()); - - fFS.codeAppend("}"); -} - -void GrGLProgramBuilder::emitAndInstallProc(const GrFragmentStage& fs, - const GrProcessorKey& key, - const char* outColor, - const char* inColor) { - GrGLInstalledFragProc* ifp = SkNEW_ARGS(GrGLInstalledFragProc, (fVS.hasLocalCoords())); - - const GrFragmentProcessor& fp = *fs.getProcessor(); - ifp->fGLProc = fp.getFactory().createGLInstance(fp); - - SkSTArray<4, GrGLProcessor::TextureSampler> samplers(fp.numTextures()); - this->emitSamplers(fp, &samplers, ifp); - - // Fragment processors can have coord transforms - SkSTArray<2, GrGLProcessor::TransformedCoords> coords(fp.numTransforms()); - this->emitTransforms(fs, &coords, ifp); - - ifp->fGLProc->emitCode(this, fp, key, outColor, inColor, coords, samplers); - - // We have to check that effects and the code they emit are consistent, ie if an effect - // asks for dst color, then the emit code needs to follow suit - verify(fp); - fFragmentProcessors->fProcs.push_back(ifp); -} - -void GrGLProgramBuilder::emitAndInstallProc(const GrGeometryProcessor& gp, - const GrProcessorKey& key, - const char* outColor, - const char* inColor) { - SkASSERT(!fGeometryProcessor); - fGeometryProcessor = SkNEW(GrGLInstalledGeoProc); - - fGeometryProcessor->fGLProc = gp.getFactory().createGLInstance(gp); - - SkSTArray<4, GrGLProcessor::TextureSampler> samplers(gp.numTextures()); - this->emitSamplers(gp, &samplers, fGeometryProcessor); - - SkSTArray<2, GrGLProcessor::TransformedCoords> coords; +template <class ProcessorStage> +void GrGLProgramBuilder::createAndEmitProcessors(const ProcessorStage* processStages[], + int effectCnt, + const EffectKeyProvider& keyProvider, + GrGLSLExpr4* fsInOutColor, + GrGLInstalledProcessors* installedProcessors) { + bool effectEmitted = false; + + GrGLSLExpr4 inColor = *fsInOutColor; + GrGLSLExpr4 outColor; + + for (int e = 0; e < effectCnt; ++e) { + // Program builders have a bit of state we need to clear with each effect + AutoStageAdvance adv(this); + const ProcessorStage& stage = *processStages[e]; + SkASSERT(stage.getProcessor()); + + if (inColor.isZeros()) { + SkString inColorName; + + // Effects have no way to communicate zeros, they treat an empty string as ones. + this->nameVariable(&inColorName, '\0', "input"); + fFS.codeAppendf("vec4 %s = %s;", inColorName.c_str(), inColor.c_str()); + inColor = inColorName; + } - // TODO remove coords from emit code signature, probably best to use a struct here so these - // updates are less painful - fGeometryProcessor->fGLProc->emitCode(this, gp, key, outColor, inColor, coords, samplers); + // create var to hold stage result + SkString outColorName; + this->nameVariable(&outColorName, '\0', "output"); + fFS.codeAppendf("vec4 %s;", outColorName.c_str()); + outColor = outColorName; + + SkASSERT(installedProcessors); + const typename ProcessorStage::Processor& processor = *stage.getProcessor(); + SkSTArray<2, GrGLProcessor::TransformedCoords> coords(processor.numTransforms()); + SkSTArray<4, GrGLProcessor::TextureSampler> samplers(processor.numTextures()); + + this->emitTransforms(stage, &coords, installedProcessors); + this->emitSamplers(processor, &samplers, installedProcessors); + + typename ProcessorStage::GLProcessor* glEffect = + processor.getFactory().createGLInstance(processor); + installedProcessors->addEffect(glEffect); + + // Enclose custom code in a block to avoid namespace conflicts + SkString openBrace; + openBrace.printf("{ // Stage %d: %s\n", fStageIndex, glEffect->name()); + fFS.codeAppend(openBrace.c_str()); + fVS.codeAppend(openBrace.c_str()); + + glEffect->emitCode(this, processor, keyProvider.get(e), outColor.c_str(), + inColor.isOnes() ? NULL : inColor.c_str(), coords, samplers); + + // We have to check that effects and the code they emit are consistent, ie if an effect + // asks for dst color, then the emit code needs to follow suit + verify(processor); + fFS.codeAppend("}"); + fVS.codeAppend("}"); + + inColor = outColor; + effectEmitted = true; + } - // We have to check that effects and the code they emit are consistent, ie if an effect - // asks for dst color, then the emit code needs to follow suit - verify(gp); + if (effectEmitted) { + *fsInOutColor = outColor; + } } void GrGLProgramBuilder::verify(const GrGeometryProcessor& gp) { @@ -334,17 +334,19 @@ void GrGLProgramBuilder::verify(const GrFragmentProcessor& fp) { SkASSERT(fFS.hasReadDstColor() == fp.willReadDstColor()); } -void GrGLProgramBuilder::emitTransforms(const GrFragmentStage& effectStage, +void GrGLProgramBuilder::emitTransforms(const GrProcessorStage& effectStage, GrGLProcessor::TransformedCoordsArray* outCoords, - GrGLInstalledFragProc* ifp) { - const GrFragmentProcessor* effect = effectStage.getProcessor(); + GrGLInstalledProcessors* installedProcessors) { + SkTArray<GrGLInstalledProcessors::Transform, true>& transforms = + installedProcessors->addTransforms(); + const GrProcessor* effect = effectStage.getProcessor(); int numTransforms = effect->numTransforms(); - ifp->fTransforms.push_back_n(numTransforms); + transforms.push_back_n(numTransforms); for (int t = 0; t < numTransforms; t++) { const char* uniName = "StageMatrix"; GrSLType varyingType = - effectStage.isPerspectiveCoordTransform(t, fVS.hasLocalCoords()) ? + effectStage.isPerspectiveCoordTransform(t, fVS.hasExplicitLocalCoords()) ? kVec3f_GrSLType : kVec2f_GrSLType; @@ -354,10 +356,10 @@ void GrGLProgramBuilder::emitTransforms(const GrFragmentStage& effectStage, suffixedUniName.appendf("_%i", t); uniName = suffixedUniName.c_str(); } - ifp->fTransforms[t].fHandle = this->addUniform(GrGLProgramBuilder::kVertex_Visibility, - kMat33f_GrSLType, - uniName, - &uniName).toShaderBuilderIndex(); + transforms[t].fHandle = this->addUniform(GrGLProgramBuilder::kVertex_Visibility, + kMat33f_GrSLType, + uniName, + &uniName).toShaderBuilderIndex(); const char* varyingName = "MatrixCoord"; SkString suffixedVaryingName; @@ -391,17 +393,18 @@ void GrGLProgramBuilder::emitTransforms(const GrFragmentStage& effectStage, void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor, GrGLProcessor::TextureSamplerArray* outSamplers, - GrGLInstalledProc* ip) { + GrGLInstalledProcessors* installedProcessors) { + SkTArray<GrGLInstalledProcessors::Sampler, true>& samplers = installedProcessors->addSamplers(); int numTextures = processor.numTextures(); - ip->fSamplers.push_back_n(numTextures); + samplers.push_back_n(numTextures); SkString name; for (int t = 0; t < numTextures; ++t) { name.printf("Sampler%d", t); - ip->fSamplers[t].fUniform = this->addUniform(GrGLProgramBuilder::kFragment_Visibility, - kSampler2D_GrSLType, - name.c_str()); + samplers[t].fUniform = this->addUniform(GrGLProgramBuilder::kFragment_Visibility, + kSampler2D_GrSLType, + name.c_str()); SkNEW_APPEND_TO_TARRAY(outSamplers, GrGLProcessor::TextureSampler, - (ip->fSamplers[t].fUniform, processor.textureAccess(t))); + (samplers[t].fUniform, processor.textureAccess(t))); } } @@ -503,14 +506,14 @@ void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs) { GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) { return SkNEW_ARGS(GrGLProgram, (fGpu, fDesc, fUniformHandles, programID, fUniforms, - fGeometryProcessor, fFragmentProcessors.get())); + fGeometryProcessor, fColorEffects, fCoverageEffects)); } -/////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// -GrGLInstalledFragProcs::~GrGLInstalledFragProcs() { - int numProcs = fProcs.count(); - for (int e = 0; e < numProcs; ++e) { - SkDELETE(fProcs[e]->fGLProc); +GrGLInstalledProcessors::~GrGLInstalledProcessors() { + int numEffects = fGLProcessors.count(); + for (int e = 0; e < numEffects; ++e) { + SkDELETE(fGLProcessors[e]); } } diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.h b/src/gpu/gl/builders/GrGLProgramBuilder.h index a8293545b2..6141058152 100644 --- a/src/gpu/gl/builders/GrGLProgramBuilder.h +++ b/src/gpu/gl/builders/GrGLProgramBuilder.h @@ -14,6 +14,8 @@ #include "../GrGLProgramDataManager.h" #include "../GrGLUniformHandle.h" +class GrGLInstalledProcessors; + /* * This is the base class for a series of interfaces. This base class *MUST* remain abstract with * NO data members because it is used in multiple interface inheritance. @@ -96,11 +98,6 @@ public: */ }; -struct GrGLInstalledProc; -struct GrGLInstalledGeoProc; -struct GrGLInstalledFragProc; -struct GrGLInstalledFragProcs; - /* * Please note - no diamond problems because of virtual inheritance. Also, both base classes * are pure virtual with no data members. This is the base class for program building. @@ -121,6 +118,9 @@ public: static GrGLProgram* CreateProgram(const GrOptDrawState&, const GrGLProgramDesc&, GrGpu::DrawType, + const GrGeometryStage* inGeometryProcessor, + const GrFragmentStage* inColorStages[], + const GrFragmentStage* inCoverageStages[], GrGpuGL* gpu); virtual UniformHandle addUniform(uint32_t visibility, @@ -150,12 +150,11 @@ public: virtual GrGLFPFragmentBuilder* getFragmentShaderBuilder() SK_OVERRIDE { return &fFS; } virtual GrGLVertexBuilder* getVertexShaderBuilder() SK_OVERRIDE { return &fVS; } - virtual void addVarying( - GrSLType type, - const char* name, - const char** vsOutName = NULL, - const char** fsInName = NULL, - GrGLShaderVar::Precision fsPrecision=GrGLShaderVar::kDefault_Precision) SK_OVERRIDE; + virtual void addVarying(GrSLType type, + const char* name, + const char** vsOutName = NULL, + const char** fsInName = NULL, + GrGLShaderVar::Precision fsPrecision=GrGLShaderVar::kDefault_Precision); // Handles for program uniforms (other than per-effect uniforms) struct BuiltinUniformHandles { @@ -175,10 +174,6 @@ public: }; protected: - typedef GrGLProgramDesc::ProcKeyProvider ProcKeyProvider; - typedef GrGLProgramDataManager::UniformInfo UniformInfo; - typedef GrGLProgramDataManager::UniformInfoArray UniformInfoArray; - static GrGLProgramBuilder* CreateProgramBuilder(const GrGLProgramDesc&, const GrOptDrawState&, GrGpu::DrawType, @@ -196,40 +191,32 @@ protected: // generating stage code. void nameVariable(SkString* out, char prefix, const char* name); void setupUniformColorAndCoverageIfNeeded(GrGLSLExpr4* inputColor, GrGLSLExpr4* inputCoverage); - void emitAndInstallProcs(const GrOptDrawState& optState, - GrGLSLExpr4* inputColor, - GrGLSLExpr4* inputCoverage); - void emitAndInstallFragProcs(int procOffset, int numProcs, GrGLSLExpr4* inOut); - template <class Proc> - void emitAndInstallProc(const Proc&, - int index, - const ProcKeyProvider, - const GrGLSLExpr4& input, - GrGLSLExpr4* output); - - // these emit functions help to keep the createAndEmitProcessors template general - void emitAndInstallProc(const GrFragmentStage&, - const GrProcessorKey&, - const char* outColor, - const char* inColor); - void emitAndInstallProc(const GrGeometryProcessor&, - const GrProcessorKey&, - const char* outColor, - const char* inColor); + void createAndEmitProcessors(const GrGeometryStage* geometryProcessor, + const GrFragmentStage* colorStages[], + const GrFragmentStage* coverageStages[], + GrGLSLExpr4* inputColor, + GrGLSLExpr4* inputCoverage); + template <class ProcessorStage> + void createAndEmitProcessors(const ProcessorStage*[], + int effectCnt, + const GrGLProgramDesc::EffectKeyProvider&, + GrGLSLExpr4* fsInOutColor, + GrGLInstalledProcessors*); void verify(const GrGeometryProcessor&); void verify(const GrFragmentProcessor&); void emitSamplers(const GrProcessor&, GrGLProcessor::TextureSamplerArray* outSamplers, - GrGLInstalledProc*); + GrGLInstalledProcessors*); // each specific program builder has a distinct transform and must override this function - virtual void emitTransforms(const GrFragmentStage&, + virtual void emitTransforms(const GrProcessorStage&, GrGLProcessor::TransformedCoordsArray* outCoords, - GrGLInstalledFragProc*); + GrGLInstalledProcessors*); GrGLProgram* finalize(); void bindUniformLocations(GrGLuint programID); bool checkLinkStatus(GrGLuint programID); void resolveUniformLocations(GrGLuint programID); + void cleanupProgram(GrGLuint programID, const SkTDArray<GrGLuint>& shaderIDs); void cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs); @@ -269,6 +256,10 @@ protected: void enterStage() { fOutOfStage = false; } int stageIndex() const { return fStageIndex; } + typedef GrGLProgramDesc::EffectKeyProvider EffectKeyProvider; + typedef GrGLProgramDataManager::UniformInfo UniformInfo; + typedef GrGLProgramDataManager::UniformInfoArray UniformInfoArray; + // number of each input/output type in a single allocation block, used by many builders static const int kVarsPerBlock; @@ -279,8 +270,9 @@ protected: bool fOutOfStage; int fStageIndex; - GrGLInstalledGeoProc* fGeometryProcessor; - SkAutoTUnref<GrGLInstalledFragProcs> fFragmentProcessors; + SkAutoTUnref<GrGLInstalledProcessors> fGeometryProcessor; + SkAutoTUnref<GrGLInstalledProcessors> fColorEffects; + SkAutoTUnref<GrGLInstalledProcessors> fCoverageEffects; const GrOptDrawState& fOptState; const GrGLProgramDesc& fDesc; @@ -294,26 +286,32 @@ protected: }; /** - * The below structs represent processors installed in programs. All processors can have texture - * samplers, but only frag processors have coord transforms, hence the need for different structs + * This class encapsulates an array of GrGLProcessors and their supporting data (coord transforms + * and textures). It is built by GrGLProgramBuilder, then used to manage the necessary GL + * state and shader uniforms in GLPrograms. Its just Plain old data, and as such is entirely public + * + * TODO We really don't need this class to have an array of processors. It makes sense for it + * to just have one, also break out the transforms */ -struct GrGLInstalledProc { - typedef GrGLProgramDataManager::UniformHandle UniformHandle; - - struct Sampler { - SkDEBUGCODE(Sampler() : fTextureUnit(-1) {}) - UniformHandle fUniform; - int fTextureUnit; - }; - SkSTArray<4, Sampler, true> fSamplers; -}; +class GrGLInstalledProcessors : public SkRefCnt { +public: + GrGLInstalledProcessors(int reserveCount, bool hasExplicitLocalCoords = false) + : fGLProcessors(reserveCount) + , fSamplers(reserveCount) + , fTransforms(reserveCount) + , fHasExplicitLocalCoords(hasExplicitLocalCoords) { + } -struct GrGLInstalledGeoProc : public GrGLInstalledProc { - GrGLGeometryProcessor* fGLProc; -}; + virtual ~GrGLInstalledProcessors(); + + typedef GrGLProgramDataManager::UniformHandle UniformHandle; + + struct Sampler { + SkDEBUGCODE(Sampler() : fTextureUnit(-1) {}) + UniformHandle fUniform; + int fTextureUnit; + }; -struct GrGLInstalledFragProc : public GrGLInstalledProc { - GrGLInstalledFragProc(bool useLocalCoords) : fGLProc(NULL), fLocalCoordAttrib(useLocalCoords) {} class ShaderVarHandle { public: bool isValid() const { return fHandle > -1; } @@ -336,14 +334,19 @@ struct GrGLInstalledFragProc : public GrGLInstalledProc { GrSLType fType; }; - GrGLFragmentProcessor* fGLProc; - SkSTArray<2, Transform, true> fTransforms; - bool fLocalCoordAttrib; -}; + void addEffect(GrGLProcessor* effect) { fGLProcessors.push_back(effect); } + SkTArray<Sampler, true>& addSamplers() { return fSamplers.push_back(); } + SkTArray<Transform, true>& addTransforms() { return fTransforms.push_back(); } -struct GrGLInstalledFragProcs : public SkRefCnt { - ~GrGLInstalledFragProcs(); - SkSTArray<8, GrGLInstalledFragProc*, true> fProcs; + SkTArray<GrGLProcessor*> fGLProcessors; + SkTArray<SkSTArray<4, Sampler, true> > fSamplers; + SkTArray<SkSTArray<2, Transform, true> > fTransforms; + bool fHasExplicitLocalCoords; + + friend class GrGLShaderBuilder; + friend class GrGLVertexShaderBuilder; + friend class GrGLFragmentShaderBuilder; + friend class GrGLGeometryShaderBuilder; }; #endif diff --git a/src/gpu/gl/builders/GrGLVertexShaderBuilder.h b/src/gpu/gl/builders/GrGLVertexShaderBuilder.h index 6e1495a746..0b85b84dfb 100644 --- a/src/gpu/gl/builders/GrGLVertexShaderBuilder.h +++ b/src/gpu/gl/builders/GrGLVertexShaderBuilder.h @@ -21,7 +21,7 @@ public: /** * Are explicit local coordinates provided as input to the vertex shader. */ - bool hasLocalCoords() const { return (fLocalCoordsVar != fPositionVar); } + bool hasExplicitLocalCoords() const { return (fLocalCoordsVar != fPositionVar); } /** Returns a vertex attribute that represents the local coords in the VS. This may be the same as positionAttribute() or it may not be. It depends upon whether the rendering code diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp index 75032bdbe6..5ab35b7d22 100644 --- a/tests/GLProgramsTest.cpp +++ b/tests/GLProgramsTest.cpp @@ -456,6 +456,9 @@ bool GrGpuGL::programUnitTest(int maxStages) { ds->reset(); continue; } + const GrGeometryStage* geometryProcessor = NULL; + SkSTArray<8, const GrFragmentStage*, true> colorStages; + SkSTArray<8, const GrFragmentStage*, true> coverageStages; GrGLProgramDesc desc; GrDeviceCoordTexture dstCopy; @@ -465,14 +468,24 @@ bool GrGpuGL::programUnitTest(int maxStages) { } if (!GrGLProgramDesc::Build(*ods, drawType, + ods->getSrcBlendCoeff(), + ods->getDstBlendCoeff(), this, dstCopy.texture() ? &dstCopy : NULL, + &geometryProcessor, + &colorStages, + &coverageStages, &desc)) { SkDebugf("Failed to generate GL program descriptor"); return false; } - SkAutoTUnref<GrGLProgram> program( - GrGLProgramBuilder::CreateProgram(*ods, desc, drawType, this)); + SkAutoTUnref<GrGLProgram> program(GrGLProgramBuilder::CreateProgram(*ods, + desc, + drawType, + geometryProcessor, + colorStages.begin(), + coverageStages.begin(), + this)); if (NULL == program.get()) { SkDebugf("Failed to create program!"); return false; |