From a408c8fb6d367d494437b8709fdfa8c822267e6e Mon Sep 17 00:00:00 2001 From: robertphillips Date: Thu, 28 Jul 2016 09:20:33 -0700 Subject: Add SkGammaColorFilter WDYT about this as a means of replacing GrContext::applyGamma with a normal SkCanvas::drawImage? GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2190573002 Review-Url: https://codereview.chromium.org/2190573002 --- gm/gammacolorfilter.cpp | 101 +++++++++++++++++++++++++++++++++++ gyp/effects.gyp | 1 + gyp/effects.gypi | 2 + include/effects/SkGammaColorFilter.h | 48 +++++++++++++++++ src/effects/SkGammaColorFilter.cpp | 56 +++++++++++++++++++ 5 files changed, 208 insertions(+) create mode 100644 gm/gammacolorfilter.cpp create mode 100644 include/effects/SkGammaColorFilter.h create mode 100644 src/effects/SkGammaColorFilter.cpp diff --git a/gm/gammacolorfilter.cpp b/gm/gammacolorfilter.cpp new file mode 100644 index 0000000000..ecb2daa214 --- /dev/null +++ b/gm/gammacolorfilter.cpp @@ -0,0 +1,101 @@ +/* + * 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 "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 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 { + GrDrawContext* drawContext = canvas->internal_private_accessTopLayerDrawContext(); + if (!drawContext) { + skiagm::GM::DrawGpuOnlyMessage(canvas); + return; + } + + sk_sp 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 const int kCellWidth = 64; + static const int kCellHeight = 64; + static const int kNumGreySteps = 16; + + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +DEF_GM(return new GammaColorFilterGM;) +} diff --git a/gyp/effects.gyp b/gyp/effects.gyp index 2402ed1c44..4dea202d3d 100644 --- a/gyp/effects.gyp +++ b/gyp/effects.gyp @@ -25,6 +25,7 @@ '../src/effects', '../src/opts', '../src/core', + '../src/gpu/effects', ], 'direct_dependent_settings': { 'include_dirs': [ diff --git a/gyp/effects.gypi b/gyp/effects.gypi index 33c8c13d41..c755ac5bff 100644 --- a/gyp/effects.gypi +++ b/gyp/effects.gypi @@ -43,6 +43,7 @@ '<(skia_src_path)/effects/SkEmbossMask_Table.h', '<(skia_src_path)/effects/SkEmbossMaskFilter.cpp', '<(skia_src_path)/effects/SkImageSource.cpp', + '<(skia_src_path)/effects/SkGammaColorFilter.cpp', '<(skia_src_path)/effects/SkGpuBlurUtils.h', '<(skia_src_path)/effects/SkGpuBlurUtils.cpp', '<(skia_src_path)/effects/SkLayerDrawLooper.cpp', @@ -104,6 +105,7 @@ '<(skia_include_path)/effects/SkDisplacementMapEffect.h', '<(skia_include_path)/effects/SkDropShadowImageFilter.h', '<(skia_include_path)/effects/SkEmbossMaskFilter.h', + '<(skia_include_path)/effects/SkGammaColorFilter.h', '<(skia_include_path)/effects/SkGradientShader.h', '<(skia_include_path)/effects/SkImageSource.h', '<(skia_include_path)/effects/SkLayerDrawLooper.h', diff --git a/include/effects/SkGammaColorFilter.h b/include/effects/SkGammaColorFilter.h new file mode 100644 index 0000000000..308926a3ab --- /dev/null +++ b/include/effects/SkGammaColorFilter.h @@ -0,0 +1,48 @@ +/* + * 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 Make(SkScalar gamma); + +#ifdef SK_SUPPORT_LEGACY_COLORFILTER_PTR + static SkColorFilter* Create(SkScalar gamma) { return Make(gamma).release(); } +#endif + + void filterSpan(const SkPMColor src[], int count, SkPMColor[]) const override; + +#if SK_SUPPORT_GPU + sk_sp asFragmentProcessor(GrContext*) 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/src/effects/SkGammaColorFilter.cpp b/src/effects/SkGammaColorFilter.cpp new file mode 100644 index 0000000000..eba8e320d8 --- /dev/null +++ b/src/effects/SkGammaColorFilter.cpp @@ -0,0 +1,56 @@ +/* + * 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 SkGammaColorFilter::Make(SkScalar gamma) { + return sk_sp(new SkGammaColorFilter(gamma)); +} + +SkGammaColorFilter::SkGammaColorFilter(SkScalar gamma) : fGamma(gamma) {} + +sk_sp 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 SkGammaColorFilter::asFragmentProcessor(GrContext*) const { + return GrGammaEffect::Make(fGamma); +} +#endif -- cgit v1.2.3