blob: 23f312d5d8cce089c6617a1b8d61dcd808370820 [file] [log] [blame]
Brian Osman088913a2019-12-19 15:44:56 -05001/*
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
Brian Osman62419612020-07-22 10:19:02 -04008#include "include/core/SkBitmap.h"
Brian Osmanf72dedd2020-01-08 13:19:58 -05009#include "include/core/SkCanvas.h"
Brian Osman92aac1e2020-08-05 16:48:58 -040010#include "include/core/SkColorFilter.h"
Brian Osman269b21c2020-08-06 12:15:53 -040011#include "include/core/SkData.h"
Brian Osmanf72dedd2020-01-08 13:19:58 -050012#include "include/core/SkPaint.h"
13#include "include/core/SkSurface.h"
Brian Osmanee426f22020-01-02 11:55:24 -050014#include "include/effects/SkRuntimeEffect.h"
Robert Phillips6d344c32020-07-06 10:56:46 -040015#include "include/gpu/GrDirectContext.h"
Brian Salomon5392c942021-03-30 16:14:37 -040016#include "src/core/SkColorSpacePriv.h"
Brian Osmand9bde072020-04-15 14:18:13 -040017#include "src/core/SkTLazy.h"
Brian Osman62419612020-07-22 10:19:02 -040018#include "src/gpu/GrColor.h"
Brian Osman088913a2019-12-19 15:44:56 -050019#include "tests/Test.h"
20
Brian Osmanf72dedd2020-01-08 13:19:58 -050021#include <algorithm>
Brian Osman8e2ef022020-09-30 13:26:43 -040022#include <thread>
Brian Osmanf72dedd2020-01-08 13:19:58 -050023
John Stiles7ce17512021-01-12 18:39:02 -050024void test_invalid_effect(skiatest::Reporter* r, const char* src, const char* expected) {
25 auto [effect, errorText] = SkRuntimeEffect::Make(SkString(src));
26 REPORTER_ASSERT(r, !effect);
27 REPORTER_ASSERT(r, errorText.contains(expected),
28 "Expected error message to contain \"%s\". Actual message: \"%s\"",
29 expected, errorText.c_str());
30};
Brian Osman088913a2019-12-19 15:44:56 -050031
Brian Osman24c18522020-11-10 16:36:01 -050032#define EMPTY_MAIN "half4 main() { return half4(0); }"
33
John Stiles7ce17512021-01-12 18:39:02 -050034DEF_TEST(SkRuntimeEffectInvalid_FPOnly, r) {
Brian Osman088913a2019-12-19 15:44:56 -050035 // Features that are only allowed in .fp files (key, in uniform, ctype, when, tracked).
36 // Ensure that these fail, and the error messages contain the relevant keyword.
John Stiles7ce17512021-01-12 18:39:02 -050037 test_invalid_effect(r, "layout(key) in bool Input;" EMPTY_MAIN, "key");
38 test_invalid_effect(r, "in uniform float Input;" EMPTY_MAIN, "in uniform");
39 test_invalid_effect(r, "layout(ctype=SkRect) float4 Input;" EMPTY_MAIN, "ctype");
40 test_invalid_effect(r, "in bool Flag; "
41 "layout(when=Flag) uniform float Input;" EMPTY_MAIN, "when");
42 test_invalid_effect(r, "layout(tracked) uniform float Input;" EMPTY_MAIN, "tracked");
43}
Brian Osman088913a2019-12-19 15:44:56 -050044
John Stiles7ce17512021-01-12 18:39:02 -050045DEF_TEST(SkRuntimeEffectInvalid_LimitedUniformTypes, r) {
Brian Osmand18967c2021-04-01 09:56:07 -040046 // Runtime SkSL supports a limited set of uniform types. No bool, for example:
John Stiles7ce17512021-01-12 18:39:02 -050047 test_invalid_effect(r, "uniform bool b;" EMPTY_MAIN, "uniform");
John Stiles7ce17512021-01-12 18:39:02 -050048}
Brian Osman088913a2019-12-19 15:44:56 -050049
John Stiles7ce17512021-01-12 18:39:02 -050050DEF_TEST(SkRuntimeEffectInvalid_NoInVariables, r) {
Brian Osmana4b91692020-08-10 14:26:16 -040051 // 'in' variables aren't allowed at all:
John Stiles7ce17512021-01-12 18:39:02 -050052 test_invalid_effect(r, "in bool b;" EMPTY_MAIN, "'in'");
53 test_invalid_effect(r, "in float f;" EMPTY_MAIN, "'in'");
54 test_invalid_effect(r, "in float2 v;" EMPTY_MAIN, "'in'");
55 test_invalid_effect(r, "in half3x3 m;" EMPTY_MAIN, "'in'");
56}
Brian Osman8783b782020-01-06 11:13:45 -050057
John Stiles7ce17512021-01-12 18:39:02 -050058DEF_TEST(SkRuntimeEffectInvalid_MarkerRequiresFloat4x4, r) {
Brian Osmana4b91692020-08-10 14:26:16 -040059 // 'marker' is only permitted on float4x4 uniforms
John Stiles7ce17512021-01-12 18:39:02 -050060 test_invalid_effect(r,
61 "layout(marker=local_to_world) uniform float3x3 localToWorld;" EMPTY_MAIN,
62 "float4x4");
63}
Brian Osmane64ae862020-07-16 15:29:15 -040064
John Stiles7ce17512021-01-12 18:39:02 -050065DEF_TEST(SkRuntimeEffectInvalid_UndefinedFunction, r) {
66 test_invalid_effect(r, "half4 missing(); half4 main() { return missing(); }",
67 "undefined function");
68}
Brian Osman182c92e2020-07-20 15:18:33 -040069
John Stiles7ce17512021-01-12 18:39:02 -050070DEF_TEST(SkRuntimeEffectInvalid_UndefinedMain, r) {
Brian Osman182c92e2020-07-20 15:18:33 -040071 // Shouldn't be possible to create an SkRuntimeEffect without "main"
John Stiles7ce17512021-01-12 18:39:02 -050072 test_invalid_effect(r, "", "main");
73}
Brian Osman82329002020-07-21 09:39:27 -040074
John Stiles7ce17512021-01-12 18:39:02 -050075DEF_TEST(SkRuntimeEffectInvalid_SkCapsDisallowed, r) {
Brian Osmanb06301e2020-11-06 11:45:36 -050076 // sk_Caps is an internal system. It should not be visible to runtime effects
John Stiles7ce17512021-01-12 18:39:02 -050077 test_invalid_effect(r, "half4 main() { return sk_Caps.integerSupport ? half4(1) : half4(0); }",
78 "unknown identifier 'sk_Caps'");
79}
Brian Osmanb06301e2020-11-06 11:45:36 -050080
Brian Osman92aac1e2020-08-05 16:48:58 -040081DEF_TEST(SkRuntimeEffectInvalidColorFilters, r) {
82 auto test = [r](const char* sksl) {
83 auto [effect, errorText] = SkRuntimeEffect::Make(SkString(sksl));
84 REPORTER_ASSERT(r, effect);
Brian Osman269b21c2020-08-06 12:15:53 -040085
Brian Osmana4b91692020-08-10 14:26:16 -040086 sk_sp<SkData> uniforms = SkData::MakeUninitialized(effect->uniformSize());
Brian Osman269b21c2020-08-06 12:15:53 -040087
Brian Osmana4b91692020-08-10 14:26:16 -040088 REPORTER_ASSERT(r, effect->makeShader(uniforms, nullptr, 0, nullptr, false));
89 REPORTER_ASSERT(r, !effect->makeColorFilter(uniforms));
Brian Osman92aac1e2020-08-05 16:48:58 -040090 };
91
92 // Runtime effects that use sample coords or sk_FragCoord are valid shaders,
93 // but not valid color filters
Brian Osman767f4442020-08-13 16:59:48 -040094 test("half4 main(float2 p) { return half2(p).xy01; }");
95 test("half4 main(float2 p) { return half2(sk_FragCoord.xy).xy01; }");
Brian Osman269b21c2020-08-06 12:15:53 -040096
97 // We also can't use layout(marker), which would give the runtime color filter CTM information
98 test("layout(marker=ctm) uniform float4x4 ctm;"
Brian Osman767f4442020-08-13 16:59:48 -040099 "half4 main(float2 p) { return half4(half(ctm[0][0]), 0, 0, 1); }");
Brian Osman92aac1e2020-08-05 16:48:58 -0400100}
101
Brian Osmanf72dedd2020-01-08 13:19:58 -0500102class TestEffect {
103public:
Brian Osman62419612020-07-22 10:19:02 -0400104 TestEffect(skiatest::Reporter* r, sk_sp<SkSurface> surface)
105 : fReporter(r), fSurface(std::move(surface)) {}
106
Brian Osman33316412020-11-06 10:42:51 -0500107 void build(const char* src) {
John Stiles1f19ce22021-02-11 17:40:03 -0500108 auto [effect, errorText] = SkRuntimeEffect::Make(SkString(src));
Brian Osmanf72dedd2020-01-08 13:19:58 -0500109 if (!effect) {
Brian Osman62419612020-07-22 10:19:02 -0400110 REPORT_FAILURE(fReporter, "effect",
Brian Osmanf72dedd2020-01-08 13:19:58 -0500111 SkStringPrintf("Effect didn't compile: %s", errorText.c_str()));
112 return;
113 }
Brian Osmand9bde072020-04-15 14:18:13 -0400114 fBuilder.init(std::move(effect));
Brian Osmanf72dedd2020-01-08 13:19:58 -0500115 }
116
Brian Osmana4b91692020-08-10 14:26:16 -0400117 SkRuntimeShaderBuilder::BuilderUniform uniform(const char* name) {
118 return fBuilder->uniform(name);
Brian Osmanf72dedd2020-01-08 13:19:58 -0500119 }
Brian Osman62419612020-07-22 10:19:02 -0400120 SkRuntimeShaderBuilder::BuilderChild child(const char* name) {
121 return fBuilder->child(name);
122 }
Brian Osmanf72dedd2020-01-08 13:19:58 -0500123
Brian Osman62419612020-07-22 10:19:02 -0400124 using PreTestFn = std::function<void(SkCanvas*, SkPaint*)>;
125
126 void test(GrColor TL, GrColor TR, GrColor BL, GrColor BR,
127 PreTestFn preTestCallback = nullptr) {
Brian Osmand9bde072020-04-15 14:18:13 -0400128 auto shader = fBuilder->makeShader(nullptr, false);
Brian Osmanf72dedd2020-01-08 13:19:58 -0500129 if (!shader) {
Brian Osman62419612020-07-22 10:19:02 -0400130 REPORT_FAILURE(fReporter, "shader", SkString("Effect didn't produce a shader"));
Brian Osmanf72dedd2020-01-08 13:19:58 -0500131 return;
132 }
133
Brian Osman62419612020-07-22 10:19:02 -0400134 SkCanvas* canvas = fSurface->getCanvas();
Brian Osmanf72dedd2020-01-08 13:19:58 -0500135 SkPaint paint;
136 paint.setShader(std::move(shader));
137 paint.setBlendMode(SkBlendMode::kSrc);
Brian Osmanf72dedd2020-01-08 13:19:58 -0500138
Brian Osman62419612020-07-22 10:19:02 -0400139 canvas->save();
140 if (preTestCallback) {
141 preTestCallback(canvas, &paint);
142 }
143 canvas->drawPaint(paint);
144 canvas->restore();
145
146 GrColor actual[4];
147 SkImageInfo info = fSurface->imageInfo();
148 if (!fSurface->readPixels(info, actual, info.minRowBytes(), 0, 0)) {
149 REPORT_FAILURE(fReporter, "readPixels", SkString("readPixels failed"));
Brian Osmanf72dedd2020-01-08 13:19:58 -0500150 return;
151 }
152
Brian Osman62419612020-07-22 10:19:02 -0400153 GrColor expected[4] = {TL, TR, BL, BR};
John Stilesc1c3c6d2020-08-15 23:22:53 -0400154 if (0 != memcmp(actual, expected, sizeof(actual))) {
Brian Osman62419612020-07-22 10:19:02 -0400155 REPORT_FAILURE(fReporter, "Runtime effect didn't match expectations",
Brian Osmanf72dedd2020-01-08 13:19:58 -0500156 SkStringPrintf("\n"
157 "Expected: [ %08x %08x %08x %08x ]\n"
158 "Got : [ %08x %08x %08x %08x ]\n"
159 "SkSL:\n%s\n",
160 TL, TR, BL, BR, actual[0], actual[1], actual[2],
Brian Osmanb6bd0d22020-08-27 10:51:22 -0400161 actual[3], fBuilder->effect()->source().c_str()));
Brian Osmanf72dedd2020-01-08 13:19:58 -0500162 }
163 }
164
Brian Osman62419612020-07-22 10:19:02 -0400165 void test(GrColor expected, PreTestFn preTestCallback = nullptr) {
166 this->test(expected, expected, expected, expected, preTestCallback);
Brian Osmanf72dedd2020-01-08 13:19:58 -0500167 }
168
169private:
Brian Osman62419612020-07-22 10:19:02 -0400170 skiatest::Reporter* fReporter;
171 sk_sp<SkSurface> fSurface;
Brian Osmand9bde072020-04-15 14:18:13 -0400172 SkTLazy<SkRuntimeShaderBuilder> fBuilder;
Brian Osmanf72dedd2020-01-08 13:19:58 -0500173};
174
Brian Osman62419612020-07-22 10:19:02 -0400175// Produces a 2x2 bitmap shader, with opaque colors:
176// [ Red, Green ]
177// [ Blue, White ]
178static sk_sp<SkShader> make_RGBW_shader() {
179 SkBitmap bmp;
180 bmp.allocPixels(SkImageInfo::Make(2, 2, kRGBA_8888_SkColorType, kPremul_SkAlphaType));
181 SkIRect topLeft = SkIRect::MakeWH(1, 1);
182 bmp.pixmap().erase(SK_ColorRED, topLeft);
183 bmp.pixmap().erase(SK_ColorGREEN, topLeft.makeOffset(1, 0));
184 bmp.pixmap().erase(SK_ColorBLUE, topLeft.makeOffset(0, 1));
185 bmp.pixmap().erase(SK_ColorWHITE, topLeft.makeOffset(1, 1));
Mike Reedb41bd152020-12-12 11:18:31 -0500186 return bmp.makeShader(SkSamplingOptions());
Brian Osman62419612020-07-22 10:19:02 -0400187}
188
Robert Phillipse94b4e12020-07-23 13:54:35 -0400189static void test_RuntimeEffect_Shaders(skiatest::Reporter* r, GrRecordingContext* rContext) {
Brian Osmanf72dedd2020-01-08 13:19:58 -0500190 SkImageInfo info = SkImageInfo::Make(2, 2, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
Robert Phillipse94b4e12020-07-23 13:54:35 -0400191 sk_sp<SkSurface> surface = rContext
192 ? SkSurface::MakeRenderTarget(rContext, SkBudgeted::kNo, info)
193 : SkSurface::MakeRaster(info);
Brian Osmanf72dedd2020-01-08 13:19:58 -0500194 REPORTER_ASSERT(r, surface);
Brian Osman62419612020-07-22 10:19:02 -0400195 TestEffect effect(r, surface);
Brian Osmanf72dedd2020-01-08 13:19:58 -0500196
Brian Osman504032e2020-01-10 10:05:24 -0500197 using float4 = std::array<float, 4>;
Brian Osmand18967c2021-04-01 09:56:07 -0400198 using int4 = std::array<int, 4>;
Brian Osman504032e2020-01-10 10:05:24 -0500199
Brian Osman62419612020-07-22 10:19:02 -0400200 // Local coords
Brian Osman33316412020-11-06 10:42:51 -0500201 effect.build("half4 main(float2 p) { return half4(half2(p - 0.5), 0, 1); }");
Brian Osman62419612020-07-22 10:19:02 -0400202 effect.test(0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF);
Brian Osmanf72dedd2020-01-08 13:19:58 -0500203
Brian Osman62419612020-07-22 10:19:02 -0400204 // Use of a simple uniform. (Draw twice with two values to ensure it's updated).
Brian Osman33316412020-11-06 10:42:51 -0500205 effect.build("uniform float4 gColor; half4 main() { return half4(gColor); }");
Brian Osmana4b91692020-08-10 14:26:16 -0400206 effect.uniform("gColor") = float4{ 0.0f, 0.25f, 0.75f, 1.0f };
Brian Osman62419612020-07-22 10:19:02 -0400207 effect.test(0xFFBF4000);
Brian Osmana4b91692020-08-10 14:26:16 -0400208 effect.uniform("gColor") = float4{ 1.0f, 0.0f, 0.0f, 0.498f };
Brian Osman62419612020-07-22 10:19:02 -0400209 effect.test(0x7F00007F); // Tests that we clamp to valid premul
Michael Ludwig5e6b3cd2020-05-27 17:02:37 -0400210
Brian Osmand18967c2021-04-01 09:56:07 -0400211 // Same, with integer uniforms
212 effect.build("uniform int4 gColor; half4 main() { return half4(gColor) / 255.0; }");
213 effect.uniform("gColor") = int4{ 0x00, 0x40, 0xBF, 0xFF };
214 effect.test(0xFFBF4000);
215 effect.uniform("gColor") = int4{ 0xFF, 0x00, 0x00, 0x7F };
216 effect.test(0x7F00007F); // Tests that we clamp to valid premul
217
Brian Osman62419612020-07-22 10:19:02 -0400218 // Test sk_FragCoord (device coords). Rotate the canvas to be sure we're seeing device coords.
219 // Since the surface is 2x2, we should see (0,0), (1,0), (0,1), (1,1). Multiply by 0.498 to
220 // make sure we're not saturating unexpectedly.
Brian Osman33316412020-11-06 10:42:51 -0500221 effect.build("half4 main() { return half4(0.498 * (half2(sk_FragCoord.xy) - 0.5), 0, 1); }");
Brian Osman62419612020-07-22 10:19:02 -0400222 effect.test(0xFF000000, 0xFF00007F, 0xFF007F00, 0xFF007F7F,
223 [](SkCanvas* canvas, SkPaint*) { canvas->rotate(45.0f); });
Michael Ludwig22534f22020-05-27 17:25:33 -0400224
Brian Osman0acb5b52020-09-02 13:45:47 -0400225 // Runtime effects should use relaxed precision rules by default
Brian Osman33316412020-11-06 10:42:51 -0500226 effect.build("half4 main(float2 p) { return float4(p - 0.5, 0, 1); }");
Brian Osman0acb5b52020-09-02 13:45:47 -0400227 effect.test(0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF);
228
Brian Osman33316412020-11-06 10:42:51 -0500229 // ... and support *returning* float4 (aka vec4), not just half4
230 effect.build("float4 main(float2 p) { return float4(p - 0.5, 0, 1); }");
231 effect.test(0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF);
232 effect.build("vec4 main(float2 p) { return float4(p - 0.5, 0, 1); }");
Brian Osmanf1319c32020-10-13 09:34:23 -0400233 effect.test(0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF);
234
Brian Osmanb4ce9442020-11-11 09:18:02 -0500235 // Mutating coords should work. (skbug.com/10918)
236 effect.build("vec4 main(vec2 p) { p -= 0.5; return vec4(p, 0, 1); }");
237 effect.test(0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF);
238 effect.build("void moveCoords(inout vec2 p) { p -= 0.5; }"
239 "vec4 main(vec2 p) { moveCoords(p); return vec4(p, 0, 1); }");
240 effect.test(0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF);
241
Brian Osmanb5f0f522020-07-23 13:28:14 -0400242 //
243 // Sampling children
244 //
245
Brian Osman62419612020-07-22 10:19:02 -0400246 // Sampling a null child should return the paint color
Brian Osman33316412020-11-06 10:42:51 -0500247 effect.build("uniform shader child;"
248 "half4 main() { return sample(child); }");
Brian Osman62419612020-07-22 10:19:02 -0400249 effect.child("child") = nullptr;
250 effect.test(0xFF00FFFF,
251 [](SkCanvas*, SkPaint* paint) { paint->setColor4f({1.0f, 1.0f, 0.0f, 1.0f}); });
252
253 sk_sp<SkShader> rgbwShader = make_RGBW_shader();
254
255 // Sampling a simple child at our coordinates (implicitly)
Brian Osman33316412020-11-06 10:42:51 -0500256 effect.build("uniform shader child;"
257 "half4 main() { return sample(child); }");
Brian Osman62419612020-07-22 10:19:02 -0400258 effect.child("child") = rgbwShader;
259 effect.test(0xFF0000FF, 0xFF00FF00, 0xFFFF0000, 0xFFFFFFFF);
260
261 // Sampling with explicit coordinates (reflecting about the diagonal)
Brian Osman33316412020-11-06 10:42:51 -0500262 effect.build("uniform shader child;"
263 "half4 main(float2 p) { return sample(child, p.yx); }");
Brian Osman62419612020-07-22 10:19:02 -0400264 effect.child("child") = rgbwShader;
265 effect.test(0xFF0000FF, 0xFFFF0000, 0xFF00FF00, 0xFFFFFFFF);
266
267 // Sampling with a matrix (again, reflecting about the diagonal)
Brian Osman33316412020-11-06 10:42:51 -0500268 effect.build("uniform shader child;"
269 "half4 main() { return sample(child, float3x3(0, 1, 0, 1, 0, 0, 0, 0, 1)); }");
Brian Osman62419612020-07-22 10:19:02 -0400270 effect.child("child") = rgbwShader;
271 effect.test(0xFF0000FF, 0xFFFF0000, 0xFF00FF00, 0xFFFFFFFF);
Brian Osmanb5f0f522020-07-23 13:28:14 -0400272
273 //
274 // Helper functions
275 //
276
277 // Test case for inlining in the pipeline-stage and fragment-shader passes (skbug.com/10526):
Brian Osman33316412020-11-06 10:42:51 -0500278 effect.build("float2 helper(float2 x) { return x + 1; }"
279 "half4 main(float2 p) { float2 v = helper(p); return half4(half2(v), 0, 1); }");
Brian Osmanb5f0f522020-07-23 13:28:14 -0400280 effect.test(0xFF00FFFF);
Brian Osmanf72dedd2020-01-08 13:19:58 -0500281}
282
283DEF_TEST(SkRuntimeEffectSimple, r) {
284 test_RuntimeEffect_Shaders(r, nullptr);
285}
286
287DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRuntimeEffectSimple_GPU, r, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400288 test_RuntimeEffect_Shaders(r, ctxInfo.directContext());
Brian Osmanf72dedd2020-01-08 13:19:58 -0500289}
Brian Osmanb6bd0d22020-08-27 10:51:22 -0400290
291DEF_TEST(SkRuntimeShaderBuilderReuse, r) {
292 const char* kSource = R"(
293 uniform half x;
294 half4 main() { return half4(x); }
295 )";
296
John Stiles1f19ce22021-02-11 17:40:03 -0500297 sk_sp<SkRuntimeEffect> effect = SkRuntimeEffect::Make(SkString(kSource)).effect;
Brian Osmanb6bd0d22020-08-27 10:51:22 -0400298 REPORTER_ASSERT(r, effect);
299
300 // Test passes if this sequence doesn't assert. skbug.com/10667
301 SkRuntimeShaderBuilder b(std::move(effect));
302 b.uniform("x") = 0.0f;
303 auto shader_0 = b.makeShader(nullptr, false);
304
305 b.uniform("x") = 1.0f;
306 auto shader_1 = b.makeShader(nullptr, true);
307}
Brian Osman8e2ef022020-09-30 13:26:43 -0400308
Derek Sollenberger9e1cedd2021-01-14 08:30:52 -0500309DEF_TEST(SkRuntimeShaderBuilderSetUniforms, r) {
310 const char* kSource = R"(
311 uniform half x;
312 uniform vec2 offset;
313 half4 main() { return half4(x); }
314 )";
315
John Stiles1f19ce22021-02-11 17:40:03 -0500316 sk_sp<SkRuntimeEffect> effect = SkRuntimeEffect::Make(SkString(kSource)).effect;
Derek Sollenberger9e1cedd2021-01-14 08:30:52 -0500317 REPORTER_ASSERT(r, effect);
318
319 SkRuntimeShaderBuilder b(std::move(effect));
320
321 // Test passes if this sequence doesn't assert.
322 float x = 1.0f;
323 REPORTER_ASSERT(r, b.uniform("x").set(&x, 1));
324
325 // add extra value to ensure that set doesn't try to use sizeof(array)
326 float origin[] = { 2.0f, 3.0f, 4.0f };
327 REPORTER_ASSERT(r, b.uniform("offset").set<float>(origin, 2));
328
329#ifndef SK_DEBUG
330 REPORTER_ASSERT(r, !b.uniform("offset").set<float>(origin, 1));
331 REPORTER_ASSERT(r, !b.uniform("offset").set<float>(origin, 3));
332#endif
333
334
335 auto shader = b.makeShader(nullptr, false);
336}
337
Brian Osman8e2ef022020-09-30 13:26:43 -0400338DEF_TEST(SkRuntimeEffectThreaded, r) {
339 // SkRuntimeEffect uses a single compiler instance, but it's mutex locked.
340 // This tests that we can safely use it from more than one thread, and also
341 // that programs don't refer to shared structures owned by the compiler.
342 // skbug.com/10589
343 static constexpr char kSource[] = "half4 main() { return sk_FragCoord.xyxy; }";
344
345 std::thread threads[16];
346 for (auto& thread : threads) {
347 thread = std::thread([r]() {
348 auto [effect, error] = SkRuntimeEffect::Make(SkString(kSource));
349 REPORTER_ASSERT(r, effect);
350 });
351 }
352
353 for (auto& thread : threads) {
354 thread.join();
355 }
356}
Mike Klein827f8c02021-02-06 09:13:01 -0600357
358DEF_TEST(SkRuntimeColorFilterSingleColor, r) {
359 // Test runtime colorfilters support filterColor4f().
360 auto [effect, err] = SkRuntimeEffect::Make(SkString{
361 "uniform shader input; half4 main() { half4 c = sample(input); return c*c; }"});
362 REPORTER_ASSERT(r, effect);
363 REPORTER_ASSERT(r, err.isEmpty());
364
365 sk_sp<SkColorFilter> input = nullptr;
366 sk_sp<SkColorFilter> cf = effect->makeColorFilter(SkData::MakeEmpty(), &input, 1);
367 REPORTER_ASSERT(r, cf);
368
369 SkColor4f c = cf->filterColor4f({0.25, 0.5, 0.75, 1.0},
370 sk_srgb_singleton(), sk_srgb_singleton());
371 REPORTER_ASSERT(r, c.fR == 0.0625f);
372 REPORTER_ASSERT(r, c.fG == 0.25f);
373 REPORTER_ASSERT(r, c.fB == 0.5625f);
374 REPORTER_ASSERT(r, c.fA == 1.0f);
375}
Brian Osman8e756f32021-02-10 10:19:27 -0500376
377static void test_RuntimeEffectStructNameReuse(skiatest::Reporter* r, GrRecordingContext* rContext) {
378 // Test that two different runtime effects can reuse struct names in a single paint operation
379 auto [childEffect, err] = SkRuntimeEffect::Make(SkString(
380 "uniform shader paint;"
381 "struct S { half4 rgba; };"
382 "void process(inout S s) { s.rgba.rgb *= 0.5; }"
383 "half4 main() { S s; s.rgba = sample(paint); process(s); return s.rgba; }"
384 ));
385 REPORTER_ASSERT(r, childEffect, "%s\n", err.c_str());
386 sk_sp<SkShader> nullChild = nullptr;
387 sk_sp<SkShader> child = childEffect->makeShader(/*uniforms=*/nullptr, &nullChild,
388 /*childCount=*/1, /*localMatrix=*/nullptr,
389 /*isOpaque=*/false);
390
391 SkImageInfo info = SkImageInfo::Make(2, 2, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
392 sk_sp<SkSurface> surface = rContext
393 ? SkSurface::MakeRenderTarget(rContext, SkBudgeted::kNo, info)
394 : SkSurface::MakeRaster(info);
395 REPORTER_ASSERT(r, surface);
396
397 TestEffect effect(r, surface);
398 effect.build(
399 "uniform shader child;"
400 "struct S { float2 coord; };"
401 "void process(inout S s) { s.coord = s.coord.yx; }"
402 "half4 main(float2 p) { S s; s.coord = p; process(s); return sample(child, s.coord); "
403 "}");
404 effect.child("child") = child;
405 effect.test(0xFF00407F, [](SkCanvas*, SkPaint* paint) {
406 paint->setColor4f({0.99608f, 0.50196f, 0.0f, 1.0f});
407 });
408}
409
410DEF_TEST(SkRuntimeStructNameReuse, r) {
411 test_RuntimeEffectStructNameReuse(r, nullptr);
412}
413
414DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRuntimeStructNameReuse_GPU, r, ctxInfo) {
415 test_RuntimeEffectStructNameReuse(r, ctxInfo.directContext());
416}
Mike Kleine0d9b862021-02-16 12:00:29 -0600417
418DEF_TEST(SkRuntimeColorFilterFlags, r) {
419 { // Here's a non-trivial filter that doesn't change alpha.
420 auto [effect, err] = SkRuntimeEffect::Make(SkString{
Brian Osmancdee1202021-04-14 09:36:49 -0400421 "half4 main(half4 color) { return color + half4(1,1,1,0); }"});
Mike Kleine0d9b862021-02-16 12:00:29 -0600422 REPORTER_ASSERT(r, effect && err.isEmpty());
Brian Osmancdee1202021-04-14 09:36:49 -0400423 sk_sp<SkColorFilter> filter = effect->makeColorFilter(SkData::MakeEmpty());
Mike Kleine0d9b862021-02-16 12:00:29 -0600424 REPORTER_ASSERT(r, filter && filter->isAlphaUnchanged());
425 }
426
427 { // Here's one that definitely changes alpha.
428 auto [effect, err] = SkRuntimeEffect::Make(SkString{
Brian Osmancdee1202021-04-14 09:36:49 -0400429 "half4 main(half4 color) { return color + half4(0,0,0,4); }"});
Mike Kleine0d9b862021-02-16 12:00:29 -0600430 REPORTER_ASSERT(r, effect && err.isEmpty());
Brian Osmancdee1202021-04-14 09:36:49 -0400431 sk_sp<SkColorFilter> filter = effect->makeColorFilter(SkData::MakeEmpty());
Mike Kleine0d9b862021-02-16 12:00:29 -0600432 REPORTER_ASSERT(r, filter && !filter->isAlphaUnchanged());
433 }
434}