Implement support for KHR_blend_equation_advanced
Uses KHR(or NV)_blend_equation_advanced to implement custom Xfer modes in hardware. BUG=skia: Review URL: https://codereview.chromium.org/1037123003
This commit is contained in:
parent
e0cab96599
commit
8917d62ef4
@ -19,6 +19,43 @@ class GrGLSLCaps;
|
||||
class GrGLXferProcessor;
|
||||
class GrProcOptInfo;
|
||||
|
||||
/**
|
||||
* Equations for alpha-blending.
|
||||
*/
|
||||
enum GrBlendEquation {
|
||||
kInvalid_GrBlendEquation = -1,
|
||||
|
||||
// Basic blend equations.
|
||||
kAdd_GrBlendEquation, //<! Cs*S + Cd*D
|
||||
kSubtract_GrBlendEquation, //<! Cs*S - Cd*D
|
||||
kReverseSubtract_GrBlendEquation, //<! Cd*D - Cs*S
|
||||
|
||||
// Advanced blend equations. These are described in the SVG and PDF specs.
|
||||
kScreen_GrBlendEquation,
|
||||
kOverlay_GrBlendEquation,
|
||||
kDarken_GrBlendEquation,
|
||||
kLighten_GrBlendEquation,
|
||||
kColorDodge_GrBlendEquation,
|
||||
kColorBurn_GrBlendEquation,
|
||||
kHardLight_GrBlendEquation,
|
||||
kSoftLight_GrBlendEquation,
|
||||
kDifference_GrBlendEquation,
|
||||
kExclusion_GrBlendEquation,
|
||||
kMultiply_GrBlendEquation,
|
||||
kHSLHue_GrBlendEquation,
|
||||
kHSLSaturation_GrBlendEquation,
|
||||
kHSLColor_GrBlendEquation,
|
||||
kHSLLuminosity_GrBlendEquation,
|
||||
|
||||
kTotalGrBlendEquationCount,
|
||||
|
||||
kFirstAdvancedGrBlendEquation = kScreen_GrBlendEquation
|
||||
};
|
||||
|
||||
inline bool GrBlendEquationIsAdvanced(GrBlendEquation equation) {
|
||||
return equation >= kFirstAdvancedGrBlendEquation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Coeffecients for alpha-blending.
|
||||
*/
|
||||
@ -53,6 +90,7 @@ enum GrBlendCoeff {
|
||||
*/
|
||||
enum GrXferBarrierType {
|
||||
kTexture_GrXferBarrierType, //<! Required when a shader reads and renders to the same texture.
|
||||
kBlend_GrXferBarrierType, //<! Required by certain blend extensions.
|
||||
};
|
||||
|
||||
/**
|
||||
@ -142,16 +180,18 @@ public:
|
||||
|
||||
struct BlendInfo {
|
||||
void reset() {
|
||||
fEquation = kAdd_GrBlendEquation;
|
||||
fSrcBlend = kOne_GrBlendCoeff;
|
||||
fDstBlend = kZero_GrBlendCoeff;
|
||||
fBlendConstant = 0;
|
||||
fWriteColor = true;
|
||||
}
|
||||
|
||||
GrBlendCoeff fSrcBlend;
|
||||
GrBlendCoeff fDstBlend;
|
||||
GrColor fBlendConstant;
|
||||
bool fWriteColor;
|
||||
GrBlendEquation fEquation;
|
||||
GrBlendCoeff fSrcBlend;
|
||||
GrBlendCoeff fDstBlend;
|
||||
GrColor fBlendConstant;
|
||||
bool fWriteColor;
|
||||
};
|
||||
|
||||
void getBlendInfo(BlendInfo* blendInfo) const {
|
||||
@ -218,6 +258,16 @@ private:
|
||||
virtual void onGetGLProcessorKey(const GrGLSLCaps& caps,
|
||||
GrProcessorKeyBuilder* b) const = 0;
|
||||
|
||||
/**
|
||||
* If not using a texture barrier, retrieves whether the subclass will require a different type
|
||||
* of barrier.
|
||||
*/
|
||||
virtual bool onWillNeedXferBarrier(const GrRenderTarget*,
|
||||
const GrDrawTargetCaps&,
|
||||
GrXferBarrierType* outBarrierType SK_UNUSED) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the hardware blend state required by this Xfer processor. The BlendInfo struct
|
||||
* comes initialized to default values, so the Xfer processor only needs to set the state it
|
||||
|
@ -638,6 +638,7 @@ void GrDrawTargetCaps::reset() {
|
||||
|
||||
fUseDrawInsteadOfClear = false;
|
||||
|
||||
fBlendEquationSupport = kBasic_BlendEquationSupport;
|
||||
fMapBufferFlags = kNone_MapFlags;
|
||||
|
||||
fMaxRenderTargetSize = 0;
|
||||
@ -662,6 +663,7 @@ GrDrawTargetCaps& GrDrawTargetCaps::operator=(const GrDrawTargetCaps& other) {
|
||||
|
||||
fUseDrawInsteadOfClear = other.fUseDrawInsteadOfClear;
|
||||
|
||||
fBlendEquationSupport = other.fBlendEquationSupport;
|
||||
fMapBufferFlags = other.fMapBufferFlags;
|
||||
|
||||
fMaxRenderTargetSize = other.fMaxRenderTargetSize;
|
||||
@ -713,6 +715,18 @@ SkString GrDrawTargetCaps::dump() const {
|
||||
r.appendf("Max Render Target Size : %d\n", fMaxRenderTargetSize);
|
||||
r.appendf("Max Sample Count : %d\n", fMaxSampleCount);
|
||||
|
||||
static const char* kBlendEquationSupportNames[] = {
|
||||
"Basic",
|
||||
"Advanced",
|
||||
"Advanced Coherent",
|
||||
};
|
||||
GR_STATIC_ASSERT(0 == kBasic_BlendEquationSupport);
|
||||
GR_STATIC_ASSERT(1 == kAdvanced_BlendEquationSupport);
|
||||
GR_STATIC_ASSERT(2 == kAdvancedCoherent_BlendEquationSupport);
|
||||
GR_STATIC_ASSERT(SK_ARRAY_COUNT(kBlendEquationSupportNames) == kLast_BlendEquationSupport + 1);
|
||||
|
||||
r.appendf("Blend Equation Support : %s\n",
|
||||
kBlendEquationSupportNames[fBlendEquationSupport]);
|
||||
r.appendf("Map Buffer Support : %s\n",
|
||||
map_flags_to_string(fMapBufferFlags).c_str());
|
||||
|
||||
|
@ -141,6 +141,30 @@ public:
|
||||
|
||||
bool useDrawInsteadOfClear() const { return fUseDrawInsteadOfClear; }
|
||||
|
||||
/**
|
||||
* Indicates the capabilities of the fixed function blend unit.
|
||||
*/
|
||||
enum BlendEquationSupport {
|
||||
kBasic_BlendEquationSupport, //<! Support to select the operator that
|
||||
// combines src and dst terms.
|
||||
kAdvanced_BlendEquationSupport, //<! Additional fixed function support for specific
|
||||
// SVG/PDF blend modes. Requires blend barriers.
|
||||
kAdvancedCoherent_BlendEquationSupport, //<! Advanced blend equation support that does not
|
||||
// require blend barriers, and permits overlap.
|
||||
|
||||
kLast_BlendEquationSupport = kAdvancedCoherent_BlendEquationSupport
|
||||
};
|
||||
|
||||
BlendEquationSupport blendEquationSupport() const { return fBlendEquationSupport; }
|
||||
|
||||
bool advancedBlendEquationSupport() const {
|
||||
return fBlendEquationSupport >= kAdvanced_BlendEquationSupport;
|
||||
}
|
||||
|
||||
bool advancedCoherentBlendEquationSupport() const {
|
||||
return kAdvancedCoherent_BlendEquationSupport == fBlendEquationSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether GPU->CPU memory mapping for GPU resources such as vertex buffers and
|
||||
* textures allows partial mappings or full mappings.
|
||||
@ -192,6 +216,7 @@ protected:
|
||||
// Driver workaround
|
||||
bool fUseDrawInsteadOfClear : 1;
|
||||
|
||||
BlendEquationSupport fBlendEquationSupport;
|
||||
uint32_t fMapBufferFlags;
|
||||
|
||||
int fMaxRenderTargetSize;
|
||||
|
@ -42,7 +42,7 @@ bool GrXferProcessor::willNeedXferBarrier(const GrRenderTarget* rt,
|
||||
*outBarrierType = kTexture_GrXferBarrierType;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return this->onWillNeedXferBarrier(rt, caps, outBarrierType);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "GrTextureAccess.h"
|
||||
#include "SkXfermode.h"
|
||||
#include "gl/GrGLCaps.h"
|
||||
#include "gl/GrGLGpu.h"
|
||||
#include "gl/GrGLProcessor.h"
|
||||
#include "gl/GrGLProgramDataManager.h"
|
||||
#include "gl/builders/GrGLProgramBuilder.h"
|
||||
@ -29,6 +30,27 @@ bool GrCustomXfermode::IsSupportedMode(SkXfermode::Mode mode) {
|
||||
// Static helpers
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static GrBlendEquation hw_blend_equation(SkXfermode::Mode mode) {
|
||||
enum { kOffset = kOverlay_GrBlendEquation - SkXfermode::kOverlay_Mode };
|
||||
return static_cast<GrBlendEquation>(mode + kOffset);
|
||||
|
||||
GR_STATIC_ASSERT(kOverlay_GrBlendEquation == SkXfermode::kOverlay_Mode + kOffset);
|
||||
GR_STATIC_ASSERT(kDarken_GrBlendEquation == SkXfermode::kDarken_Mode + kOffset);
|
||||
GR_STATIC_ASSERT(kLighten_GrBlendEquation == SkXfermode::kLighten_Mode + kOffset);
|
||||
GR_STATIC_ASSERT(kColorDodge_GrBlendEquation == SkXfermode::kColorDodge_Mode + kOffset);
|
||||
GR_STATIC_ASSERT(kColorBurn_GrBlendEquation == SkXfermode::kColorBurn_Mode + kOffset);
|
||||
GR_STATIC_ASSERT(kHardLight_GrBlendEquation == SkXfermode::kHardLight_Mode + kOffset);
|
||||
GR_STATIC_ASSERT(kSoftLight_GrBlendEquation == SkXfermode::kSoftLight_Mode + kOffset);
|
||||
GR_STATIC_ASSERT(kDifference_GrBlendEquation == SkXfermode::kDifference_Mode + kOffset);
|
||||
GR_STATIC_ASSERT(kExclusion_GrBlendEquation == SkXfermode::kExclusion_Mode + kOffset);
|
||||
GR_STATIC_ASSERT(kMultiply_GrBlendEquation == SkXfermode::kMultiply_Mode + kOffset);
|
||||
GR_STATIC_ASSERT(kHSLHue_GrBlendEquation == SkXfermode::kHue_Mode + kOffset);
|
||||
GR_STATIC_ASSERT(kHSLSaturation_GrBlendEquation == SkXfermode::kSaturation_Mode + kOffset);
|
||||
GR_STATIC_ASSERT(kHSLColor_GrBlendEquation == SkXfermode::kColor_Mode + kOffset);
|
||||
GR_STATIC_ASSERT(kHSLLuminosity_GrBlendEquation == SkXfermode::kLuminosity_Mode + kOffset);
|
||||
GR_STATIC_ASSERT(kTotalGrBlendEquationCount == SkXfermode::kLastMode + 1 + kOffset);
|
||||
}
|
||||
|
||||
static void hard_light(GrGLFragmentBuilder* fsBuilder,
|
||||
const char* final,
|
||||
const char* src,
|
||||
@ -510,15 +532,30 @@ public:
|
||||
const GrDrawTargetCaps& caps) override;
|
||||
|
||||
SkXfermode::Mode mode() const { return fMode; }
|
||||
bool hasCoverage() const { return fHasCoverage; }
|
||||
bool hasHWBlendEquation() const { return kInvalid_GrBlendEquation != fHWBlendEquation; }
|
||||
|
||||
GrBlendEquation hwBlendEquation() const {
|
||||
SkASSERT(this->hasHWBlendEquation());
|
||||
return fHWBlendEquation;
|
||||
}
|
||||
|
||||
private:
|
||||
CustomXP(SkXfermode::Mode mode, const GrDeviceCoordTexture* dstCopy, bool willReadDstColor);
|
||||
|
||||
void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
|
||||
|
||||
bool onWillNeedXferBarrier(const GrRenderTarget* rt,
|
||||
const GrDrawTargetCaps& caps,
|
||||
GrXferBarrierType* outBarrierType) const override;
|
||||
|
||||
void onGetBlendInfo(BlendInfo*) const override;
|
||||
|
||||
bool onIsEqual(const GrXferProcessor& xpBase) const override;
|
||||
|
||||
SkXfermode::Mode fMode;
|
||||
bool fHasCoverage;
|
||||
GrBlendEquation fHWBlendEquation;
|
||||
|
||||
typedef GrXferProcessor INHERITED;
|
||||
};
|
||||
@ -540,24 +577,48 @@ public:
|
||||
GLCustomXP(const GrXferProcessor&) {}
|
||||
~GLCustomXP() override {}
|
||||
|
||||
static void GenKey(const GrXferProcessor& proc, const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
|
||||
uint32_t key = proc.numTextures();
|
||||
static void GenKey(const GrXferProcessor& p, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) {
|
||||
const CustomXP& xp = p.cast<CustomXP>();
|
||||
uint32_t key = xp.numTextures();
|
||||
SkASSERT(key <= 1);
|
||||
key |= proc.cast<CustomXP>().mode() << 1;
|
||||
key |= xp.hasCoverage() << 1;
|
||||
if (xp.hasHWBlendEquation()) {
|
||||
SkASSERT(caps.advBlendEqInteraction() > 0); // 0 will mean !xp.hasHWBlendEquation().
|
||||
key |= caps.advBlendEqInteraction() << 2;
|
||||
}
|
||||
if (!xp.hasHWBlendEquation() || caps.mustEnableSpecificAdvBlendEqs()) {
|
||||
GR_STATIC_ASSERT(GrGLSLCaps::kLast_AdvBlendEqInteraction < 4);
|
||||
key |= xp.mode() << 4;
|
||||
}
|
||||
b->add32(key);
|
||||
}
|
||||
|
||||
private:
|
||||
void onEmitCode(const EmitArgs& args) override {
|
||||
SkXfermode::Mode mode = args.fXP.cast<CustomXP>().mode();
|
||||
const CustomXP& xp = args.fXP.cast<CustomXP>();
|
||||
GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
|
||||
const char* dstColor = fsBuilder->dstColor();
|
||||
|
||||
emit_custom_xfermode_code(mode, fsBuilder, args.fOutputPrimary, args.fInputColor, dstColor);
|
||||
|
||||
fsBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;",
|
||||
args.fOutputPrimary, args.fOutputPrimary, args.fInputCoverage,
|
||||
args.fInputCoverage, dstColor);
|
||||
if (xp.hasHWBlendEquation()) {
|
||||
// The blend mode will be implemented in hardware; only output the src color.
|
||||
fsBuilder->enableAdvancedBlendEquationIfNeeded(xp.hwBlendEquation());
|
||||
if (xp.hasCoverage()) {
|
||||
// Do coverage modulation by multiplying it into the src color before blending.
|
||||
// (See getOptimizations())
|
||||
fsBuilder->codeAppendf("%s = %s * %s;",
|
||||
args.fOutputPrimary, args.fInputCoverage, args.fInputColor);
|
||||
} else {
|
||||
fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputColor);
|
||||
}
|
||||
} else {
|
||||
const char* dstColor = fsBuilder->dstColor();
|
||||
emit_custom_xfermode_code(xp.mode(), fsBuilder, args.fOutputPrimary, args.fInputColor,
|
||||
dstColor);
|
||||
if (xp.hasCoverage()) {
|
||||
fsBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;",
|
||||
args.fOutputPrimary, args.fOutputPrimary,
|
||||
args.fInputCoverage, args.fInputCoverage, dstColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {}
|
||||
@ -569,7 +630,10 @@ private:
|
||||
|
||||
CustomXP::CustomXP(SkXfermode::Mode mode, const GrDeviceCoordTexture* dstCopy,
|
||||
bool willReadDstColor)
|
||||
: INHERITED(dstCopy, willReadDstColor), fMode(mode) {
|
||||
: INHERITED(dstCopy, willReadDstColor),
|
||||
fMode(mode),
|
||||
fHasCoverage(true),
|
||||
fHWBlendEquation(kInvalid_GrBlendEquation) {
|
||||
this->initClassID<CustomXP>();
|
||||
}
|
||||
|
||||
@ -578,12 +642,15 @@ void CustomXP::onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder
|
||||
}
|
||||
|
||||
GrGLXferProcessor* CustomXP::createGLInstance() const {
|
||||
SkASSERT(this->willReadDstColor() != this->hasHWBlendEquation());
|
||||
return SkNEW_ARGS(GLCustomXP, (*this));
|
||||
}
|
||||
|
||||
bool CustomXP::onIsEqual(const GrXferProcessor& other) const {
|
||||
const CustomXP& s = other.cast<CustomXP>();
|
||||
return fMode == s.fMode;
|
||||
return fMode == s.fMode &&
|
||||
fHasCoverage == s.fHasCoverage &&
|
||||
fHWBlendEquation == s.fHWBlendEquation;
|
||||
}
|
||||
|
||||
GrXferProcessor::OptFlags CustomXP::getOptimizations(const GrProcOptInfo& colorPOI,
|
||||
@ -591,7 +658,131 @@ GrXferProcessor::OptFlags CustomXP::getOptimizations(const GrProcOptInfo& colorP
|
||||
bool doesStencilWrite,
|
||||
GrColor* overrideColor,
|
||||
const GrDrawTargetCaps& caps) {
|
||||
return GrXferProcessor::kNone_Opt;
|
||||
/*
|
||||
Most the optimizations we do here are based on tweaking alpha for coverage.
|
||||
|
||||
The general SVG blend equation is defined in the spec as follows:
|
||||
|
||||
Dca' = B(Sc, Dc) * Sa * Da + Y * Sca * (1-Da) + Z * Dca * (1-Sa)
|
||||
Da' = X * Sa * Da + Y * Sa * (1-Da) + Z * Da * (1-Sa)
|
||||
|
||||
(Note that Sca, Dca indicate RGB vectors that are premultiplied by alpha,
|
||||
and that B(Sc, Dc) is a mode-specific function that accepts non-multiplied
|
||||
RGB colors.)
|
||||
|
||||
For every blend mode supported by this class, i.e. the "advanced" blend
|
||||
modes, X=Y=Z=1 and this equation reduces to the PDF blend equation.
|
||||
|
||||
It can be shown that when X=Y=Z=1, these equations can modulate alpha for
|
||||
coverage.
|
||||
|
||||
|
||||
== Color ==
|
||||
|
||||
We substitute Y=Z=1 and define a blend() function that calculates Dca' in
|
||||
terms of premultiplied alpha only:
|
||||
|
||||
blend(Sca, Dca, Sa, Da) = {Dca : if Sa == 0,
|
||||
Sca : if Da == 0,
|
||||
B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa) : if Sa,Da != 0}
|
||||
|
||||
And for coverage modulation, we use a post blend src-over model:
|
||||
|
||||
Dca'' = f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
|
||||
|
||||
(Where f is the fractional coverage.)
|
||||
|
||||
Next we show that canTweakAlphaForCoverage() is true by proving the
|
||||
following relationship:
|
||||
|
||||
blend(f*Sca, Dca, f*Sa, Da) == f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
|
||||
|
||||
General case (f,Sa,Da != 0):
|
||||
|
||||
f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
|
||||
= f * (B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa)) + (1-f) * Dca [Sa,Da != 0, definition of blend()]
|
||||
= B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + f*Dca * (1-Sa) + Dca - f*Dca
|
||||
= B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da + f*Dca - f*Dca * Sa + Dca - f*Dca
|
||||
= B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da - f*Dca * Sa + Dca
|
||||
= B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) - f*Dca * Sa + Dca
|
||||
= B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa)
|
||||
= B(f*Sca/f*Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa) [f!=0]
|
||||
= blend(f*Sca, Dca, f*Sa, Da) [definition of blend()]
|
||||
|
||||
Corner cases (Sa=0, Da=0, and f=0):
|
||||
|
||||
Sa=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
|
||||
= f * Dca + (1-f) * Dca [Sa=0, definition of blend()]
|
||||
= Dca
|
||||
= blend(0, Dca, 0, Da) [definition of blend()]
|
||||
= blend(f*Sca, Dca, f*Sa, Da) [Sa=0]
|
||||
|
||||
Da=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
|
||||
= f * Sca + (1-f) * Dca [Da=0, definition of blend()]
|
||||
= f * Sca [Da=0]
|
||||
= blend(f*Sca, 0, f*Sa, 0) [definition of blend()]
|
||||
= blend(f*Sca, Dca, f*Sa, Da) [Da=0]
|
||||
|
||||
f=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
|
||||
= Dca [f=0]
|
||||
= blend(0, Dca, 0, Da) [definition of blend()]
|
||||
= blend(f*Sca, Dca, f*Sa, Da) [f=0]
|
||||
|
||||
== Alpha ==
|
||||
|
||||
We substitute X=Y=Z=1 and define a blend() function that calculates Da':
|
||||
|
||||
blend(Sa, Da) = Sa * Da + Sa * (1-Da) + Da * (1-Sa)
|
||||
= Sa * Da + Sa - Sa * Da + Da - Da * Sa
|
||||
= Sa + Da - Sa * Da
|
||||
|
||||
We use the same model for coverage modulation as we did with color:
|
||||
|
||||
Da'' = f * blend(Sa, Da) + (1-f) * Da
|
||||
|
||||
And show that canTweakAlphaForCoverage() is true by proving the following
|
||||
relationship:
|
||||
|
||||
blend(f*Sa, Da) == f * blend(Sa, Da) + (1-f) * Da
|
||||
|
||||
|
||||
f * blend(Sa, Da) + (1-f) * Da
|
||||
= f * (Sa + Da - Sa * Da) + (1-f) * Da
|
||||
= f*Sa + f*Da - f*Sa * Da + Da - f*Da
|
||||
= f*Sa - f*Sa * Da + Da
|
||||
= f*Sa + Da - f*Sa * Da
|
||||
= blend(f*Sa, Da)
|
||||
*/
|
||||
|
||||
OptFlags flags = kNone_Opt;
|
||||
if (colorPOI.allStagesMultiplyInput()) {
|
||||
flags = flags | kCanTweakAlphaForCoverage_OptFlag;
|
||||
}
|
||||
if (coveragePOI.isSolidWhite()) {
|
||||
flags = flags | kIgnoreCoverage_OptFlag;
|
||||
fHasCoverage = false;
|
||||
}
|
||||
if (caps.advancedBlendEquationSupport() && !coveragePOI.isFourChannelOutput()) {
|
||||
// This blend mode can be implemented in hardware.
|
||||
fHWBlendEquation = hw_blend_equation(fMode);
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
bool CustomXP::onWillNeedXferBarrier(const GrRenderTarget* rt,
|
||||
const GrDrawTargetCaps& caps,
|
||||
GrXferBarrierType* outBarrierType) const {
|
||||
if (this->hasHWBlendEquation() && !caps.advancedCoherentBlendEquationSupport()) {
|
||||
*outBarrierType = kBlend_GrXferBarrierType;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CustomXP::onGetBlendInfo(BlendInfo* blendInfo) const {
|
||||
if (this->hasHWBlendEquation()) {
|
||||
blendInfo->fEquation = this->hwBlendEquation();
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@ -609,6 +800,19 @@ GrCustomXPFactory::onCreateXferProcessor(const GrDrawTargetCaps& caps,
|
||||
return CustomXP::Create(fMode, dstCopy, this->willReadDstColor(caps, colorPOI, coveragePOI));
|
||||
}
|
||||
|
||||
bool GrCustomXPFactory::willReadDstColor(const GrDrawTargetCaps& caps,
|
||||
const GrProcOptInfo& colorPOI,
|
||||
const GrProcOptInfo& coveragePOI) const {
|
||||
if (!caps.advancedBlendEquationSupport()) {
|
||||
// No hardware support for advanced blend equations; we will need to do it in the shader.
|
||||
return true;
|
||||
}
|
||||
if (coveragePOI.isFourChannelOutput()) {
|
||||
// Advanced blend equations can't tweak alpha for RGB coverage.
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GrCustomXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI,
|
||||
const GrProcOptInfo& coveragePOI,
|
||||
|
@ -75,9 +75,7 @@ private:
|
||||
|
||||
bool willReadDstColor(const GrDrawTargetCaps& caps,
|
||||
const GrProcOptInfo& colorPOI,
|
||||
const GrProcOptInfo& coveragePOI) const override {
|
||||
return true;
|
||||
}
|
||||
const GrProcOptInfo& coveragePOI) const override;
|
||||
|
||||
bool onIsEqual(const GrXPFactory& xpfBase) const override {
|
||||
const GrCustomXPFactory& xpf = xpfBase.cast<GrCustomXPFactory>();
|
||||
|
@ -269,6 +269,21 @@ bool GrGLCaps::init(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {
|
||||
fStencilWrapOpsSupport = true;
|
||||
}
|
||||
|
||||
if (kIntel_GrGLVendor != ctxInfo.vendor()) {
|
||||
if (ctxInfo.hasExtension("GL_KHR_blend_equation_advanced_coherent") ||
|
||||
ctxInfo.hasExtension("GL_NV_blend_equation_advanced_coherent")) {
|
||||
fBlendEquationSupport = kAdvancedCoherent_BlendEquationSupport;
|
||||
} else if (ctxInfo.hasExtension("GL_KHR_blend_equation_advanced") ||
|
||||
ctxInfo.hasExtension("GL_NV_blend_equation_advanced")) {
|
||||
fBlendEquationSupport = kAdvanced_BlendEquationSupport;
|
||||
} else {
|
||||
fBlendEquationSupport = kBasic_BlendEquationSupport;
|
||||
}
|
||||
} else {
|
||||
// On Intel platforms, KHR_blend_equation_advanced is not conformant.
|
||||
fBlendEquationSupport = kBasic_BlendEquationSupport;
|
||||
}
|
||||
|
||||
if (kGL_GrGLStandard == standard) {
|
||||
fMapBufferFlags = kCanMap_MapFlag; // we require VBO support and the desktop VBO
|
||||
// extension includes glMapBuffer.
|
||||
@ -352,7 +367,7 @@ bool GrGLCaps::init(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {
|
||||
this->initConfigTexturableTable(ctxInfo, gli);
|
||||
this->initConfigRenderableTable(ctxInfo);
|
||||
|
||||
reinterpret_cast<GrGLSLCaps*>(fShaderCaps.get())->init(ctxInfo, gli);
|
||||
reinterpret_cast<GrGLSLCaps*>(fShaderCaps.get())->init(ctxInfo, gli, *this);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -914,6 +929,7 @@ void GrGLSLCaps::reset() {
|
||||
fDropsTileOnZeroDivide = false;
|
||||
fFBFetchSupport = false;
|
||||
fFBFetchNeedsCustomOutput = false;
|
||||
fAdvBlendEqInteraction = kNotSupported_AdvBlendEqInteraction;
|
||||
fFBFetchColorName = NULL;
|
||||
fFBFetchExtensionString = NULL;
|
||||
}
|
||||
@ -927,13 +943,16 @@ GrGLSLCaps& GrGLSLCaps::operator= (const GrGLSLCaps& caps) {
|
||||
fDropsTileOnZeroDivide = caps.fDropsTileOnZeroDivide;
|
||||
fFBFetchSupport = caps.fFBFetchSupport;
|
||||
fFBFetchNeedsCustomOutput = caps.fFBFetchNeedsCustomOutput;
|
||||
fAdvBlendEqInteraction = caps.fAdvBlendEqInteraction;
|
||||
fFBFetchColorName = caps.fFBFetchColorName;
|
||||
fFBFetchExtensionString = caps.fFBFetchExtensionString;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool GrGLSLCaps::init(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {
|
||||
bool GrGLSLCaps::init(const GrGLContextInfo& ctxInfo,
|
||||
const GrGLInterface* gli,
|
||||
const GrGLCaps& glCaps) {
|
||||
this->reset();
|
||||
if (!ctxInfo.isInitialized()) {
|
||||
return false;
|
||||
@ -1010,6 +1029,18 @@ bool GrGLSLCaps::init(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli)
|
||||
ctxInfo.hasExtension("GL_OES_standard_derivatives");
|
||||
}
|
||||
|
||||
if (glCaps.advancedBlendEquationSupport()) {
|
||||
bool coherent = glCaps.advancedCoherentBlendEquationSupport();
|
||||
if (ctxInfo.hasExtension(coherent ? "GL_NV_blend_equation_advanced_coherent"
|
||||
: "GL_NV_blend_equation_advanced")) {
|
||||
fAdvBlendEqInteraction = kAutomatic_AdvBlendEqInteraction;
|
||||
} else {
|
||||
fAdvBlendEqInteraction = kGeneralEnable_AdvBlendEqInteraction;
|
||||
// TODO: Use the following on any platform where "blend_support_all_equations" is slow.
|
||||
//fAdvBlendEqInteraction = kSpecificEnables_AdvBlendEqInteraction;
|
||||
}
|
||||
}
|
||||
|
||||
this->initShaderPrecisionTable(ctxInfo, gli);
|
||||
|
||||
return true;
|
||||
@ -1018,10 +1049,24 @@ bool GrGLSLCaps::init(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli)
|
||||
SkString GrGLSLCaps::dump() const {
|
||||
SkString r = INHERITED::dump();
|
||||
|
||||
static const char* kAdvBlendEqInteractionStr[] = {
|
||||
"Not Supported",
|
||||
"Automatic",
|
||||
"General Enable",
|
||||
"Specific Enables",
|
||||
};
|
||||
GR_STATIC_ASSERT(0 == kNotSupported_AdvBlendEqInteraction);
|
||||
GR_STATIC_ASSERT(1 == kAutomatic_AdvBlendEqInteraction);
|
||||
GR_STATIC_ASSERT(2 == kGeneralEnable_AdvBlendEqInteraction);
|
||||
GR_STATIC_ASSERT(3 == kSpecificEnables_AdvBlendEqInteraction);
|
||||
GR_STATIC_ASSERT(SK_ARRAY_COUNT(kAdvBlendEqInteractionStr) == kLast_AdvBlendEqInteraction + 1);
|
||||
|
||||
r.appendf("--- GLSL-Specific ---\n");
|
||||
|
||||
r.appendf("FB Fetch Support: %s\n", (fFBFetchSupport ? "YES" : "NO"));
|
||||
r.appendf("Drops tile on zero divide: %s\n", (fDropsTileOnZeroDivide ? "YES" : "NO"));
|
||||
r.appendf("Advanced blend equation interaction: %s\n",
|
||||
kAdvBlendEqInteractionStr[fAdvBlendEqInteraction]);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -379,6 +379,19 @@ class GrGLSLCaps : public GrShaderCaps {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(GrGLSLCaps)
|
||||
|
||||
/**
|
||||
* Indicates how GLSL must interact with advanced blend equations. The KHR extension requires
|
||||
* special layout qualifiers in the fragment shader.
|
||||
*/
|
||||
enum AdvBlendEqInteraction {
|
||||
kNotSupported_AdvBlendEqInteraction, //<! No _blend_equation_advanced extension
|
||||
kAutomatic_AdvBlendEqInteraction, //<! No interaction required
|
||||
kGeneralEnable_AdvBlendEqInteraction, //<! layout(blend_support_all_equations) out
|
||||
kSpecificEnables_AdvBlendEqInteraction, //<! Specific layout qualifiers per equation
|
||||
|
||||
kLast_AdvBlendEqInteraction = kSpecificEnables_AdvBlendEqInteraction
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a GrGLSLCaps that advertises no support for any extensions,
|
||||
* formats, etc. Call init to initialize from a GrGLContextInfo.
|
||||
@ -399,7 +412,7 @@ public:
|
||||
* Initializes the GrGLSLCaps to the set of features supported in the current
|
||||
* OpenGL context accessible via ctxInfo.
|
||||
*/
|
||||
bool init(const GrGLContextInfo& ctxInfo, const GrGLInterface* glInterface);
|
||||
bool init(const GrGLContextInfo&, const GrGLInterface*, const GrGLCaps&);
|
||||
|
||||
/**
|
||||
* Some helper functions for encapsulating various extensions to read FB Buffer on openglES
|
||||
@ -416,6 +429,16 @@ public:
|
||||
|
||||
bool dropsTileOnZeroDivide() const { return fDropsTileOnZeroDivide; }
|
||||
|
||||
AdvBlendEqInteraction advBlendEqInteraction() const { return fAdvBlendEqInteraction; }
|
||||
|
||||
bool mustEnableAdvBlendEqs() const {
|
||||
return fAdvBlendEqInteraction >= kGeneralEnable_AdvBlendEqInteraction;
|
||||
}
|
||||
|
||||
bool mustEnableSpecificAdvBlendEqs() const {
|
||||
return fAdvBlendEqInteraction == kSpecificEnables_AdvBlendEqInteraction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string containing the caps info.
|
||||
*/
|
||||
@ -432,6 +455,8 @@ private:
|
||||
const char* fFBFetchColorName;
|
||||
const char* fFBFetchExtensionString;
|
||||
|
||||
AdvBlendEqInteraction fAdvBlendEqInteraction;
|
||||
|
||||
typedef GrShaderCaps INHERITED;
|
||||
};
|
||||
|
||||
|
@ -39,6 +39,49 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
static const GrGLenum gXfermodeEquation2Blend[] = {
|
||||
// Basic OpenGL blend equations.
|
||||
GR_GL_FUNC_ADD,
|
||||
GR_GL_FUNC_SUBTRACT,
|
||||
GR_GL_FUNC_REVERSE_SUBTRACT,
|
||||
|
||||
// GL_KHR_blend_equation_advanced.
|
||||
GR_GL_SCREEN,
|
||||
GR_GL_OVERLAY,
|
||||
GR_GL_DARKEN,
|
||||
GR_GL_LIGHTEN,
|
||||
GR_GL_COLORDODGE,
|
||||
GR_GL_COLORBURN,
|
||||
GR_GL_HARDLIGHT,
|
||||
GR_GL_SOFTLIGHT,
|
||||
GR_GL_DIFFERENCE,
|
||||
GR_GL_EXCLUSION,
|
||||
GR_GL_MULTIPLY,
|
||||
GR_GL_HSL_HUE,
|
||||
GR_GL_HSL_SATURATION,
|
||||
GR_GL_HSL_COLOR,
|
||||
GR_GL_HSL_LUMINOSITY
|
||||
};
|
||||
GR_STATIC_ASSERT(0 == kAdd_GrBlendEquation);
|
||||
GR_STATIC_ASSERT(1 == kSubtract_GrBlendEquation);
|
||||
GR_STATIC_ASSERT(2 == kReverseSubtract_GrBlendEquation);
|
||||
GR_STATIC_ASSERT(3 == kScreen_GrBlendEquation);
|
||||
GR_STATIC_ASSERT(4 == kOverlay_GrBlendEquation);
|
||||
GR_STATIC_ASSERT(5 == kDarken_GrBlendEquation);
|
||||
GR_STATIC_ASSERT(6 == kLighten_GrBlendEquation);
|
||||
GR_STATIC_ASSERT(7 == kColorDodge_GrBlendEquation);
|
||||
GR_STATIC_ASSERT(8 == kColorBurn_GrBlendEquation);
|
||||
GR_STATIC_ASSERT(9 == kHardLight_GrBlendEquation);
|
||||
GR_STATIC_ASSERT(10 == kSoftLight_GrBlendEquation);
|
||||
GR_STATIC_ASSERT(11 == kDifference_GrBlendEquation);
|
||||
GR_STATIC_ASSERT(12 == kExclusion_GrBlendEquation);
|
||||
GR_STATIC_ASSERT(13 == kMultiply_GrBlendEquation);
|
||||
GR_STATIC_ASSERT(14 == kHSLHue_GrBlendEquation);
|
||||
GR_STATIC_ASSERT(15 == kHSLSaturation_GrBlendEquation);
|
||||
GR_STATIC_ASSERT(16 == kHSLColor_GrBlendEquation);
|
||||
GR_STATIC_ASSERT(17 == kHSLLuminosity_GrBlendEquation);
|
||||
GR_STATIC_ASSERT(18 == kTotalGrBlendEquationCount);
|
||||
|
||||
static const GrGLenum gXfermodeCoeff2Blend[] = {
|
||||
GR_GL_ZERO,
|
||||
GR_GL_ONE,
|
||||
@ -2077,39 +2120,55 @@ void GrGLGpu::flushHWAAState(GrRenderTarget* rt, bool useHWAA) {
|
||||
|
||||
void GrGLGpu::flushBlend(const GrXferProcessor::BlendInfo& blendInfo) {
|
||||
// Any optimization to disable blending should have already been applied and
|
||||
// tweaked the coeffs to (1, 0).
|
||||
// tweaked the equation to "add" or "subtract", and the coeffs to (1, 0).
|
||||
|
||||
GrBlendEquation equation = blendInfo.fEquation;
|
||||
GrBlendCoeff srcCoeff = blendInfo.fSrcBlend;
|
||||
GrBlendCoeff dstCoeff = blendInfo.fDstBlend;
|
||||
bool blendOff = kOne_GrBlendCoeff == srcCoeff && kZero_GrBlendCoeff == dstCoeff;
|
||||
bool blendOff = (kAdd_GrBlendEquation == equation || kSubtract_GrBlendEquation == equation) &&
|
||||
kOne_GrBlendCoeff == srcCoeff && kZero_GrBlendCoeff == dstCoeff;
|
||||
if (blendOff) {
|
||||
if (kNo_TriState != fHWBlendState.fEnabled) {
|
||||
GL_CALL(Disable(GR_GL_BLEND));
|
||||
fHWBlendState.fEnabled = kNo_TriState;
|
||||
}
|
||||
} else {
|
||||
if (kYes_TriState != fHWBlendState.fEnabled) {
|
||||
GL_CALL(Enable(GR_GL_BLEND));
|
||||
fHWBlendState.fEnabled = kYes_TriState;
|
||||
}
|
||||
if (fHWBlendState.fSrcCoeff != srcCoeff ||
|
||||
fHWBlendState.fDstCoeff != dstCoeff) {
|
||||
GL_CALL(BlendFunc(gXfermodeCoeff2Blend[srcCoeff],
|
||||
gXfermodeCoeff2Blend[dstCoeff]));
|
||||
fHWBlendState.fSrcCoeff = srcCoeff;
|
||||
fHWBlendState.fDstCoeff = dstCoeff;
|
||||
}
|
||||
GrColor blendConst = blendInfo.fBlendConstant;
|
||||
if ((BlendCoeffReferencesConstant(srcCoeff) ||
|
||||
BlendCoeffReferencesConstant(dstCoeff)) &&
|
||||
(!fHWBlendState.fConstColorValid ||
|
||||
fHWBlendState.fConstColor != blendConst)) {
|
||||
GrGLfloat c[4];
|
||||
GrColorToRGBAFloat(blendConst, c);
|
||||
GL_CALL(BlendColor(c[0], c[1], c[2], c[3]));
|
||||
fHWBlendState.fConstColor = blendConst;
|
||||
fHWBlendState.fConstColorValid = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (kYes_TriState != fHWBlendState.fEnabled) {
|
||||
GL_CALL(Enable(GR_GL_BLEND));
|
||||
fHWBlendState.fEnabled = kYes_TriState;
|
||||
}
|
||||
|
||||
if (fHWBlendState.fEquation != equation) {
|
||||
GL_CALL(BlendEquation(gXfermodeEquation2Blend[equation]));
|
||||
fHWBlendState.fEquation = equation;
|
||||
}
|
||||
|
||||
if (GrBlendEquationIsAdvanced(equation)) {
|
||||
SkASSERT(this->caps()->advancedBlendEquationSupport());
|
||||
// Advanced equations have no other blend state.
|
||||
return;
|
||||
}
|
||||
|
||||
if (fHWBlendState.fSrcCoeff != srcCoeff ||
|
||||
fHWBlendState.fDstCoeff != dstCoeff) {
|
||||
GL_CALL(BlendFunc(gXfermodeCoeff2Blend[srcCoeff],
|
||||
gXfermodeCoeff2Blend[dstCoeff]));
|
||||
fHWBlendState.fSrcCoeff = srcCoeff;
|
||||
fHWBlendState.fDstCoeff = dstCoeff;
|
||||
}
|
||||
|
||||
GrColor blendConst = blendInfo.fBlendConstant;
|
||||
if ((BlendCoeffReferencesConstant(srcCoeff) ||
|
||||
BlendCoeffReferencesConstant(dstCoeff)) &&
|
||||
(!fHWBlendState.fConstColorValid ||
|
||||
fHWBlendState.fConstColor != blendConst)) {
|
||||
GrGLfloat c[4];
|
||||
GrColorToRGBAFloat(blendConst, c);
|
||||
GL_CALL(BlendColor(c[0], c[1], c[2], c[3]));
|
||||
fHWBlendState.fConstColor = blendConst;
|
||||
fHWBlendState.fConstColorValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2736,6 +2795,11 @@ void GrGLGpu::xferBarrier(GrXferBarrierType type) {
|
||||
SkASSERT(this->caps()->textureBarrierSupport());
|
||||
GL_CALL(TextureBarrier());
|
||||
return;
|
||||
case kBlend_GrXferBarrierType:
|
||||
SkASSERT(GrDrawTargetCaps::kAdvanced_BlendEquationSupport ==
|
||||
this->caps()->blendEquationSupport());
|
||||
GL_CALL(BlendBarrier());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -438,6 +438,7 @@ private:
|
||||
} fHWGeometryState;
|
||||
|
||||
struct {
|
||||
GrBlendEquation fEquation;
|
||||
GrBlendCoeff fSrcCoeff;
|
||||
GrBlendCoeff fDstCoeff;
|
||||
GrColor fConstColor;
|
||||
@ -445,6 +446,7 @@ private:
|
||||
TriState fEnabled;
|
||||
|
||||
void invalidate() {
|
||||
fEquation = kInvalid_GrBlendEquation;
|
||||
fSrcCoeff = kInvalid_GrBlendCoeff;
|
||||
fDstCoeff = kInvalid_GrBlendCoeff;
|
||||
fConstColorValid = false;
|
||||
|
@ -36,6 +36,47 @@ static void append_default_precision_qualifier(GrSLPrecision p,
|
||||
}
|
||||
}
|
||||
|
||||
static const char* specific_layout_qualifier_name(GrBlendEquation equation) {
|
||||
SkASSERT(GrBlendEquationIsAdvanced(equation));
|
||||
|
||||
static const char* kLayoutQualifierNames[] = {
|
||||
"blend_support_screen",
|
||||
"blend_support_overlay",
|
||||
"blend_support_darken",
|
||||
"blend_support_lighten",
|
||||
"blend_support_colordodge",
|
||||
"blend_support_colorburn",
|
||||
"blend_support_hardlight",
|
||||
"blend_support_softlight",
|
||||
"blend_support_difference",
|
||||
"blend_support_exclusion",
|
||||
"blend_support_multiply",
|
||||
"blend_support_hsl_hue",
|
||||
"blend_support_hsl_saturation",
|
||||
"blend_support_hsl_color",
|
||||
"blend_support_hsl_luminosity"
|
||||
};
|
||||
return kLayoutQualifierNames[equation - kFirstAdvancedGrBlendEquation];
|
||||
|
||||
GR_STATIC_ASSERT(0 == kScreen_GrBlendEquation - kFirstAdvancedGrBlendEquation);
|
||||
GR_STATIC_ASSERT(1 == kOverlay_GrBlendEquation - kFirstAdvancedGrBlendEquation);
|
||||
GR_STATIC_ASSERT(2 == kDarken_GrBlendEquation - kFirstAdvancedGrBlendEquation);
|
||||
GR_STATIC_ASSERT(3 == kLighten_GrBlendEquation - kFirstAdvancedGrBlendEquation);
|
||||
GR_STATIC_ASSERT(4 == kColorDodge_GrBlendEquation - kFirstAdvancedGrBlendEquation);
|
||||
GR_STATIC_ASSERT(5 == kColorBurn_GrBlendEquation - kFirstAdvancedGrBlendEquation);
|
||||
GR_STATIC_ASSERT(6 == kHardLight_GrBlendEquation - kFirstAdvancedGrBlendEquation);
|
||||
GR_STATIC_ASSERT(7 == kSoftLight_GrBlendEquation - kFirstAdvancedGrBlendEquation);
|
||||
GR_STATIC_ASSERT(8 == kDifference_GrBlendEquation - kFirstAdvancedGrBlendEquation);
|
||||
GR_STATIC_ASSERT(9 == kExclusion_GrBlendEquation - kFirstAdvancedGrBlendEquation);
|
||||
GR_STATIC_ASSERT(10 == kMultiply_GrBlendEquation - kFirstAdvancedGrBlendEquation);
|
||||
GR_STATIC_ASSERT(11 == kHSLHue_GrBlendEquation - kFirstAdvancedGrBlendEquation);
|
||||
GR_STATIC_ASSERT(12 == kHSLSaturation_GrBlendEquation - kFirstAdvancedGrBlendEquation);
|
||||
GR_STATIC_ASSERT(13 == kHSLColor_GrBlendEquation - kFirstAdvancedGrBlendEquation);
|
||||
GR_STATIC_ASSERT(14 == kHSLLuminosity_GrBlendEquation - kFirstAdvancedGrBlendEquation);
|
||||
GR_STATIC_ASSERT(SK_ARRAY_COUNT(kLayoutQualifierNames) ==
|
||||
kTotalGrBlendEquationCount - kFirstAdvancedGrBlendEquation);
|
||||
}
|
||||
|
||||
GrGLFragmentShaderBuilder::DstReadKey
|
||||
GrGLFragmentShaderBuilder::KeyForDstRead(const GrTexture* dstCopy, const GrGLCaps& caps) {
|
||||
uint32_t key = kYesDstRead_DstReadKeyBit;
|
||||
@ -183,6 +224,23 @@ const char* GrGLFragmentShaderBuilder::dstColor() {
|
||||
}
|
||||
}
|
||||
|
||||
void GrGLFragmentShaderBuilder::enableAdvancedBlendEquationIfNeeded(GrBlendEquation equation) {
|
||||
SkASSERT(GrBlendEquationIsAdvanced(equation));
|
||||
|
||||
const GrGLSLCaps& caps = *fProgramBuilder->gpu()->glCaps().glslCaps();
|
||||
if (!caps.mustEnableAdvBlendEqs()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->addFeature(1 << kBlendEquationAdvanced_GLSLPrivateFeature,
|
||||
"GL_KHR_blend_equation_advanced");
|
||||
if (caps.mustEnableSpecificAdvBlendEqs()) {
|
||||
this->addLayoutQualifier(specific_layout_qualifier_name(equation), kOut_InterfaceQualifier);
|
||||
} else {
|
||||
this->addLayoutQualifier("blend_support_all_equations", kOut_InterfaceQualifier);
|
||||
}
|
||||
}
|
||||
|
||||
void GrGLFragmentShaderBuilder::enableCustomOutput() {
|
||||
if (!fHasCustomColorOutput) {
|
||||
fHasCustomColorOutput = true;
|
||||
|
@ -66,6 +66,11 @@ public:
|
||||
no effect advertised that it will read the destination. */
|
||||
virtual const char* dstColor() = 0;
|
||||
|
||||
/** Adds any necessary layout qualifiers in order to legalize the supplied blend equation with
|
||||
this shader. It is only legal to call this method with an advanced blend equation, and only
|
||||
if these equations are supported. */
|
||||
virtual void enableAdvancedBlendEquationIfNeeded(GrBlendEquation) = 0;
|
||||
|
||||
private:
|
||||
typedef GrGLFragmentBuilder INHERITED;
|
||||
};
|
||||
@ -95,6 +100,8 @@ public:
|
||||
const char* fragmentPosition() override;
|
||||
const char* dstColor() override;
|
||||
|
||||
void enableAdvancedBlendEquationIfNeeded(GrBlendEquation) override;
|
||||
|
||||
private:
|
||||
// Private public interface, used by GrGLProgramBuilder to build a fragment shader
|
||||
void enableCustomOutput();
|
||||
@ -123,7 +130,8 @@ private:
|
||||
*/
|
||||
enum GLSLPrivateFeature {
|
||||
kFragCoordConventions_GLSLPrivateFeature = kLastGLSLFeature + 1,
|
||||
kLastGLSLPrivateFeature = kFragCoordConventions_GLSLPrivateFeature
|
||||
kBlendEquationAdvanced_GLSLPrivateFeature,
|
||||
kLastGLSLPrivateFeature = kBlendEquationAdvanced_GLSLPrivateFeature
|
||||
};
|
||||
|
||||
// Interpretation of DstReadKey when generating code
|
||||
|
@ -173,7 +173,8 @@ void GrGLShaderBuilder::appendTextureLookup(const char* samplerName,
|
||||
}
|
||||
|
||||
void GrGLShaderBuilder::addLayoutQualifier(const char* param, InterfaceQualifier interface) {
|
||||
SkASSERT(fProgramBuilder->gpu()->glslGeneration() >= k330_GrGLSLGeneration);
|
||||
SkASSERT(fProgramBuilder->gpu()->glslGeneration() >= k330_GrGLSLGeneration ||
|
||||
fProgramBuilder->gpu()->glCaps().glslCaps()->mustEnableAdvBlendEqs());
|
||||
fLayoutParams[interface].push_back() = param;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user