diff options
author | bsalomon <bsalomon@google.com> | 2016-01-12 13:29:26 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-01-12 13:29:26 -0800 |
commit | 7f9b2e4a45775e8cdd3f98260a66c0c6e1840550 (patch) | |
tree | 2634c3fe68d98ece6e9a30a4db7a251303c587ca /src/gpu | |
parent | 87a721b2465c9ccfa191ce9f5012f92be7731fbc (diff) |
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
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/GrProgramDesc.h | 9 | ||||
-rw-r--r-- | src/gpu/GrSwizzle.h | 52 | ||||
-rw-r--r-- | src/gpu/gl/GrGLCaps.cpp | 13 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.cpp | 41 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.h | 4 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgramDesc.cpp | 32 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgramDesc.h | 5 | ||||
-rw-r--r-- | src/gpu/gl/builders/GrGLProgramBuilder.cpp | 18 | ||||
-rw-r--r-- | src/gpu/gl/builders/GrGLProgramBuilder.h | 1 | ||||
-rwxr-xr-x | src/gpu/glsl/GrGLSLCaps.h | 8 |
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. |