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:
parent
87a721b246
commit
7f9b2e4a45
@ -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',
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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); }
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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&);
|
||||
|
@ -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.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user