aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
authorGravatar egdaniel <egdaniel@google.com>2014-12-10 07:43:49 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2014-12-10 07:43:50 -0800
commit4dffc940c430eec66d4707490eace19c9b3f7904 (patch)
treecce5e8c525a5acec67c4398c95c165223320d679 /src/gpu
parent28828d00b20d90b6caf91e4b0b31e80acadf2d57 (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.h5
-rw-r--r--src/gpu/GrOptDrawState.cpp43
-rw-r--r--src/gpu/GrOptDrawState.h3
-rw-r--r--src/gpu/GrProcessor.cpp12
-rw-r--r--src/gpu/GrProgramDesc.h41
-rw-r--r--src/gpu/effects/GrPorterDuffXferProcessor.cpp123
-rw-r--r--src/gpu/gl/GrGLProcessor.h10
-rw-r--r--src/gpu/gl/GrGLProgram.cpp23
-rw-r--r--src/gpu/gl/GrGLProgram.h7
-rw-r--r--src/gpu/gl/GrGLProgramDesc.cpp15
-rw-r--r--src/gpu/gl/GrGLXferProcessor.h61
-rw-r--r--src/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp49
-rw-r--r--src/gpu/gl/builders/GrGLFragmentShaderBuilder.h2
-rw-r--r--src/gpu/gl/builders/GrGLLegacyNvprProgramBuilder.cpp3
-rw-r--r--src/gpu/gl/builders/GrGLNvprProgramBuilder.cpp3
-rw-r--r--src/gpu/gl/builders/GrGLProgramBuilder.cpp65
-rw-r--r--src/gpu/gl/builders/GrGLProgramBuilder.h24
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 {