aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Brian Osman <brianosman@google.com>2017-01-26 09:32:33 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-01-26 15:27:49 +0000
commit964dec3948721808491b21b4ff4ff41a466443ec (patch)
tree57e3d48e97aecafc872a9cce6285e9edea775cf8
parentd6016013bdf843013f7fb8648fc5a64ce7e77005 (diff)
Move SkGammaColorFilter to tools, limit to sRGB
Similarly, limit GrGammaEffect to sRGB (and rename it). BUG=skia: Change-Id: I88feef11ab7040bca2fa4c2eed71923ded87a0d0 Reviewed-on: https://skia-review.googlesource.com/7375 Commit-Queue: Brian Osman <brianosman@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com>
-rw-r--r--gm/gammacolorfilter.cpp98
-rw-r--r--gn/effects.gni2
-rw-r--r--gn/gm.gni1
-rw-r--r--gn/gpu.gni4
-rw-r--r--include/effects/SkGammaColorFilter.h44
-rw-r--r--samplecode/SampleApp.cpp3
-rw-r--r--src/effects/SkGammaColorFilter.cpp57
-rw-r--r--src/gpu/GrContext.cpp2
-rw-r--r--src/gpu/GrYUVProvider.cpp4
-rw-r--r--src/gpu/effects/GrGammaEffect.cpp148
-rw-r--r--src/gpu/effects/GrSRGBEffect.cpp109
-rw-r--r--src/gpu/effects/GrSRGBEffect.h (renamed from src/gpu/effects/GrGammaEffect.h)19
-rw-r--r--tests/ApplyGammaTest.cpp147
-rw-r--r--tools/sk_tool_utils.cpp42
-rw-r--r--tools/sk_tool_utils.h6
-rw-r--r--tools/viewer/sk_app/mac/RasterWindowContext_mac.cpp5
16 files changed, 249 insertions, 442 deletions
diff --git a/gm/gammacolorfilter.cpp b/gm/gammacolorfilter.cpp
index 9e39025b0a..84ebc43def 100644
--- a/gm/gammacolorfilter.cpp
+++ b/gm/gammacolorfilter.cpp
@@ -1,102 +1,8 @@
/*
- * Copyright 2016 Google Inc.
+ * Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
-#include "gm.h"
-#include "SkGammaColorFilter.h"
-#include "SkImage.h"
-
-// Fill a width x height block with a horizontal ramp from 0 to 255
-static void draw_grey_ramp(SkCanvas* canvas, int width, int height, int numSteps) {
- int greyPerStep = SkScalarRoundToInt(255.0f / numSteps);
- int widthPerStep = SkScalarRoundToInt(width / SkIntToScalar(numSteps));
-
- SkIRect rect = SkIRect::MakeWH(widthPerStep, height);
-
- SkPaint paint;
- int grey = 0;
- int x = 0;
- for (int i = 0; i < numSteps-1; ++i) {
- paint.setColor(SkColorSetARGB(255, grey, grey, grey));
-
- rect.offsetTo(x, 0);
- canvas->drawRect(SkRect::Make(rect), paint);
-
- x += widthPerStep;
- grey += greyPerStep;
- }
-
- paint.setColor(SK_ColorWHITE);
- rect.setLTRB(x, 0, width, height);
- canvas->drawRect(SkRect::Make(rect), paint);
-}
-
-static sk_sp<SkImage> create_grey_ramp(int width, int height, int numSteps) {
- SkBitmap bm;
- bm.allocN32Pixels(width, height);
- SkCanvas canvas(bm);
- canvas.clear(0x0);
-
- draw_grey_ramp(&canvas, width, height, numSteps);
-
- return SkImage::MakeFromBitmap(bm);
-}
-
-namespace skiagm {
-
-class GammaColorFilterGM : public GM {
-public:
- GammaColorFilterGM() {
- this->setBGColor(SK_ColorBLACK);
- }
-
-protected:
-
- SkString onShortName() override {
- return SkString("gammacolorfilter");
- }
-
- SkISize onISize() override {
- return SkISize::Make(4 * kCellWidth, kCellHeight);
- }
-
- void onDraw(SkCanvas* canvas) override {
- GrRenderTargetContext* renderTargetContext =
- canvas->internal_private_accessTopLayerRenderTargetContext();
- if (!renderTargetContext) {
- skiagm::GM::DrawGpuOnlyMessage(canvas);
- return;
- }
-
- sk_sp<SkImage> image(create_grey_ramp(kCellWidth, kCellHeight/2, kNumGreySteps));
-
- // Leftmost is a non-gamma pair
- draw_grey_ramp(canvas, kCellWidth, kCellHeight/2, kNumGreySteps);
- canvas->drawImage(image, 0, kCellHeight/2);
- canvas->translate(SkIntToScalar(image->width()), 0);
-
- for (auto gamma : { 1.0f, 1.0f / 1.8f, 1.0f / 2.2f }) {
- SkPaint paint;
- paint.setColorFilter(SkGammaColorFilter::Make(gamma));
-
- draw_grey_ramp(canvas, kCellWidth, kCellHeight/2, kNumGreySteps);
- canvas->drawImage(image, 0, kCellHeight/2, &paint);
- canvas->translate(SkIntToScalar(image->width()), 0);
- }
- }
-
-private:
- static constexpr int kCellWidth = 64;
- static constexpr int kCellHeight = 64;
- static constexpr int kNumGreySteps = 16;
-
- typedef GM INHERITED;
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-DEF_GM(return new GammaColorFilterGM;)
-}
+// Temporary. When gn_to_bp.py works for DM, we can remove this.
diff --git a/gn/effects.gni b/gn/effects.gni
index b3459e36d9..f08f57bf72 100644
--- a/gn/effects.gni
+++ b/gn/effects.gni
@@ -37,7 +37,6 @@ skia_effects_sources = [
"$_src/effects/SkEmbossMask_Table.h",
"$_src/effects/SkEmbossMaskFilter.cpp",
"$_src/effects/SkImageSource.cpp",
- "$_src/effects/SkGammaColorFilter.cpp",
"$_src/effects/SkGaussianEdgeShader.cpp",
"$_src/effects/SkLayerDrawLooper.cpp",
"$_src/effects/SkLayerRasterizer.cpp",
@@ -105,7 +104,6 @@ skia_effects_sources = [
"$_include/effects/SkDiscretePathEffect.h",
"$_include/effects/SkDisplacementMapEffect.h",
"$_include/effects/SkDropShadowImageFilter.h",
- "$_include/effects/SkGammaColorFilter.h",
"$_include/effects/SkGaussianEdgeShader.h",
"$_include/effects/SkGradientShader.h",
"$_include/effects/SkImageSource.h",
diff --git a/gn/gm.gni b/gn/gm.gni
index 758611becc..4b6dbf90cd 100644
--- a/gn/gm.gni
+++ b/gn/gm.gni
@@ -127,7 +127,6 @@ gm_sources = [
"$_gm/fontscaler.cpp",
"$_gm/fontscalerdistortable.cpp",
"$_gm/gamma.cpp",
- "$_gm/gammacolorfilter.cpp",
"$_gm/gammatext.cpp",
"$_gm/gamut.cpp",
"$_gm/gaussianedge.cpp",
diff --git a/gn/gpu.gni b/gn/gpu.gni
index 3013270f22..e7e629d26e 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -315,8 +315,6 @@ skia_gpu_sources = [
"$_src/gpu/effects/GrDistanceFieldGeoProc.h",
"$_src/gpu/effects/GrDitherEffect.cpp",
"$_src/gpu/effects/GrDitherEffect.h",
- "$_src/gpu/effects/GrGammaEffect.cpp",
- "$_src/gpu/effects/GrGammaEffect.h",
"$_src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp",
"$_src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h",
"$_src/gpu/effects/GrMatrixConvolutionEffect.cpp",
@@ -334,6 +332,8 @@ skia_gpu_sources = [
"$_src/gpu/effects/GrSimpleTextureEffect.h",
"$_src/gpu/effects/GrSingleTextureEffect.cpp",
"$_src/gpu/effects/GrSingleTextureEffect.h",
+ "$_src/gpu/effects/GrSRGBEffect.cpp",
+ "$_src/gpu/effects/GrSRGBEffect.h",
"$_src/gpu/effects/GrTextureDomain.cpp",
"$_src/gpu/effects/GrTextureDomain.h",
"$_src/gpu/effects/GrTextureStripAtlas.cpp",
diff --git a/include/effects/SkGammaColorFilter.h b/include/effects/SkGammaColorFilter.h
deleted file mode 100644
index 72c464e33b..0000000000
--- a/include/effects/SkGammaColorFilter.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkGammaColorFilter_DEFINED
-#define SkGammaColorFilter_DEFINED
-
-#include "SkColorFilter.h"
-#include "SkRefCnt.h"
-
-// This colorfilter can be used to perform pixel-by-pixel conversion between linear and
-// power-law color spaces. A gamma of 2.2 is interpreted to mean convert from sRGB to linear
-// while a gamma of 1/2.2 is interpreted to mean convert from linear to sRGB. Any other
-// values are just directly applied (i.e., out = in^gamma)
-//
-// More complicated color space mapping (i.e., ICC profiles) should be handled via the
-// SkColorSpace object.
-class SK_API SkGammaColorFilter : public SkColorFilter {
-public:
- static sk_sp<SkColorFilter> Make(SkScalar gamma);
-
- void filterSpan(const SkPMColor src[], int count, SkPMColor[]) const override;
-
-#if SK_SUPPORT_GPU
- sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*, SkColorSpace*) const override;
-#endif
-
- SK_TO_STRING_OVERRIDE()
- SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLumaColorFilter)
-
-protected:
- void flatten(SkWriteBuffer&) const override;
-
-private:
- SkGammaColorFilter(SkScalar gamma);
-
- SkScalar fGamma;
- typedef SkColorFilter INHERITED;
-};
-
-#endif
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index bd298dfa11..5b0b9d605d 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -16,7 +16,6 @@
#include "SkCommandLineFlags.h"
#include "SkData.h"
#include "SkDocument.h"
-#include "SkGammaColorFilter.h"
#include "SkGraphics.h"
#include "SkOSFile.h"
#include "SkOSPath.h"
@@ -358,7 +357,7 @@ public:
SkPaint gammaPaint;
gammaPaint.setBlendMode(SkBlendMode::kSrc);
if (doGamma) {
- gammaPaint.setColorFilter(SkGammaColorFilter::Make(1.0f / 2.2f));
+ gammaPaint.setColorFilter(sk_tool_utils::MakeLinearToSRGBColorFilter());
}
gpuCanvas->drawImage(offscreenImage, 0, 0, &gammaPaint);
diff --git a/src/effects/SkGammaColorFilter.cpp b/src/effects/SkGammaColorFilter.cpp
deleted file mode 100644
index 181ab770f4..0000000000
--- a/src/effects/SkGammaColorFilter.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkGammaColorFilter.h"
-
-#include "SkReadBuffer.h"
-#include "SkString.h"
-
-#if SK_SUPPORT_GPU
-#include "effects/GrGammaEffect.h"
-#endif
-
-void SkGammaColorFilter::filterSpan(const SkPMColor src[], int count,
- SkPMColor dst[]) const {
- // Gamma-correcting bytes to bytes is pretty questionable.
- SkASSERT(0);
- for (int i = 0; i < count; ++i) {
- SkPMColor c = src[i];
-
- // TODO: implement cpu gamma correction?
- dst[i] = c;
- }
-}
-
-sk_sp<SkColorFilter> SkGammaColorFilter::Make(SkScalar gamma) {
- return sk_sp<SkColorFilter>(new SkGammaColorFilter(gamma));
-}
-
-SkGammaColorFilter::SkGammaColorFilter(SkScalar gamma) : fGamma(gamma) {}
-
-sk_sp<SkFlattenable> SkGammaColorFilter::CreateProc(SkReadBuffer& buffer) {
- SkScalar gamma = buffer.readScalar();
-
- return Make(gamma);
-}
-
-void SkGammaColorFilter::flatten(SkWriteBuffer& buffer) const {
- this->INHERITED::flatten(buffer);
- buffer.writeScalar(fGamma);
-}
-
-#ifndef SK_IGNORE_TO_STRING
-void SkGammaColorFilter::toString(SkString* str) const {
- str->appendf("SkGammaColorFilter (%.2f)", fGamma);
-}
-#endif
-
-#if SK_SUPPORT_GPU
-sk_sp<GrFragmentProcessor> SkGammaColorFilter::asFragmentProcessor(GrContext*,
- SkColorSpace*) const {
- return GrGammaEffect::Make(fGamma);
-}
-#endif
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 1733e2853f..db8863fca0 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -23,8 +23,6 @@
#include "SkGrPriv.h"
#include "effects/GrConfigConversionEffect.h"
-#include "effects/GrGammaEffect.h"
-#include "ops/GrCopySurfaceOp.h"
#include "text/GrTextBlobCache.h"
#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
diff --git a/src/gpu/GrYUVProvider.cpp b/src/gpu/GrYUVProvider.cpp
index f3231a49da..ade72a6cce 100644
--- a/src/gpu/GrYUVProvider.cpp
+++ b/src/gpu/GrYUVProvider.cpp
@@ -10,7 +10,7 @@
#include "GrRenderTargetContext.h"
#include "GrTextureProxy.h"
#include "GrYUVProvider.h"
-#include "effects/GrGammaEffect.h"
+#include "effects/GrSRGBEffect.h"
#include "effects/GrYUVEffect.h"
#include "SkAutoMalloc.h"
@@ -149,7 +149,7 @@ sk_sp<GrTexture> GrYUVProvider::refAsTexture(GrContext* ctx,
if (ctx->caps()->srgbWriteControl()) {
paint.setDisableOutputConversionToSRGB(true);
} else {
- paint.addColorFragmentProcessor(GrGammaEffect::Make(2.2f));
+ paint.addColorFragmentProcessor(GrSRGBEffect::Make(GrSRGBEffect::Mode::kSRGBToLinear));
}
}
diff --git a/src/gpu/effects/GrGammaEffect.cpp b/src/gpu/effects/GrGammaEffect.cpp
deleted file mode 100644
index 8b9363e843..0000000000
--- a/src/gpu/effects/GrGammaEffect.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrGammaEffect.h"
-
-#include "GrContext.h"
-#include "GrCoordTransform.h"
-#include "GrFragmentProcessor.h"
-#include "GrInvariantOutput.h"
-#include "GrProcessor.h"
-#include "glsl/GrGLSLFragmentProcessor.h"
-#include "glsl/GrGLSLFragmentShaderBuilder.h"
-
-class GrGLGammaEffect : public GrGLSLFragmentProcessor {
-public:
- void emitCode(EmitArgs& args) override {
- const GrGammaEffect& ge = args.fFp.cast<GrGammaEffect>();
- GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
- GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
-
- const char* gammaUniName = nullptr;
- if (GrGammaEffect::Mode::kExponential == ge.mode()) {
- fGammaUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
- kDefault_GrSLPrecision, "Gamma", &gammaUniName);
- }
-
- SkString srgbFuncName;
- static const GrShaderVar gSrgbArgs[] = {
- GrShaderVar("x", kFloat_GrSLType),
- };
- switch (ge.mode()) {
- case GrGammaEffect::Mode::kLinearToSRGB:
- fragBuilder->emitFunction(kFloat_GrSLType,
- "linear_to_srgb",
- SK_ARRAY_COUNT(gSrgbArgs),
- gSrgbArgs,
- "return (x <= 0.0031308) ? (x * 12.92) "
- ": (1.055 * pow(x, 0.416666667) - 0.055);",
- &srgbFuncName);
- break;
- case GrGammaEffect::Mode::kSRGBToLinear:
- fragBuilder->emitFunction(kFloat_GrSLType,
- "srgb_to_linear",
- SK_ARRAY_COUNT(gSrgbArgs),
- gSrgbArgs,
- "return (x <= 0.04045) ? (x / 12.92) "
- ": pow((x + 0.055) / 1.055, 2.4);",
- &srgbFuncName);
- default:
- // No helper function needed
- break;
- }
-
- if (nullptr == args.fInputColor) {
- args.fInputColor = "vec4(1)";
- }
-
- if (GrGammaEffect::Mode::kExponential == ge.mode()) {
- fragBuilder->codeAppendf("%s = vec4(pow(%s.rgb, vec3(%s)), %s.a);",
- args.fOutputColor, args.fInputColor, gammaUniName,
- args.fInputColor);
- } else {
- 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);
- }
- }
-
- void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {
- const GrGammaEffect& ge = proc.cast<GrGammaEffect>();
- if (GrGammaEffect::Mode::kExponential == ge.mode()) {
- pdman.set1f(fGammaUni, ge.gamma());
- }
- }
-
- static inline void GenKey(const GrProcessor& processor, const GrShaderCaps&,
- GrProcessorKeyBuilder* b) {
- const GrGammaEffect& ge = processor.cast<GrGammaEffect>();
- uint32_t key = static_cast<uint32_t>(ge.mode());
- b->add32(key);
- }
-
-private:
- GrGLSLProgramDataManager::UniformHandle fGammaUni;
-
- typedef GrGLSLFragmentProcessor INHERITED;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-GrGammaEffect::GrGammaEffect(Mode mode, SkScalar gamma)
- : fMode(mode)
- , fGamma(gamma) {
- this->initClassID<GrGammaEffect>();
-}
-
-bool GrGammaEffect::onIsEqual(const GrFragmentProcessor& s) const {
- const GrGammaEffect& other = s.cast<GrGammaEffect>();
- return
- other.fMode == fMode &&
- (fMode != Mode::kExponential || other.fGamma == fGamma);
-}
-
-void GrGammaEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
- inout->setToUnknown();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrGammaEffect);
-
-sk_sp<GrFragmentProcessor> GrGammaEffect::TestCreate(GrProcessorTestData* d) {
- // We want to be sure and test sRGB sometimes
- Mode testMode = static_cast<Mode>(d->fRandom->nextRangeU(0, 2));
- SkScalar gamma = d->fRandom->nextRangeScalar(0.5f, 2.0f);
- return sk_sp<GrFragmentProcessor>(new GrGammaEffect(testMode, gamma));
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-void GrGammaEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
- GrProcessorKeyBuilder* b) const {
- GrGLGammaEffect::GenKey(*this, caps, b);
-}
-
-GrGLSLFragmentProcessor* GrGammaEffect::onCreateGLSLInstance() const {
- return new GrGLGammaEffect();
-}
-
-sk_sp<GrFragmentProcessor> GrGammaEffect::Make(SkScalar gamma) {
- // TODO: Once our public-facing API for specifying gamma curves settles down, expose this,
- // and allow clients to explicitly request sRGB, rather than inferring from the exponent.
- // Note that AdobeRGB (for example) is speficied as x^2.2, not the Rec.709 curves.
- if (SkScalarNearlyEqual(gamma, 2.2f)) {
- return sk_sp<GrFragmentProcessor>(new GrGammaEffect(Mode::kSRGBToLinear, 2.2f));
- } else if (SkScalarNearlyEqual(gamma, 1.0f / 2.2f)) {
- return sk_sp<GrFragmentProcessor>(new GrGammaEffect(Mode::kLinearToSRGB, 1.0f / 2.2f));
- } else {
- return sk_sp<GrFragmentProcessor>(new GrGammaEffect(Mode::kExponential, gamma));
- }
-}
diff --git a/src/gpu/effects/GrSRGBEffect.cpp b/src/gpu/effects/GrSRGBEffect.cpp
new file mode 100644
index 0000000000..67600ef320
--- /dev/null
+++ b/src/gpu/effects/GrSRGBEffect.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrSRGBEffect.h"
+
+#include "GrContext.h"
+#include "GrFragmentProcessor.h"
+#include "GrInvariantOutput.h"
+#include "GrProcessor.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+
+class GrGLSRGBEffect : public GrGLSLFragmentProcessor {
+public:
+ void emitCode(EmitArgs& args) override {
+ const GrSRGBEffect& srgbe = args.fFp.cast<GrSRGBEffect>();
+ GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+
+ SkString srgbFuncName;
+ static const GrShaderVar gSrgbArgs[] = {
+ GrShaderVar("x", kFloat_GrSLType),
+ };
+ switch (srgbe.mode()) {
+ case GrSRGBEffect::Mode::kLinearToSRGB:
+ fragBuilder->emitFunction(kFloat_GrSLType,
+ "linear_to_srgb",
+ SK_ARRAY_COUNT(gSrgbArgs),
+ gSrgbArgs,
+ "return (x <= 0.0031308) ? (x * 12.92) "
+ ": (1.055 * pow(x, 0.416666667) - 0.055);",
+ &srgbFuncName);
+ break;
+ case GrSRGBEffect::Mode::kSRGBToLinear:
+ fragBuilder->emitFunction(kFloat_GrSLType,
+ "srgb_to_linear",
+ SK_ARRAY_COUNT(gSrgbArgs),
+ gSrgbArgs,
+ "return (x <= 0.04045) ? (x / 12.92) "
+ ": pow((x + 0.055) / 1.055, 2.4);",
+ &srgbFuncName);
+ break;
+ }
+
+ if (nullptr == args.fInputColor) {
+ 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);
+ }
+
+ 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());
+ b->add32(key);
+ }
+
+private:
+ typedef GrGLSLFragmentProcessor INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrSRGBEffect::GrSRGBEffect(Mode mode)
+ : fMode(mode) {
+ this->initClassID<GrSRGBEffect>();
+}
+
+bool GrSRGBEffect::onIsEqual(const GrFragmentProcessor& s) const {
+ const GrSRGBEffect& other = s.cast<GrSRGBEffect>();
+ return other.fMode == fMode;
+}
+
+void GrSRGBEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
+ inout->setToUnknown();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSRGBEffect);
+
+sk_sp<GrFragmentProcessor> GrSRGBEffect::TestCreate(GrProcessorTestData* d) {
+ Mode testMode = static_cast<Mode>(d->fRandom->nextRangeU(0, 1));
+ return sk_sp<GrFragmentProcessor>(new GrSRGBEffect(testMode));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GrSRGBEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+ GrProcessorKeyBuilder* b) const {
+ GrGLSRGBEffect::GenKey(*this, caps, b);
+}
+
+GrGLSLFragmentProcessor* GrSRGBEffect::onCreateGLSLInstance() const {
+ return new GrGLSRGBEffect();
+}
+
+sk_sp<GrFragmentProcessor> GrSRGBEffect::Make(Mode mode) {
+ return sk_sp<GrFragmentProcessor>(new GrSRGBEffect(mode));
+}
diff --git a/src/gpu/effects/GrGammaEffect.h b/src/gpu/effects/GrSRGBEffect.h
index a3e4b0e5e3..2952689c4e 100644
--- a/src/gpu/effects/GrGammaEffect.h
+++ b/src/gpu/effects/GrSRGBEffect.h
@@ -5,31 +5,29 @@
* found in the LICENSE file.
*/
-#ifndef GrGammaEffect_DEFINED
-#define GrGammaEffect_DEFINED
+#ifndef GrSRGBEffect_DEFINED
+#define GrSRGBEffect_DEFINED
#include "GrFragmentProcessor.h"
-class GrGammaEffect : public GrFragmentProcessor {
+class GrSRGBEffect : public GrFragmentProcessor {
public:
enum class Mode {
kLinearToSRGB,
kSRGBToLinear,
- kExponential,
};
/**
- * Creates an effect that applies a gamma curve.
- */
- static sk_sp<GrFragmentProcessor> Make(SkScalar gamma);
+ * Creates an effect that applies the sRGB transfer function (or its inverse)
+ */
+ static sk_sp<GrFragmentProcessor> Make(Mode mode);
- const char* name() const override { return "Gamma"; }
+ const char* name() const override { return "sRGB"; }
Mode mode() const { return fMode; }
- SkScalar gamma() const { return fGamma; }
private:
- GrGammaEffect(Mode mode, SkScalar gamma);
+ GrSRGBEffect(Mode mode);
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
@@ -37,7 +35,6 @@ private:
void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
Mode fMode;
- SkScalar fGamma;
GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
diff --git a/tests/ApplyGammaTest.cpp b/tests/ApplyGammaTest.cpp
index 4f1f828966..dbb7210c1a 100644
--- a/tests/ApplyGammaTest.cpp
+++ b/tests/ApplyGammaTest.cpp
@@ -12,60 +12,63 @@
#include "GrContext.h"
#include "SkCanvas.h"
-#include "SkGammaColorFilter.h"
+#include "SkColorFilter.h"
#include "SkSurface.h"
#include "SkUtils.h"
+#include "sk_tool_utils.h"
- // using anonymous namespace because these functions are used as template params.
-namespace {
/** convert 0..1 linear value to 0..1 srgb */
-float linear_to_srgb(float linear) {
+static float linear_to_srgb(float linear) {
if (linear <= 0.0031308) {
return linear * 12.92f;
} else {
return 1.055f * powf(linear, 1.f / 2.4f) - 0.055f;
}
}
-}
-bool check_gamma(uint32_t src, uint32_t dst, float gamma, float error, uint32_t* expected) {
- if (SkScalarNearlyEqual(gamma, 1.f)) {
- *expected = src;
- return src == dst;
+/** convert 0..1 srgb value to 0..1 linear */
+static float srgb_to_linear(float srgb) {
+ if (srgb <= 0.04045f) {
+ return srgb / 12.92f;
} else {
- bool result = true;
- uint32_t expectedColor = src & 0xff000000;
+ return powf((srgb + 0.055f) / 1.055f, 2.4f);
+ }
+}
- // Alpha should always be exactly preserved.
- if ((src & 0xff000000) != (dst & 0xff000000)) {
- result = false;
- }
+bool check_gamma(uint32_t src, uint32_t dst, bool toSRGB, float error,
+ uint32_t* expected) {
+ bool result = true;
+ uint32_t expectedColor = src & 0xff000000;
- 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);
- if (SkScalarNearlyEqual(gamma, 1.0f / 2.2f)) {
- lower = linear_to_srgb(lower / 255.f);
- upper = linear_to_srgb(upper / 255.f);
- } else {
- lower = powf(lower / 255.f, gamma);
- upper = powf(upper / 255.f, gamma);
- }
- 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)) {
- result = false;
- }
- uint8_t expectedComponent = SkScalarRoundToInt((lower + upper) * 127.5f);
- expectedColor |= expectedComponent << (c * 8);
- }
+ // Alpha should always be exactly preserved.
+ if ((src & 0xff000000) != (dst & 0xff000000)) {
+ result = false;
+ }
- *expected = expectedColor;
- return result;
+ 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);
+ if (toSRGB) {
+ lower = linear_to_srgb(lower / 255.f);
+ upper = linear_to_srgb(upper / 255.f);
+ } else {
+ lower = srgb_to_linear(lower / 255.f);
+ upper = srgb_to_linear(upper / 255.f);
+ }
+ 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)) {
+ result = false;
+ }
+ uint8_t expectedComponent = SkScalarRoundToInt((lower + upper) * 127.5f);
+ expectedColor |= expectedComponent << (c * 8);
}
+
+ *expected = expectedColor;
+ return result;
}
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ApplyGamma, reporter, ctxInfo) {
@@ -94,48 +97,46 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ApplyGamma, reporter, ctxInfo) {
// We allow more error on GPUs with lower precision shader variables.
float error = context->caps()->shaderCaps()->floatPrecisionVaries() ? 1.2f : 0.5f;
- for (auto dOrigin : { kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin }) {
- for (auto gamma : { 1.0f, 1.0f / 1.8f, 1.0f / 2.2f }) {
- sk_sp<SkSurface> dst(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo,
- ii, 0, dOrigin, nullptr));
+ for (auto toSRGB : { false, true }) {
+ sk_sp<SkSurface> dst(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, ii));
- if (!dst) {
- ERRORF(reporter, "Could not create surfaces for copy surface test.");
- continue;
- }
+ if (!dst) {
+ ERRORF(reporter, "Could not create surfaces for copy surface test.");
+ continue;
+ }
- SkCanvas* dstCanvas = dst->getCanvas();
+ SkCanvas* dstCanvas = dst->getCanvas();
- dstCanvas->clear(SK_ColorRED);
- dstCanvas->flush();
+ dstCanvas->clear(SK_ColorRED);
+ dstCanvas->flush();
- SkPaint gammaPaint;
- gammaPaint.setBlendMode(SkBlendMode::kSrc);
- gammaPaint.setColorFilter(SkGammaColorFilter::Make(gamma));
+ SkPaint gammaPaint;
+ gammaPaint.setBlendMode(SkBlendMode::kSrc);
+ gammaPaint.setColorFilter(toSRGB ? sk_tool_utils::MakeLinearToSRGBColorFilter()
+ : sk_tool_utils::MakeSRGBToLinearColorFilter());
- dstCanvas->drawBitmap(bm, 0, 0, &gammaPaint);
- dstCanvas->flush();
+ dstCanvas->drawBitmap(bm, 0, 0, &gammaPaint);
+ dstCanvas->flush();
- sk_memset32(read.get(), 0, kW * kH);
- if (!dstCanvas->readPixels(ii, read.get(), kRowBytes, 0, 0)) {
- ERRORF(reporter, "Error calling readPixels");
- continue;
- }
+ sk_memset32(read.get(), 0, kW * kH);
+ if (!dstCanvas->readPixels(ii, read.get(), kRowBytes, 0, 0)) {
+ ERRORF(reporter, "Error calling readPixels");
+ continue;
+ }
- bool abort = false;
- // Validate that pixels were copied/transformed correctly.
- for (int y = 0; y < kH && !abort; ++y) {
- for (int x = 0; x < kW && !abort; ++x) {
- uint32_t r = read.get()[y * kW + x];
- uint32_t s = srcPixels.get()[y * kW + x];
- uint32_t expected;
- if (!check_gamma(s, r, gamma, error, &expected)) {
- ERRORF(reporter, "Expected dst %d,%d to contain 0x%08x "
- "from src 0x%08x and gamma %f. Got %08x",
- x, y, expected, s, gamma, r);
- abort = true;
- break;
- }
+ bool abort = false;
+ // Validate that pixels were copied/transformed correctly.
+ for (int y = 0; y < kH && !abort; ++y) {
+ for (int x = 0; x < kW && !abort; ++x) {
+ uint32_t r = read.get()[y * kW + x];
+ uint32_t s = srcPixels.get()[y * kW + x];
+ uint32_t expected;
+ if (!check_gamma(s, r, toSRGB, error, &expected)) {
+ ERRORF(reporter, "Expected dst %d,%d to contain 0x%08x "
+ "from src 0x%08x and mode %s. Got %08x", x, y, expected, s,
+ toSRGB ? "ToSRGB" : "ToLinear", r);
+ abort = true;
+ break;
}
}
}
diff --git a/tools/sk_tool_utils.cpp b/tools/sk_tool_utils.cpp
index 93f5b107f2..0383897bd8 100644
--- a/tools/sk_tool_utils.cpp
+++ b/tools/sk_tool_utils.cpp
@@ -22,6 +22,38 @@
DEFINE_bool(portableFonts, false, "Use portable fonts");
+#if SK_SUPPORT_GPU
+#include "effects/GrSRGBEffect.h"
+#include "SkColorFilter.h"
+
+// Color filter that just wraps GrSRGBEffect
+class SkSRGBColorFilter : public SkColorFilter {
+public:
+ static sk_sp<SkColorFilter> Make(GrSRGBEffect::Mode mode) {
+ return sk_sp<SkColorFilter>(new SkSRGBColorFilter(mode));
+ }
+
+ sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*, SkColorSpace*) const override {
+ return GrSRGBEffect::Make(fMode);
+ }
+
+ void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const override {
+ SK_ABORT("SkSRGBColorFilter is only implemented for GPU");
+ }
+ Factory getFactory() const override { return nullptr; }
+
+#ifndef SK_IGNORE_TO_STRING
+ void toString(SkString* str) const override {}
+#endif
+
+private:
+ SkSRGBColorFilter(GrSRGBEffect::Mode mode) : fMode(mode) {}
+
+ GrSRGBEffect::Mode fMode;
+ typedef SkColorFilter INHERITED;
+};
+#endif
+
namespace sk_tool_utils {
/* these are the default fonts chosen by Chrome for serif, sans-serif, and monospace */
@@ -586,4 +618,14 @@ void copy_to_g8(SkBitmap* dst, const SkBitmap& src) {
}
}
+#if SK_SUPPORT_GPU
+sk_sp<SkColorFilter> MakeLinearToSRGBColorFilter() {
+ return SkSRGBColorFilter::Make(GrSRGBEffect::Mode::kLinearToSRGB);
+}
+
+sk_sp<SkColorFilter> MakeSRGBToLinearColorFilter() {
+ return SkSRGBColorFilter::Make(GrSRGBEffect::Mode::kSRGBToLinear);
+}
+#endif
+
} // namespace sk_tool_utils
diff --git a/tools/sk_tool_utils.h b/tools/sk_tool_utils.h
index ffe8084f7f..e319411349 100644
--- a/tools/sk_tool_utils.h
+++ b/tools/sk_tool_utils.h
@@ -19,6 +19,7 @@
class SkBitmap;
class SkCanvas;
+class SkColorFilter;
class SkPaint;
class SkPath;
class SkRRect;
@@ -254,6 +255,11 @@ namespace sk_tool_utils {
void copy_to_g8(SkBitmap* dst, const SkBitmap& src);
+#if SK_SUPPORT_GPU
+ sk_sp<SkColorFilter> MakeLinearToSRGBColorFilter();
+ sk_sp<SkColorFilter> MakeSRGBToLinearColorFilter();
+#endif
+
} // namespace sk_tool_utils
#endif // sk_tool_utils_DEFINED
diff --git a/tools/viewer/sk_app/mac/RasterWindowContext_mac.cpp b/tools/viewer/sk_app/mac/RasterWindowContext_mac.cpp
index fd2f2effb1..4749bc79a2 100644
--- a/tools/viewer/sk_app/mac/RasterWindowContext_mac.cpp
+++ b/tools/viewer/sk_app/mac/RasterWindowContext_mac.cpp
@@ -8,7 +8,8 @@
#include "../GLWindowContext.h"
#include "SkCanvas.h"
-#include "SkGammaColorFilter.h"
+#include "SkColorFilter.h"
+#include "sk_tool_utils.h"
#include "WindowContextFactory_mac.h"
#include "SDL.h"
@@ -123,7 +124,7 @@ void RasterWindowContext_mac::onSwapBuffers() {
SkPaint gammaPaint;
gammaPaint.setBlendMode(SkBlendMode::kSrc);
if (doGamma) {
- gammaPaint.setColorFilter(SkGammaColorFilter::Make(1.0f / 2.2f));
+ gammaPaint.setColorFilter(sk_tool_utils::MakeLinearToSRGBColorFilter());
}
sk_sp<SkSurface> gpuSurface = INHERITED::getBackbufferSurface();