Chromium Code Reviews| Index: src/effects/SkTableColorFilter.cpp |
| diff --git a/src/effects/SkTableColorFilter.cpp b/src/effects/SkTableColorFilter.cpp |
| index ca2757f299c7cc16c8cdd8e75582f7e2e10a3ace..e4daf20b006e11d92a59a681bd15409b8365c0a3 100644 |
| --- a/src/effects/SkTableColorFilter.cpp |
| +++ b/src/effects/SkTableColorFilter.cpp |
| @@ -277,17 +277,17 @@ bool SkTable_ColorFilter::asComponentTable(SkBitmap* table) const { |
| #include "GrFragmentProcessor.h" |
| #include "GrTBackendProcessorFactory.h" |
| +#include "SkGr.h" |
| +#include "effects/GrTextureStripAtlas.h" |
|
reed1
2014/10/28 13:42:41
do we need to qualify this header's path? We don't
|
| #include "gl/GrGLProcessor.h" |
| #include "gl/builders/GrGLProgramBuilder.h" |
| -#include "SkGr.h" |
| + |
| class GLColorTableEffect; |
| class ColorTableEffect : public GrFragmentProcessor { |
| public: |
| - static GrFragmentProcessor* Create(GrTexture* texture, unsigned flags) { |
| - return SkNEW_ARGS(ColorTableEffect, (texture, flags)); |
| - } |
| + static GrFragmentProcessor* Create(GrContext* context, SkBitmap bitmap, unsigned flags); |
| virtual ~ColorTableEffect(); |
| @@ -296,18 +296,25 @@ public: |
| typedef GLColorTableEffect GLProcessor; |
| + const GrTextureStripAtlas* atlas() const { return fAtlas; } |
| + int atlasRow() const { return fRow; } |
| + |
| private: |
| - virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE{ return true; } |
| + virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE; |
| virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE; |
| - explicit ColorTableEffect(GrTexture* texture, unsigned flags); |
| + ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row, unsigned flags); |
| GR_DECLARE_FRAGMENT_PROCESSOR_TEST; |
| - GrTextureAccess fTextureAccess; |
| - unsigned fFlags; // currently not used in shader code, just to assist |
| - // onComputeInvariantOutput(). |
| + GrTextureAccess fTextureAccess; |
| + |
| + // currently not used in shader code, just to assist onComputeInvariantOutput(). |
| + unsigned fFlags; |
| + |
| + GrTextureStripAtlas* fAtlas; |
| + int fRow; |
| typedef GrFragmentProcessor INHERITED; |
| }; |
| @@ -324,12 +331,12 @@ public: |
| const TransformedCoordsArray&, |
| const TextureSamplerArray&) SK_OVERRIDE; |
| - virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE {} |
| + virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE; |
| static void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder* b) {} |
| private: |
| - |
| + UniformHandle fRGBAYValuesUni; |
| typedef GrGLFragmentProcessor INHERITED; |
| }; |
| @@ -337,6 +344,25 @@ GLColorTableEffect::GLColorTableEffect(const GrBackendProcessorFactory& factory, |
| : INHERITED(factory) { |
| } |
| +void GLColorTableEffect::setData(const GrGLProgramDataManager& pdm, const GrProcessor& proc) { |
| + // The textures are organized in a strip where the rows are ordered a, r, g, b. |
| + float rgbaYValues[4]; |
| + const ColorTableEffect& cte = proc.cast<ColorTableEffect>(); |
| + if (cte.atlas()) { |
| + SkScalar yDelta = cte.atlas()->getNormalizedTexelHeight(); |
| + rgbaYValues[3] = cte.atlas()->getYOffset(cte.atlasRow()) + SK_ScalarHalf * yDelta; |
| + rgbaYValues[0] = rgbaYValues[3] + yDelta; |
| + rgbaYValues[1] = rgbaYValues[0] + yDelta; |
| + rgbaYValues[2] = rgbaYValues[1] + yDelta; |
| + } else { |
| + rgbaYValues[3] = 0.125; |
| + rgbaYValues[0] = 0.375; |
| + rgbaYValues[1] = 0.625; |
| + rgbaYValues[2] = 0.875; |
| + } |
| + pdm.set4fv(fRGBAYValuesUni, 1, rgbaYValues); |
| +} |
| + |
| void GLColorTableEffect::emitCode(GrGLFPBuilder* builder, |
| const GrFragmentProcessor&, |
| const GrProcessorKey&, |
| @@ -344,7 +370,9 @@ void GLColorTableEffect::emitCode(GrGLFPBuilder* builder, |
| const char* inputColor, |
| const TransformedCoordsArray&, |
| const TextureSamplerArray& samplers) { |
| - |
| + const char* yoffsets; |
| + fRGBAYValuesUni = builder->addUniform(GrGLFPBuilder::kFragment_Visibility, |
| + kVec4f_GrSLType, "yoffsets", &yoffsets); |
| static const float kColorScaleFactor = 255.0f / 256.0f; |
| static const float kColorOffsetFactor = 1.0f / 512.0f; |
| GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); |
| @@ -363,40 +391,84 @@ void GLColorTableEffect::emitCode(GrGLFPBuilder* builder, |
| kColorOffsetFactor, kColorOffsetFactor); |
| } |
| + SkString coord; |
| + |
| fsBuilder->codeAppendf("\t\t%s.a = ", outputColor); |
| - fsBuilder->appendTextureLookup(samplers[0], "vec2(coord.a, 0.125)"); |
| + coord.printf("vec2(coord.a, %s.a)", yoffsets); |
| + fsBuilder->appendTextureLookup(samplers[0], coord.c_str()); |
| fsBuilder->codeAppend(";\n"); |
| fsBuilder->codeAppendf("\t\t%s.r = ", outputColor); |
| - fsBuilder->appendTextureLookup(samplers[0], "vec2(coord.r, 0.375)"); |
| + coord.printf("vec2(coord.r, %s.r)", yoffsets); |
| + fsBuilder->appendTextureLookup(samplers[0], coord.c_str()); |
| fsBuilder->codeAppend(";\n"); |
| fsBuilder->codeAppendf("\t\t%s.g = ", outputColor); |
| - fsBuilder->appendTextureLookup(samplers[0], "vec2(coord.g, 0.625)"); |
| + coord.printf("vec2(coord.g, %s.g)", yoffsets); |
| + fsBuilder->appendTextureLookup(samplers[0], coord.c_str()); |
| fsBuilder->codeAppend(";\n"); |
| fsBuilder->codeAppendf("\t\t%s.b = ", outputColor); |
| - fsBuilder->appendTextureLookup(samplers[0], "vec2(coord.b, 0.875)"); |
| + coord.printf("vec2(coord.b, %s.b)", yoffsets); |
| + fsBuilder->appendTextureLookup(samplers[0], coord.c_str()); |
| fsBuilder->codeAppend(";\n"); |
| fsBuilder->codeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor); |
| } |
| /////////////////////////////////////////////////////////////////////////////// |
| +GrFragmentProcessor* ColorTableEffect::Create(GrContext* context, SkBitmap bitmap, unsigned flags) { |
| + |
| + GrTextureStripAtlas::Desc desc; |
| + desc.fWidth = bitmap.width(); |
| + desc.fHeight = 128; |
| + desc.fRowHeight = bitmap.height(); |
| + desc.fContext = context; |
| + desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info()); |
| + GrTextureStripAtlas* atlas = GrTextureStripAtlas::GetAtlas(desc); |
| + int row = atlas->lockRow(bitmap); |
| + SkAutoTUnref<GrTexture> texture; |
| + if (-1 == row) { |
| + atlas = NULL; |
| + // Passing params=NULL because this effect does no tiling or filtering. |
| + texture.reset(GrRefCachedBitmapTexture(context, bitmap, NULL)); |
| + } else { |
| + texture.reset(SkRef(atlas->getTexture())); |
| + } |
| + |
| + return SkNEW_ARGS(ColorTableEffect, (texture, atlas, row, flags)); |
| +} |
| -ColorTableEffect::ColorTableEffect(GrTexture* texture, unsigned flags) |
| +ColorTableEffect::ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row, |
| + unsigned flags) |
| : fTextureAccess(texture, "a") |
| - , fFlags(flags) { |
| + , fFlags(flags) |
| + , fAtlas(atlas) |
| + , fRow(row) { |
| + |
| this->addTextureAccess(&fTextureAccess); |
| } |
| ColorTableEffect::~ColorTableEffect() { |
| + if (fAtlas) { |
| + fAtlas->unlockRow(fRow); |
| + } |
| } |
| const GrBackendFragmentProcessorFactory& ColorTableEffect::getFactory() const { |
| return GrTBackendFragmentProcessorFactory<ColorTableEffect>::getInstance(); |
| } |
| +bool ColorTableEffect::onIsEqual(const GrFragmentProcessor& other) const { |
| + // For non-atlased instances, the texture (compared by base class) is sufficient to |
| + // differentiate different tables. For atlased instances we ensure they are using the |
| + // same row. |
| + const ColorTableEffect& that = other.cast<ColorTableEffect>(); |
| + SkASSERT(SkToBool(fAtlas) == SkToBool(that.fAtlas)); |
| + // Ok to always do this comparison since both would be -1 if non-atlased. |
| + return fRow == that.fRow; |
| +} |
| + |
| void ColorTableEffect::onComputeInvariantOutput(InvariantOutput* inout) const { |
| // If we kept the table in the effect then we could actually run known inputs through the |
| // table. |
| @@ -424,17 +496,34 @@ GrFragmentProcessor* ColorTableEffect::TestCreate(SkRandom* random, |
| GrContext* context, |
| const GrDrawTargetCaps&, |
| GrTexture* textures[]) { |
| - static unsigned kAllFlags = SkTable_ColorFilter::kR_Flag | SkTable_ColorFilter::kG_Flag | |
| - SkTable_ColorFilter::kB_Flag | SkTable_ColorFilter::kA_Flag; |
| - return ColorTableEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx], kAllFlags); |
| + int flags = 0; |
| + uint8_t luts[256][4]; |
| + do { |
| + for (int i = 0; i < 4; ++i) { |
| + flags |= random->nextBool() ? (1 << i): 0; |
| + } |
| + } while (!flags); |
| + for (int i = 0; i < 4; ++i) { |
| + if (flags & (1 << i)) { |
| + for (int j = 0; j < 256; ++j) { |
| + luts[j][i] = SkToU8(random->nextBits(8)); |
| + } |
| + } |
| + } |
| + SkAutoTUnref<SkColorFilter> filter(SkTableColorFilter::CreateARGB( |
| + (flags & (1 << 0)) ? luts[0] : NULL, |
| + (flags & (1 << 1)) ? luts[1] : NULL, |
| + (flags & (1 << 2)) ? luts[2] : NULL, |
| + (flags & (1 << 3)) ? luts[3] : NULL |
| + )); |
| + return filter->asFragmentProcessor(context); |
| } |
| GrFragmentProcessor* SkTable_ColorFilter::asFragmentProcessor(GrContext* context) const { |
| SkBitmap bitmap; |
| this->asComponentTable(&bitmap); |
| - // passing NULL because this effect does no tiling or filtering. |
| - SkAutoTUnref<GrTexture> texture(GrRefCachedBitmapTexture(context, bitmap, NULL)); |
| - return texture ? ColorTableEffect::Create(texture, fFlags) : NULL; |
| + |
| + return ColorTableEffect::Create(context, bitmap, fFlags); |
| } |
| #endif // SK_SUPPORT_GPU |