Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
runtimecolorfilter.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2019 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "gm/gm.h"
12#include "include/core/SkData.h"
17#include "include/core/SkSize.h"
22#include "tools/DecodeUtils.h"
23#include "tools/Resources.h"
24
25#include <stddef.h>
26#include <utility>
27
28const char* gNoop = R"(
29 half4 main(half4 color) {
30 return color;
31 }
32)";
33
34const char* gLumaSrc = R"(
35 half4 main(half4 color) {
36 return dot(color.rgb, half3(0.3, 0.6, 0.1)).000r;
37 }
38)";
39
40// Build up the same effect with increasingly complex control flow syntax.
41// All of these are semantically equivalent and can be reduced in principle to one basic block.
42
43// Simplest to run; hardest to write?
44const char* gTernary = R"(
45 half4 main(half4 color) {
46 half luma = dot(color.rgb, half3(0.3, 0.6, 0.1));
47
48 half scale = luma < 0.33333 ? 0.5
49 : luma < 0.66666 ? (0.166666 + 2.0 * (luma - 0.33333)) / luma
50 : /* else */ (0.833333 + 0.5 * (luma - 0.66666)) / luma;
51 return half4(color.rgb * scale, color.a);
52 }
53)";
54
55// Uses conditional if statements but no early return.
56const char* gIfs = R"(
57 half4 main(half4 color) {
58 half luma = dot(color.rgb, half3(0.3, 0.6, 0.1));
59
60 half scale = 0;
61 if (luma < 0.33333) {
62 scale = 0.5;
63 } else if (luma < 0.66666) {
64 scale = (0.166666 + 2.0 * (luma - 0.33333)) / luma;
65 } else {
66 scale = (0.833333 + 0.5 * (luma - 0.66666)) / luma;
67 }
68 return half4(color.rgb * scale, color.a);
69 }
70)";
71
72// Distilled from AOSP tone mapping shaders, more like what people tend to write.
73const char* gEarlyReturn = R"(
74 half4 main(half4 color) {
75 half luma = dot(color.rgb, half3(0.3, 0.6, 0.1));
76
77 half scale = 0;
78 if (luma < 0.33333) {
79 return half4(color.rgb * 0.5, color.a);
80 } else if (luma < 0.66666) {
81 scale = 0.166666 + 2.0 * (luma - 0.33333);
82 } else {
83 scale = 0.833333 + 0.5 * (luma - 0.66666);
84 }
85 return half4(color.rgb * (scale/luma), color.a);
86 }
87)";
88
90public:
92
93protected:
94 SkString getName() const override { return SkString("runtimecolorfilter"); }
95
96 SkISize getISize() override { return SkISize::Make(256 * 3, 256 * 2); }
97
98 void onOnceBeforeDraw() override {
99 fImg = ToolUtils::GetResourceAsImage("images/mandrill_256.png");
100 }
101
102 void onDraw(SkCanvas* canvas) override {
103 auto draw_filter = [&](const char* src) {
104 auto [effect, err] = SkRuntimeEffect::MakeForColorFilter(SkString(src));
105 if (!effect) {
106 SkDebugf("%s\n%s\n", src, err.c_str());
107 }
108 SkASSERT(effect);
109 SkPaint p;
110 p.setColorFilter(effect->makeColorFilter(nullptr));
111 canvas->drawImage(fImg, 0, 0, SkSamplingOptions(), &p);
112 canvas->translate(256, 0);
113 };
114
115 for (const char* src : {gNoop, gLumaSrc}) {
116 draw_filter(src);
117 }
118 canvas->translate(-256*2, 256);
119 for (const char* src : {gTernary, gIfs, gEarlyReturn}) {
120 draw_filter(src);
121 }
122 }
123
125};
126DEF_GM(return new RuntimeColorFilterGM;)
127
128DEF_SIMPLE_GM(runtimecolorfilter_vertices_atlas_and_patch, canvas, 404, 404) {
129 const SkRect r = SkRect::MakeWH(128, 128);
130
131 // Make a vertices that draws the same as SkRect 'r'.
132 SkPoint pos[4];
133 r.toQuad(pos);
136
137 // Make an image from the vertices to do equivalent drawAtlas, drawPatch using an image shader.
138 auto info = SkImageInfo::Make({128, 128},
141 canvas->imageInfo().refColorSpace());
142 auto surf = SkSurfaces::Raster(info);
143 surf->getCanvas()->drawVertices(verts, SkBlendMode::kDst, SkPaint());
144 auto atlas = surf->makeImageSnapshot();
145 auto xform = SkRSXform::Make(1, 0, 0, 0);
146
147 // Make a patch that draws the same as the SkRect 'r'
148 SkVector vx = pos[1] - pos[0];
149 SkVector vy = pos[3] - pos[0];
150 vx.setLength(vx.length()/3.f);
151 vy.setLength(vy.length()/3.f);
152 const SkPoint cubics[12] = {
153 pos[0], pos[0] + vx, pos[1] - vx,
154 pos[1], pos[1] + vy, pos[2] - vy,
155 pos[2], pos[2] - vx, pos[3] + vx,
156 pos[3], pos[3] - vy, pos[0] + vy
157 };
158
160 if (!effect) {
161 SkDebugf("%s\n%s\n", gLumaSrc, err.c_str());
162 }
163 SkASSERT(effect);
164 sk_sp<SkColorFilter> colorfilter = effect->makeColorFilter(nullptr);
165
166 auto makePaint = [&](bool useCF, bool useShader) {
168 paint.setColorFilter(useCF ? colorfilter : nullptr);
169 paint.setShader(useShader ? atlas->makeShader(SkFilterMode::kNearest) : nullptr);
170 return paint;
171 };
172
173 auto drawVertices = [&](float x, bool useCF, bool useShader) {
174 SkAutoCanvasRestore acr(canvas, /*doSave=*/true);
175 canvas->translate(x, 0);
176 // Use just the shader or just the vertex colors.
177 auto mode = useShader ? SkBlendMode::kSrc : SkBlendMode::kDst;
178 canvas->drawVertices(verts, mode, makePaint(useCF, useShader));
179 };
180
181 auto drawAtlas = [&](float x, bool useCF) {
182 SkAutoCanvasRestore acr(canvas, /*doSave=*/true);
183 canvas->translate(x, 0);
184 SkPaint paint = makePaint(useCF, /*useShader=*/false);
185 constexpr SkColor kColor = SK_ColorWHITE;
186 canvas->drawAtlas(atlas.get(),
187 &xform,
188 &r,
189 &kColor,
190 1,
193 nullptr,
194 &paint);
195 };
196
197 auto drawPatch = [&](float x, bool useCF) {
198 SkAutoCanvasRestore acr(canvas, true);
199 canvas->translate(x, 0);
200 SkPaint paint = makePaint(useCF, /*useShader=*/true);
201 canvas->drawPatch(cubics, nullptr, pos, SkBlendMode::kModulate, paint);
202 };
203
204 drawVertices( 0, /*useCF=*/false, /*useShader=*/false);
205 drawVertices( r.width() + 10, /*useCF=*/ true, /*useShader=*/false);
206 drawVertices(2*(r.width() + 10), /*useCF=*/ true, /*useShader=*/ true);
207
208 canvas->translate(0, r.height() + 10);
209 drawAtlas( 0, /*useCF=*/false);
210 drawAtlas(r.width() + 10, /*useCF=*/ true);
211
212 canvas->translate(0, r.height() + 10);
213 drawPatch( 0, /*useCF=*/false);
214 drawPatch(r.width() + 10, /*useCF=*/ true);
215}
static constexpr SkColor kColor
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
SkPoint pos
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition SkAlphaType.h:29
#define SkASSERT(cond)
Definition SkAssert.h:116
@ kModulate
r = s*d
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition SkColorType.h:24
constexpr SkColor SK_ColorYELLOW
Definition SkColor.h:139
uint32_t SkColor
Definition SkColor.h:37
constexpr SkColor SK_ColorCYAN
Definition SkColor.h:143
constexpr SkColor SK_ColorBLUE
Definition SkColor.h:135
constexpr SkColor SK_ColorGREEN
Definition SkColor.h:131
constexpr SkColor SK_ColorWHITE
Definition SkColor.h:122
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
void onOnceBeforeDraw() override
SkString getName() const override
RuntimeColorFilterGM()=default
SkISize getISize() override
void onDraw(SkCanvas *canvas) override
void translate(SkScalar dx, SkScalar dy)
void drawImage(const SkImage *image, SkScalar left, SkScalar top)
Definition SkCanvas.h:1528
sk_sp< SkShader > makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &, const SkMatrix *localMatrix=nullptr) const
Definition SkImage.cpp:179
static Result MakeForColorFilter(SkString sksl, const Options &)
static sk_sp< SkVertices > MakeCopy(VertexMode mode, int vertexCount, const SkPoint positions[], const SkPoint texs[], const SkColor colors[], int indexCount, const uint16_t indices[])
@ kTriangleFan_VertexMode
Definition SkVertices.h:33
T * get() const
Definition SkRefCnt.h:303
const Paint & paint
#define DEF_GM(CODE)
Definition gm.h:40
#define DEF_SIMPLE_GM(NAME, CANVAS, W, H)
Definition gm.h:50
double x
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
sk_sp< SkImage > GetResourceAsImage(const char *resource)
Definition DecodeUtils.h:25
const char * gTernary
const char * gNoop
const char * gLumaSrc
const char * gIfs
const char * gEarlyReturn
static constexpr SkISize Make(int32_t w, int32_t h)
Definition SkSize.h:20
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
bool setLength(float length)
Definition SkPoint.cpp:30
float length() const
static SkRSXform Make(SkScalar scos, SkScalar ssin, SkScalar tx, SkScalar ty)
Definition SkRSXform.h:24
void toQuad(SkPoint quad[4]) const
Definition SkRect.cpp:50
constexpr float height() const
Definition SkRect.h:769
constexpr float width() const
Definition SkRect.h:762
static constexpr SkRect MakeWH(float w, float h)
Definition SkRect.h:609