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/GrSurfacePriv.h',
'<(skia_src_path)/gpu/GrSurface.cpp',
'<(skia_src_path)/gpu/GrSwizzle.h',
'<(skia_src_path)/gpu/GrTexture.cpp',
'<(skia_src_path)/gpu/GrTextureParamsAdjuster.h',
'<(skia_src_path)/gpu/GrTextureParamsAdjuster.cpp',

View File

@ -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;

View File

@ -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];

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
// Make sure we initialized everything.
ConfigInfo defaultEntry;

View File

@ -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);

View File

@ -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); }

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
*/
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 {

View File

@ -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

View File

@ -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());
}

View File

@ -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&);

View File

@ -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.