diff options
author | 2014-12-10 07:43:49 -0800 | |
---|---|---|
committer | 2014-12-10 07:43:50 -0800 | |
commit | 4dffc940c430eec66d4707490eace19c9b3f7904 (patch) | |
tree | cce5e8c525a5acec67c4398c95c165223320d679 /src/gpu | |
parent | 28828d00b20d90b6caf91e4b0b31e80acadf2d57 (diff) |
Create xfer processor backend.
This includes:
-Having an actual XP stage at the end of the gl pipeline.
-All Blending work is handled by XP until actually setting GL blend states
-GLPrograms test to test XP
BUG=skia:
Review URL: https://codereview.chromium.org/764643004
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/GrGeometryProcessor.h | 5 | ||||
-rw-r--r-- | src/gpu/GrOptDrawState.cpp | 43 | ||||
-rw-r--r-- | src/gpu/GrOptDrawState.h | 3 | ||||
-rw-r--r-- | src/gpu/GrProcessor.cpp | 12 | ||||
-rw-r--r-- | src/gpu/GrProgramDesc.h | 41 | ||||
-rw-r--r-- | src/gpu/effects/GrPorterDuffXferProcessor.cpp | 123 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProcessor.h | 10 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgram.cpp | 23 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgram.h | 7 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgramDesc.cpp | 15 | ||||
-rw-r--r-- | src/gpu/gl/GrGLXferProcessor.h | 61 | ||||
-rw-r--r-- | src/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp | 49 | ||||
-rw-r--r-- | src/gpu/gl/builders/GrGLFragmentShaderBuilder.h | 2 | ||||
-rw-r--r-- | src/gpu/gl/builders/GrGLLegacyNvprProgramBuilder.cpp | 3 | ||||
-rw-r--r-- | src/gpu/gl/builders/GrGLNvprProgramBuilder.cpp | 3 | ||||
-rw-r--r-- | src/gpu/gl/builders/GrGLProgramBuilder.cpp | 65 | ||||
-rw-r--r-- | src/gpu/gl/builders/GrGLProgramBuilder.h | 24 |
17 files changed, 305 insertions, 184 deletions
diff --git a/src/gpu/GrGeometryProcessor.h b/src/gpu/GrGeometryProcessor.h index 4801069005..a0cfc09d45 100644 --- a/src/gpu/GrGeometryProcessor.h +++ b/src/gpu/GrGeometryProcessor.h @@ -62,7 +62,10 @@ public: virtual const char* name() const = 0; - /** Implemented using GLProcessor::GenKey as described in this class's comment. */ + /** + * Sets a unique key on the GrProcessorKeyBuilder that is directly associated with this geometry + * processor's GL backend implementation. + */ virtual void getGLProcessorKey(const GrBatchTracker& bt, const GrGLCaps& caps, GrProcessorKeyBuilder* b) const = 0; diff --git a/src/gpu/GrOptDrawState.cpp b/src/gpu/GrOptDrawState.cpp index 409305ce33..9ebe551d6b 100644 --- a/src/gpu/GrOptDrawState.cpp +++ b/src/gpu/GrOptDrawState.cpp @@ -44,7 +44,8 @@ GrOptDrawState::GrOptDrawState(const GrDrawState& drawState, drawState.isColorWriteDisabled(), drawState.getStencil().doesWrite(), &fColor, - &fCoverage); + &fCoverage, + caps); } // When path rendering the stencil settings are not always set on the draw state @@ -146,42 +147,6 @@ GrOptDrawState::GrOptDrawState(const GrDrawState& drawState, init.fCoverage = this->getCoverage(); fGeometryProcessor->initBatchTracker(&fBatchTracker, init); } - - this->setOutputStateInfo(drawState, coverageColor, optFlags, caps); -} - -void GrOptDrawState::setOutputStateInfo(const GrDrawState& ds, - GrColor coverage, - GrXferProcessor::OptFlags optFlags, - const GrDrawTargetCaps& caps) { - // Set this default and then possibly change our mind if there is coverage. - fDescInfo.fPrimaryOutputType = GrProgramDesc::kModulate_PrimaryOutputType; - fDescInfo.fSecondaryOutputType = GrProgramDesc::kNone_SecondaryOutputType; - - // Determine whether we should use dual source blending or shader code to keep coverage - // separate from color. - bool keepCoverageSeparate = !(optFlags & GrXferProcessor::kSetCoverageDrawing_OptFlag); - if (keepCoverageSeparate && !ds.hasSolidCoverage(coverage)) { - if (caps.dualSourceBlendingSupport()) { - if (kZero_GrBlendCoeff == fDstBlend) { - // write the coverage value to second color - fDescInfo.fSecondaryOutputType = GrProgramDesc::kCoverage_SecondaryOutputType; - fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff; - } else if (kSA_GrBlendCoeff == fDstBlend) { - // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered. - fDescInfo.fSecondaryOutputType = GrProgramDesc::kCoverageISA_SecondaryOutputType; - fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff; - } else if (kSC_GrBlendCoeff == fDstBlend) { - // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered. - fDescInfo.fSecondaryOutputType = GrProgramDesc::kCoverageISC_SecondaryOutputType; - fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff; - } - } else if (fDescInfo.fReadsDst && - kOne_GrBlendCoeff == fSrcBlend && - kZero_GrBlendCoeff == fDstBlend) { - fDescInfo.fPrimaryOutputType = GrProgramDesc::kCombineWithDst_PrimaryOutputType; - } - } } void GrOptDrawState::adjustProgramFromOptimizations(const GrDrawState& ds, @@ -262,6 +227,10 @@ bool GrOptDrawState::operator== (const GrOptDrawState& that) const { return false; } + if (!this->getXferProcessor()->isEqual(*that.getXferProcessor())) { + return false; + } + // The program desc comparison should have already assured that the stage counts match. SkASSERT(this->numFragmentStages() == that.numFragmentStages()); for (int i = 0; i < this->numFragmentStages(); i++) { diff --git a/src/gpu/GrOptDrawState.h b/src/gpu/GrOptDrawState.h index cf5737373c..55a5071d41 100644 --- a/src/gpu/GrOptDrawState.h +++ b/src/gpu/GrOptDrawState.h @@ -79,7 +79,8 @@ public: int numCoverageStages() const { return fFragmentStages.count() - fNumColorStages; } int numFragmentStages() const { return fFragmentStages.count(); } int numTotalStages() const { - return this->numFragmentStages() + (this->hasGeometryProcessor() ? 1 : 0); + // the + 1 at the end is for the xferProcessor which will always be present + return this->numFragmentStages() + (this->hasGeometryProcessor() ? 1 : 0) + 1; } bool hasGeometryProcessor() const { return SkToBool(fGeometryProcessor.get()); } diff --git a/src/gpu/GrProcessor.cpp b/src/gpu/GrProcessor.cpp index ccd4d7f7e8..2bcd9b46a2 100644 --- a/src/gpu/GrProcessor.cpp +++ b/src/gpu/GrProcessor.cpp @@ -32,9 +32,9 @@ GrProcessorTestFactory<GrFragmentProcessor>::GetFactories() { } template<> -SkTArray<GrProcessorTestFactory<GrXferProcessor>*, true>* -GrProcessorTestFactory<GrXferProcessor>::GetFactories() { - static SkTArray<GrProcessorTestFactory<GrXferProcessor>*, true> gFactories; +SkTArray<GrProcessorTestFactory<GrXPFactory>*, true>* +GrProcessorTestFactory<GrXPFactory>::GetFactories() { + static SkTArray<GrProcessorTestFactory<GrXPFactory>*, true> gFactories; return &gFactories; } @@ -52,7 +52,7 @@ GrProcessorTestFactory<GrGeometryProcessor>::GetFactories() { */ static const int kFPFactoryCount = 37; static const int kGPFactoryCount = 14; -static const int kXPFactoryCount = 0; +static const int kXPFactoryCount = 1; template<> void GrProcessorTestFactory<GrFragmentProcessor>::VerifyFactoryCount() { @@ -69,9 +69,9 @@ void GrProcessorTestFactory<GrGeometryProcessor>::VerifyFactoryCount() { } template<> -void GrProcessorTestFactory<GrXferProcessor>::VerifyFactoryCount() { +void GrProcessorTestFactory<GrXPFactory>::VerifyFactoryCount() { if (kXPFactoryCount != GetFactories()->count()) { - SkFAIL("Wrong number of xfer processor factories!"); + SkFAIL("Wrong number of xp factory factories!"); } } diff --git a/src/gpu/GrProgramDesc.h b/src/gpu/GrProgramDesc.h index a20b99f749..3d53842e43 100644 --- a/src/gpu/GrProgramDesc.h +++ b/src/gpu/GrProgramDesc.h @@ -55,36 +55,6 @@ public: } - /////////////////////////////////////////////////////////////////////////// - /// @name Stage Output Types - //// - - enum PrimaryOutputType { - // Modulate color and coverage, write result as the color output. - kModulate_PrimaryOutputType, - // Combines the coverage, dst, and color as coverage * color + (1 - coverage) * dst. This - // can only be set if fDstReadKey is non-zero. - kCombineWithDst_PrimaryOutputType, - - kPrimaryOutputTypeCnt, - }; - - enum SecondaryOutputType { - // There is no secondary output - kNone_SecondaryOutputType, - // Writes coverage as the secondary output. Only set if dual source blending is supported - // and primary output is kModulate. - kCoverage_SecondaryOutputType, - // Writes coverage * (1 - colorA) as the secondary output. Only set if dual source blending - // is supported and primary output is kModulate. - kCoverageISA_SecondaryOutputType, - // Writes coverage * (1 - colorRGBA) as the secondary output. Only set if dual source - // blending is supported and primary output is kModulate. - kCoverageISC_SecondaryOutputType, - - kSecondaryOutputTypeCnt, - }; - // Specifies where the initial color comes from before the stages are applied. enum ColorInput { kAllOnes_ColorInput, @@ -105,9 +75,6 @@ public: ColorInput fColorInput : 8; ColorInput fCoverageInput : 8; - PrimaryOutputType fPrimaryOutputType : 8; - SecondaryOutputType fSecondaryOutputType : 8; - SkBool8 fHasGeometryProcessor; int8_t fColorEffectCnt; int8_t fCoverageEffectCnt; @@ -140,10 +107,7 @@ public: fInputCoverageIsUsed == that.fInputCoverageIsUsed && fReadsDst == that.fReadsDst && fReadsFragPosition == that.fReadsFragPosition && - fRequiresLocalCoordAttrib == that.fRequiresLocalCoordAttrib && - fPrimaryOutputType == that.fPrimaryOutputType && - fSecondaryOutputType == that.fSecondaryOutputType; - + fRequiresLocalCoordAttrib == that.fRequiresLocalCoordAttrib; } bool operator!=(const DescInfo& that) const { return !(*this == that); }; // TODO when GPs control uniform / attribute handling of color / coverage, then we can @@ -162,9 +126,6 @@ public: bool fReadsFragPosition; bool fRequiresLocalCoordAttrib; - // Fragment shader color outputs - GrProgramDesc::PrimaryOutputType fPrimaryOutputType : 8; - GrProgramDesc::SecondaryOutputType fSecondaryOutputType : 8; }; private: diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp index 2b4b1334f8..097854622d 100644 --- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp +++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp @@ -9,11 +9,12 @@ #include "GrBlend.h" #include "GrDrawState.h" +#include "GrDrawTargetCaps.h" #include "GrInvariantOutput.h" #include "GrProcessor.h" #include "GrTypes.h" #include "GrXferProcessor.h" -#include "gl/GrGLProcessor.h" +#include "gl/GrGLXferProcessor.h" #include "gl/builders/GrGLFragmentShaderBuilder.h" #include "gl/builders/GrGLProgramBuilder.h" @@ -42,19 +43,40 @@ public: virtual ~GrGLPorterDuffXferProcessor() {} - virtual void emitCode(GrGLFPBuilder* builder, - const GrFragmentProcessor& fp, - const char* outputColor, - const char* inputColor, - const TransformedCoordsArray& coords, - const TextureSamplerArray& samplers) SK_OVERRIDE { - GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); - fsBuilder->codeAppendf("%s = %s;", outputColor, inputColor); + virtual void emitCode(const EmitArgs& args) SK_OVERRIDE { + const GrPorterDuffXferProcessor& xp = args.fXP.cast<GrPorterDuffXferProcessor>(); + GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); + if (xp.hasSecondaryOutput()) { + switch(xp.secondaryOutputType()) { + case GrPorterDuffXferProcessor::kCoverage_SecondaryOutputType: + fsBuilder->codeAppendf("%s = %s;", args.fOutputSecondary, args.fInputCoverage); + break; + case GrPorterDuffXferProcessor::kCoverageISA_SecondaryOutputType: + fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", + args.fOutputSecondary, args.fInputColor, + args.fInputCoverage); + break; + case GrPorterDuffXferProcessor::kCoverageISC_SecondaryOutputType: + fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", + args.fOutputSecondary, args.fInputColor, + args.fInputCoverage); + break; + default: + SkFAIL("Unexpected Secondary Output"); + } + } + + fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor, + args.fInputCoverage); } - virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE {}; + virtual void setData(const GrGLProgramDataManager&, const GrXferProcessor&) SK_OVERRIDE {}; - static void GenKey(const GrProcessor&, const GrGLCaps& caps, GrProcessorKeyBuilder* b) {}; + static void GenKey(const GrProcessor& processor, const GrGLCaps& caps, + GrProcessorKeyBuilder* b) { + const GrPorterDuffXferProcessor& xp = processor.cast<GrPorterDuffXferProcessor>(); + b->add32(xp.secondaryOutputType()); + }; private: typedef GrGLXferProcessor INHERITED; @@ -64,7 +86,10 @@ private: GrPorterDuffXferProcessor::GrPorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, GrColor constant) - : fSrcBlend(srcBlend), fDstBlend(dstBlend), fBlendConstant(constant) { + : fSrcBlend(srcBlend) + , fDstBlend(dstBlend) + , fBlendConstant(constant) + , fSecondaryOutputType(kNone_SecondaryOutputType) { this->initClassID<GrPorterDuffXferProcessor>(); } @@ -76,7 +101,7 @@ void GrPorterDuffXferProcessor::getGLProcessorKey(const GrGLCaps& caps, GrGLPorterDuffXferProcessor::GenKey(*this, caps, b); } -GrGLFragmentProcessor* GrPorterDuffXferProcessor::createGLInstance() const { +GrGLXferProcessor* GrPorterDuffXferProcessor::createGLInstance() const { return SkNEW_ARGS(GrGLPorterDuffXferProcessor, (*this)); } @@ -90,7 +115,54 @@ GrPorterDuffXferProcessor::getOptimizations(const GrProcOptInfo& colorPOI, bool isCoverageDrawing, bool colorWriteDisabled, bool doesStencilWrite, - GrColor* color, uint8_t* coverage) { + GrColor* color, uint8_t* coverage, + const GrDrawTargetCaps& caps) { + GrXferProcessor::OptFlags optFlags = this->internalGetOptimizations(colorPOI, + coveragePOI, + isCoverageDrawing, + colorWriteDisabled, + doesStencilWrite, + color, + coverage); + + this->calcOutputTypes(optFlags, caps, isCoverageDrawing, + colorPOI.readsDst() || coveragePOI.readsDst()); + return optFlags; +} + +void GrPorterDuffXferProcessor::calcOutputTypes(GrXferProcessor::OptFlags optFlags, + const GrDrawTargetCaps& caps, + bool isCoverageDrawing, bool readsDst) { + // If we do have coverage determine whether it matters. Dual source blending is expensive so + // we don't do it if we are doing coverage drawing. If we aren't then We always do dual source + // blending if we have any effective coverage stages OR the geometry processor doesn't emits + // solid coverage. + if (!(optFlags & kSetCoverageDrawing_OptFlag) && !isCoverageDrawing) { + if (caps.dualSourceBlendingSupport()) { + if (kZero_GrBlendCoeff == fDstBlend) { + // write the coverage value to second color + fSecondaryOutputType = kCoverage_SecondaryOutputType; + fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff; + } else if (kSA_GrBlendCoeff == fDstBlend) { + // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered. + fSecondaryOutputType = kCoverageISA_SecondaryOutputType; + fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff; + } else if (kSC_GrBlendCoeff == fDstBlend) { + // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered. + fSecondaryOutputType = kCoverageISC_SecondaryOutputType; + fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff; + } + } + } +} + +GrXferProcessor::OptFlags +GrPorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPOI, + const GrProcOptInfo& coveragePOI, + bool isCoverageDrawing, + bool colorWriteDisabled, + bool doesStencilWrite, + GrColor* color, uint8_t* coverage) { if (colorWriteDisabled) { fSrcBlend = kZero_GrBlendCoeff; fDstBlend = kOne_GrBlendCoeff; @@ -192,6 +264,11 @@ GrPorterDuffXferProcessor::getOptimizations(const GrProcOptInfo& colorPOI, return GrXferProcessor::kNone_Opt; } + +bool GrPorterDuffXferProcessor::hasSecondaryOutput() const { + return kNone_SecondaryOutputType != fSecondaryOutputType; +} + /////////////////////////////////////////////////////////////////////////////// GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst) @@ -450,4 +527,22 @@ bool GrPorterDuffXPFactory::getOpaqueAndKnownColor(const GrProcOptInfo& colorPOI return opaque; } +GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory); + +GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random, + GrContext*, + const GrDrawTargetCaps&, + GrTexture*[]) { + GrBlendCoeff src; + do { + src = GrBlendCoeff(random->nextRangeU(kFirstPublicGrBlendCoeff, kLastPublicGrBlendCoeff)); + } while (GrBlendCoeffRefsSrc(src)); + + GrBlendCoeff dst; + do { + dst = GrBlendCoeff(random->nextRangeU(kFirstPublicGrBlendCoeff, kLastPublicGrBlendCoeff)); + } while (GrBlendCoeffRefsDst(dst)); + + return GrPorterDuffXPFactory::Create(src, dst); +} diff --git a/src/gpu/gl/GrGLProcessor.h b/src/gpu/gl/GrGLProcessor.h index 6dccd33bac..a4fad753ec 100644 --- a/src/gpu/gl/GrGLProcessor.h +++ b/src/gpu/gl/GrGLProcessor.h @@ -117,14 +117,4 @@ private: typedef GrGLProcessor INHERITED; }; -class GrGLXferProcessor : public GrGLFragmentProcessor { -public: - GrGLXferProcessor() {} - - virtual ~GrGLXferProcessor() {} - -private: - typedef GrGLFragmentProcessor INHERITED; -}; - #endif diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp index 29c44ac56c..da687c1eb6 100644 --- a/src/gpu/gl/GrGLProgram.cpp +++ b/src/gpu/gl/GrGLProgram.cpp @@ -12,11 +12,13 @@ #include "GrCoordTransform.h" #include "GrGLGeometryProcessor.h" #include "GrGLProcessor.h" +#include "GrGLXferProcessor.h" #include "GrGpuGL.h" #include "GrGLPathRendering.h" #include "GrGLShaderVar.h" #include "GrGLSL.h" #include "GrOptDrawState.h" +#include "GrXferProcessor.h" #include "SkXfermode.h" #define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X) @@ -57,6 +59,7 @@ GrGLProgram::GrGLProgram(GrGpuGL* gpu, GrGLuint programID, const UniformInfoArray& uniforms, GrGLInstalledGeoProc* geometryProcessor, + GrGLInstalledXferProc* xferProcessor, GrGLInstalledFragProcs* fragmentProcessors) : fColor(GrColor_ILLEGAL) , fCoverage(0) @@ -64,6 +67,7 @@ GrGLProgram::GrGLProgram(GrGpuGL* gpu, , fBuiltinUniformHandles(builtinUniforms) , fProgramID(programID) , fGeometryProcessor(geometryProcessor) + , fXferProcessor(xferProcessor) , fFragmentProcessors(SkRef(fragmentProcessors)) , fDesc(desc) , fGpu(gpu) @@ -91,6 +95,9 @@ void GrGLProgram::initSamplerUniforms() { if (fGeometryProcessor.get()) { this->initSamplers(fGeometryProcessor.get(), &texUnitIdx); } + if (fXferProcessor.get()) { + this->initSamplers(fXferProcessor.get(), &texUnitIdx); + } int numProcs = fFragmentProcessors->fProcs.count(); for (int i = 0; i < numProcs; i++) { this->initSamplers(fFragmentProcessors->fProcs[i], &texUnitIdx); @@ -162,6 +169,11 @@ void GrGLProgram::setData(const GrOptDrawState& optState) { fGeometryProcessor->fGLProc->setData(fProgramDataManager, gp, bt); this->bindTextures(fGeometryProcessor, gp); } + if (fXferProcessor.get()) { + const GrXferProcessor& xp = *optState.getXferProcessor(); + fXferProcessor->fGLProc->setData(fProgramDataManager, xp); + this->bindTextures(fXferProcessor, xp); + } this->setFragmentData(optState); // Some of GrGLProgram subclasses need to update state here @@ -284,8 +296,10 @@ GrGLNvprProgramBase::GrGLNvprProgramBase(GrGpuGL* gpu, const BuiltinUniformHandles& builtinUniforms, GrGLuint programID, const UniformInfoArray& uniforms, + GrGLInstalledXferProc* xferProcessor, GrGLInstalledFragProcs* fragmentProcessors) - : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, NULL, fragmentProcessors) { + : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, NULL, + xferProcessor, fragmentProcessors) { } void GrGLNvprProgramBase::onSetMatrixAndRenderTargetHeight(const GrOptDrawState& optState) { @@ -303,9 +317,11 @@ GrGLNvprProgram::GrGLNvprProgram(GrGpuGL* gpu, const BuiltinUniformHandles& builtinUniforms, GrGLuint programID, const UniformInfoArray& uniforms, + GrGLInstalledXferProc* xferProcessor, GrGLInstalledFragProcs* fragmentProcessors, const SeparableVaryingInfoArray& separableVaryings) - : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, fragmentProcessors) { + : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, + xferProcessor, fragmentProcessors) { int count = separableVaryings.count(); fVaryings.push_back_n(count); for (int i = 0; i < count; i++) { @@ -353,9 +369,10 @@ GrGLLegacyNvprProgram::GrGLLegacyNvprProgram(GrGpuGL* gpu, const BuiltinUniformHandles& builtinUniforms, GrGLuint programID, const UniformInfoArray& uniforms, + GrGLInstalledXferProc* xp, GrGLInstalledFragProcs* fps, int texCoordSetCnt) - : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, fps) + : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, xp, fps) , fTexCoordSetCnt(texCoordSetCnt) { } diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h index 36bf860233..ea8be85251 100644 --- a/src/gpu/gl/GrGLProgram.h +++ b/src/gpu/gl/GrGLProgram.h @@ -141,6 +141,7 @@ protected: GrGLuint programID, const UniformInfoArray&, GrGLInstalledGeoProc* geometryProcessor, + GrGLInstalledXferProc* xferProcessor, GrGLInstalledFragProcs* fragmentProcessors); // Sets the texture units for samplers. @@ -180,6 +181,7 @@ protected: // the installed effects SkAutoTDelete<GrGLInstalledGeoProc> fGeometryProcessor; + SkAutoTDelete<GrGLInstalledXferProc> fXferProcessor; SkAutoTUnref<GrGLInstalledFragProcs> fFragmentProcessors; GrProgramDesc fDesc; @@ -205,6 +207,7 @@ protected: const BuiltinUniformHandles&, GrGLuint programID, const UniformInfoArray&, + GrGLInstalledXferProc* xferProcessor, GrGLInstalledFragProcs* fragmentProcessors); virtual void onSetMatrixAndRenderTargetHeight(const GrOptDrawState&); @@ -223,6 +226,7 @@ private: const BuiltinUniformHandles&, GrGLuint programID, const UniformInfoArray&, + GrGLInstalledXferProc* xferProcessor, GrGLInstalledFragProcs* fragmentProcessors, const SeparableVaryingInfoArray& separableVaryings); virtual void didSetData(GrGpu::DrawType) SK_OVERRIDE; @@ -252,7 +256,8 @@ private: const BuiltinUniformHandles&, GrGLuint programID, const UniformInfoArray&, - GrGLInstalledFragProcs* fragmentProcessors, + GrGLInstalledXferProc* xp, + GrGLInstalledFragProcs* fps, int texCoordSetCnt); virtual void didSetData(GrGpu::DrawType) SK_OVERRIDE; virtual void setTransformData(const GrPendingFragmentStage&, diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp index 068386c3aa..2476c5532c 100644 --- a/src/gpu/gl/GrGLProgramDesc.cpp +++ b/src/gpu/gl/GrGLProgramDesc.cpp @@ -189,13 +189,21 @@ bool GrGLProgramDescBuilder::Build(const GrOptDrawState& optState, const GrFragmentProcessor& fp = *fps.getProcessor(); GrProcessorKeyBuilder b(&desc->fKey); fp.getGLProcessorKey(gpu->glCaps(), &b); - if (!get_meta_key(*fps.getProcessor(), gpu->glCaps(), - gen_transform_key(fps, requiresLocalCoordAttrib), 0, &b)) { + if (!get_meta_key(fp, gpu->glCaps(), + gen_transform_key(fps, requiresLocalCoordAttrib), 0, &b)) { desc->fKey.reset(); return false; } } + const GrXferProcessor& xp = *optState.getXferProcessor(); + GrProcessorKeyBuilder b(&desc->fKey); + xp.getGLProcessorKey(gpu->glCaps(), &b); + if (!get_meta_key(xp, gpu->glCaps(), 0, 0, &b)) { + desc->fKey.reset(); + return false; + } + // --------DO NOT MOVE HEADER ABOVE THIS LINE-------------------------------------------------- // Because header is a pointer into the dynamic array, we can't push any new data into the key // below here. @@ -260,9 +268,6 @@ bool GrGLProgramDescBuilder::Build(const GrOptDrawState& optState, header->fFragPosKey = 0; } - header->fPrimaryOutputType = descInfo.fPrimaryOutputType; - header->fSecondaryOutputType = descInfo.fSecondaryOutputType; - header->fColorEffectCnt = optState.numColorStages(); header->fCoverageEffectCnt = optState.numCoverageStages(); desc->finalize(); diff --git a/src/gpu/gl/GrGLXferProcessor.h b/src/gpu/gl/GrGLXferProcessor.h new file mode 100644 index 0000000000..5c92559031 --- /dev/null +++ b/src/gpu/gl/GrGLXferProcessor.h @@ -0,0 +1,61 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrGLXferProcessor_DEFINED +#define GrGLXferProcessor_DEFINED + +#include "GrGLProcessor.h" + +class GrGLXPBuilder; + +class GrGLXferProcessor { +public: + GrGLXferProcessor() {} + virtual ~GrGLXferProcessor() {} + + typedef GrGLProcessor::TextureSamplerArray TextureSamplerArray; + struct EmitArgs { + EmitArgs(GrGLXPBuilder* pb, + const GrXferProcessor& xp, + const char* inputColor, + const char* inputCoverage, + const char* outputPrimary, + const char* outputSecondary, + const TextureSamplerArray& samplers) + : fPB(pb) + , fXP(xp) + , fInputColor(inputColor) + , fInputCoverage(inputCoverage) + , fOutputPrimary(outputPrimary) + , fOutputSecondary(outputSecondary) + , fSamplers(samplers) {} + + GrGLXPBuilder* fPB; + const GrXferProcessor& fXP; + const char* fInputColor; + const char* fInputCoverage; + const char* fOutputPrimary; + const char* fOutputSecondary; + const TextureSamplerArray& fSamplers; + }; + /** + * This is similar to emitCode() in the base class, except it takes a full shader builder. + * This allows the effect subclass to emit vertex code. + */ + virtual void emitCode(const EmitArgs&) = 0; + + /** A GrGLXferProcessor instance can be reused with any GrGLXferProcessor that produces + the same stage key; this function reads data from a GrGLXferProcessor and uploads any + uniform variables required by the shaders created in emitCode(). The GrXferProcessor + parameter is guaranteed to be of the same type that created this GrGLXferProcessor and + to have an identical processor key as the one that created this GrGLXferProcessor. */ + virtual void setData(const GrGLProgramDataManager&, + const GrXferProcessor&) = 0; +private: + typedef GrGLProcessor INHERITED; +}; +#endif diff --git a/src/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp b/src/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp index 49be12d8ba..b6daca7978 100644 --- a/src/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp +++ b/src/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp @@ -256,55 +256,6 @@ const char* GrGLFragmentShaderBuilder::getSecondaryColorOutputName() const { return dual_source_output_name(); } -void GrGLFragmentShaderBuilder::enableSecondaryOutput(const GrGLSLExpr4& inputColor, - const GrGLSLExpr4& inputCoverage) { - this->enableSecondaryOutput(); - const char* secondaryOutputName = this->getSecondaryColorOutputName(); - GrGLSLExpr4 coeff(1); - switch (fProgramBuilder->header().fSecondaryOutputType) { - case GrProgramDesc::kCoverage_SecondaryOutputType: - break; - case GrProgramDesc::kCoverageISA_SecondaryOutputType: - // Get (1-A) into coeff - coeff = GrGLSLExpr4::VectorCast(GrGLSLExpr1(1) - inputColor.a()); - break; - case GrProgramDesc::kCoverageISC_SecondaryOutputType: - // Get (1-RGBA) into coeff - coeff = GrGLSLExpr4(1) - inputColor; - break; - default: - SkFAIL("Unexpected Secondary Output"); - } - // Get coeff * coverage into modulate and then write that to the dual source output. - this->codeAppendf("\t%s = %s;\n", secondaryOutputName, (coeff * inputCoverage).c_str()); -} - -void GrGLFragmentShaderBuilder::combineColorAndCoverage(const GrGLSLExpr4& inputColor, - const GrGLSLExpr4& inputCoverage) { - GrGLSLExpr4 fragColor = inputColor * inputCoverage; - switch (fProgramBuilder->header().fPrimaryOutputType) { - case GrProgramDesc::kModulate_PrimaryOutputType: - break; - case GrProgramDesc::kCombineWithDst_PrimaryOutputType: - { - // Tack on "+(1-coverage)dst onto the frag color. - GrGLSLExpr4 dstCoeff = GrGLSLExpr4(1) - inputCoverage; - GrGLSLExpr4 dstContribution = dstCoeff * GrGLSLExpr4(this->dstColor()); - fragColor = fragColor + dstContribution; - } - break; - default: - SkFAIL("Unknown Primary Output"); - } - - // On any post 1.10 GLSL supporting GPU, we declare custom output - if (k110_GrGLSLGeneration != fProgramBuilder->gpu()->glslGeneration()) { - this->enableCustomOutput(); - } - - this->codeAppendf("\t%s = %s;\n", this->getPrimaryColorOutputName(), fragColor.c_str()); -} - bool GrGLFragmentShaderBuilder::compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const { GrGpuGL* gpu = fProgramBuilder->gpu(); diff --git a/src/gpu/gl/builders/GrGLFragmentShaderBuilder.h b/src/gpu/gl/builders/GrGLFragmentShaderBuilder.h index 03f0e7f7a6..456ec4f27c 100644 --- a/src/gpu/gl/builders/GrGLFragmentShaderBuilder.h +++ b/src/gpu/gl/builders/GrGLFragmentShaderBuilder.h @@ -100,8 +100,6 @@ private: void enableSecondaryOutput(); const char* getPrimaryColorOutputName() const; const char* getSecondaryColorOutputName() const; - void enableSecondaryOutput(const GrGLSLExpr4& inputColor, const GrGLSLExpr4& inputCoverage); - void combineColorAndCoverage(const GrGLSLExpr4& inputColor, const GrGLSLExpr4& inputCoverage); bool compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const; void bindFragmentShaderLocations(GrGLuint programID); diff --git a/src/gpu/gl/builders/GrGLLegacyNvprProgramBuilder.cpp b/src/gpu/gl/builders/GrGLLegacyNvprProgramBuilder.cpp index b251593bfe..b90bab2c1d 100644 --- a/src/gpu/gl/builders/GrGLLegacyNvprProgramBuilder.cpp +++ b/src/gpu/gl/builders/GrGLLegacyNvprProgramBuilder.cpp @@ -45,5 +45,6 @@ void GrGLLegacyNvprProgramBuilder::emitTransforms(const GrPendingFragmentStage& GrGLProgram* GrGLLegacyNvprProgramBuilder::createProgram(GrGLuint programID) { return SkNEW_ARGS(GrGLLegacyNvprProgram, (fGpu, fDesc, fUniformHandles, programID, fUniforms, - fFragmentProcessors.get(), fTexCoordSetCnt)); + fXferProcessor, fFragmentProcessors.get(), + fTexCoordSetCnt)); } diff --git a/src/gpu/gl/builders/GrGLNvprProgramBuilder.cpp b/src/gpu/gl/builders/GrGLNvprProgramBuilder.cpp index f5a55866ee..ba19275f6f 100644 --- a/src/gpu/gl/builders/GrGLNvprProgramBuilder.cpp +++ b/src/gpu/gl/builders/GrGLNvprProgramBuilder.cpp @@ -72,5 +72,6 @@ GrGLProgram* GrGLNvprProgramBuilder::createProgram(GrGLuint programID) { // building this->resolveSeparableVaryings(programID); return SkNEW_ARGS(GrGLNvprProgram, (fGpu, fDesc, fUniformHandles, programID, fUniforms, - fFragmentProcessors.get(), fSeparableVaryingInfos)); + fXferProcessor, fFragmentProcessors.get(), + fSeparableVaryingInfos)); } diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp index ab77e05938..8ea03fbba7 100644 --- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp +++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp @@ -9,6 +9,7 @@ #include "gl/GrGLProgram.h" #include "gl/GrGLSLPrettyPrint.h" #include "gl/GrGLUniformHandle.h" +#include "../GrGLXferProcessor.h" #include "../GrGpuGL.h" #include "GrCoordTransform.h" #include "GrGLLegacyNvprProgramBuilder.h" @@ -55,20 +56,12 @@ GrGLProgram* GrGLProgramBuilder::CreateProgram(const GrOptDrawState& optState, G pb->emitAndInstallProcs(&inputColor, &inputCoverageVec4); - // write the secondary color output if necessary - if (GrProgramDesc::kNone_SecondaryOutputType != header.fSecondaryOutputType) { - pb->fFS.enableSecondaryOutput(inputColor, inputCoverageVec4); - } - - pb->fFS.combineColorAndCoverage(inputColor, inputCoverageVec4); - return pb->finalize(); } -GrGLProgramBuilder* -GrGLProgramBuilder::CreateProgramBuilder(const GrOptDrawState& optState, - bool hasGeometryProcessor, - GrGpuGL* gpu) { +GrGLProgramBuilder* GrGLProgramBuilder::CreateProgramBuilder(const GrOptDrawState& optState, + bool hasGeometryProcessor, + GrGpuGL* gpu) { const GrProgramDesc& desc = optState.programDesc(); if (GrGLProgramDescBuilder::GetHeader(desc).fUseNvpr) { SkASSERT(gpu->glCaps().pathRenderingSupport()); @@ -95,6 +88,7 @@ GrGLProgramBuilder::GrGLProgramBuilder(GrGpuGL* gpu, const GrOptDrawState& optSt , fOutOfStage(true) , fStageIndex(-1) , fGeometryProcessor(NULL) + , fXferProcessor(NULL) , fOptState(optState) , fDesc(optState.programDesc()) , fGpu(gpu) @@ -256,6 +250,8 @@ void GrGLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr if (fOptState.hasGeometryProcessor()) { fVS.transformToNormalizedDeviceSpace(); } + + this->emitAndInstallXferProc(*fOptState.getXferProcessor(), *inputColor, *inputCoverage); } void GrGLProgramBuilder::emitAndInstallFragProcs(int procOffset, @@ -364,10 +360,55 @@ void GrGLProgramBuilder::emitAndInstallProc(const GrGeometryProcessor& gp, verify(gp); } +void GrGLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp, + const GrGLSLExpr4& colorIn, + const GrGLSLExpr4& coverageIn) { + // Program builders have a bit of state we need to clear with each effect + AutoStageAdvance adv(this); + + SkASSERT(!fXferProcessor); + fXferProcessor = SkNEW(GrGLInstalledXferProc); + + fXferProcessor->fGLProc.reset(xp.createGLInstance()); + + // Enable dual source secondary output if we have one + if (xp.hasSecondaryOutput()) { + fFS.enableSecondaryOutput(); + } + + // On any post 1.10 GLSL supporting GPU, we declare custom output + if (k110_GrGLSLGeneration != fFS.fProgramBuilder->gpu()->glslGeneration()) { + fFS.enableCustomOutput(); + } + + SkString openBrace; + openBrace.printf("{ // Xfer Processor: %s\n", xp.name()); + fFS.codeAppend(openBrace.c_str()); + + SkSTArray<4, GrGLProcessor::TextureSampler> samplers(xp.numTextures()); + this->emitSamplers(xp, &samplers, fXferProcessor); + + GrGLXferProcessor::EmitArgs args(this, xp, colorIn.c_str(), coverageIn.c_str(), + fFS.getPrimaryColorOutputName(), + fFS.getSecondaryColorOutputName(), samplers); + fXferProcessor->fGLProc->emitCode(args); + + // 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(xp); + fFS.codeAppend("}"); +} + void GrGLProgramBuilder::verify(const GrGeometryProcessor& gp) { SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition()); } +void GrGLProgramBuilder::verify(const GrXferProcessor& xp) { + // TODO: Once will readDst is only xp enable this assert and remove it from the + // FragmentProcessor verify() + //SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor()); +} + void GrGLProgramBuilder::verify(const GrFragmentProcessor& fp) { SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition()); SkASSERT(fFS.hasReadDstColor() == fp.willReadDstColor()); @@ -539,7 +580,7 @@ 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, fXferProcessor, fFragmentProcessors.get())); } /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.h b/src/gpu/gl/builders/GrGLProgramBuilder.h index 1798e604db..69eed27252 100644 --- a/src/gpu/gl/builders/GrGLProgramBuilder.h +++ b/src/gpu/gl/builders/GrGLProgramBuilder.h @@ -14,6 +14,7 @@ #include "../GrGLProgramDataManager.h" #include "../GrGLUniformHandle.h" #include "../GrGLGeometryProcessor.h" +#include "../GrGLXferProcessor.h" #include "../../GrOptDrawState.h" #include "../../GrPendingFragmentStage.h" @@ -111,6 +112,7 @@ private: friend class GrGLVertexBuilder; friend class GrGLGeometryBuilder; + friend class GrGLXferBuilder; friend class GrGLFragmentShaderBuilder; }; @@ -170,8 +172,18 @@ public: */ }; +/* a specializations for XPs. Lets the user add uniforms and FS code */ +class GrGLXPBuilder : public virtual GrGLUniformBuilder { +public: + virtual GrGLFPFragmentBuilder* getFragmentShaderBuilder() = 0; + + /* + * *NOTE* NO MEMBERS ALLOWED, MULTIPLE INHERITANCE + */ +}; struct GrGLInstalledProc; struct GrGLInstalledGeoProc; +struct GrGLInstalledXferProc; struct GrGLInstalledFragProc; struct GrGLInstalledFragProcs; @@ -183,7 +195,8 @@ struct GrGLInstalledFragProcs; * respective builders */ class GrGLProgramBuilder : public GrGLGPBuilder, - public GrGLFPBuilder { + public GrGLFPBuilder, + public GrGLXPBuilder { public: /** Generates a shader program. * @@ -283,8 +296,12 @@ protected: void emitAndInstallProc(const GrGeometryProcessor&, const char* outColor, const char* outCoverage); + void emitAndInstallXferProc(const GrXferProcessor&, + const GrGLSLExpr4& colorIn, + const GrGLSLExpr4& coverageIn); void verify(const GrGeometryProcessor&); + void verify(const GrXferProcessor&); void verify(const GrFragmentProcessor&); void emitSamplers(const GrProcessor&, GrGLProcessor::TextureSamplerArray* outSamplers, @@ -358,6 +375,7 @@ protected: int fStageIndex; GrGLInstalledGeoProc* fGeometryProcessor; + GrGLInstalledXferProc* fXferProcessor; SkAutoTUnref<GrGLInstalledFragProcs> fFragmentProcessors; const GrOptDrawState& fOptState; @@ -391,6 +409,10 @@ struct GrGLInstalledGeoProc : public GrGLInstalledProc { SkAutoTDelete<GrGLGeometryProcessor> fGLProc; }; +struct GrGLInstalledXferProc : public GrGLInstalledProc { + SkAutoTDelete<GrGLXferProcessor> fGLProc; +}; + struct GrGLInstalledFragProc : public GrGLInstalledProc { GrGLInstalledFragProc() : fGLProc(NULL) {} class ShaderVarHandle { |