Add dual source blending support for proper blending with coverage.
Review URL: http://codereview.appspot.com/4535088/ git-svn-id: http://skia.googlecode.com/svn/trunk@1390 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
3c14d0f3d1
commit
271cffc77b
@ -453,7 +453,7 @@ public:
|
||||
* @param srcCoef coeffecient applied to the src color.
|
||||
* @param dstCoef coeffecient applied to the dst color.
|
||||
*/
|
||||
void setBlendFunc(GrBlendCoeff srcCoef, GrBlendCoeff dstCoef);
|
||||
void setBlendFunc(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff);
|
||||
|
||||
/**
|
||||
* Sets the blending function constant referenced by the following blending
|
||||
|
@ -69,6 +69,12 @@
|
||||
/* GL_DST_ALPHA */
|
||||
/* GL_ONE_MINUS_DST_ALPHA */
|
||||
|
||||
/* ExtendedBlendFactors */
|
||||
#define GR_GL_SRC1_COLOR 0x88F9
|
||||
#define GR_GL_ONE_MINUS_SRC1_COLOR 0x88FA
|
||||
/* GL_SRC1_ALPHA */
|
||||
#define GR_GL_ONE_MINUS_SRC1_ALPHA 0x88FB
|
||||
|
||||
/* BlendEquationSeparate */
|
||||
#define GR_GL_FUNC_ADD 0x8006
|
||||
#define GR_GL_BLEND_EQUATION 0x8009
|
||||
|
@ -63,6 +63,7 @@ typedef unsigned int GrGLenum;
|
||||
typedef unsigned char GrGLboolean;
|
||||
typedef unsigned int GrGLbitfield;
|
||||
typedef signed char GrGLbyte;
|
||||
typedef char GrGLchar;
|
||||
typedef short GrGLshort;
|
||||
typedef int GrGLint;
|
||||
typedef int GrGLsizei;
|
||||
@ -199,6 +200,9 @@ extern "C" {
|
||||
// Buffer mapping (extension in ES).
|
||||
typedef GrGLvoid* (GR_GL_FUNCTION_TYPE *GrGLMapBufferProc)(GrGLenum target, GrGLenum access);
|
||||
typedef GrGLboolean (GR_GL_FUNCTION_TYPE *GrGLUnmapBufferProc)(GrGLenum target);
|
||||
|
||||
// Dual source blending
|
||||
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLBindFragDataLocationIndexedProc)(GrGLuint program, GrGLuint colorNumber, GrGLuint index, const GrGLchar * name);
|
||||
} // extern "C"
|
||||
|
||||
/*
|
||||
@ -333,6 +337,9 @@ struct GrGLInterface {
|
||||
GrGLMapBufferProc fMapBuffer;
|
||||
GrGLUnmapBufferProc fUnmapBuffer;
|
||||
|
||||
// Dual Source Blending
|
||||
GrGLBindFragDataLocationIndexedProc fBindFragDataLocationIndexed;
|
||||
|
||||
// Code that initializes this struct using a static initializer should
|
||||
// make this the last entry in the static initializer. It can help to guard
|
||||
// against failing to initialize newly-added members of this struct.
|
||||
|
@ -59,6 +59,21 @@ struct GrGpuStats {
|
||||
class GrGpu : public GrDrawTarget {
|
||||
|
||||
public:
|
||||
/**
|
||||
* Additional blend coeffecients for dual source blending, not exposed
|
||||
* through GrPaint/GrContext.
|
||||
*/
|
||||
enum ExtendedBlendCoeffs {
|
||||
// source 2 refers to second output color when
|
||||
// using dual source blending.
|
||||
kS2C_BlendCoeff = kPublicBlendCoeffCount,
|
||||
kIS2C_BlendCoeff,
|
||||
kS2A_BlendCoeff,
|
||||
kIS2A_BlendCoeff,
|
||||
|
||||
kTotalBlendCoeffCount
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an instance of GrGpu that matches the specified Engine backend.
|
||||
* If the requested engine is not supported (at compile-time or run-time)
|
||||
@ -189,6 +204,15 @@ public:
|
||||
*/
|
||||
bool supports4x4DownsampleFilter() const { return f4X4DownsampleFilterSupport; }
|
||||
|
||||
/**
|
||||
* Does this instance support dual-source blending? Required for proper
|
||||
* blending with partial coverage with certain blend modes (dst coeff is
|
||||
* not 1, ISA, or ISC)
|
||||
*/
|
||||
bool supportsDualSourceBlending() const {
|
||||
return fDualSourceBlendingSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum width of a render target. If a texture/rt is created
|
||||
* with a width less than this size the GrGpu object will clamp it to this
|
||||
@ -371,6 +395,7 @@ protected:
|
||||
bool fAALineSupport;
|
||||
bool fFSAASupport;
|
||||
bool f4X4DownsampleFilterSupport; // supports GrSamplerState::k4x4Downsample_Filter
|
||||
bool fDualSourceBlendingSupport;
|
||||
|
||||
// set by subclass to true if index and vertex buffers can be locked, false
|
||||
// otherwise.
|
||||
|
@ -232,7 +232,7 @@ enum GrBlendCoeff {
|
||||
kConstA_BlendCoeff, //<! constant color alpha
|
||||
kIConstA_BlendCoeff, //<! one minus constant color alpha
|
||||
|
||||
kBlendCoeffCount
|
||||
kPublicBlendCoeffCount
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -374,10 +374,34 @@ void GrDrawTarget::disableState(uint32_t bits) {
|
||||
fCurrDrawState.fFlagBits &= ~(bits);
|
||||
}
|
||||
|
||||
void GrDrawTarget::setBlendFunc(GrBlendCoeff srcCoef,
|
||||
GrBlendCoeff dstCoef) {
|
||||
fCurrDrawState.fSrcBlend = srcCoef;
|
||||
fCurrDrawState.fDstBlend = dstCoef;
|
||||
void GrDrawTarget::setBlendFunc(GrBlendCoeff srcCoeff,
|
||||
GrBlendCoeff dstCoeff) {
|
||||
fCurrDrawState.fSrcBlend = srcCoeff;
|
||||
fCurrDrawState.fDstBlend = dstCoeff;
|
||||
#if GR_DEBUG
|
||||
switch (dstCoeff) {
|
||||
case kDC_BlendCoeff:
|
||||
case kIDC_BlendCoeff:
|
||||
case kDA_BlendCoeff:
|
||||
case kIDA_BlendCoeff:
|
||||
GrPrintf("Unexpected dst blend coeff. Won't work correctly with"
|
||||
"coverage stages.\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (srcCoeff) {
|
||||
case kSC_BlendCoeff:
|
||||
case kISC_BlendCoeff:
|
||||
case kSA_BlendCoeff:
|
||||
case kISA_BlendCoeff:
|
||||
GrPrintf("Unexpected src blend coeff. Won't work correctly with"
|
||||
"coverage stages.\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void GrDrawTarget::setColor(GrColor c) {
|
||||
@ -482,10 +506,16 @@ void GrDrawTarget::setIndexSourceToBuffer(const GrIndexBuffer* buffer) {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool GrDrawTarget::canDisableBlend() const {
|
||||
// If we're using edge antialiasing, we can't force blend off.
|
||||
// If we compute a coverage value (using edge AA or a coverage stage) then
|
||||
// we can't force blending off.
|
||||
if (fCurrDrawState.fEdgeAANumEdges > 0) {
|
||||
return false;
|
||||
}
|
||||
for (int s = fCurrDrawState.fFirstCoverageStage; s < kNumStages; ++s) {
|
||||
if (this->isStageEnabled(s)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((kOne_BlendCoeff == fCurrDrawState.fSrcBlend) &&
|
||||
(kZero_BlendCoeff == fCurrDrawState.fDstBlend)) {
|
||||
@ -510,8 +540,8 @@ bool GrDrawTarget::canDisableBlend() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ...and there isn't a texture with an alpha channel...
|
||||
for (int s = 0; s < kNumStages; ++s) {
|
||||
// ...and there isn't a texture stage with an alpha channel...
|
||||
for (int s = 0; s < fCurrDrawState.fFirstCoverageStage; ++s) {
|
||||
if (this->isStageEnabled(s)) {
|
||||
GrAssert(NULL != fCurrDrawState.fTextures[s]);
|
||||
|
||||
|
@ -333,6 +333,15 @@ bool GrGLInterface::validate(GrEngine engine) const {
|
||||
}
|
||||
}
|
||||
|
||||
// Dual source blending
|
||||
if (kDesktop_GrGLBinding == fBindingsExported &&
|
||||
(has_gl_extension_from_string("GL_ARB_blend_func_extended", ext) ||
|
||||
(3 < major) || (3 == major && 3 <= minor))) {
|
||||
if (NULL == fBindFragDataLocationIndexed) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -99,6 +99,9 @@ static inline const char* all_zeros_vec(int count) {
|
||||
return ZEROSVEC[count];
|
||||
}
|
||||
|
||||
static inline const char* declared_color_output_name() { return "fsColorOut"; }
|
||||
static inline const char* dual_source_output_name() { return "dualSourceOut"; }
|
||||
|
||||
static void tex_matrix_name(int stage, GrStringBuilder* s) {
|
||||
#if GR_GL_ATTRIBUTE_MATRICES
|
||||
*s = "aTexM";
|
||||
@ -144,12 +147,32 @@ GrGLProgram::GrGLProgram() {
|
||||
GrGLProgram::~GrGLProgram() {
|
||||
}
|
||||
|
||||
void GrGLProgram::overrideBlend(GrBlendCoeff* srcCoeff,
|
||||
GrBlendCoeff* dstCoeff) const {
|
||||
switch (fProgramDesc.fDualSrcOutput) {
|
||||
case ProgramDesc::kNone_DualSrcOutput:
|
||||
break;
|
||||
// the prog will write a coverage value to the secondary
|
||||
// output and the dst is blended by one minus that value.
|
||||
case ProgramDesc::kCoverage_DualSrcOutput:
|
||||
case ProgramDesc::kCoverageISA_DualSrcOutput:
|
||||
case ProgramDesc::kCoverageISC_DualSrcOutput:
|
||||
*dstCoeff = (GrBlendCoeff)GrGpu::kIS2C_BlendCoeff;
|
||||
break;
|
||||
default:
|
||||
GrCrash("Unexpected dual source blend output");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GrGLProgram::buildKey(GrBinHashKeyBuilder& key) const {
|
||||
// Add stage configuration to the key
|
||||
key.keyData(reinterpret_cast<const uint8_t*>(&fProgramDesc), sizeof(ProgramDesc));
|
||||
}
|
||||
|
||||
// assigns modulation of two vars to an output var
|
||||
// vars can be vec4s or floats (or one of each)
|
||||
// result is always vec4
|
||||
// if either var is "" then assign to the other var
|
||||
// if both are "" then assign all ones
|
||||
static inline void modulate_helper(const char* outputVar,
|
||||
@ -167,15 +190,17 @@ static inline void modulate_helper(const char* outputVar,
|
||||
if (!has0 && !has1) {
|
||||
code->appendf("\t%s = %s;\n", outputVar, all_ones_vec(4));
|
||||
} else if (!has0) {
|
||||
code->appendf("\t%s = %s;\n", outputVar, var1);
|
||||
code->appendf("\t%s = vec4(%s);\n", outputVar, var1);
|
||||
} else if (!has1) {
|
||||
code->appendf("\t%s = %s;\n", outputVar, var0);
|
||||
code->appendf("\t%s = vec4(%s);\n", outputVar, var0);
|
||||
} else {
|
||||
code->appendf("\t%s = %s * %s;\n", outputVar, var0, var1);
|
||||
code->appendf("\t%s = vec4(%s * %s);\n", outputVar, var0, var1);
|
||||
}
|
||||
}
|
||||
|
||||
// assigns addition of two vars to an output var
|
||||
// vars can be vec4s or floats (or one of each)
|
||||
// result is always vec4
|
||||
// if either var is "" then assign to the other var
|
||||
// if both are "" then assign all zeros
|
||||
static inline void add_helper(const char* outputVar,
|
||||
@ -193,11 +218,11 @@ static inline void add_helper(const char* outputVar,
|
||||
if (!has0 && !has1) {
|
||||
code->appendf("\t%s = %s;\n", outputVar, all_zeros_vec(4));
|
||||
} else if (!has0) {
|
||||
code->appendf("\t%s = %s;\n", outputVar, var1);
|
||||
code->appendf("\t%s = vec4(%s);\n", outputVar, var1);
|
||||
} else if (!has1) {
|
||||
code->appendf("\t%s = %s;\n", outputVar, var0);
|
||||
code->appendf("\t%s = vec4(%s);\n", outputVar, var0);
|
||||
} else {
|
||||
code->appendf("\t%s = %s + %s;\n", outputVar, var0, var1);
|
||||
code->appendf("\t%s = vec4(%s + %s);\n", outputVar, var0, var1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -325,6 +350,21 @@ bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
|
||||
needBlendInputs(uniformCoeff, colorCoeff,
|
||||
&needColorFilterUniform, &needComputedColor);
|
||||
|
||||
// the dual source output has no canonical var name, have to
|
||||
// declare an output, which is incompatible with gl_FragColor/gl_FragData.
|
||||
const char* fsColorOutput;
|
||||
bool dualSourceOutputWritten = false;
|
||||
bool usingDeclaredOutputs = ProgramDesc::kNone_DualSrcOutput !=
|
||||
fProgramDesc.fDualSrcOutput;
|
||||
if (usingDeclaredOutputs) {
|
||||
GrAssert(0 == segments.fHeader.size());
|
||||
segments.fHeader.printf("#version 150\n");
|
||||
fsColorOutput = declared_color_output_name();
|
||||
segments.fFSOutputs.appendf("out vec4 %s;\n", fsColorOutput);
|
||||
} else {
|
||||
fsColorOutput = "gl_FragColor";
|
||||
}
|
||||
|
||||
#if GR_GL_ATTRIBUTE_MATRICES
|
||||
segments.fVSAttrs += "attribute mat3 " VIEW_MATRIX_NAME ";\n";
|
||||
programData->fUniLocations.fViewMatrixUni = kSetAsAttribute;
|
||||
@ -433,7 +473,9 @@ bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
|
||||
bool wroteFragColorZero = false;
|
||||
if (SkXfermode::kZero_Coeff == uniformCoeff &&
|
||||
SkXfermode::kZero_Coeff == colorCoeff) {
|
||||
segments.fFSCode.appendf("\tgl_FragColor = %s;\n", all_zeros_vec(4));
|
||||
segments.fFSCode.appendf("\t%s = %s;\n",
|
||||
fsColorOutput,
|
||||
all_zeros_vec(4));
|
||||
wroteFragColorZero = true;
|
||||
} else if (SkXfermode::kDst_Mode != fProgramDesc.fColorFilterXfermode) {
|
||||
segments.fFSCode.appendf("\tvec4 filteredColor;\n");
|
||||
@ -447,11 +489,11 @@ bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
|
||||
// compute the partial coverage (coverage stages and edge aa)
|
||||
|
||||
GrStringBuilder inCoverage;
|
||||
bool coverageIsScalar = false;
|
||||
|
||||
// we will want to compute coverage for some blend when there is no
|
||||
// color (when dual source blending is enabled). But for now we have this if
|
||||
if (!wroteFragColorZero) {
|
||||
// we don't need to compute coverage at all if we know the final shader
|
||||
// output will be zero and we don't have a dual src blend output.
|
||||
if (!wroteFragColorZero ||
|
||||
ProgramDesc::kNone_DualSrcOutput != fProgramDesc.fDualSrcOutput) {
|
||||
if (fProgramDesc.fEdgeAANumEdges > 0) {
|
||||
segments.fFSUnis.append("uniform vec3 " EDGES_UNI_NAME "[");
|
||||
segments.fFSUnis.appendS32(fProgramDesc.fEdgeAANumEdges);
|
||||
@ -483,7 +525,6 @@ bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
|
||||
}
|
||||
segments.fFSCode.append(";\n");
|
||||
inCoverage = "edgeAlpha";
|
||||
coverageIsScalar = true;
|
||||
}
|
||||
|
||||
GrStringBuilder outCoverage;
|
||||
@ -516,26 +557,48 @@ bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
|
||||
&segments,
|
||||
&programData->fUniLocations.fStages[s]);
|
||||
inCoverage = outCoverage;
|
||||
coverageIsScalar = false;
|
||||
}
|
||||
}
|
||||
if (ProgramDesc::kNone_DualSrcOutput != fProgramDesc.fDualSrcOutput) {
|
||||
segments.fFSOutputs.appendf("out vec4 %s;\n",
|
||||
dual_source_output_name());
|
||||
bool outputIsZero = false;
|
||||
GrStringBuilder coeff;
|
||||
if (ProgramDesc::kCoverage_DualSrcOutput !=
|
||||
fProgramDesc.fDualSrcOutput && !wroteFragColorZero) {
|
||||
if (!inColor.size()) {
|
||||
outputIsZero = true;
|
||||
} else {
|
||||
if (fProgramDesc.fDualSrcOutput ==
|
||||
ProgramDesc::kCoverageISA_DualSrcOutput) {
|
||||
coeff.printf("(1 - %s.a)", inColor.c_str());
|
||||
} else {
|
||||
coeff.printf("(vec4(1,1,1,1) - %s)", inColor.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (outputIsZero) {
|
||||
segments.fFSCode.appendf("\t%s = %s;\n",
|
||||
dual_source_output_name(),
|
||||
all_zeros_vec(4));
|
||||
} else {
|
||||
modulate_helper(dual_source_output_name(),
|
||||
coeff.c_str(),
|
||||
inCoverage.c_str(),
|
||||
&segments.fFSCode);
|
||||
}
|
||||
dualSourceOutputWritten = true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: ADD dual source blend output based on coverage here
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// combine color and coverage as frag color
|
||||
|
||||
if (!wroteFragColorZero) {
|
||||
if (coverageIsScalar && !inColor.size()) {
|
||||
GrStringBuilder oldCoverage = inCoverage;
|
||||
inCoverage.swap(oldCoverage);
|
||||
inCoverage.printf("vec4(%s,%s,%s,%s)", oldCoverage.c_str(),
|
||||
oldCoverage.c_str(), oldCoverage.c_str(),
|
||||
oldCoverage.c_str());
|
||||
}
|
||||
modulate_helper("gl_FragColor", inColor.c_str(),
|
||||
inCoverage.c_str(), &segments.fFSCode);
|
||||
modulate_helper(fsColorOutput,
|
||||
inColor.c_str(),
|
||||
inCoverage.c_str(),
|
||||
&segments.fFSCode);
|
||||
}
|
||||
|
||||
segments.fVSCode.append("}\n");
|
||||
@ -548,7 +611,10 @@ bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this->bindAttribsAndLinkProgram(texCoordAttrs, programData)) {
|
||||
if (!this->bindOutputsAttribsAndLinkProgram(texCoordAttrs,
|
||||
usingDeclaredOutputs,
|
||||
dualSourceOutputWritten,
|
||||
programData)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -560,10 +626,16 @@ bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
|
||||
bool GrGLProgram::CompileFSAndVS(const ShaderCodeSegments& segments,
|
||||
CachedData* programData) {
|
||||
|
||||
const char* strings[4];
|
||||
int lengths[4];
|
||||
static const int MAX_STRINGS = 6;
|
||||
const char* strings[MAX_STRINGS];
|
||||
int lengths[MAX_STRINGS];
|
||||
int stringCnt = 0;
|
||||
|
||||
if (segments.fHeader.size()) {
|
||||
strings[stringCnt] = segments.fHeader.c_str();
|
||||
lengths[stringCnt] = segments.fHeader.size();
|
||||
++stringCnt;
|
||||
}
|
||||
if (segments.fVSUnis.size()) {
|
||||
strings[stringCnt] = segments.fVSUnis.c_str();
|
||||
lengths[stringCnt] = segments.fVSUnis.size();
|
||||
@ -586,12 +658,14 @@ bool GrGLProgram::CompileFSAndVS(const ShaderCodeSegments& segments,
|
||||
++stringCnt;
|
||||
|
||||
#if PRINT_SHADERS
|
||||
GrPrintf(segments.fHeader.c_str());
|
||||
GrPrintf(segments.fVSUnis.c_str());
|
||||
GrPrintf(segments.fVSAttrs.c_str());
|
||||
GrPrintf(segments.fVaryings.c_str());
|
||||
GrPrintf(segments.fVSCode.c_str());
|
||||
GrPrintf("\n");
|
||||
#endif
|
||||
GrAssert(stringCnt <= MAX_STRINGS);
|
||||
programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER,
|
||||
stringCnt,
|
||||
strings,
|
||||
@ -603,6 +677,11 @@ bool GrGLProgram::CompileFSAndVS(const ShaderCodeSegments& segments,
|
||||
|
||||
stringCnt = 0;
|
||||
|
||||
if (segments.fHeader.size()) {
|
||||
strings[stringCnt] = segments.fHeader.c_str();
|
||||
lengths[stringCnt] = segments.fHeader.size();
|
||||
++stringCnt;
|
||||
}
|
||||
if (strlen(GrShaderPrecision()) > 1) {
|
||||
strings[stringCnt] = GrShaderPrecision();
|
||||
lengths[stringCnt] = strlen(GrShaderPrecision());
|
||||
@ -618,6 +697,11 @@ bool GrGLProgram::CompileFSAndVS(const ShaderCodeSegments& segments,
|
||||
lengths[stringCnt] = segments.fVaryings.size();
|
||||
++stringCnt;
|
||||
}
|
||||
if (segments.fFSOutputs.size()) {
|
||||
strings[stringCnt] = segments.fFSOutputs.c_str();
|
||||
lengths[stringCnt] = segments.fFSOutputs.size();
|
||||
++stringCnt;
|
||||
}
|
||||
|
||||
GrAssert(segments.fFSCode.size());
|
||||
strings[stringCnt] = segments.fFSCode.c_str();
|
||||
@ -625,12 +709,15 @@ bool GrGLProgram::CompileFSAndVS(const ShaderCodeSegments& segments,
|
||||
++stringCnt;
|
||||
|
||||
#if PRINT_SHADERS
|
||||
GrPrintf(segments.fHeader.c_str());
|
||||
GrPrintf(GrShaderPrecision());
|
||||
GrPrintf(segments.fFSUnis.c_str());
|
||||
GrPrintf(segments.fVaryings.c_str());
|
||||
GrPrintf(segments.fFSOutputs.c_str());
|
||||
GrPrintf(segments.fFSCode.c_str());
|
||||
GrPrintf("\n");
|
||||
#endif
|
||||
GrAssert(stringCnt <= MAX_STRINGS);
|
||||
programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER,
|
||||
stringCnt,
|
||||
strings,
|
||||
@ -639,6 +726,7 @@ bool GrGLProgram::CompileFSAndVS(const ShaderCodeSegments& segments,
|
||||
if (!programData->fFShaderID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -678,8 +766,11 @@ GrGLuint GrGLProgram::CompileShader(GrGLenum type,
|
||||
return shader;
|
||||
}
|
||||
|
||||
bool GrGLProgram::bindAttribsAndLinkProgram(GrStringBuilder texCoordAttrNames[],
|
||||
CachedData* programData) const {
|
||||
bool GrGLProgram::bindOutputsAttribsAndLinkProgram(
|
||||
GrStringBuilder texCoordAttrNames[],
|
||||
bool bindColorOut,
|
||||
bool bindDualSrcOut,
|
||||
CachedData* programData) const {
|
||||
programData->fProgramID = GR_GL(CreateProgram());
|
||||
if (!programData->fProgramID) {
|
||||
return false;
|
||||
@ -689,6 +780,15 @@ bool GrGLProgram::bindAttribsAndLinkProgram(GrStringBuilder texCoordAttrNames[],
|
||||
GR_GL(AttachShader(progID, programData->fVShaderID));
|
||||
GR_GL(AttachShader(progID, programData->fFShaderID));
|
||||
|
||||
if (bindColorOut) {
|
||||
GR_GL(BindFragDataLocationIndexed(programData->fProgramID,
|
||||
0, 0, declared_color_output_name()));
|
||||
}
|
||||
if (bindDualSrcOut) {
|
||||
GR_GL(BindFragDataLocationIndexed(programData->fProgramID,
|
||||
0, 1, dual_source_output_name()));
|
||||
}
|
||||
|
||||
// Bind the attrib locations to same values for all shaders
|
||||
GR_GL(BindAttribLocation(progID, PositionAttributeIdx(), POS_ATTR_NAME));
|
||||
for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
|
||||
@ -699,7 +799,6 @@ bool GrGLProgram::bindAttribsAndLinkProgram(GrStringBuilder texCoordAttrNames[],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (kSetAsAttribute == programData->fUniLocations.fViewMatrixUni) {
|
||||
GR_GL(BindAttribLocation(progID,
|
||||
ViewMatrixAttributeIdx(),
|
||||
@ -1072,7 +1171,7 @@ void GrGLProgram::genStageCode(int stageNum,
|
||||
segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear);
|
||||
segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str());
|
||||
} else {
|
||||
segments->fFSCode.appendf("\t%s = %s(%s, %s)%s %s;\n", fsOutColor, texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), smear, modulate.c_str());
|
||||
segments->fFSCode.appendf("\t%s = %s(%s, %s)%s%s;\n", fsOutColor, texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), smear, modulate.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,17 +19,19 @@
|
||||
|
||||
#include "GrGLInterface.h"
|
||||
#include "GrStringBuilder.h"
|
||||
#include "GrDrawTarget.h"
|
||||
#include "GrGpu.h"
|
||||
|
||||
#include "SkXfermode.h"
|
||||
|
||||
class GrBinHashKeyBuilder;
|
||||
|
||||
struct ShaderCodeSegments {
|
||||
GrStringBuilder fHeader; // VS+FS, GLSL version, etc
|
||||
GrStringBuilder fVSUnis;
|
||||
GrStringBuilder fVSAttrs;
|
||||
GrStringBuilder fVaryings;
|
||||
GrStringBuilder fFSUnis;
|
||||
GrStringBuilder fFSOutputs;
|
||||
GrStringBuilder fVSCode;
|
||||
GrStringBuilder fFSCode;
|
||||
};
|
||||
@ -65,6 +67,14 @@ public:
|
||||
*/
|
||||
bool genProgram(CachedData* programData) const;
|
||||
|
||||
/**
|
||||
* The shader may modify the blend coeffecients. Params are in/out
|
||||
*/
|
||||
void overrideBlend(GrBlendCoeff* srcCoeff, GrBlendCoeff* dstCoeff) const;
|
||||
|
||||
/**
|
||||
* Attribute indices
|
||||
*/
|
||||
static int PositionAttributeIdx() { return 0; }
|
||||
static int TexCoordAttributeIdx(int tcIdx) { return 1 + tcIdx; }
|
||||
static int ColorAttributeIdx() { return 1 + GrDrawTarget::kMaxTexCoords; }
|
||||
@ -94,6 +104,17 @@ private:
|
||||
kUniform_ColorType = 2,
|
||||
} fColorType;
|
||||
|
||||
// Dual-src blending makes use of a secondary output color that can be
|
||||
// used as a per-pixel blend coeffecient. This controls whether a
|
||||
// secondary source is output and what value it holds.
|
||||
enum DualSrcOutput {
|
||||
kNone_DualSrcOutput,
|
||||
kCoverage_DualSrcOutput,
|
||||
kCoverageISA_DualSrcOutput,
|
||||
kCoverageISC_DualSrcOutput,
|
||||
kDualSrcOutputCnt
|
||||
} fDualSrcOutput;
|
||||
|
||||
int fFirstCoverageStage;
|
||||
bool fEmitsPointSize;
|
||||
int fEdgeAANumEdges;
|
||||
@ -181,7 +202,6 @@ public:
|
||||
memcpy(this, &other, sizeof(*this));
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// IDs
|
||||
@ -238,8 +258,11 @@ private:
|
||||
|
||||
// Creates a GL program ID, binds shader attributes to GL vertex attrs, and
|
||||
// links the program
|
||||
bool bindAttribsAndLinkProgram(GrStringBuilder texCoordAttrNames[GrDrawTarget::kMaxTexCoords],
|
||||
CachedData* programData) const;
|
||||
bool bindOutputsAttribsAndLinkProgram(
|
||||
GrStringBuilder texCoordAttrNames[GrDrawTarget::kMaxTexCoords],
|
||||
bool bindColorOut,
|
||||
bool bindDualSrcOut,
|
||||
CachedData* programData) const;
|
||||
|
||||
// Gets locations for all uniforms set to kUseUniform and initializes cache
|
||||
// to invalid values.
|
||||
|
@ -42,9 +42,15 @@ static const GrGLenum gXfermodeCoeff2Blend[] = {
|
||||
GR_GL_ONE_MINUS_CONSTANT_COLOR,
|
||||
GR_GL_CONSTANT_ALPHA,
|
||||
GR_GL_ONE_MINUS_CONSTANT_ALPHA,
|
||||
|
||||
// extended blend coeffs
|
||||
GR_GL_SRC1_COLOR,
|
||||
GR_GL_ONE_MINUS_SRC1_COLOR,
|
||||
GR_GL_SRC1_ALPHA,
|
||||
GR_GL_ONE_MINUS_SRC1_ALPHA,
|
||||
};
|
||||
|
||||
bool GrGpuGL::BlendCoefReferencesConstant(GrBlendCoeff coeff) {
|
||||
bool GrGpuGL::BlendCoeffReferencesConstant(GrBlendCoeff coeff) {
|
||||
static const bool gCoeffReferencesBlendConst[] = {
|
||||
false,
|
||||
false,
|
||||
@ -60,28 +66,40 @@ bool GrGpuGL::BlendCoefReferencesConstant(GrBlendCoeff coeff) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
|
||||
// extended blend coeffs
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
};
|
||||
return gCoeffReferencesBlendConst[coeff];
|
||||
GR_STATIC_ASSERT(kBlendCoeffCount == GR_ARRAY_COUNT(gCoeffReferencesBlendConst));
|
||||
GR_STATIC_ASSERT(kTotalBlendCoeffCount == GR_ARRAY_COUNT(gCoeffReferencesBlendConst));
|
||||
|
||||
GR_STATIC_ASSERT(0 == kZero_BlendCoeff);
|
||||
GR_STATIC_ASSERT(1 == kOne_BlendCoeff);
|
||||
GR_STATIC_ASSERT(2 == kSC_BlendCoeff);
|
||||
GR_STATIC_ASSERT(3 == kISC_BlendCoeff);
|
||||
GR_STATIC_ASSERT(4 == kDC_BlendCoeff);
|
||||
GR_STATIC_ASSERT(5 == kIDC_BlendCoeff);
|
||||
GR_STATIC_ASSERT(6 == kSA_BlendCoeff);
|
||||
GR_STATIC_ASSERT(7 == kISA_BlendCoeff);
|
||||
GR_STATIC_ASSERT(8 == kDA_BlendCoeff);
|
||||
GR_STATIC_ASSERT(9 == kIDA_BlendCoeff);
|
||||
GR_STATIC_ASSERT(10 == kConstC_BlendCoeff);
|
||||
GR_STATIC_ASSERT(11 == kIConstC_BlendCoeff);
|
||||
GR_STATIC_ASSERT(12 == kConstA_BlendCoeff);
|
||||
GR_STATIC_ASSERT(13 == kIConstA_BlendCoeff);
|
||||
|
||||
GR_STATIC_ASSERT(14 == kS2C_BlendCoeff);
|
||||
GR_STATIC_ASSERT(15 == kIS2C_BlendCoeff);
|
||||
GR_STATIC_ASSERT(16 == kS2A_BlendCoeff);
|
||||
GR_STATIC_ASSERT(17 == kIS2A_BlendCoeff);
|
||||
|
||||
// assertion for gXfermodeCoeff2Blend have to be in GrGpu scope
|
||||
GR_STATIC_ASSERT(kTotalBlendCoeffCount == GR_ARRAY_COUNT(gXfermodeCoeff2Blend));
|
||||
}
|
||||
|
||||
GR_STATIC_ASSERT(0 == kZero_BlendCoeff);
|
||||
GR_STATIC_ASSERT(1 == kOne_BlendCoeff);
|
||||
GR_STATIC_ASSERT(2 == kSC_BlendCoeff);
|
||||
GR_STATIC_ASSERT(3 == kISC_BlendCoeff);
|
||||
GR_STATIC_ASSERT(4 == kDC_BlendCoeff);
|
||||
GR_STATIC_ASSERT(5 == kIDC_BlendCoeff);
|
||||
GR_STATIC_ASSERT(6 == kSA_BlendCoeff);
|
||||
GR_STATIC_ASSERT(7 == kISA_BlendCoeff);
|
||||
GR_STATIC_ASSERT(8 == kDA_BlendCoeff);
|
||||
GR_STATIC_ASSERT(9 == kIDA_BlendCoeff);
|
||||
GR_STATIC_ASSERT(10 == kConstC_BlendCoeff);
|
||||
GR_STATIC_ASSERT(11 == kIConstC_BlendCoeff);
|
||||
GR_STATIC_ASSERT(12 == kConstA_BlendCoeff);
|
||||
GR_STATIC_ASSERT(13 == kIConstA_BlendCoeff);
|
||||
|
||||
GR_STATIC_ASSERT(kBlendCoeffCount == GR_ARRAY_COUNT(gXfermodeCoeff2Blend));
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void GrGpuGL::AdjustTextureMatrix(const GrGLTexture* texture,
|
||||
@ -1652,7 +1670,9 @@ void GrGpuGL::flushAAState(GrPrimitiveType type) {
|
||||
}
|
||||
}
|
||||
|
||||
void GrGpuGL::flushBlend(GrPrimitiveType type) {
|
||||
void GrGpuGL::flushBlend(GrPrimitiveType type,
|
||||
GrBlendCoeff srcCoeff,
|
||||
GrBlendCoeff dstCoeff) {
|
||||
if (GrIsPrimTypeLines(type) && useSmoothLines()) {
|
||||
if (fHWBlendDisabled) {
|
||||
GR_GL(Enable(GR_GL_BLEND));
|
||||
@ -1676,15 +1696,15 @@ void GrGpuGL::flushBlend(GrPrimitiveType type) {
|
||||
fHWBlendDisabled = blendOff;
|
||||
}
|
||||
if (!blendOff) {
|
||||
if (fHWDrawState.fSrcBlend != fCurrDrawState.fSrcBlend ||
|
||||
fHWDrawState.fDstBlend != fCurrDrawState.fDstBlend) {
|
||||
GR_GL(BlendFunc(gXfermodeCoeff2Blend[fCurrDrawState.fSrcBlend],
|
||||
gXfermodeCoeff2Blend[fCurrDrawState.fDstBlend]));
|
||||
fHWDrawState.fSrcBlend = fCurrDrawState.fSrcBlend;
|
||||
fHWDrawState.fDstBlend = fCurrDrawState.fDstBlend;
|
||||
if (fHWDrawState.fSrcBlend != srcCoeff ||
|
||||
fHWDrawState.fDstBlend != dstCoeff) {
|
||||
GR_GL(BlendFunc(gXfermodeCoeff2Blend[srcCoeff],
|
||||
gXfermodeCoeff2Blend[dstCoeff]));
|
||||
fHWDrawState.fSrcBlend = srcCoeff;
|
||||
fHWDrawState.fDstBlend = dstCoeff;
|
||||
}
|
||||
if ((BlendCoefReferencesConstant(fCurrDrawState.fSrcBlend) ||
|
||||
BlendCoefReferencesConstant(fCurrDrawState.fDstBlend)) &&
|
||||
if ((BlendCoeffReferencesConstant(srcCoeff) ||
|
||||
BlendCoeffReferencesConstant(dstCoeff)) &&
|
||||
fHWDrawState.fBlendConstant != fCurrDrawState.fBlendConstant) {
|
||||
|
||||
float c[] = {
|
||||
@ -1787,7 +1807,6 @@ bool GrGpuGL::flushGLStateCommon(GrPrimitiveType type) {
|
||||
}
|
||||
this->flushRenderTarget(rect);
|
||||
this->flushAAState(type);
|
||||
this->flushBlend(type);
|
||||
|
||||
if ((fCurrDrawState.fFlagBits & kDither_StateBit) !=
|
||||
(fHWDrawState.fFlagBits & kDither_StateBit)) {
|
||||
|
@ -116,13 +116,17 @@ protected:
|
||||
// flushes state that is common to fixed and programmable GL
|
||||
// dither
|
||||
// line smoothing
|
||||
// blend func
|
||||
// texture binding
|
||||
// sampler state (filtering, tiling)
|
||||
// FBO binding
|
||||
// line width
|
||||
bool flushGLStateCommon(GrPrimitiveType type);
|
||||
|
||||
// subclass should call this to flush the blend state
|
||||
void flushBlend(GrPrimitiveType type,
|
||||
GrBlendCoeff srcCoeff,
|
||||
GrBlendCoeff dstCoeff);
|
||||
|
||||
// adjusts texture matrix to account for orientation, size, and npotness
|
||||
static void AdjustTextureMatrix(const GrGLTexture* texture,
|
||||
GrSamplerState::SampleMode mode,
|
||||
@ -134,7 +138,7 @@ protected:
|
||||
static bool TextureMatrixIsIdentity(const GrGLTexture* texture,
|
||||
const GrSamplerState& sampler);
|
||||
|
||||
static bool BlendCoefReferencesConstant(GrBlendCoeff coeff);
|
||||
static bool BlendCoeffReferencesConstant(GrBlendCoeff coeff);
|
||||
|
||||
private:
|
||||
|
||||
@ -156,7 +160,6 @@ private:
|
||||
void flushRenderTarget(const GrIRect* bound);
|
||||
void flushStencil();
|
||||
void flushAAState(GrPrimitiveType type);
|
||||
void flushBlend(GrPrimitiveType type);
|
||||
|
||||
void resolveRenderTarget(GrGLRenderTarget* texture);
|
||||
|
||||
|
@ -57,6 +57,7 @@ static const GrGLenum gMatrixMode2Enum[] = {
|
||||
|
||||
GrGpuGLFixed::GrGpuGLFixed() {
|
||||
f4X4DownsampleFilterSupport = false;
|
||||
fDualSourceBlendingSupport = false;
|
||||
}
|
||||
|
||||
GrGpuGLFixed::~GrGpuGLFixed() {
|
||||
@ -136,8 +137,8 @@ bool GrGpuGLFixed::flushGraphicsState(GrPrimitiveType type) {
|
||||
}
|
||||
|
||||
if (GR_GL_SUPPORT_ES1) {
|
||||
if (BlendCoefReferencesConstant(fCurrDrawState.fSrcBlend) ||
|
||||
BlendCoefReferencesConstant(fCurrDrawState.fDstBlend)) {
|
||||
if (BlendCoeffReferencesConstant(fCurrDrawState.fSrcBlend) ||
|
||||
BlendCoeffReferencesConstant(fCurrDrawState.fDstBlend)) {
|
||||
unimpl("ES1 doesn't support blend constant");
|
||||
return false;
|
||||
}
|
||||
@ -147,6 +148,8 @@ bool GrGpuGLFixed::flushGraphicsState(GrPrimitiveType type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this->flushBlend(type, fCurrDrawState.fSrcBlend, fCurrDrawState.fDstBlend);
|
||||
|
||||
if (fDirtyFlags.fRenderTargetChanged) {
|
||||
flushProjectionMatrix();
|
||||
}
|
||||
|
@ -195,6 +195,15 @@ void GrGpuGLShaders::ProgramUnitTest() {
|
||||
|
||||
pdesc.fEdgeAANumEdges = (random.nextF() * (getMaxEdges() + 1));
|
||||
|
||||
if (fDualSourceBlendingSupport) {
|
||||
pdesc.fDualSrcOutput =
|
||||
(GrGLProgram::ProgramDesc::DualSrcOutput)
|
||||
(int)(random.nextF() * GrGLProgram::ProgramDesc::kDualSrcOutputCnt);
|
||||
} else {
|
||||
pdesc.fDualSrcOutput =
|
||||
GrGLProgram::ProgramDesc::kNone_DualSrcOutput;
|
||||
}
|
||||
|
||||
for (int s = 0; s < kNumStages; ++s) {
|
||||
// enable the stage?
|
||||
if (random.nextF() > .5f) {
|
||||
@ -234,7 +243,17 @@ void GrGpuGLShaders::ProgramUnitTest() {
|
||||
GrGpuGLShaders::GrGpuGLShaders() {
|
||||
|
||||
resetContext();
|
||||
int major, minor;
|
||||
gl_version(&major, &minor);
|
||||
|
||||
f4X4DownsampleFilterSupport = true;
|
||||
if (GR_GL_SUPPORT_DESKTOP) {
|
||||
fDualSourceBlendingSupport =
|
||||
major > 3 ||(3 == major && 3 <= minor) ||
|
||||
has_gl_extension("GL_ARB_blend_func_extended");
|
||||
} else {
|
||||
fDualSourceBlendingSupport = false;
|
||||
}
|
||||
|
||||
fProgramData = NULL;
|
||||
fProgramCache = new ProgramCache();
|
||||
@ -533,6 +552,11 @@ bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
|
||||
GR_GL(UseProgram(fProgramData->fProgramID));
|
||||
fHWProgramID = fProgramData->fProgramID;
|
||||
}
|
||||
GrBlendCoeff srcCoeff = fCurrDrawState.fSrcBlend;
|
||||
GrBlendCoeff dstCoeff = fCurrDrawState.fDstBlend;
|
||||
|
||||
fCurrentProgram.overrideBlend(&srcCoeff, &dstCoeff);
|
||||
this->flushBlend(type, srcCoeff, dstCoeff);
|
||||
|
||||
this->flushColor();
|
||||
|
||||
@ -677,16 +701,6 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
|
||||
|
||||
desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
|
||||
|
||||
// coverage vs. color only applies when there is a color filter
|
||||
// (currently)
|
||||
if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) {
|
||||
desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
|
||||
} else {
|
||||
// use canonical value when this won't affect generated
|
||||
// code to prevent duplicate programs.
|
||||
desc.fFirstCoverageStage = kNumStages;
|
||||
}
|
||||
|
||||
#if GR_AGGRESSIVE_SHADER_OPTS
|
||||
if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
|
||||
desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
|
||||
@ -704,12 +718,15 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
|
||||
|
||||
desc.fEdgeAANumEdges = fCurrDrawState.fEdgeAANumEdges;
|
||||
|
||||
int lastEnabledStage = -1;
|
||||
|
||||
for (int s = 0; s < kNumStages; ++s) {
|
||||
GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
|
||||
|
||||
stage.fEnabled = this->isStageEnabled(s);
|
||||
|
||||
if (stage.fEnabled) {
|
||||
lastEnabledStage = s;
|
||||
GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
|
||||
GrAssert(NULL != texture);
|
||||
// we matrix to invert when orientation is TopDown, so make sure
|
||||
@ -775,6 +792,43 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
|
||||
stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
|
||||
}
|
||||
}
|
||||
|
||||
desc.fDualSrcOutput = GrGLProgram::ProgramDesc::kNone_DualSrcOutput;
|
||||
// use canonical value when coverage/color distinction won't affect
|
||||
// generated code to prevent duplicate programs.
|
||||
desc.fFirstCoverageStage = kNumStages;
|
||||
if (fCurrDrawState.fFirstCoverageStage <= lastEnabledStage) {
|
||||
// color filter is applied between color/coverage computation
|
||||
if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) {
|
||||
desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
|
||||
}
|
||||
|
||||
// We could consider cases where the final color is solid (0xff alpha)
|
||||
// and the dst coeff can correctly be set to a non-dualsrc gl value.
|
||||
// (e.g. solid draw, and dst coeff is kZero. It's correct to make
|
||||
// the dst coeff be kISA. Or solid draw with kSA can be tweaked to be
|
||||
// kOne).
|
||||
if (fDualSourceBlendingSupport) {
|
||||
if (kZero_BlendCoeff == fCurrDrawState.fDstBlend) {
|
||||
// write the coverage value to second color
|
||||
desc.fDualSrcOutput =
|
||||
GrGLProgram::ProgramDesc::kCoverage_DualSrcOutput;
|
||||
desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
|
||||
} else if (kSA_BlendCoeff == fCurrDrawState.fDstBlend) {
|
||||
// SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
|
||||
// cover
|
||||
desc.fDualSrcOutput =
|
||||
GrGLProgram::ProgramDesc::kCoverageISA_DualSrcOutput;
|
||||
desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
|
||||
} else if (kSC_BlendCoeff == fCurrDrawState.fDstBlend) {
|
||||
// SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
|
||||
// cover
|
||||
desc.fDualSrcOutput =
|
||||
GrGLProgram::ProgramDesc::kCoverageISC_DualSrcOutput;
|
||||
desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -155,6 +155,8 @@ void GrGLSetDefaultGLInterface() {
|
||||
gDefaultInterface.fBlitFramebuffer = glBlitFramebufferEXT;
|
||||
#endif
|
||||
#endif
|
||||
gDefaultInterface.fBindFragDataLocationIndexed = NULL;
|
||||
|
||||
gDefaultInterface.fBindingsExported = kDesktop_GrGLBinding;
|
||||
|
||||
gDefaultInterfaceInit = true;
|
||||
|
@ -174,6 +174,7 @@ void GrGLSetDefaultGLInterface() {
|
||||
// we must have FBOs
|
||||
return;
|
||||
}
|
||||
GR_GL_GET_PROC(BindFragDataLocationIndexed);
|
||||
gDefaultInterface.fBindingsExported = kDesktop_GrGLBinding;
|
||||
|
||||
gDefaultInterfaceInit = true;
|
||||
|
@ -133,6 +133,7 @@ void GrGLSetDefaultGLInterface() {
|
||||
GR_GL_GET_PROC(VertexAttribPointer);
|
||||
gDefaultInterface.fVertexPointer = glVertexPointer;
|
||||
gDefaultInterface.fViewport = glViewport;
|
||||
GR_GL_GET_PROC(BindFragDataLocationIndexed);
|
||||
|
||||
// First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since
|
||||
// GL_ARB_framebuffer_object doesn't use ARB suffix.)
|
||||
|
@ -139,6 +139,7 @@ void GrGLSetDefaultGLInterface() {
|
||||
GR_GL_GET_PROC(UseProgram);
|
||||
GR_GL_GET_PROC(VertexAttrib4fv);
|
||||
GR_GL_GET_PROC(VertexAttribPointer);
|
||||
GR_GL_GET_PROC(BindFragDataLocationIndexed);
|
||||
|
||||
// First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since
|
||||
// GL_ARB_framebuffer_object doesn't use ARB suffix.)
|
||||
|
@ -1504,6 +1504,7 @@
|
||||
'../samplecode/SampleUnitMapper.cpp',
|
||||
'../samplecode/SampleVertices.cpp',
|
||||
'../samplecode/SampleXfermodes.cpp',
|
||||
'../samplecode/SampleXfermodesBlur.cpp',
|
||||
],
|
||||
'sources!': [
|
||||
'../samplecode/SampleSkLayer.cpp', #relies on SkMatrix44 which doesn't compile
|
||||
|
182
samplecode/SampleXfermodesBlur.cpp
Normal file
182
samplecode/SampleXfermodesBlur.cpp
Normal file
@ -0,0 +1,182 @@
|
||||
#include "SampleCode.h"
|
||||
#include "SkView.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "Sk64.h"
|
||||
#include "SkCornerPathEffect.h"
|
||||
#include "SkGradientShader.h"
|
||||
#include "SkGraphics.h"
|
||||
#include "SkImageDecoder.h"
|
||||
#include "SkKernel33MaskFilter.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkRandom.h"
|
||||
#include "SkRegion.h"
|
||||
#include "SkShader.h"
|
||||
#include "SkUtils.h"
|
||||
#include "SkColorPriv.h"
|
||||
#include "SkColorFilter.h"
|
||||
#include "SkTime.h"
|
||||
#include "SkTypeface.h"
|
||||
#include "SkXfermode.h"
|
||||
|
||||
#include "SkStream.h"
|
||||
#include "SkXMLParser.h"
|
||||
#include "SkColorPriv.h"
|
||||
#include "SkImageDecoder.h"
|
||||
#include "SkBlurMaskFilter.h"
|
||||
|
||||
static void setNamedTypeface(SkPaint* paint, const char name[]) {
|
||||
SkTypeface* face = SkTypeface::CreateFromName(name, SkTypeface::kNormal);
|
||||
paint->setTypeface(face);
|
||||
SkSafeUnref(face);
|
||||
}
|
||||
|
||||
static uint16_t gBG[] = { 0xFFFF, 0xCCCF, 0xCCCF, 0xFFFF };
|
||||
|
||||
class XfermodesBlurView : public SampleView {
|
||||
SkBitmap fBG;
|
||||
SkBitmap fSrcB, fDstB;
|
||||
|
||||
void draw_mode(SkCanvas* canvas, SkXfermode* mode, int alpha,
|
||||
SkScalar x, SkScalar y) {
|
||||
SkPaint p;
|
||||
SkMaskFilter* mf = SkBlurMaskFilter::Create(5, SkBlurMaskFilter::kNormal_BlurStyle, 0);
|
||||
p.setMaskFilter(mf)->unref();
|
||||
|
||||
SkScalar ww = SkIntToScalar(W);
|
||||
SkScalar hh = SkIntToScalar(H);
|
||||
|
||||
// draw a circle covering the upper
|
||||
// left three quarters of the canvas
|
||||
p.setColor(0xFFCC44FF);
|
||||
SkRect r;
|
||||
r.set(0, 0, ww*3/4, hh*3/4);
|
||||
r.offset(x, y);
|
||||
canvas->drawOval(r, p);
|
||||
|
||||
p.setXfermode(mode);
|
||||
|
||||
// draw a square overlapping the circle
|
||||
// in the lower right of the canvas
|
||||
p.setColor(0x00AA6633 | alpha << 24);
|
||||
r.set(ww/3, hh/3, ww*19/20, hh*19/20);
|
||||
r.offset(x, y);
|
||||
canvas->drawRect(r, p);
|
||||
}
|
||||
|
||||
public:
|
||||
const static int W = 64;
|
||||
const static int H = 64;
|
||||
XfermodesBlurView() {
|
||||
const int W = 64;
|
||||
const int H = 64;
|
||||
|
||||
fBG.setConfig(SkBitmap::kARGB_4444_Config, 2, 2, 4);
|
||||
fBG.setPixels(gBG);
|
||||
fBG.setIsOpaque(true);
|
||||
}
|
||||
|
||||
protected:
|
||||
// overrides from SkEventSink
|
||||
virtual bool onQuery(SkEvent* evt) {
|
||||
if (SampleCode::TitleQ(*evt)) {
|
||||
SampleCode::TitleR(evt, "XfermodesBlur");
|
||||
return true;
|
||||
}
|
||||
return this->INHERITED::onQuery(evt);
|
||||
}
|
||||
|
||||
virtual void onDrawContent(SkCanvas* canvas) {
|
||||
canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
|
||||
|
||||
const struct {
|
||||
SkXfermode::Mode fMode;
|
||||
const char* fLabel;
|
||||
} gModes[] = {
|
||||
{ SkXfermode::kClear_Mode, "Clear" },
|
||||
{ SkXfermode::kSrc_Mode, "Src" },
|
||||
{ SkXfermode::kDst_Mode, "Dst" },
|
||||
{ SkXfermode::kSrcOver_Mode, "SrcOver" },
|
||||
{ SkXfermode::kDstOver_Mode, "DstOver" },
|
||||
{ SkXfermode::kSrcIn_Mode, "SrcIn" },
|
||||
{ SkXfermode::kDstIn_Mode, "DstIn" },
|
||||
{ SkXfermode::kSrcOut_Mode, "SrcOut" },
|
||||
{ SkXfermode::kDstOut_Mode, "DstOut" },
|
||||
{ SkXfermode::kSrcATop_Mode, "SrcATop" },
|
||||
{ SkXfermode::kDstATop_Mode, "DstATop" },
|
||||
{ SkXfermode::kXor_Mode, "Xor" },
|
||||
|
||||
{ SkXfermode::kPlus_Mode, "Plus" },
|
||||
/*{ SkXfermode::kMultiply_Mode, "Multiply" },
|
||||
{ SkXfermode::kScreen_Mode, "Screen" },
|
||||
{ SkXfermode::kOverlay_Mode, "Overlay" },
|
||||
{ SkXfermode::kDarken_Mode, "Darken" },
|
||||
{ SkXfermode::kLighten_Mode, "Lighten" },
|
||||
{ SkXfermode::kColorDodge_Mode, "ColorDodge" },
|
||||
{ SkXfermode::kColorBurn_Mode, "ColorBurn" },
|
||||
{ SkXfermode::kHardLight_Mode, "HardLight" },
|
||||
{ SkXfermode::kSoftLight_Mode, "SoftLight" },
|
||||
{ SkXfermode::kDifference_Mode, "Difference" },
|
||||
{ SkXfermode::kExclusion_Mode, "Exclusion" },*/
|
||||
};
|
||||
|
||||
const SkScalar w = SkIntToScalar(W);
|
||||
const SkScalar h = SkIntToScalar(H);
|
||||
SkShader* s = SkShader::CreateBitmapShader(fBG,
|
||||
SkShader::kRepeat_TileMode,
|
||||
SkShader::kRepeat_TileMode);
|
||||
SkMatrix m;
|
||||
m.setScale(SkIntToScalar(6), SkIntToScalar(6));
|
||||
s->setLocalMatrix(m);
|
||||
|
||||
SkPaint labelP;
|
||||
labelP.setAntiAlias(true);
|
||||
labelP.setLCDRenderText(true);
|
||||
labelP.setTextAlign(SkPaint::kCenter_Align);
|
||||
setNamedTypeface(&labelP, "Menlo Regular");
|
||||
|
||||
const int W = 5;
|
||||
|
||||
SkScalar x0 = 0;
|
||||
for (int twice = 0; twice < 2; twice++) {
|
||||
SkScalar x = x0, y = 0;
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) {
|
||||
SkXfermode* mode = SkXfermode::Create(gModes[i].fMode);
|
||||
SkAutoUnref aur(mode);
|
||||
SkRect r;
|
||||
r.set(x, y, x+w, y+h);
|
||||
|
||||
SkPaint p;
|
||||
p.setStyle(SkPaint::kFill_Style);
|
||||
p.setShader(s);
|
||||
canvas->drawRect(r, p);
|
||||
|
||||
canvas->saveLayer(&r, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag);
|
||||
draw_mode(canvas, mode, twice ? 0x88 : 0xFF, r.fLeft, r.fTop);
|
||||
canvas->restore();
|
||||
|
||||
r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
|
||||
p.setStyle(SkPaint::kStroke_Style);
|
||||
p.setShader(NULL);
|
||||
canvas->drawRect(r, p);
|
||||
|
||||
canvas->drawText(gModes[i].fLabel, strlen(gModes[i].fLabel),
|
||||
x + w/2, y - labelP.getTextSize()/2, labelP);
|
||||
x += w + SkIntToScalar(10);
|
||||
if ((i % W) == W - 1) {
|
||||
x = x0;
|
||||
y += h + SkIntToScalar(30);
|
||||
}
|
||||
}
|
||||
x0 += SkIntToScalar(400);
|
||||
}
|
||||
s->unref();
|
||||
}
|
||||
|
||||
private:
|
||||
typedef SampleView INHERITED;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static SkView* MyFactory() { return new XfermodesBlurView; }
|
||||
static SkViewRegister reg(MyFactory);
|
@ -345,6 +345,7 @@ void kill_dummy(HWND dummy) {
|
||||
#define WGL_SUPPORT_OPENGL_ARB 0x2010
|
||||
#define WGL_DOUBLE_BUFFER_ARB 0x2011
|
||||
#define WGL_COLOR_BITS_ARB 0x2014
|
||||
#define WGL_ALPHA_BITS_ARB 0x201B
|
||||
#define WGL_STENCIL_BITS_ARB 0x2023
|
||||
#define WGL_FULL_ACCELERATION_ARB 0x2027
|
||||
|
||||
@ -419,6 +420,7 @@ HGLRC create_gl(HWND hwnd) {
|
||||
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
|
||||
WGL_SUPPORT_OPENGL_ARB, TRUE,
|
||||
WGL_COLOR_BITS_ARB, 24,
|
||||
WGL_ALPHA_BITS_ARB, 8,
|
||||
WGL_STENCIL_BITS_ARB, 8,
|
||||
#if USE_MSAA
|
||||
WGL_SAMPLE_BUFFERS_ARB, TRUE,
|
||||
|
Loading…
Reference in New Issue
Block a user