Swizzle shader output and blend when using GL_RED to implement kAlpha_8_GrPixelConfig

GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1584473002

Review URL: https://codereview.chromium.org/1584473002
This commit is contained in:
bsalomon 2016-01-12 13:29:26 -08:00 committed by Commit bot
parent 87a721b246
commit 7f9b2e4a45
11 changed files with 140 additions and 44 deletions

View File

@ -175,6 +175,7 @@
'<(skia_src_path)/gpu/GrSoftwarePathRenderer.h', '<(skia_src_path)/gpu/GrSoftwarePathRenderer.h',
'<(skia_src_path)/gpu/GrSurfacePriv.h', '<(skia_src_path)/gpu/GrSurfacePriv.h',
'<(skia_src_path)/gpu/GrSurface.cpp', '<(skia_src_path)/gpu/GrSurface.cpp',
'<(skia_src_path)/gpu/GrSwizzle.h',
'<(skia_src_path)/gpu/GrTexture.cpp', '<(skia_src_path)/gpu/GrTexture.cpp',
'<(skia_src_path)/gpu/GrTextureParamsAdjuster.h', '<(skia_src_path)/gpu/GrTextureParamsAdjuster.h',
'<(skia_src_path)/gpu/GrTextureParamsAdjuster.cpp', '<(skia_src_path)/gpu/GrTextureParamsAdjuster.cpp',

View File

