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:
parent
8c508b4413
commit
c230414861
@ -51,6 +51,14 @@ imagemagnifier
|
||||
#reed
|
||||
modecolorfilters
|
||||
|
||||
#egdaniel
|
||||
xfermodes
|
||||
xfermodes2
|
||||
xfermodes3
|
||||
mixed_xfermodes
|
||||
lumafilter
|
||||
xfermodeimagefilter
|
||||
|
||||
#humper skia:2049
|
||||
dashcubics
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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++) {
|
||||
|
@ -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;
|
||||
|
@ -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!");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -117,14 +117,4 @@ private:
|
||||
typedef GrGLProcessor INHERITED;
|
||||
};
|
||||
|
||||
class GrGLXferProcessor : public GrGLFragmentProcessor {
|
||||
public:
|
||||
GrGLXferProcessor() {}
|
||||
|
||||
virtual ~GrGLXferProcessor() {}
|
||||
|
||||
private:
|
||||
typedef GrGLFragmentProcessor INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -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) {
|
||||
}
|
||||
|
||||
|
@ -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&,
|
||||
|
@ -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();
|
||||
|
61
src/gpu/gl/GrGLXferProcessor.h
Normal file
61
src/gpu/gl/GrGLXferProcessor.h
Normal 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
|
@ -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 ||
|
||||
|
@ -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); }
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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()));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user