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:

Committed: https://skia.googlesource.com/skia/+/4dffc940c430eec66d4707490eace19c9b3f7904

Review URL: https://codereview.chromium.org/764643004
This commit is contained in:
egdaniel 2014-12-11 13:15:13 -08:00 committed by Commit bot
parent 8c508b4413
commit c230414861
25 changed files with 476 additions and 264 deletions

View File

@ -51,6 +51,14 @@ imagemagnifier
#reed
modecolorfilters
#egdaniel
xfermodes
xfermodes2
xfermodes3
mixed_xfermodes
lumafilter
xfermodeimagefilter
#humper skia:2049
dashcubics

View File

@ -149,6 +149,14 @@ private:
const GrDrawTargetCaps&, \
GrTexture* dummyTextures[2])
#define GR_DECLARE_XP_FACTORY_TEST \
static GrProcessorTestFactory<GrXPFactory> gTestFactory SK_UNUSED; \
static GrXPFactory* TestCreate(SkRandom*, \
GrContext*, \
const GrDrawTargetCaps&, \
GrTexture* dummyTextures[2])
/** GrProcessor subclasses should insert this macro in their implementation file. They must then
* also implement this static function:
* GrProcessor* TestCreate(SkRandom*,
@ -163,6 +171,9 @@ private:
#define GR_DEFINE_FRAGMENT_PROCESSOR_TEST(Effect) \
GrProcessorTestFactory<GrFragmentProcessor> Effect :: gTestFactory(Effect :: TestCreate)
#define GR_DEFINE_XP_FACTORY_TEST(Factory) \
GrProcessorTestFactory<GrXPFactory> Factory :: gTestFactory(Factory :: TestCreate)
#define GR_DEFINE_GEOMETRY_PROCESSOR_TEST(Effect) \
GrProcessorTestFactory<GrGeometryProcessor> Effect :: gTestFactory(Effect :: TestCreate)
@ -172,18 +183,27 @@ private:
// its definitions will compile.
#define GR_DECLARE_FRAGMENT_PROCESSOR_TEST \
static GrFragmentProcessor* TestCreate(SkRandom*, \
GrContext*, \
const GrDrawTargetCaps&, \
GrTexture* dummyTextures[2])
GrContext*, \
const GrDrawTargetCaps&, \
GrTexture* dummyTextures[2])
#define GR_DEFINE_FRAGMENT_PROCESSOR_TEST(X)
// The unit test relies on static initializers. Just declare the TestCreate function so that
// its definitions will compile.
#define GR_DECLARE_XP_FACTORY_TEST \
static GrXPFactory* TestCreate(SkRandom*, \
GrContext*, \
const GrDrawTargetCaps&, \
GrTexture* dummyTextures[2])
#define GR_DEFINE_XP_FACTORY_TEST(X)
// The unit test relies on static initializers. Just declare the TestCreate function so that
// its definitions will compile.
#define GR_DECLARE_GEOMETRY_PROCESSOR_TEST \
static GrGeometryProcessor* TestCreate(SkRandom*, \
GrContext*, \
const GrDrawTargetCaps&, \
GrTexture* dummyTextures[2])
GrContext*, \
const GrDrawTargetCaps&, \
GrTexture* dummyTextures[2])
#define GR_DEFINE_GEOMETRY_PROCESSOR_TEST(X)
#endif // !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS

View File

@ -9,10 +9,13 @@
#define GrXferProcessor_DEFINED
#include "GrColor.h"
#include "GrFragmentProcessor.h"
#include "GrProcessor.h"
#include "GrTypes.h"
#include "SkXfermode.h"
class GrDrawTargetCaps;
class GrGLCaps;
class GrGLXferProcessor;
class GrProcOptInfo;
/**
@ -28,8 +31,20 @@ class GrProcOptInfo;
* A GrXferProcessor is never installed directly into our draw state, but instead is created from a
* GrXPFactory once we have finalized the state of our draw.
*/
class GrXferProcessor : public GrFragmentProcessor {
class GrXferProcessor : public GrProcessor {
public:
/**
* Sets a unique key on the GrProcessorKeyBuilder that is directly associated with this xfer
* processor's GL backend implementation.
*/
virtual void getGLProcessorKey(const GrGLCaps& caps,
GrProcessorKeyBuilder* b) const = 0;
/** Returns a new instance of the appropriate *GL* implementation class
for the given GrXferProcessor; caller is responsible for deleting
the object. */
virtual GrGLXferProcessor* createGLInstance() const = 0;
/**
* Optimizations for blending / coverage that an OptDrawState should apply to itself.
*/
@ -74,7 +89,8 @@ public:
bool colorWriteDisabled,
bool doesStencilWrite,
GrColor* color,
uint8_t* coverage) = 0;
uint8_t* coverage,
const GrDrawTargetCaps& caps) = 0;
struct BlendInfo {
GrBlendCoeff fSrcBlend;
@ -87,6 +103,27 @@ public:
/** Will this prceossor read the destination pixel value? */
bool willReadDstColor() const { return fWillReadDstColor; }
/**
* Returns whether or not this xferProcossor will set a secondary output to be used with dual
* source blending.
*/
virtual bool hasSecondaryOutput() const { return false; }
/** Returns true if this and other processor conservatively draw identically. It can only return
true when the two processor are of the same subclass (i.e. they return the same object from
from getFactory()).
A return value of true from isEqual() should not be used to test whether the processor would
generate the same shader code. To test for identical code generation use getGLProcessorKey*/
bool isEqual(const GrXferProcessor& that) const {
if (this->classID() != that.classID()) {
return false;
}
return this->onIsEqual(that);
}
protected:
GrXferProcessor() : fWillReadDstColor(false) {}
@ -98,6 +135,7 @@ protected:
void setWillReadDstColor() { fWillReadDstColor = true; }
private:
virtual bool onIsEqual(const GrXferProcessor&) const = 0;
bool fWillReadDstColor;

View File

@ -26,20 +26,53 @@ public:
virtual const char* name() const { return "Porter Duff"; }
virtual void getGLProcessorKey(const GrGLCaps& caps,
GrProcessorKeyBuilder* b) const SK_OVERRIDE;
void getGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const SK_OVERRIDE;
virtual GrGLFragmentProcessor* createGLInstance() const SK_OVERRIDE;
GrGLXferProcessor* createGLInstance() const SK_OVERRIDE;
virtual GrXferProcessor::OptFlags getOptimizations(const GrProcOptInfo& colorPOI,
const GrProcOptInfo& coveragePOI,
bool isCoverageDrawing,
bool colorWriteDisabled,
bool doesStencilWrite,
GrColor* color,
uint8_t* coverage) SK_OVERRIDE;
virtual bool hasSecondaryOutput() const SK_OVERRIDE;
virtual void getBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const SK_OVERRIDE {
///////////////////////////////////////////////////////////////////////////
/// @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,
};
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,
};
PrimaryOutputType primaryOutputType() const { return fPrimaryOutputType; }
SecondaryOutputType secondaryOutputType() const { return fSecondaryOutputType; }
GrXferProcessor::OptFlags getOptimizations(const GrProcOptInfo& colorPOI,
const GrProcOptInfo& coveragePOI,
bool isCoverageDrawing,
bool colorWriteDisabled,
bool doesStencilWrite,
GrColor* color,
uint8_t* coverage,
const GrDrawTargetCaps& caps) SK_OVERRIDE;
void getBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const SK_OVERRIDE {
blendInfo->fSrcBlend = fSrcBlend;
blendInfo->fDstBlend = fDstBlend;
blendInfo->fBlendConstant = fBlendConstant;
@ -48,21 +81,36 @@ public:
private:
GrPorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, GrColor constant);
virtual bool onIsEqual(const GrFragmentProcessor& fpBase) const SK_OVERRIDE {
const GrPorterDuffXferProcessor& xp = fpBase.cast<GrPorterDuffXferProcessor>();
bool onIsEqual(const GrXferProcessor& xpBase) const SK_OVERRIDE {
const GrPorterDuffXferProcessor& xp = xpBase.cast<GrPorterDuffXferProcessor>();
if (fSrcBlend != xp.fSrcBlend ||
fDstBlend != xp.fDstBlend ||
fBlendConstant != xp.fBlendConstant) {
fBlendConstant != xp.fBlendConstant ||
fPrimaryOutputType != xp.fPrimaryOutputType ||
fSecondaryOutputType != xp.fSecondaryOutputType) {
return false;
}
return true;
}
virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE;
void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE;
GrXferProcessor::OptFlags internalGetOptimizations(const GrProcOptInfo& colorPOI,
const GrProcOptInfo& coveragePOI,
bool isCoverageDrawing,
bool colorWriteDisabled,
bool doesStencilWrite,
GrColor* color,
uint8_t* coverage);
void calcOutputTypes(GrXferProcessor::OptFlags blendOpts, const GrDrawTargetCaps& caps,
bool hasSolidCoverage, bool readDst);
GrBlendCoeff fSrcBlend;
GrBlendCoeff fDstBlend;
GrColor fBlendConstant;
PrimaryOutputType fPrimaryOutputType;
SecondaryOutputType fSecondaryOutputType;
typedef GrXferProcessor INHERITED;
};
@ -107,6 +155,8 @@ private:
return (fSrcCoeff == xpf.fSrcCoeff && fDstCoeff == xpf.fDstCoeff);
}
GR_DECLARE_XP_FACTORY_TEST;
GrBlendCoeff fSrcCoeff;
GrBlendCoeff fDstCoeff;

