blob: 930193b035022508cf538a22aef3abfa08ef3ffb [file] [log] [blame]
Mike Reed3fd3cc92019-06-20 12:40:30 -04001/*
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"
9#include "include/core/SkCanvas.h"
Mike Reed3fd3cc92019-06-20 12:40:30 -040010#include "include/core/SkData.h"
Mike Reed3fd3cc92019-06-20 12:40:30 -040011#include "include/core/SkPaint.h"
Mike Reed3fd3cc92019-06-20 12:40:30 -040012#include "include/core/SkSize.h"
13#include "include/core/SkString.h"
Mike Reed146722e2020-02-13 12:36:28 -050014#include "include/effects/SkImageFilters.h"
Brian Osmanee426f22020-01-02 11:55:24 -050015#include "include/effects/SkRuntimeEffect.h"
Mike Reed146722e2020-02-13 12:36:28 -050016#include "tools/Resources.h"
Mike Reed3fd3cc92019-06-20 12:40:30 -040017
Mike Reed3fd3cc92019-06-20 12:40:30 -040018const char* gProg = R"(
Brian Osmanc937bc52019-12-09 12:07:09 -050019 uniform half4 gColor;
Mike Reed3fd3cc92019-06-20 12:40:30 -040020
Brian Osman7353dc52020-02-07 13:37:12 -050021 void main(float2 p, inout half4 color) {
22 color = half4(half2(p)*(1.0/255), gColor.b, 1);
Mike Reed3fd3cc92019-06-20 12:40:30 -040023 }
24)";
25
26class RuntimeShader : public skiagm::GM {
Mike Reed3fd3cc92019-06-20 12:40:30 -040027 bool runAsBench() const override { return true; }
28
Hal Canary594fe852019-07-18 13:35:49 -040029 SkString onShortName() override { return SkString("runtime_shader"); }
Mike Reed3fd3cc92019-06-20 12:40:30 -040030
Hal Canary594fe852019-07-18 13:35:49 -040031 SkISize onISize() override { return {512, 256}; }
Mike Reed3fd3cc92019-06-20 12:40:30 -040032
Mike Reed3fd3cc92019-06-20 12:40:30 -040033 void onDraw(SkCanvas* canvas) override {
Brian Osman32253062020-02-05 11:37:08 -050034 sk_sp<SkRuntimeEffect> gEffect = std::get<0>(SkRuntimeEffect::Make(SkString(gProg)));
Brian Osman93de1622019-12-26 08:43:05 -050035 SkASSERT(gEffect);
36
37 SkMatrix localM;
38 localM.setRotate(90, 128, 128);
39
40 SkColor4f inputColor = { 1, 0, 0, 1 };
41 auto shader = gEffect->makeShader(SkData::MakeWithCopy(&inputColor, sizeof(inputColor)),
42 nullptr, 0, &localM, true);
Mike Reed3fd3cc92019-06-20 12:40:30 -040043 SkPaint p;
Brian Osman93de1622019-12-26 08:43:05 -050044 p.setShader(std::move(shader));
Mike Reed3fd3cc92019-06-20 12:40:30 -040045 canvas->drawRect({0, 0, 256, 256}, p);
46 }
Mike Reed3fd3cc92019-06-20 12:40:30 -040047};
48DEF_GM(return new RuntimeShader;)
Mike Reed146722e2020-02-13 12:36:28 -050049
50static sk_sp<SkShader> make_shader(sk_sp<SkImage> img, SkISize size) {
51 SkMatrix scale = SkMatrix::MakeScale(size.width() / (float)img->width(),
52 size.height() / (float)img->height());
53 return img->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, &scale);
54}
55
56#include "include/core/SkSurface.h"
57#include "include/effects/SkGradientShader.h"
58#include "include/utils/SkRandom.h"
59
60static sk_sp<SkShader> make_threshold(SkISize size) {
61 auto info = SkImageInfo::Make(size.width(), size.height(), kAlpha_8_SkColorType,
62 kPremul_SkAlphaType);
63 auto surf = SkSurface::MakeRaster(info);
64 auto canvas = surf->getCanvas();
65
66 const SkScalar rad = 50;
67 SkColor colors[] = {SK_ColorBLACK, 0};
68 SkPaint paint;
69 paint.setAntiAlias(true);
70 paint.setShader(SkGradientShader::MakeRadial({0,0}, rad, colors, nullptr, 2, SkTileMode::kClamp));
71
72 SkPaint layerPaint;
73 const SkScalar sigma = 16.0f;
74 layerPaint.setImageFilter(SkImageFilters::Blur(sigma, sigma, nullptr));
75 canvas->saveLayer(nullptr, &layerPaint);
76
77 SkRandom rand;
78 for (int i = 0; i < 25; ++i) {
79 SkScalar x = rand.nextF() * size.width();
80 SkScalar y = rand.nextF() * size.height();
81 canvas->save();
82 canvas->translate(x, y);
83 canvas->drawCircle(0, 0, rad, paint);
84 canvas->restore();
85 }
86
87 canvas->restore(); // apply the blur
88
89 return surf->makeImageSnapshot()->makeShader();
90}
91
92class ThresholdRT : public skiagm::GM {
93 sk_sp<SkShader> fBefore, fAfter, fThreshold;
94 sk_sp<SkRuntimeEffect> fEffect;
95
96 float fCutoff = 0.5; // so we get something interested when we're not animated
97
98 void onOnceBeforeDraw() override {
99 const SkISize size = {256, 256};
100 fThreshold = make_threshold(size);
101 fBefore = make_shader(GetResourceAsImage("images/mandrill_256.png"), size);
102 fAfter = make_shader(GetResourceAsImage("images/dog.jpg"), size);
103
104 const char code[] = R"(
105 in fragmentProcessor before_map;
106 in fragmentProcessor after_map;
107 in fragmentProcessor threshold_map;
108
109 uniform float cutoff;
110 uniform float slope;
111
112 float smooth_cutoff(float x) {
113 x = x * slope + (0.5 - slope * cutoff);
114 return clamp(x, 0, 1);
115 }
116
117 void main(float2 xy, inout half4 color) {
118 half4 before = sample(before_map, xy);
119 half4 after = sample(after_map, xy);
120
121 float m = smooth_cutoff(sample(threshold_map, xy).r);
122 color = mix(before, after, half(m));
123 }
124 )";
125 auto [effect, error] = SkRuntimeEffect::Make(SkString(code));
126 if (!effect) {
127 SkDebugf("runtime error %s\n", error.c_str());
128 }
129 fEffect = effect;
130 }
131
132 bool runAsBench() const override { return true; }
133
134 SkString onShortName() override { return SkString("threshold_rt"); }
135
136 SkISize onISize() override { return {256, 256}; }
137
138 DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
139 if (canvas->getGrContext() == nullptr) {
140 // until SkSL can handle child processors on the raster backend
141 return DrawResult::kSkip;
142 }
143
144 struct {
145 float cutoff, slope;
146 } uni = {
147 fCutoff, 10
148 };
149 sk_sp<SkData> data = SkData::MakeWithCopy(&uni, sizeof(uni));
150 sk_sp<SkShader> children[] = { fBefore, fAfter, fThreshold };
151
152 SkPaint paint;
153 paint.setShader(fEffect->makeShader(data, children, SK_ARRAY_COUNT(children),
154 nullptr, true));
155 canvas->drawRect({0, 0, 256, 256}, paint);
156
157 auto draw = [&](SkScalar x, SkScalar y, sk_sp<SkShader> shader) {
158 paint.setShader(shader);
159 canvas->save();
160 canvas->translate(x, y);
161 canvas->drawRect({0, 0, 256, 256}, paint);
162 canvas->restore();
163 };
164 draw(256, 0, fThreshold);
165 draw( 0, 256, fBefore);
166 draw(256, 256, fAfter);
167
168 return DrawResult::kOk;
169 }
170
171 bool onAnimate(double nanos) override {
172 double t = sin(nanos / (1000 * 1000 * 1000));
173 fCutoff = float(t + 1) * 0.55f - 0.05f;
174 return true;
175 }
176};
177DEF_GM(return new ThresholdRT;)