@ -70,15 +70,16 @@ public:
} }
struct KeyHeader { struct KeyHeader {
uint8_t fFragPosKey; // set by GrGLShaderBuilder if there are // Set by GrGLShaderBuilder if there are effects that read the fragment position. Otherwise,
// effects that read the fragment position. // 0.
// Otherwise, 0. uint8_t fFragPosKey;
// Set to uniquely idenitify any swizzling of the shader's output color(s).
uint8_t fOutputSwizzle;
uint8_t fSnapVerticesToPixelCenters; uint8_t fSnapVerticesToPixelCenters;
int8_t fColorEffectCnt; int8_t fColorEffectCnt;
int8_t fCoverageEffectCnt; int8_t fCoverageEffectCnt;
uint8_t fIgnoresCoverage; uint8_t fIgnoresCoverage;
}; };
GR_STATIC_ASSERT(sizeof(KeyHeader) == 5);
int numColorEffects() const { int numColorEffects() const {
return this->header().fColorEffectCnt; return this->header().fColorEffectCnt;

View File

@ -9,6 +9,7 @@
#define GrSwizzle_DEFINED #define GrSwizzle_DEFINED
#include "GrTypes.h" #include "GrTypes.h"
#include "GrColor.h"
/** Represents a rgba swizzle. It can be converted either into a string or a eight bit int. /** Represents a rgba swizzle. It can be converted either into a string or a eight bit int.
Currently there is no way to specify an arbitrary swizzle, just some static swizzles and an Currently there is no way to specify an arbitrary swizzle, just some static swizzles and an
@ -17,11 +18,23 @@ class GrSwizzle {
public: public:
GrSwizzle() { *this = RGBA(); } GrSwizzle() { *this = RGBA(); }
GrSwizzle(const GrSwizzle& that) { *this = that; }
GrSwizzle& operator=(const GrSwizzle& that) { GrSwizzle& operator=(const GrSwizzle& that) {
memcpy(this, &that, sizeof(GrSwizzle)); memcpy(this, &that, sizeof(GrSwizzle));
return *this; return *this;
} }
/** Recreates a GrSwizzle from the output of asKey() */
void setFromKey(uint8_t key) {
fKey = key;
for (int i = 0; i < 4; ++i) {
fSwiz[i] = IdxToChar(key & 3);
key >>= 2;
}
SkASSERT(fSwiz[4] == 0);
}
bool operator==(const GrSwizzle& that) const { return this->asUInt() == that.asUInt(); } bool operator==(const GrSwizzle& that) const { return this->asUInt() == that.asUInt(); }
bool operator!=(const GrSwizzle& that) const { return !(*this == that); } bool operator!=(const GrSwizzle& that) const { return !(*this == that); }
@ -32,6 +45,25 @@ public:
/** 4 char null terminated string consisting only of chars 'r', 'g', 'b', 'a'. */ /** 4 char null terminated string consisting only of chars 'r', 'g', 'b', 'a'. */
const char* c_str() const { return fSwiz; } const char* c_str() const { return fSwiz; }
/** Applies this swizzle to the input color and returns the swizzled color. */
GrColor applyTo(GrColor color) const {
int idx;
uint32_t key = fKey;
// Index of the input color that should be mapped to output r.
idx = (key & 3);
uint32_t outR = (color >> idx * 8) & 0xFF;
key >>= 2;
idx = (key & 3);
uint32_t outG = (color >> idx * 8) & 0xFF;
key >>= 2;
idx = (key & 3);
uint32_t outB = (color >> idx * 8) & 0xFF;
key >>= 2;
idx = (key & 3);
uint32_t outA = (color >> idx * 8) & 0xFF;
return GrColorPackRGBA(outR, outG, outB, outA);
}
static const GrSwizzle& RGBA() { static const GrSwizzle& RGBA() {
static GrSwizzle gRGBA("rgba"); static GrSwizzle gRGBA("rgba");
return gRGBA; return gRGBA;
@ -59,19 +91,31 @@ private:
static int CharToIdx(char c) { static int CharToIdx(char c) {
switch (c) { switch (c) {
case 'r': case 'r':
return 0; return (GrColor_SHIFT_R / 8);
case 'g': case 'g':
return 1; return (GrColor_SHIFT_G / 8);
case 'b': case 'b':
return 2; return (GrColor_SHIFT_B / 8);
case 'a': case 'a':
return 3; return (GrColor_SHIFT_A / 8);
default: default:
SkFAIL("Invalid swizzle char"); SkFAIL("Invalid swizzle char");
return 0; return 0;
} }
} }
static /* constexpr */ char IToC(int idx) {
return (8*idx) == GrColor_SHIFT_R ? 'r' :
(8*idx) == GrColor_SHIFT_G ? 'g' :
(8*idx) == GrColor_SHIFT_B ? 'b' : 'a';
}
static char IdxToChar(int c) {
// Hopefully this array gets computed at compile time.
static const char gStr[4] = { IToC(0), IToC(1), IToC(2), IToC(3) };
return gStr[c];
}
explicit GrSwizzle(const char* str) { explicit GrSwizzle(const char* str) {
SkASSERT(strlen(str) == 4); SkASSERT(strlen(str) == 4);
fSwiz[0] = str[0]; fSwiz[0] = str[0];

View File

@ -1548,6 +1548,19 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
} }
} }
// Shader output swizzles will default to RGBA. When we've use GL_RED instead of GL_ALPHA to
// implement kAlpha_8_GrPixelConfig we need to swizzle the shader outputs so the alpha channel
// gets written to the single component.
if (this->textureRedSupport()) {
for (int i = 0; i < kGrPixelConfigCnt; ++i) {
GrPixelConfig config = static_cast<GrPixelConfig>(i);
if (GrPixelConfigIsAlphaOnly(config) &&
fConfigTable[i].fFormats.fBaseInternalFormat == GR_GL_RED) {
glslCaps->fConfigOutputSwizzle[i] = GrSwizzle::AAAA();
}
}
}
#ifdef SK_DEBUG #ifdef SK_DEBUG
// Make sure we initialized everything. // Make sure we initialized everything.
ConfigInfo defaultEntry; ConfigInfo defaultEntry;

View File

@ -1570,7 +1570,10 @@ bool GrGLGpu::flushGLState(const DrawArgs& args) {
} }
if (blendInfo.fWriteColor) { if (blendInfo.fWriteColor) {
this->flushBlend(blendInfo); // Swizzle the blend to match what the shader will output.
const GrSwizzle& swizzle = this->glCaps().glslCaps()->configOutputSwizzle(
args.fPipeline->getRenderTarget()->config());
this->flushBlend(blendInfo, swizzle);
} }
SkSTArray<8, const GrTextureAccess*> textureAccesses; SkSTArray<8, const GrTextureAccess*> textureAccesses;
@ -1650,7 +1653,7 @@ void GrGLGpu::setupGeometry(const GrPrimitiveProcessor& primProc,
void GrGLGpu::buildProgramDesc(GrProgramDesc* desc, void GrGLGpu::buildProgramDesc(GrProgramDesc* desc,
const GrPrimitiveProcessor& primProc, const GrPrimitiveProcessor& primProc,
const GrPipeline& pipeline) const { const GrPipeline& pipeline) const {
if (!GrGLProgramDescBuilder::Build(desc, primProc, pipeline, this)) { if (!GrGLProgramDescBuilder::Build(desc, primProc, pipeline, *this->glCaps().glslCaps())) {
SkDEBUGFAIL("Failed to generate GL program descriptor"); SkDEBUGFAIL("Failed to generate GL program descriptor");
} }
} }
@ -2395,7 +2398,7 @@ void GrGLGpu::flushHWAAState(GrRenderTarget* rt, bool useHWAA) {
} }
} }
void GrGLGpu::flushBlend(const GrXferProcessor::BlendInfo& blendInfo) { void GrGLGpu::flushBlend(const GrXferProcessor::BlendInfo& blendInfo, const GrSwizzle& swizzle) {
// Any optimization to disable blending should have already been applied and // Any optimization to disable blending should have already been applied and
// tweaked the equation to "add" or "subtract", and the coeffs to (1, 0). // tweaked the equation to "add" or "subtract", and the coeffs to (1, 0).
@ -2448,15 +2451,16 @@ void GrGLGpu::flushBlend(const GrXferProcessor::BlendInfo& blendInfo) {
fHWBlendState.fDstCoeff = dstCoeff; fHWBlendState.fDstCoeff = dstCoeff;
} }
GrColor blendConst = blendInfo.fBlendConstant; if ((BlendCoeffReferencesConstant(srcCoeff) || BlendCoeffReferencesConstant(dstCoeff))) {
if ((BlendCoeffReferencesConstant(srcCoeff) || GrColor blendConst = blendInfo.fBlendConstant;
BlendCoeffReferencesConstant(dstCoeff)) && blendConst = swizzle.applyTo(blendConst);
(!fHWBlendState.fConstColorValid || fHWBlendState.fConstColor != blendConst)) { if (!fHWBlendState.fConstColorValid || fHWBlendState.fConstColor != blendConst) {
GrGLfloat c[4]; GrGLfloat c[4];
GrColorToRGBAFloat(blendConst, c); GrColorToRGBAFloat(blendConst, c);
GL_CALL(BlendColor(c[0], c[1], c[2], c[3])); GL_CALL(BlendColor(c[0], c[1], c[2], c[3]));
fHWBlendState.fConstColor = blendConst; fHWBlendState.fConstColor = blendConst;
fHWBlendState.fConstColorValid = true; fHWBlendState.fConstColorValid = true;
}
} }
} }
@ -2840,6 +2844,12 @@ bool GrGLGpu::onCopySurface(GrSurface* dst,
GrSurface* src, GrSurface* src,
const SkIRect& srcRect, const SkIRect& srcRect,
const SkIPoint& dstPoint) { const SkIPoint& dstPoint) {
// None of our copy methods can handle a swizzle. TODO: Make copySurfaceAsDraw handle the
// swizzle.
if (this->glCaps().glslCaps()->configOutputSwizzle(src->config()) !=
this->glCaps().glslCaps()->configOutputSwizzle(dst->config())) {
return false;
}
if (src->asTexture() && dst->asRenderTarget()) { if (src->asTexture() && dst->asRenderTarget()) {
this->copySurfaceAsDraw(dst, src, srcRect, dstPoint); this->copySurfaceAsDraw(dst, src, srcRect, dstPoint);
return true; return true;
@ -3064,6 +3074,9 @@ void GrGLGpu::createWireRectProgram() {
} }
void GrGLGpu::drawDebugWireRect(GrRenderTarget* rt, const SkIRect& rect, GrColor color) { void GrGLGpu::drawDebugWireRect(GrRenderTarget* rt, const SkIRect& rect, GrColor color) {
// TODO: This should swizzle the output to match dst's config, though it is a debugging
// visualization.
this->handleDirtyContext(); this->handleDirtyContext();
if (!fWireRectProgram.fProgram) { if (!fWireRectProgram.fProgram) {
this->createWireRectProgram(); this->createWireRectProgram();
@ -3114,7 +3127,7 @@ void GrGLGpu::drawDebugWireRect(GrRenderTarget* rt, const SkIRect& rect, GrColor
GrXferProcessor::BlendInfo blendInfo; GrXferProcessor::BlendInfo blendInfo;
blendInfo.reset(); blendInfo.reset();
this->flushBlend(blendInfo); this->flushBlend(blendInfo, GrSwizzle::RGBA());
this->flushColorWrite(true); this->flushColorWrite(true);
this->flushDrawFace(GrPipelineBuilder::kBoth_DrawFace); this->flushDrawFace(GrPipelineBuilder::kBoth_DrawFace);
this->flushHWAAState(glRT, false); this->flushHWAAState(glRT, false);
@ -3185,7 +3198,7 @@ void GrGLGpu::copySurfaceAsDraw(GrSurface* dst,
GrXferProcessor::BlendInfo blendInfo; GrXferProcessor::BlendInfo blendInfo;
blendInfo.reset(); blendInfo.reset();
this->flushBlend(blendInfo); this->flushBlend(blendInfo, GrSwizzle::RGBA());
this->flushColorWrite(true); this->flushColorWrite(true);
this->flushDrawFace(GrPipelineBuilder::kBoth_DrawFace); this->flushDrawFace(GrPipelineBuilder::kBoth_DrawFace);
this->flushHWAAState(dstRT, false); this->flushHWAAState(dstRT, false);

View File

@ -26,6 +26,7 @@
class GrPipeline; class GrPipeline;
class GrNonInstancedVertices; class GrNonInstancedVertices;
class GrSwizzle;
#ifdef SK_DEVELOPER #ifdef SK_DEVELOPER
#define PROGRAM_CACHE_STATS #define PROGRAM_CACHE_STATS
@ -199,8 +200,7 @@ private:
const GrNonInstancedVertices& vertices, const GrNonInstancedVertices& vertices,
size_t* indexOffsetInBytes); size_t* indexOffsetInBytes);
// Subclasses should call this to flush the blend state. void flushBlend(const GrXferProcessor::BlendInfo& blendInfo, const GrSwizzle&);
void flushBlend(const GrXferProcessor::BlendInfo& blendInfo);
bool hasExtension(const char* ext) const { return fGLContext->hasExtension(ext); } bool hasExtension(const char* ext) const { return fGLContext->hasExtension(ext); }

View File

@ -46,7 +46,7 @@ static void add_texture_key(GrProcessorKeyBuilder* b, const GrProcessor& proc,
* function because it is hairy, though FPs do not have attribs, and GPs do not have transforms * function because it is hairy, though FPs do not have attribs, and GPs do not have transforms
*/ */
static bool gen_meta_key(const GrProcessor& proc, static bool gen_meta_key(const GrProcessor& proc,
const GrGLCaps& caps, const GrGLSLCaps& glslCaps,
uint32_t transformKey, uint32_t transformKey,
GrProcessorKeyBuilder* b) { GrProcessorKeyBuilder* b) {
size_t processorKeySize = b->size(); size_t processorKeySize = b->size();
@ -58,7 +58,7 @@ static bool gen_meta_key(const GrProcessor& proc,
return false; return false;
} }
add_texture_key(b, proc, *caps.glslCaps()); add_texture_key(b, proc, glslCaps);
uint32_t* key = b->add32n(2); uint32_t* key = b->add32n(2);
key[0] = (classID << 16) | SkToU32(processorKeySize); key[0] = (classID << 16) | SkToU32(processorKeySize);
@ -68,25 +68,24 @@ static bool gen_meta_key(const GrProcessor& proc,
static bool gen_frag_proc_and_meta_keys(const GrPrimitiveProcessor& primProc, static bool gen_frag_proc_and_meta_keys(const GrPrimitiveProcessor& primProc,
const GrFragmentProcessor& fp, const GrFragmentProcessor& fp,
const GrGLCaps& caps, const GrGLSLCaps& glslCaps,
GrProcessorKeyBuilder* b) { GrProcessorKeyBuilder* b) {
for (int i = 0; i < fp.numChildProcessors(); ++i) { for (int i = 0; i < fp.numChildProcessors(); ++i) {
if (!gen_frag_proc_and_meta_keys(primProc, fp.childProcessor(i), caps, b)) { if (!gen_frag_proc_and_meta_keys(primProc, fp.childProcessor(i), glslCaps, b)) {
return false; return false;
} }
} }
fp.getGLSLProcessorKey(*caps.glslCaps(), b); fp.getGLSLProcessorKey(glslCaps, b);
//**** use glslCaps here? return gen_meta_key(fp, glslCaps, primProc.getTransformKey(fp.coordTransforms(),
return gen_meta_key(fp, caps, primProc.getTransformKey(fp.coordTransforms(), fp.numTransformsExclChildren()), b);
fp.numTransformsExclChildren()), b);
} }
bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc, bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc,
const GrPrimitiveProcessor& primProc, const GrPrimitiveProcessor& primProc,
const GrPipeline& pipeline, const GrPipeline& pipeline,
const GrGLGpu* gpu) { const GrGLSLCaps& glslCaps) {
// The descriptor is used as a cache key. Thus when a field of the // The descriptor is used as a cache key. Thus when a field of the
// descriptor will not affect program generation (because of the attribute // descriptor will not affect program generation (because of the attribute
// bindings in use or other descriptor field settings) it should be set // bindings in use or other descriptor field settings) it should be set
@ -101,25 +100,23 @@ bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc,
GrProcessorKeyBuilder b(&glDesc->key()); GrProcessorKeyBuilder b(&glDesc->key());
primProc.getGLSLProcessorKey(*gpu->glCaps().glslCaps(), &b); primProc.getGLSLProcessorKey(glslCaps, &b);
//**** use glslCaps here? if (!gen_meta_key(primProc, glslCaps, 0, &b)) {
if (!gen_meta_key(primProc, gpu->glCaps(), 0, &b)) {
glDesc->key().reset(); glDesc->key().reset();
return false; return false;
} }
for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) { for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
const GrFragmentProcessor& fp = pipeline.getFragmentProcessor(i); const GrFragmentProcessor& fp = pipeline.getFragmentProcessor(i);
if (!gen_frag_proc_and_meta_keys(primProc, fp, gpu->glCaps(), &b)) { if (!gen_frag_proc_and_meta_keys(primProc, fp, glslCaps, &b)) {
glDesc->key().reset(); glDesc->key().reset();
return false; return false;
} }
} }
const GrXferProcessor& xp = pipeline.getXferProcessor(); const GrXferProcessor& xp = pipeline.getXferProcessor();
xp.getGLSLProcessorKey(*gpu->glCaps().glslCaps(), &b); xp.getGLSLProcessorKey(glslCaps, &b);
//**** use glslCaps here? if (!gen_meta_key(xp, glslCaps, 0, &b)) {
if (!gen_meta_key(xp, gpu->glCaps(), 0, &b)) {
glDesc->key().reset(); glDesc->key().reset();
return false; return false;
} }
@ -139,6 +136,9 @@ bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc,
header->fFragPosKey = 0; header->fFragPosKey = 0;
} }
header->fOutputSwizzle =
glslCaps.configOutputSwizzle(pipeline.getRenderTarget()->config()).asKey();
if (pipeline.ignoresCoverage()) { if (pipeline.ignoresCoverage()) {
header->fIgnoresCoverage = 1; header->fIgnoresCoverage = 1;
} else { } else {

View File

@ -52,14 +52,13 @@ public:
* general draw information, as well as the specific color, geometry, * general draw information, as well as the specific color, geometry,
* and coverage stages which will be used to generate the GL Program for * and coverage stages which will be used to generate the GL Program for
* this optstate. * this optstate.
* @param GrGLGpu A GL Gpu, the caps and Gpu object are used to output processor specific * @param GrGLSLCaps Capabilities of the GLSL backend.
* parts of the descriptor.
* @param GrProgramDesc The built and finalized descriptor * @param GrProgramDesc The built and finalized descriptor
**/ **/
static bool Build(GrProgramDesc*, static bool Build(GrProgramDesc*,
const GrPrimitiveProcessor&, const GrPrimitiveProcessor&,
const GrPipeline&, const GrPipeline&,
const GrGLGpu*); const GrGLSLCaps&);
}; };
#endif #endif

View File

@ -10,6 +10,7 @@
#include "GrAutoLocaleSetter.h" #include "GrAutoLocaleSetter.h"
#include "GrCoordTransform.h" #include "GrCoordTransform.h"
#include "GrGLProgramBuilder.h" #include "GrGLProgramBuilder.h"
#include "GrSwizzle.h"
#include "GrTexture.h" #include "GrTexture.h"
#include "SkRTConf.h" #include "SkRTConf.h"
#include "SkTraceEvent.h" #include "SkTraceEvent.h"
@ -95,6 +96,7 @@ bool GrGLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr
inputCoverage); inputCoverage);
this->emitAndInstallXferProc(this->pipeline().getXferProcessor(), *inputColor, *inputCoverage, this->emitAndInstallXferProc(this->pipeline().getXferProcessor(), *inputColor, *inputCoverage,
this->pipeline().ignoresCoverage()); this->pipeline().ignoresCoverage());
this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOutput());
return true; return true;
} }
@ -262,6 +264,22 @@ void GrGLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
fFS.codeAppend("}"); fFS.codeAppend("}");
} }
void GrGLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) {
// Swizzle the fragment shader outputs if necessary.
GrSwizzle swizzle;
swizzle.setFromKey(this->desc().header().fOutputSwizzle);
if (swizzle != GrSwizzle::RGBA()) {
fFS.codeAppendf("%s = %s.%s;", fFS.getPrimaryColorOutputName(),
fFS.getPrimaryColorOutputName(),
swizzle.c_str());
if (hasSecondaryOutput) {
fFS.codeAppendf("%s = %s.%s;", fFS.getSecondaryColorOutputName(),
fFS.getSecondaryColorOutputName(),
swizzle.c_str());
}
}
}
void GrGLProgramBuilder::verify(const GrPrimitiveProcessor& gp) { void GrGLProgramBuilder::verify(const GrPrimitiveProcessor& gp) {
SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition()); SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition());
} }