View File

@ -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;

View File

@ -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
@ -56,9 +57,6 @@ GrOptDrawState::GrOptDrawState(const GrDrawState& drawState,
// indicate that this can be skipped.
fFlags = 0;
fDrawFace = GrDrawState::kInvalid_DrawFace;
fSrcBlend = kZero_GrBlendCoeff;
fDstBlend = kZero_GrBlendCoeff;
fBlendConstant = 0x0;
fViewMatrix.reset();
return;
}
@ -108,9 +106,6 @@ GrOptDrawState::GrOptDrawState(const GrDrawState& drawState,
GrXferProcessor::BlendInfo blendInfo;
fXferProcessor->getBlendInfo(&blendInfo);
fSrcBlend = blendInfo.fSrcBlend;
fDstBlend = blendInfo.fDstBlend;
fBlendConstant = blendInfo.fBlendConstant;
this->adjustProgramFromOptimizations(drawState, optFlags, colorPOI, coveragePOI,
&firstColorStageIdx, &firstCoverageStageIdx);
@ -146,42 +141,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,
@ -237,10 +196,7 @@ bool GrOptDrawState::operator== (const GrOptDrawState& that) const {
this->fNumColorStages != that.fNumColorStages ||
this->fScissorState != that.fScissorState ||
!this->fViewMatrix.cheapEqualTo(that.fViewMatrix) ||
this->fSrcBlend != that.fSrcBlend ||
this->fDstBlend != that.fDstBlend ||
this->fDrawType != that.fDrawType ||
this->fBlendConstant != that.fBlendConstant ||
this->fFlags != that.fFlags ||
this->fStencilSettings != that.fStencilSettings ||
this->fDrawFace != that.fDrawFace ||
@ -262,6 +218,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++) {

View File

@ -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()); }
@ -102,21 +103,6 @@ public:
/// @}
///////////////////////////////////////////////////////////////////////////
/// @name Blending
////
GrBlendCoeff getSrcBlendCoeff() const { return fSrcBlend; }
GrBlendCoeff getDstBlendCoeff() const { return fDstBlend; }
/**
* Retrieves the last value set by setBlendConstant()
* @return the blending constant value
*/
GrColor getBlendConstant() const { return fBlendConstant; }
/// @}
///////////////////////////////////////////////////////////////////////////
/// @name View Matrix
////
@ -223,13 +209,10 @@ private:
ScissorState fScissorState;
GrColor fColor;
SkMatrix fViewMatrix;
GrColor fBlendConstant;
GrStencilSettings fStencilSettings;
uint8_t fCoverage;
GrDrawState::DrawFace fDrawFace;
GrDeviceCoordTexture fDstCopy;
GrBlendCoeff fSrcBlend;
GrBlendCoeff fDstBlend;
uint32_t fFlags;
ProgramGeometryProcessor fGeometryProcessor;
GrBatchTracker fBatchTracker;

