diff options
-rw-r--r-- | src/core/SkColorFilter.cpp | 6 | ||||
-rw-r--r-- | src/gpu/GrYUVProvider.cpp | 3 | ||||
-rw-r--r-- | src/gpu/effects/GrSRGBEffect.cpp | 52 | ||||
-rw-r--r-- | src/gpu/effects/GrSRGBEffect.h | 13 | ||||
-rw-r--r-- | tests/ApplyGammaTest.cpp | 31 |
5 files changed, 69 insertions, 36 deletions
diff --git a/src/core/SkColorFilter.cpp b/src/core/SkColorFilter.cpp index 6cc8ae8161..d8e68c8db5 100644 --- a/src/core/SkColorFilter.cpp +++ b/src/core/SkColorFilter.cpp @@ -216,11 +216,13 @@ public: #if SK_SUPPORT_GPU sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext* x, SkColorSpace* cs) const override { + // wish our caller would let us know if our input was opaque... + GrSRGBEffect::Alpha alpha = GrSRGBEffect::Alpha::kPremul; switch (fDir) { case Direction::kLinearToSRGB: - return GrSRGBEffect::Make(GrSRGBEffect::Mode::kLinearToSRGB); + return GrSRGBEffect::Make(GrSRGBEffect::Mode::kLinearToSRGB, alpha); case Direction::kSRGBToLinear: - return GrSRGBEffect::Make(GrSRGBEffect::Mode::kSRGBToLinear); + return GrSRGBEffect::Make(GrSRGBEffect::Mode::kSRGBToLinear, alpha); } return nullptr; } diff --git a/src/gpu/GrYUVProvider.cpp b/src/gpu/GrYUVProvider.cpp index 5ab926be35..df7113911f 100644 --- a/src/gpu/GrYUVProvider.cpp +++ b/src/gpu/GrYUVProvider.cpp @@ -148,7 +148,8 @@ sk_sp<GrTextureProxy> GrYUVProvider::refAsTextureProxy(GrContext* ctx, if (ctx->caps()->srgbWriteControl()) { paint.setDisableOutputConversionToSRGB(true); } else { - paint.addColorFragmentProcessor(GrSRGBEffect::Make(GrSRGBEffect::Mode::kSRGBToLinear)); + paint.addColorFragmentProcessor(GrSRGBEffect::Make(GrSRGBEffect::Mode::kSRGBToLinear, + GrSRGBEffect::Alpha::kOpaque)); } } diff --git a/src/gpu/effects/GrSRGBEffect.cpp b/src/gpu/effects/GrSRGBEffect.cpp index c9a48b3d84..294e7f4551 100644 --- a/src/gpu/effects/GrSRGBEffect.cpp +++ b/src/gpu/effects/GrSRGBEffect.cpp @@ -47,18 +47,26 @@ public: args.fInputColor = "vec4(1)"; } - fragBuilder->codeAppendf("%s = vec4(%s(%s.r), %s(%s.g), %s(%s.b), %s.a);", - args.fOutputColor, - srgbFuncName.c_str(), args.fInputColor, - srgbFuncName.c_str(), args.fInputColor, - srgbFuncName.c_str(), args.fInputColor, - args.fInputColor); + fragBuilder->codeAppendf("vec4 color = %s;", args.fInputColor); + if (srgbe.alpha() == GrSRGBEffect::Alpha::kPremul) { + fragBuilder->codeAppendf("float nonZeroAlpha = max(color.a, 0.00001);"); + fragBuilder->codeAppendf("color = vec4(color.rgb / nonZeroAlpha, color.a);"); + } + fragBuilder->codeAppendf("color = vec4(%s(color.r), %s(color.g), %s(color.b), color.a);", + srgbFuncName.c_str(), + srgbFuncName.c_str(), + srgbFuncName.c_str()); + if (srgbe.alpha() == GrSRGBEffect::Alpha::kPremul) { + fragBuilder->codeAppendf("color = vec4(color.rgb, 1) * color.a;"); + } + fragBuilder->codeAppendf("%s = color;", args.fOutputColor); } static inline void GenKey(const GrProcessor& processor, const GrShaderCaps&, GrProcessorKeyBuilder* b) { const GrSRGBEffect& srgbe = processor.cast<GrSRGBEffect>(); - uint32_t key = static_cast<uint32_t>(srgbe.mode()); + uint32_t key = static_cast<uint32_t>(srgbe.mode()) | + (static_cast<uint32_t>(srgbe.alpha()) << 1); b->add32(key); } @@ -68,10 +76,12 @@ private: /////////////////////////////////////////////////////////////////////////////// -GrSRGBEffect::GrSRGBEffect(Mode mode) - : INHERITED(kPreservesOpaqueInput_OptimizationFlag | - kConstantOutputForConstantInput_OptimizationFlag) - , fMode(mode) { +GrSRGBEffect::GrSRGBEffect(Mode mode, Alpha alpha) + : INHERITED(kPreservesOpaqueInput_OptimizationFlag | + kConstantOutputForConstantInput_OptimizationFlag) + , fMode(mode) + , fAlpha(alpha) +{ this->initClassID<GrSRGBEffect>(); } @@ -87,17 +97,19 @@ static inline float linear_to_srgb(float linear) { return (linear <= 0.0031308) ? linear * 12.92f : 1.055f * powf(linear, 1.f / 2.4f) - 0.055f; } -GrColor4f GrSRGBEffect::constantOutputForConstantInput(GrColor4f input) const { +GrColor4f GrSRGBEffect::constantOutputForConstantInput(GrColor4f color) const { + color = color.unpremul(); switch (fMode) { case Mode::kLinearToSRGB: - return GrColor4f(linear_to_srgb(input.fRGBA[0]), linear_to_srgb(input.fRGBA[1]), - linear_to_srgb(input.fRGBA[2]), input.fRGBA[3]); + color = GrColor4f(linear_to_srgb(color.fRGBA[0]), linear_to_srgb(color.fRGBA[1]), + linear_to_srgb(color.fRGBA[2]), color.fRGBA[3]); + break; case Mode::kSRGBToLinear: - return GrColor4f(srgb_to_linear(input.fRGBA[0]), srgb_to_linear(input.fRGBA[1]), - srgb_to_linear(input.fRGBA[2]), input.fRGBA[3]); + color = GrColor4f(srgb_to_linear(color.fRGBA[0]), srgb_to_linear(color.fRGBA[1]), + srgb_to_linear(color.fRGBA[2]), color.fRGBA[3]); + break; } - SkFAIL("Unexpected mode"); - return GrColor4f::TransparentBlack(); + return color.premul(); } /////////////////////////////////////////////////////////////////////////////// @@ -107,7 +119,7 @@ GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSRGBEffect); #if GR_TEST_UTILS sk_sp<GrFragmentProcessor> GrSRGBEffect::TestCreate(GrProcessorTestData* d) { Mode testMode = static_cast<Mode>(d->fRandom->nextRangeU(0, 1)); - return GrSRGBEffect::Make(testMode); + return GrSRGBEffect::Make(testMode, Alpha::kPremul); } #endif @@ -119,6 +131,6 @@ void GrSRGBEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, } GrGLSLFragmentProcessor* GrSRGBEffect::onCreateGLSLInstance() const { - return new GrGLSRGBEffect(); + return new GrGLSRGBEffect; } diff --git a/src/gpu/effects/GrSRGBEffect.h b/src/gpu/effects/GrSRGBEffect.h index f91224e56d..13d8bc3cb9 100644 --- a/src/gpu/effects/GrSRGBEffect.h +++ b/src/gpu/effects/GrSRGBEffect.h @@ -17,19 +17,25 @@ public: kSRGBToLinear, }; + enum class Alpha { + kPremul, + kOpaque, + }; + /** * Creates an effect that applies the sRGB transfer function (or its inverse) */ - static sk_sp<GrFragmentProcessor> Make(Mode mode) { - return sk_sp<GrFragmentProcessor>(new GrSRGBEffect(mode)); + static sk_sp<GrFragmentProcessor> Make(Mode mode, Alpha alpha) { + return sk_sp<GrFragmentProcessor>(new GrSRGBEffect(mode, alpha)); } const char* name() const override { return "sRGB"; } Mode mode() const { return fMode; } + Alpha alpha() const { return fAlpha; } private: - GrSRGBEffect(Mode mode); + GrSRGBEffect(Mode mode, Alpha); GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; @@ -38,6 +44,7 @@ private: GrColor4f constantOutputForConstantInput(GrColor4f input) const override; Mode fMode; + Alpha fAlpha; GR_DECLARE_FRAGMENT_PROCESSOR_TEST diff --git a/tests/ApplyGammaTest.cpp b/tests/ApplyGammaTest.cpp index 79dbfc7cd9..83b5968a9b 100644 --- a/tests/ApplyGammaTest.cpp +++ b/tests/ApplyGammaTest.cpp @@ -44,10 +44,17 @@ bool check_gamma(uint32_t src, uint32_t dst, bool toSRGB, float error, result = false; } + // need to unpremul before we can perform srgb magic + float invScale = 0; + float alpha = SkGetPackedA32(src); + if (alpha) { + invScale = 255.0f / alpha; + } + for (int c = 0; c < 3; ++c) { - uint8_t srcComponent = (src & (0xff << (c * 8))) >> (c * 8); - float lower = SkTMax(0.f, (float)srcComponent - error); - float upper = SkTMin(255.f, (float)srcComponent + error); + float srcComponent = ((src & (0xff << (c * 8))) >> (c * 8)) * invScale; + float lower = SkTMax(0.f, srcComponent - error); + float upper = SkTMin(255.f, srcComponent + error); if (toSRGB) { lower = linear_to_srgb(lower / 255.f); upper = linear_to_srgb(upper / 255.f); @@ -55,14 +62,16 @@ bool check_gamma(uint32_t src, uint32_t dst, bool toSRGB, float error, lower = srgb_to_linear(lower / 255.f); upper = srgb_to_linear(upper / 255.f); } + lower *= alpha; + upper *= alpha; SkASSERT(lower >= 0.f && lower <= 255.f); SkASSERT(upper >= 0.f && upper <= 255.f); uint8_t dstComponent = (dst & (0xff << (c * 8))) >> (c * 8); - if (dstComponent < SkScalarFloorToInt(lower * 255.f) || - dstComponent > SkScalarCeilToInt(upper * 255.f)) { + if (dstComponent < SkScalarFloorToInt(lower) || + dstComponent > SkScalarCeilToInt(upper)) { result = false; } - uint8_t expectedComponent = SkScalarRoundToInt((lower + upper) * 127.5f); + uint8_t expectedComponent = SkScalarRoundToInt((lower + upper) * 0.5f); expectedColor |= expectedComponent << (c * 8); } @@ -72,8 +81,8 @@ bool check_gamma(uint32_t src, uint32_t dst, bool toSRGB, float error, DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ApplyGamma, reporter, ctxInfo) { GrContext* context = ctxInfo.grContext(); - static const int kW = 10; - static const int kH = 10; + static const int kW = 256; + static const int kH = 256; static const size_t kRowBytes = sizeof(uint32_t) * kW; GrSurfaceDesc baseDesc; @@ -84,8 +93,10 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ApplyGamma, reporter, ctxInfo) { const SkImageInfo ii = SkImageInfo::MakeN32Premul(kW, kH); SkAutoTMalloc<uint32_t> srcPixels(kW * kH); - for (int i = 0; i < kW * kH; ++i) { - srcPixels.get()[i] = i; + for (int y = 0; y < kH; ++y) { + for (int x = 0; x < kW; ++x) { + srcPixels.get()[y*kW+x] = SkPreMultiplyARGB(x, y, x, 0xFF); + } } SkBitmap bm; |