aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
authorGravatar bsalomon <bsalomon@google.com>2016-01-12 13:29:26 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2016-01-12 13:29:26 -0800
commit7f9b2e4a45775e8cdd3f98260a66c0c6e1840550 (patch)
tree2634c3fe68d98ece6e9a30a4db7a251303c587ca /src/gpu
parent87a721b2465c9ccfa191ce9f5012f92be7731fbc (diff)
Swizzle shader output and blend when using GL_RED to implement kAlpha_8_GrPixelConfig
Diffstat (limited to 'src/gpu')
-rw-r--r--src/gpu/GrProgramDesc.h9
-rw-r--r--src/gpu/GrSwizzle.h52
-rw-r--r--src/gpu/gl/GrGLCaps.cpp13
-rw-r--r--src/gpu/gl/GrGLGpu.cpp41
-rw-r--r--src/gpu/gl/GrGLGpu.h4
-rw-r--r--src/gpu/gl/GrGLProgramDesc.cpp32
-rw-r--r--src/gpu/gl/GrGLProgramDesc.h5
-rw-r--r--src/gpu/gl/builders/GrGLProgramBuilder.cpp18
-rw-r--r--src/gpu/gl/builders/GrGLProgramBuilder.h1
-rwxr-xr-xsrc/gpu/glsl/GrGLSLCaps.h8
10 files changed, 139 insertions, 44 deletions
diff --git a/src/gpu/GrProgramDesc.h b/src/gpu/GrProgramDesc.h
index 13dd14935d..63e060ee62 100644
--- a/src/gpu/GrProgramDesc.h
+++ b/src/gpu/GrProgramDesc.h
@@ -70,15 +70,16 @@ public:
}
struct KeyHeader {
- uint8_t fFragPosKey; // set by GrGLShaderBuilder if there are
- // effects that read the fragment position.
- // Otherwise, 0.
+ // Set by GrGLShaderBuilder if there are effects that read the fragment position. Otherwise,
+ // 0.
+ uint8_t fFragPosKey;
+ // Set to uniquely idenitify any swizzling of the shader's output color(s).
+ uint8_t fOutputSwizzle;
uint8_t fSnapVerticesToPixelCenters;
int8_t fColorEffectCnt;
int8_t fCoverageEffectCnt;
uint8_t fIgnoresCoverage;
};
- GR_STATIC_ASSERT(sizeof(KeyHeader) == 5);
int numColorEffects() const {
return this->header().fColorEffectCnt;
diff --git a/src/gpu/GrSwizzle.h b/src/gpu/GrSwizzle.h
index 87ea9534b9..48748803dd 100644
--- a/src/gpu/GrSwizzle.h
+++ b/src/gpu/GrSwizzle.h
@@ -9,6 +9,7 @@
#define GrSwizzle_DEFINED
#include "GrTypes.h"
+#include "GrColor.h"
/** 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
@@ -17,11 +18,23 @@ class GrSwizzle {
public:
GrSwizzle() { *this = RGBA(); }
+ GrSwizzle(const GrSwizzle& that) { *this = that; }
+
GrSwizzle& operator=(const GrSwizzle& that) {
memcpy(this, &that, sizeof(GrSwizzle));
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 == that); }
@@ -32,6 +45,25 @@ public:
/** 4 char null terminated string consisting only of chars 'r', 'g', 'b', 'a'. */
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 GrSwizzle gRGBA("rgba");
return gRGBA;
@@ -59,19 +91,31 @@ private:
static int CharToIdx(char c) {
switch (c) {
case 'r':
- return 0;
+ return (GrColor_SHIFT_R / 8);
case 'g':
- return 1;
+ return (GrColor_SHIFT_G / 8);
case 'b':
- return 2;
+ return (GrColor_SHIFT_B / 8);
case 'a':
- return 3;
+ return (GrColor_SHIFT_A / 8);
default:
SkFAIL("Invalid swizzle char");
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) {
SkASSERT(strlen(str) == 4);
fSwiz[0] = str[0];
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 5605babcec..678c62abb8 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -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
// Make sure we initialized everything.
ConfigInfo defaultEntry;
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index b095e66ea3..8033ea60e5 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -1570,7 +1570,10 @@ bool GrGLGpu::flushGLState(const DrawArgs& args) {
}
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;
@@ -1650,7 +1653,7 @@ void GrGLGpu::setupGeometry(const GrPrimitiveProcessor& primProc,
void GrGLGpu::buildProgramDesc(GrProgramDesc* desc,
const GrPrimitiveProcessor& primProc,
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");
}
}
@@ -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
// 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;
}
- 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;
+ if ((BlendCoeffReferencesConstant(srcCoeff) || BlendCoeffReferencesConstant(dstCoeff))) {
+ GrColor blendConst = blendInfo.fBlendConstant;
+ blendConst = swizzle.applyTo(blendConst);
+ if (!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;
+ }
}
}
@@ -2840,6 +2844,12 @@ bool GrGLGpu::onCopySurface(GrSurface* dst,
GrSurface* src,
const SkIRect& srcRect,
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()) {
this->copySurfaceAsDraw(dst, src, srcRect, dstPoint);
return true;
@@ -3064,6 +3074,9 @@ void GrGLGpu::createWireRectProgram() {
}
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();
if (!fWireRectProgram.fProgram) {
this->createWireRectProgram();
@@ -3114,7 +3127,7 @@ void GrGLGpu::drawDebugWireRect(GrRenderTarget* rt, const SkIRect& rect, GrColor
GrXferProcessor::BlendInfo blendInfo;
blendInfo.reset();
- this->flushBlend(blendInfo);
+ this->flushBlend(blendInfo, GrSwizzle::RGBA());
this->flushColorWrite(true);
this->flushDrawFace(GrPipelineBuilder::kBoth_DrawFace);
this->flushHWAAState(glRT, false);
@@ -3185,7 +3198,7 @@ void GrGLGpu::copySurfaceAsDraw(GrSurface* dst,
GrXferProcessor::BlendInfo blendInfo;
blendInfo.reset();
- this->flushBlend(blendInfo);
+ this->flushBlend(blendInfo, GrSwizzle::RGBA());
this->flushColorWrite(true);
this->flushDrawFace(GrPipelineBuilder::kBoth_DrawFace);
this->flushHWAAState(dstRT, false);
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 532a864f07..cdd8a38c66 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -26,6 +26,7 @@
class GrPipeline;
class GrNonInstancedVertices;
+class GrSwizzle;
#ifdef SK_DEVELOPER
#define PROGRAM_CACHE_STATS
@@ -199,8 +200,7 @@ private:
const GrNonInstancedVertices& vertices,
size_t* indexOffsetInBytes);
- // Subclasses should call this to flush the blend state.
- void flushBlend(const GrXferProcessor::BlendInfo& blendInfo);
+ void flushBlend(const GrXferProcessor::BlendInfo& blendInfo, const GrSwizzle&);
bool hasExtension(const char* ext) const { return fGLContext->hasExtension(ext); }
diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp
index 45e01e7c84..4c95e2b532 100644
--- a/src/gpu/gl/GrGLProgramDesc.cpp
+++ b/src/gpu/gl/GrGLProgramDesc.cpp
@@ -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
*/
static bool gen_meta_key(const GrProcessor& proc,
- const GrGLCaps& caps,
+ const GrGLSLCaps& glslCaps,
uint32_t transformKey,
GrProcessorKeyBuilder* b) {
size_t processorKeySize = b->size();
@@ -58,7 +58,7 @@ static bool gen_meta_key(const GrProcessor& proc,
return false;
}
- add_texture_key(b, proc, *caps.glslCaps());
+ add_texture_key(b, proc, glslCaps);
uint32_t* key = b->add32n(2);
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,
const GrFragmentProcessor& fp,
- const GrGLCaps& caps,
+ const GrGLSLCaps& glslCaps,
GrProcessorKeyBuilder* b) {
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;
}
}
- fp.getGLSLProcessorKey(*caps.glslCaps(), b);
+ fp.getGLSLProcessorKey(glslCaps, b);
- //**** use glslCaps here?
- return gen_meta_key(fp, caps, primProc.getTransformKey(fp.coordTransforms(),
- fp.numTransformsExclChildren()), b);
+ return gen_meta_key(fp, glslCaps, primProc.getTransformKey(fp.coordTransforms(),
+ fp.numTransformsExclChildren()), b);
}
bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc,
const GrPrimitiveProcessor& primProc,
const GrPipeline& pipeline,
- const GrGLGpu* gpu) {
+ const GrGLSLCaps& glslCaps) {
// The descriptor is used as a cache key. Thus when a field of the
// descriptor will not affect program generation (because of the attribute
// 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());
- primProc.getGLSLProcessorKey(*gpu->glCaps().glslCaps(), &b);
- //**** use glslCaps here?
- if (!gen_meta_key(primProc, gpu->glCaps(), 0, &b)) {
+ primProc.getGLSLProcessorKey(glslCaps, &b);
+ if (!gen_meta_key(primProc, glslCaps, 0, &b)) {
glDesc->key().reset();
return false;
}
for (int i = 0; i < pipeline.numFragmentProcessors(); ++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();
return false;
}
}
const GrXferProcessor& xp = pipeline.getXferProcessor();
- xp.getGLSLProcessorKey(*gpu->glCaps().glslCaps(), &b);
- //**** use glslCaps here?
- if (!gen_meta_key(xp, gpu->glCaps(), 0, &b)) {
+ xp.getGLSLProcessorKey(glslCaps, &b);
+ if (!gen_meta_key(xp, glslCaps, 0, &b)) {
glDesc->key().reset();
return false;
}
@@ -139,6 +136,9 @@ bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc,
header->fFragPosKey = 0;
}
+ header->fOutputSwizzle =
+ glslCaps.configOutputSwizzle(pipeline.getRenderTarget()->config()).asKey();
+
if (pipeline.ignoresCoverage()) {
header->fIgnoresCoverage = 1;
} else {
diff --git a/src/gpu/gl/GrGLProgramDesc.h b/src/gpu/gl/GrGLProgramDesc.h
index 7ce79ecae9..0ebf6a228e 100644
--- a/src/gpu/gl/GrGLProgramDesc.h
+++ b/src/gpu/gl/GrGLProgramDesc.h
@@ -52,14 +52,13 @@ public:
* general draw information, as well as the specific color, geometry,
* and coverage stages which will be used to generate the GL Program for
* this optstate.
- * @param GrGLGpu A GL Gpu, the caps and Gpu object are used to output processor specific
- * parts of the descriptor.
+ * @param GrGLSLCaps Capabilities of the GLSL backend.
* @param GrProgramDesc The built and finalized descriptor
**/
static bool Build(GrProgramDesc*,
const GrPrimitiveProcessor&,
const GrPipeline&,
- const GrGLGpu*);
+ const GrGLSLCaps&);
};
#endif
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index 97fcce59b7..4360f7858d 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -10,6 +10,7 @@
#include "GrAutoLocaleSetter.h"
#include "GrCoordTransform.h"
#include "GrGLProgramBuilder.h"
+#include "GrSwizzle.h"
#include "GrTexture.h"
#include "SkRTConf.h"
#include "SkTraceEvent.h"
@@ -95,6 +96,7 @@ bool GrGLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr
inputCoverage);
this->emitAndInstallXferProc(this->pipeline().getXferProcessor(), *inputColor, *inputCoverage,
this->pipeline().ignoresCoverage());
+ this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOutput());
return true;
}
@@ -262,6 +264,22 @@ void GrGLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
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) {
SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition());
}
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.h b/src/gpu/gl/builders/GrGLProgramBuilder.h
index cbec5a9863..70cfad5633 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.h
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.h
@@ -92,6 +92,7 @@ private:
const GrGLSLExpr4& colorIn,
const GrGLSLExpr4& coverageIn,
bool ignoresCoverage);
+ void emitFSOutputSwizzle(bool hasSecondaryOutput);
void verify(const GrPrimitiveProcessor&);
void verify(const GrXferProcessor&);
diff --git a/src/gpu/glsl/GrGLSLCaps.h b/src/gpu/glsl/GrGLSLCaps.h
index eba9602e5a..136bef466c 100755
--- a/src/gpu/glsl/GrGLSLCaps.h
+++ b/src/gpu/glsl/GrGLSLCaps.h
@@ -108,12 +108,17 @@ public:
/**
* 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
- * 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 {
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; }
/**
@@ -150,6 +155,7 @@ private:
AdvBlendEqInteraction fAdvBlendEqInteraction;
GrSwizzle fConfigTextureSwizzle[kGrPixelConfigCnt];
+ GrSwizzle fConfigOutputSwizzle[kGrPixelConfigCnt];
friend class GrGLCaps; // For initialization.