View File

@ -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!");
}
}

View File

@ -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:

View File

@ -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,45 @@ 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);
if (GrPorterDuffXferProcessor::kCombineWithDst_PrimaryOutputType == xp.primaryOutputType()){
fsBuilder->codeAppendf("%s += (vec4(1.0) - %s) * %s;", args.fOutputPrimary,
args.fInputCoverage, fsBuilder->dstColor());
}
}
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.primaryOutputType());
b->add32(xp.secondaryOutputType());
};
private:
typedef GrGLXferProcessor INHERITED;
@ -64,7 +91,11 @@ private:
GrPorterDuffXferProcessor::GrPorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend,
GrColor constant)
: fSrcBlend(srcBlend), fDstBlend(dstBlend), fBlendConstant(constant) {
: fSrcBlend(srcBlend)
, fDstBlend(dstBlend)
, fBlendConstant(constant)
, fPrimaryOutputType(kModulate_PrimaryOutputType)
, fSecondaryOutputType(kNone_SecondaryOutputType) {
this->initClassID<GrPorterDuffXferProcessor>();
}
@ -76,7 +107,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 +121,58 @@ 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 || coveragePOI.isSolidWhite(),
colorPOI.readsDst() || coveragePOI.readsDst());
return optFlags;
}
void GrPorterDuffXferProcessor::calcOutputTypes(GrXferProcessor::OptFlags optFlags,
const GrDrawTargetCaps& caps,
bool hasSolidCoverage, 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) && !hasSolidCoverage) {
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;
}
} else if (readsDst &&
kOne_GrBlendCoeff == fSrcBlend &&
kZero_GrBlendCoeff == fDstBlend) {
fPrimaryOutputType = kCombineWithDst_PrimaryOutputType;
}
}
}
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 +274,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 +537,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);
}