View File

@ -92,6 +92,7 @@ private:
const GrGLSLExpr4& colorIn, const GrGLSLExpr4& colorIn,
const GrGLSLExpr4& coverageIn, const GrGLSLExpr4& coverageIn,
bool ignoresCoverage); bool ignoresCoverage);
void emitFSOutputSwizzle(bool hasSecondaryOutput);
void verify(const GrPrimitiveProcessor&); void verify(const GrPrimitiveProcessor&);
void verify(const GrXferProcessor&); void verify(const GrXferProcessor&);

View File

@ -108,12 +108,17 @@ public:
/** /**
* Given a texture's config, this determines what swizzle must be appended to accesses to the * Given a texture's config, this determines what swizzle must be appended to accesses to the
* texture in generated shader code. Swizzling may be implemented in texture parameters or a * texture in generated shader code. Swizzling may be implemented in texture parameters or a
* sampler rather than in the shader. In this case the shader swizzle will always be "rgba". * sampler rather than in the shader. In this case the returned swizzle will always be "rgba".
*/ */
const GrSwizzle& configTextureSwizzle(GrPixelConfig config) const { const GrSwizzle& configTextureSwizzle(GrPixelConfig config) const {
return fConfigTextureSwizzle[config]; return fConfigTextureSwizzle[config];
} }
/** Swizzle that should occur on the fragment shader outputs for a given config. */
const GrSwizzle& configOutputSwizzle(GrPixelConfig config) const {
return fConfigOutputSwizzle[config];
}
GrGLSLGeneration generation() const { return fGLSLGeneration; } GrGLSLGeneration generation() const { return fGLSLGeneration; }
/** /**
@ -150,6 +155,7 @@ private:
AdvBlendEqInteraction fAdvBlendEqInteraction; AdvBlendEqInteraction fAdvBlendEqInteraction;
GrSwizzle fConfigTextureSwizzle[kGrPixelConfigCnt]; GrSwizzle fConfigTextureSwizzle[kGrPixelConfigCnt];
GrSwizzle fConfigOutputSwizzle[kGrPixelConfigCnt];
friend class GrGLCaps; // For initialization. friend class GrGLCaps; // For initialization.