View File

@ -117,14 +117,4 @@ private:
typedef GrGLProcessor INHERITED;
};
class GrGLXferProcessor : public GrGLFragmentProcessor {
public:
GrGLXferProcessor() {}
virtual ~GrGLXferProcessor() {}
private:
typedef GrGLFragmentProcessor INHERITED;
};
#endif

View File

@ -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) {
}

View File

@ -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&,

View File

@ -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();

View File

@ -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

View File

@ -1919,10 +1919,14 @@ void GrGpuGL::flushAAState(const GrOptDrawState& optState) {
}
}
void GrGpuGL::flushBlend(const GrOptDrawState& optState, bool isLines,
GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
void GrGpuGL::flushBlend(const GrOptDrawState& optState) {
// Any optimization to disable blending should have already been applied and
// tweaked the coeffs to (1, 0).
GrXferProcessor::BlendInfo blendInfo;
optState.getXferProcessor()->getBlendInfo(&blendInfo);
GrBlendCoeff srcCoeff = blendInfo.fSrcBlend;
GrBlendCoeff dstCoeff = blendInfo.fDstBlend;
bool blendOff = kOne_GrBlendCoeff == srcCoeff && kZero_GrBlendCoeff == dstCoeff;
if (blendOff) {
if (kNo_TriState != fHWBlendState.fEnabled) {
@ -1941,7 +1945,7 @@ void GrGpuGL::flushBlend(const GrOptDrawState& optState, bool isLines,
fHWBlendState.fSrcCoeff = srcCoeff;
fHWBlendState.fDstCoeff = dstCoeff;
}
GrColor blendConst = optState.getBlendConstant();
GrColor blendConst = blendInfo.fBlendConstant;
if ((BlendCoeffReferencesConstant(srcCoeff) ||
BlendCoeffReferencesConstant(dstCoeff)) &&
(!fHWBlendState.fConstColorValid ||

View File

@ -172,11 +172,7 @@ private:
size_t* indexOffsetInBytes);
// Subclasses should call this to flush the blend state.
// The params should be the final coefficients to apply
// (after any blending optimizations or dual source blending considerations
// have been accounted for).
void flushBlend(const GrOptDrawState& optState, bool isLines,
GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff);
void flushBlend(const GrOptDrawState& optState);
bool hasExtension(const char* ext) const { return fGLContext.hasExtension(ext); }

View File

@ -213,9 +213,6 @@ bool GrGpuGL::flushGraphicsState(const GrOptDrawState& optState) {
} else {
this->flushMiscFixedFunctionState(optState);
GrBlendCoeff srcCoeff = optState.getSrcBlendCoeff();
GrBlendCoeff dstCoeff = optState.getDstBlendCoeff();
fCurrentProgram.reset(fProgramCache->getProgram(optState));
if (NULL == fCurrentProgram.get()) {
SkDEBUGFAIL("Failed to create program!");
@ -230,7 +227,7 @@ bool GrGpuGL::flushGraphicsState(const GrOptDrawState& optState) {
fHWProgramID = programID;
}
this->flushBlend(optState, kDrawLines_DrawType == optState.drawType(), srcCoeff, dstCoeff);
this->flushBlend(optState);
fCurrentProgram->setData(optState);
}

View File

@ -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();

View File

@ -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);

View File

@ -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));
}

View File

@ -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));
}

View File

@ -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)
@ -260,6 +254,8 @@ void GrGLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr
if (fOptState.hasGeometryProcessor()) {
fVS.transformToNormalizedDeviceSpace();
}
this->emitAndInstallXferProc(*fOptState.getXferProcessor(), *inputColor, *inputCoverage);
}
void GrGLProgramBuilder::emitAndInstallFragProcs(int procOffset,
@ -368,10 +364,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());
@ -543,7 +584,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()));
}
///////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -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 {

View File

@ -121,6 +121,14 @@ static GrRenderTarget* random_render_target(GrContext* context,
return SkRef(texture->asRenderTarget());
}
static void set_random_xpf(GrContext* context, const GrDrawTargetCaps& caps, GrDrawState* ds,
SkRandom* random, GrTexture* dummyTextures[]) {
SkAutoTUnref<const GrXPFactory> xpf(
GrProcessorTestFactory<GrXPFactory>::CreateStage(random, context, caps, dummyTextures));
SkASSERT(xpf);
ds->setXPFactory(xpf.get());
}
static void set_random_gp(GrContext* context,
const GrDrawTargetCaps& caps,
GrDrawState* ds,
@ -195,22 +203,6 @@ static void set_random_state(GrDrawState* ds, SkRandom* random) {
ds->enableState(state);
}
// this function will randomly pick non-self referencing blend modes
static void set_random_blend_func(GrDrawState* ds, SkRandom* random) {
GrBlendCoeff src;
do {
src = GrBlendCoeff(random->nextRangeU(kFirstPublicGrBlendCoeff, kLastPublicGrBlendCoeff));
} while (GrBlendCoeffRefsSrc(src));
GrBlendCoeff dst;
do {
dst = GrBlendCoeff(random->nextRangeU(kFirstPublicGrBlendCoeff, kLastPublicGrBlendCoeff));
} while (GrBlendCoeffRefsDst(dst));
GrXPFactory* xpFactory = GrPorterDuffXPFactory::Create(src, dst);
ds->setXPFactory(xpFactory)->unref();
}
// right now, the only thing we seem to care about in drawState's stencil is 'doesWrite()'
static void set_random_stencil(GrDrawState* ds, SkRandom* random) {
GR_STATIC_CONST_SAME_STENCIL(kDoesWriteStencil,
@ -310,9 +302,12 @@ bool GrDrawTarget::programUnitTest(int maxStages) {
usePathRendering,
&random,
dummyTextures);
// creates a random xfer processor factory on the draw state
set_random_xpf(fContext, gpu->glCaps(), &ds, &random, dummyTextures);
set_random_hints(&ds, &random);
set_random_state(&ds, &random);
set_random_blend_func(&ds, &random);
set_random_stencil(&ds, &random);
GrDeviceCoordTexture dstCopy;