1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2019 Google LLC 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h" 9cb93a386Sopenharmony_ci#include "include/core/SkBlender.h" 10cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 11cb93a386Sopenharmony_ci#include "include/core/SkColorFilter.h" 12cb93a386Sopenharmony_ci#include "include/core/SkData.h" 13cb93a386Sopenharmony_ci#include "include/core/SkPaint.h" 14cb93a386Sopenharmony_ci#include "include/core/SkSurface.h" 15cb93a386Sopenharmony_ci#include "include/effects/SkBlenders.h" 16cb93a386Sopenharmony_ci#include "include/effects/SkRuntimeEffect.h" 17cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h" 18cb93a386Sopenharmony_ci#include "src/core/SkColorSpacePriv.h" 19cb93a386Sopenharmony_ci#include "src/core/SkRuntimeEffectPriv.h" 20cb93a386Sopenharmony_ci#include "src/core/SkTLazy.h" 21cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h" 22cb93a386Sopenharmony_ci#include "src/gpu/GrColor.h" 23cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h" 24cb93a386Sopenharmony_ci#include "src/gpu/GrFragmentProcessor.h" 25cb93a386Sopenharmony_ci#include "src/gpu/GrImageInfo.h" 26cb93a386Sopenharmony_ci#include "src/gpu/SurfaceFillContext.h" 27cb93a386Sopenharmony_ci#include "src/gpu/effects/GrSkSLFP.h" 28cb93a386Sopenharmony_ci#include "tests/Test.h" 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ci#include <algorithm> 31cb93a386Sopenharmony_ci#include <thread> 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_civoid test_invalid_effect(skiatest::Reporter* r, const char* src, const char* expected) { 34cb93a386Sopenharmony_ci auto [effect, errorText] = SkRuntimeEffect::MakeForShader(SkString(src)); 35cb93a386Sopenharmony_ci REPORTER_ASSERT(r, !effect); 36cb93a386Sopenharmony_ci REPORTER_ASSERT(r, errorText.contains(expected), 37cb93a386Sopenharmony_ci "Expected error message to contain \"%s\". Actual message: \"%s\"", 38cb93a386Sopenharmony_ci expected, errorText.c_str()); 39cb93a386Sopenharmony_ci}; 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci#define EMPTY_MAIN "half4 main(float2 p) { return half4(0); }" 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_ciDEF_TEST(SkRuntimeEffectInvalid_LimitedUniformTypes, r) { 44cb93a386Sopenharmony_ci // Runtime SkSL supports a limited set of uniform types. No bool, for example: 45cb93a386Sopenharmony_ci test_invalid_effect(r, "uniform bool b;" EMPTY_MAIN, "uniform"); 46cb93a386Sopenharmony_ci} 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_ciDEF_TEST(SkRuntimeEffectInvalid_NoInVariables, r) { 49cb93a386Sopenharmony_ci // 'in' variables aren't allowed at all: 50cb93a386Sopenharmony_ci test_invalid_effect(r, "in bool b;" EMPTY_MAIN, "'in'"); 51cb93a386Sopenharmony_ci test_invalid_effect(r, "in float f;" EMPTY_MAIN, "'in'"); 52cb93a386Sopenharmony_ci test_invalid_effect(r, "in float2 v;" EMPTY_MAIN, "'in'"); 53cb93a386Sopenharmony_ci test_invalid_effect(r, "in half3x3 m;" EMPTY_MAIN, "'in'"); 54cb93a386Sopenharmony_ci} 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ciDEF_TEST(SkRuntimeEffectInvalid_UndefinedFunction, r) { 57cb93a386Sopenharmony_ci test_invalid_effect(r, "half4 missing(); half4 main(float2 p) { return missing(); }", 58cb93a386Sopenharmony_ci "function 'half4 missing()' is not defined"); 59cb93a386Sopenharmony_ci} 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_ciDEF_TEST(SkRuntimeEffectInvalid_UndefinedMain, r) { 62cb93a386Sopenharmony_ci // Shouldn't be possible to create an SkRuntimeEffect without "main" 63cb93a386Sopenharmony_ci test_invalid_effect(r, "", "main"); 64cb93a386Sopenharmony_ci} 65cb93a386Sopenharmony_ci 66cb93a386Sopenharmony_ciDEF_TEST(SkRuntimeEffectInvalid_SkCapsDisallowed, r) { 67cb93a386Sopenharmony_ci // sk_Caps is an internal system. It should not be visible to runtime effects 68cb93a386Sopenharmony_ci test_invalid_effect( 69cb93a386Sopenharmony_ci r, 70cb93a386Sopenharmony_ci "half4 main(float2 p) { return sk_Caps.integerSupport ? half4(1) : half4(0); }", 71cb93a386Sopenharmony_ci "unknown identifier 'sk_Caps'"); 72cb93a386Sopenharmony_ci} 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_ciDEF_TEST(SkRuntimeEffect_DeadCodeEliminationStackOverflow, r) { 75cb93a386Sopenharmony_ci // Verify that a deeply-nested loop does not cause stack overflow during SkVM dead-code 76cb93a386Sopenharmony_ci // elimination. 77cb93a386Sopenharmony_ci auto [effect, errorText] = SkRuntimeEffect::MakeForColorFilter(SkString(R"( 78cb93a386Sopenharmony_ci half4 main(half4 color) { 79cb93a386Sopenharmony_ci half value = color.r; 80cb93a386Sopenharmony_ci 81cb93a386Sopenharmony_ci for (int a=0; a<10; ++a) { // 10 82cb93a386Sopenharmony_ci for (int b=0; b<10; ++b) { // 100 83cb93a386Sopenharmony_ci for (int c=0; c<10; ++c) { // 1000 84cb93a386Sopenharmony_ci for (int d=0; d<10; ++d) { // 10000 85cb93a386Sopenharmony_ci ++value; 86cb93a386Sopenharmony_ci }}}} 87cb93a386Sopenharmony_ci 88cb93a386Sopenharmony_ci return value.xxxx; 89cb93a386Sopenharmony_ci } 90cb93a386Sopenharmony_ci )")); 91cb93a386Sopenharmony_ci REPORTER_ASSERT(r, effect, "%s", errorText.c_str()); 92cb93a386Sopenharmony_ci} 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ciDEF_TEST(SkRuntimeEffectCanDisableES2Restrictions, r) { 95cb93a386Sopenharmony_ci auto test_valid_es3 = [](skiatest::Reporter* r, const char* sksl) { 96cb93a386Sopenharmony_ci SkRuntimeEffect::Options opt = SkRuntimeEffectPriv::ES3Options(); 97cb93a386Sopenharmony_ci auto [effect, errorText] = SkRuntimeEffect::MakeForShader(SkString(sksl), opt); 98cb93a386Sopenharmony_ci REPORTER_ASSERT(r, effect, "%s", errorText.c_str()); 99cb93a386Sopenharmony_ci }; 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ci test_invalid_effect(r, "float f[2] = float[2](0, 1);" EMPTY_MAIN, "construction of array type"); 102cb93a386Sopenharmony_ci test_valid_es3 (r, "float f[2] = float[2](0, 1);" EMPTY_MAIN); 103cb93a386Sopenharmony_ci} 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_ciDEF_TEST(SkRuntimeEffectForColorFilter, r) { 106cb93a386Sopenharmony_ci // Tests that the color filter factory rejects or accepts certain SkSL constructs 107cb93a386Sopenharmony_ci auto test_valid = [r](const char* sksl) { 108cb93a386Sopenharmony_ci auto [effect, errorText] = SkRuntimeEffect::MakeForColorFilter(SkString(sksl)); 109cb93a386Sopenharmony_ci REPORTER_ASSERT(r, effect, "%s", errorText.c_str()); 110cb93a386Sopenharmony_ci }; 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ci auto test_invalid = [r](const char* sksl, const char* expected) { 113cb93a386Sopenharmony_ci auto [effect, errorText] = SkRuntimeEffect::MakeForColorFilter(SkString(sksl)); 114cb93a386Sopenharmony_ci REPORTER_ASSERT(r, !effect); 115cb93a386Sopenharmony_ci REPORTER_ASSERT(r, 116cb93a386Sopenharmony_ci errorText.contains(expected), 117cb93a386Sopenharmony_ci "Expected error message to contain \"%s\". Actual message: \"%s\"", 118cb93a386Sopenharmony_ci expected, 119cb93a386Sopenharmony_ci errorText.c_str()); 120cb93a386Sopenharmony_ci }; 121cb93a386Sopenharmony_ci 122cb93a386Sopenharmony_ci // Color filters must use the 'half4 main(half4)' signature. Either color can be float4/vec4 123cb93a386Sopenharmony_ci test_valid("half4 main(half4 c) { return c; }"); 124cb93a386Sopenharmony_ci test_valid("float4 main(half4 c) { return c; }"); 125cb93a386Sopenharmony_ci test_valid("half4 main(float4 c) { return c; }"); 126cb93a386Sopenharmony_ci test_valid("float4 main(float4 c) { return c; }"); 127cb93a386Sopenharmony_ci test_valid("vec4 main(half4 c) { return c; }"); 128cb93a386Sopenharmony_ci test_valid("half4 main(vec4 c) { return c; }"); 129cb93a386Sopenharmony_ci test_valid("vec4 main(vec4 c) { return c; }"); 130cb93a386Sopenharmony_ci 131cb93a386Sopenharmony_ci // Invalid return types 132cb93a386Sopenharmony_ci test_invalid("void main(half4 c) {}", "'main' must return"); 133cb93a386Sopenharmony_ci test_invalid("half3 main(half4 c) { return c.rgb; }", "'main' must return"); 134cb93a386Sopenharmony_ci 135cb93a386Sopenharmony_ci // Invalid argument types (some are valid as shaders, but not color filters) 136cb93a386Sopenharmony_ci test_invalid("half4 main() { return half4(1); }", "'main' parameter"); 137cb93a386Sopenharmony_ci test_invalid("half4 main(float2 p) { return half4(1); }", "'main' parameter"); 138cb93a386Sopenharmony_ci test_invalid("half4 main(float2 p, half4 c) { return c; }", "'main' parameter"); 139cb93a386Sopenharmony_ci 140cb93a386Sopenharmony_ci // sk_FragCoord should not be available 141cb93a386Sopenharmony_ci test_invalid("half4 main(half4 c) { return sk_FragCoord.xy01; }", "unknown identifier"); 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_ci // Sampling a child shader requires that we pass explicit coords 144cb93a386Sopenharmony_ci test_valid("uniform shader child;" 145cb93a386Sopenharmony_ci "half4 main(half4 c) { return child.eval(c.rg); }"); 146cb93a386Sopenharmony_ci 147cb93a386Sopenharmony_ci // Sampling a colorFilter requires a color 148cb93a386Sopenharmony_ci test_valid("uniform colorFilter child;" 149cb93a386Sopenharmony_ci "half4 main(half4 c) { return child.eval(c); }"); 150cb93a386Sopenharmony_ci 151cb93a386Sopenharmony_ci // Sampling a blender requires two colors 152cb93a386Sopenharmony_ci test_valid("uniform blender child;" 153cb93a386Sopenharmony_ci "half4 main(half4 c) { return child.eval(c, c); }"); 154cb93a386Sopenharmony_ci} 155cb93a386Sopenharmony_ci 156cb93a386Sopenharmony_ciDEF_TEST(SkRuntimeEffectForBlender, r) { 157cb93a386Sopenharmony_ci // Tests that the blender factory rejects or accepts certain SkSL constructs 158cb93a386Sopenharmony_ci auto test_valid = [r](const char* sksl) { 159cb93a386Sopenharmony_ci auto [effect, errorText] = SkRuntimeEffect::MakeForBlender(SkString(sksl)); 160cb93a386Sopenharmony_ci REPORTER_ASSERT(r, effect, "%s", errorText.c_str()); 161cb93a386Sopenharmony_ci }; 162cb93a386Sopenharmony_ci 163cb93a386Sopenharmony_ci auto test_invalid = [r](const char* sksl, const char* expected) { 164cb93a386Sopenharmony_ci auto [effect, errorText] = SkRuntimeEffect::MakeForBlender(SkString(sksl)); 165cb93a386Sopenharmony_ci REPORTER_ASSERT(r, !effect); 166cb93a386Sopenharmony_ci REPORTER_ASSERT(r, 167cb93a386Sopenharmony_ci errorText.contains(expected), 168cb93a386Sopenharmony_ci "Expected error message to contain \"%s\". Actual message: \"%s\"", 169cb93a386Sopenharmony_ci expected, 170cb93a386Sopenharmony_ci errorText.c_str()); 171cb93a386Sopenharmony_ci }; 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_ci // Blenders must use the 'half4 main(half4, half4)' signature. Any mixture of float4/vec4/half4 174cb93a386Sopenharmony_ci // is allowed. 175cb93a386Sopenharmony_ci test_valid("half4 main(half4 s, half4 d) { return s; }"); 176cb93a386Sopenharmony_ci test_valid("float4 main(float4 s, float4 d) { return d; }"); 177cb93a386Sopenharmony_ci test_valid("float4 main(half4 s, float4 d) { return s; }"); 178cb93a386Sopenharmony_ci test_valid("half4 main(float4 s, half4 d) { return d; }"); 179cb93a386Sopenharmony_ci test_valid("vec4 main(half4 s, half4 d) { return s; }"); 180cb93a386Sopenharmony_ci test_valid("half4 main(vec4 s, vec4 d) { return d; }"); 181cb93a386Sopenharmony_ci test_valid("vec4 main(vec4 s, vec4 d) { return s; }"); 182cb93a386Sopenharmony_ci 183cb93a386Sopenharmony_ci // Invalid return types 184cb93a386Sopenharmony_ci test_invalid("void main(half4 s, half4 d) {}", "'main' must return"); 185cb93a386Sopenharmony_ci test_invalid("half3 main(half4 s, half4 d) { return s.rgb; }", "'main' must return"); 186cb93a386Sopenharmony_ci 187cb93a386Sopenharmony_ci // Invalid argument types (some are valid as shaders/color filters) 188cb93a386Sopenharmony_ci test_invalid("half4 main() { return half4(1); }", "'main' parameter"); 189cb93a386Sopenharmony_ci test_invalid("half4 main(half4 c) { return c; }", "'main' parameter"); 190cb93a386Sopenharmony_ci test_invalid("half4 main(float2 p) { return half4(1); }", "'main' parameter"); 191cb93a386Sopenharmony_ci test_invalid("half4 main(float2 p, half4 c) { return c; }", "'main' parameter"); 192cb93a386Sopenharmony_ci test_invalid("half4 main(float2 p, half4 a, half4 b) { return a; }", "'main' parameter"); 193cb93a386Sopenharmony_ci test_invalid("half4 main(half4 a, half4 b, half4 c) { return a; }", "'main' parameter"); 194cb93a386Sopenharmony_ci 195cb93a386Sopenharmony_ci // sk_FragCoord should not be available 196cb93a386Sopenharmony_ci test_invalid("half4 main(half4 s, half4 d) { return sk_FragCoord.xy01; }", 197cb93a386Sopenharmony_ci "unknown identifier"); 198cb93a386Sopenharmony_ci 199cb93a386Sopenharmony_ci // Sampling a child shader requires that we pass explicit coords 200cb93a386Sopenharmony_ci test_valid("uniform shader child;" 201cb93a386Sopenharmony_ci "half4 main(half4 s, half4 d) { return child.eval(s.rg); }"); 202cb93a386Sopenharmony_ci 203cb93a386Sopenharmony_ci // Sampling a colorFilter requires a color 204cb93a386Sopenharmony_ci test_valid("uniform colorFilter child;" 205cb93a386Sopenharmony_ci "half4 main(half4 s, half4 d) { return child.eval(d); }"); 206cb93a386Sopenharmony_ci 207cb93a386Sopenharmony_ci // Sampling a blender requires two colors 208cb93a386Sopenharmony_ci test_valid("uniform blender child;" 209cb93a386Sopenharmony_ci "half4 main(half4 s, half4 d) { return child.eval(s, d); }"); 210cb93a386Sopenharmony_ci} 211cb93a386Sopenharmony_ci 212cb93a386Sopenharmony_ciDEF_TEST(SkRuntimeEffectForShader, r) { 213cb93a386Sopenharmony_ci // Tests that the shader factory rejects or accepts certain SkSL constructs 214cb93a386Sopenharmony_ci auto test_valid = [r](const char* sksl, SkRuntimeEffect::Options options = {}) { 215cb93a386Sopenharmony_ci auto [effect, errorText] = SkRuntimeEffect::MakeForShader(SkString(sksl), options); 216cb93a386Sopenharmony_ci REPORTER_ASSERT(r, effect, "%s", errorText.c_str()); 217cb93a386Sopenharmony_ci }; 218cb93a386Sopenharmony_ci 219cb93a386Sopenharmony_ci auto test_invalid = [r](const char* sksl, 220cb93a386Sopenharmony_ci const char* expected, 221cb93a386Sopenharmony_ci SkRuntimeEffect::Options options = {}) { 222cb93a386Sopenharmony_ci auto [effect, errorText] = SkRuntimeEffect::MakeForShader(SkString(sksl)); 223cb93a386Sopenharmony_ci REPORTER_ASSERT(r, !effect); 224cb93a386Sopenharmony_ci REPORTER_ASSERT(r, 225cb93a386Sopenharmony_ci errorText.contains(expected), 226cb93a386Sopenharmony_ci "Expected error message to contain \"%s\". Actual message: \"%s\"", 227cb93a386Sopenharmony_ci expected, 228cb93a386Sopenharmony_ci errorText.c_str()); 229cb93a386Sopenharmony_ci }; 230cb93a386Sopenharmony_ci 231cb93a386Sopenharmony_ci // Shaders must use either the 'half4 main(float2)' or 'half4 main(float2, half4)' signature 232cb93a386Sopenharmony_ci // Either color can be half4/float4/vec4, but the coords must be float2/vec2 233cb93a386Sopenharmony_ci test_valid("half4 main(float2 p) { return p.xyxy; }"); 234cb93a386Sopenharmony_ci test_valid("float4 main(float2 p) { return p.xyxy; }"); 235cb93a386Sopenharmony_ci test_valid("vec4 main(float2 p) { return p.xyxy; }"); 236cb93a386Sopenharmony_ci test_valid("half4 main(vec2 p) { return p.xyxy; }"); 237cb93a386Sopenharmony_ci test_valid("vec4 main(vec2 p) { return p.xyxy; }"); 238cb93a386Sopenharmony_ci test_valid("half4 main(float2 p, half4 c) { return c; }"); 239cb93a386Sopenharmony_ci test_valid("half4 main(float2 p, float4 c) { return c; }"); 240cb93a386Sopenharmony_ci test_valid("half4 main(float2 p, vec4 c) { return c; }"); 241cb93a386Sopenharmony_ci test_valid("float4 main(float2 p, half4 c) { return c; }"); 242cb93a386Sopenharmony_ci test_valid("vec4 main(float2 p, half4 c) { return c; }"); 243cb93a386Sopenharmony_ci test_valid("vec4 main(vec2 p, vec4 c) { return c; }"); 244cb93a386Sopenharmony_ci 245cb93a386Sopenharmony_ci // Invalid return types 246cb93a386Sopenharmony_ci test_invalid("void main(float2 p) {}", "'main' must return"); 247cb93a386Sopenharmony_ci test_invalid("half3 main(float2 p) { return p.xy1; }", "'main' must return"); 248cb93a386Sopenharmony_ci 249cb93a386Sopenharmony_ci // Invalid argument types (some are valid as color filters, but not shaders) 250cb93a386Sopenharmony_ci test_invalid("half4 main() { return half4(1); }", "'main' parameter"); 251cb93a386Sopenharmony_ci test_invalid("half4 main(half4 c) { return c; }", "'main' parameter"); 252cb93a386Sopenharmony_ci 253cb93a386Sopenharmony_ci // sk_FragCoord should be available, but only if we've enabled it via Options 254cb93a386Sopenharmony_ci test_invalid("half4 main(float2 p) { return sk_FragCoord.xy01; }", 255cb93a386Sopenharmony_ci "unknown identifier 'sk_FragCoord'"); 256cb93a386Sopenharmony_ci 257cb93a386Sopenharmony_ci SkRuntimeEffect::Options optionsWithFragCoord; 258cb93a386Sopenharmony_ci SkRuntimeEffectPriv::EnableFragCoord(&optionsWithFragCoord); 259cb93a386Sopenharmony_ci test_valid("half4 main(float2 p) { return sk_FragCoord.xy01; }", optionsWithFragCoord); 260cb93a386Sopenharmony_ci 261cb93a386Sopenharmony_ci // Sampling a child shader requires that we pass explicit coords 262cb93a386Sopenharmony_ci test_valid("uniform shader child;" 263cb93a386Sopenharmony_ci "half4 main(float2 p) { return child.eval(p); }"); 264cb93a386Sopenharmony_ci 265cb93a386Sopenharmony_ci // Sampling a colorFilter requires a color 266cb93a386Sopenharmony_ci test_valid("uniform colorFilter child;" 267cb93a386Sopenharmony_ci "half4 main(float2 p, half4 c) { return child.eval(c); }"); 268cb93a386Sopenharmony_ci 269cb93a386Sopenharmony_ci // Sampling a blender requires two colors 270cb93a386Sopenharmony_ci test_valid("uniform blender child;" 271cb93a386Sopenharmony_ci "half4 main(float2 p, half4 c) { return child.eval(c, c); }"); 272cb93a386Sopenharmony_ci} 273cb93a386Sopenharmony_ci 274cb93a386Sopenharmony_ciusing PreTestFn = std::function<void(SkCanvas*, SkPaint*)>; 275cb93a386Sopenharmony_ci 276cb93a386Sopenharmony_civoid paint_canvas(SkCanvas* canvas, SkPaint* paint, const PreTestFn& preTestCallback) { 277cb93a386Sopenharmony_ci canvas->save(); 278cb93a386Sopenharmony_ci if (preTestCallback) { 279cb93a386Sopenharmony_ci preTestCallback(canvas, paint); 280cb93a386Sopenharmony_ci } 281cb93a386Sopenharmony_ci canvas->drawPaint(*paint); 282cb93a386Sopenharmony_ci canvas->restore(); 283cb93a386Sopenharmony_ci} 284cb93a386Sopenharmony_ci 285cb93a386Sopenharmony_cistatic void verify_2x2_surface_results(skiatest::Reporter* r, 286cb93a386Sopenharmony_ci const SkRuntimeEffect* effect, 287cb93a386Sopenharmony_ci SkSurface* surface, 288cb93a386Sopenharmony_ci std::array<GrColor, 4> expected) { 289cb93a386Sopenharmony_ci std::array<GrColor, 4> actual; 290cb93a386Sopenharmony_ci SkImageInfo info = surface->imageInfo(); 291cb93a386Sopenharmony_ci if (!surface->readPixels(info, actual.data(), info.minRowBytes(), /*srcX=*/0, /*srcY=*/0)) { 292cb93a386Sopenharmony_ci REPORT_FAILURE(r, "readPixels", SkString("readPixels failed")); 293cb93a386Sopenharmony_ci return; 294cb93a386Sopenharmony_ci } 295cb93a386Sopenharmony_ci 296cb93a386Sopenharmony_ci if (actual != expected) { 297cb93a386Sopenharmony_ci REPORT_FAILURE(r, "Runtime effect didn't match expectations", 298cb93a386Sopenharmony_ci SkStringPrintf("\n" 299cb93a386Sopenharmony_ci "Expected: [ %08x %08x %08x %08x ]\n" 300cb93a386Sopenharmony_ci "Got : [ %08x %08x %08x %08x ]\n" 301cb93a386Sopenharmony_ci "SkSL:\n%s\n", 302cb93a386Sopenharmony_ci expected[0], expected[1], expected[2], expected[3], 303cb93a386Sopenharmony_ci actual[0], actual[1], actual[2], actual[3], 304cb93a386Sopenharmony_ci effect->source().c_str())); 305cb93a386Sopenharmony_ci } 306cb93a386Sopenharmony_ci} 307cb93a386Sopenharmony_ci 308cb93a386Sopenharmony_ciclass TestEffect { 309cb93a386Sopenharmony_cipublic: 310cb93a386Sopenharmony_ci TestEffect(skiatest::Reporter* r, sk_sp<SkSurface> surface) 311cb93a386Sopenharmony_ci : fReporter(r), fSurface(std::move(surface)) {} 312cb93a386Sopenharmony_ci 313cb93a386Sopenharmony_ci void build(const char* src) { 314cb93a386Sopenharmony_ci SkRuntimeEffect::Options options; 315cb93a386Sopenharmony_ci SkRuntimeEffectPriv::EnableFragCoord(&options); 316cb93a386Sopenharmony_ci auto [effect, errorText] = SkRuntimeEffect::MakeForShader(SkString(src), options); 317cb93a386Sopenharmony_ci if (!effect) { 318cb93a386Sopenharmony_ci REPORT_FAILURE(fReporter, "effect", 319cb93a386Sopenharmony_ci SkStringPrintf("Effect didn't compile: %s", errorText.c_str())); 320cb93a386Sopenharmony_ci return; 321cb93a386Sopenharmony_ci } 322cb93a386Sopenharmony_ci fBuilder.init(std::move(effect)); 323cb93a386Sopenharmony_ci } 324cb93a386Sopenharmony_ci 325cb93a386Sopenharmony_ci SkRuntimeShaderBuilder::BuilderUniform uniform(const char* name) { 326cb93a386Sopenharmony_ci return fBuilder->uniform(name); 327cb93a386Sopenharmony_ci } 328cb93a386Sopenharmony_ci 329cb93a386Sopenharmony_ci SkRuntimeShaderBuilder::BuilderChild child(const char* name) { 330cb93a386Sopenharmony_ci return fBuilder->child(name); 331cb93a386Sopenharmony_ci } 332cb93a386Sopenharmony_ci 333cb93a386Sopenharmony_ci void test(std::array<GrColor, 4> expected, PreTestFn preTestCallback = nullptr) { 334cb93a386Sopenharmony_ci auto shader = fBuilder->makeShader(/*localMatrix=*/nullptr, /*isOpaque=*/false); 335cb93a386Sopenharmony_ci if (!shader) { 336cb93a386Sopenharmony_ci REPORT_FAILURE(fReporter, "shader", SkString("Effect didn't produce a shader")); 337cb93a386Sopenharmony_ci return; 338cb93a386Sopenharmony_ci } 339cb93a386Sopenharmony_ci 340cb93a386Sopenharmony_ci SkCanvas* canvas = fSurface->getCanvas(); 341cb93a386Sopenharmony_ci SkPaint paint; 342cb93a386Sopenharmony_ci paint.setShader(std::move(shader)); 343cb93a386Sopenharmony_ci paint.setBlendMode(SkBlendMode::kSrc); 344cb93a386Sopenharmony_ci 345cb93a386Sopenharmony_ci paint_canvas(canvas, &paint, preTestCallback); 346cb93a386Sopenharmony_ci 347cb93a386Sopenharmony_ci verify_2x2_surface_results(fReporter, fBuilder->effect(), fSurface.get(), expected); 348cb93a386Sopenharmony_ci } 349cb93a386Sopenharmony_ci 350cb93a386Sopenharmony_ci void test(GrColor expected, PreTestFn preTestCallback = nullptr) { 351cb93a386Sopenharmony_ci this->test({expected, expected, expected, expected}, preTestCallback); 352cb93a386Sopenharmony_ci } 353cb93a386Sopenharmony_ci 354cb93a386Sopenharmony_ciprivate: 355cb93a386Sopenharmony_ci skiatest::Reporter* fReporter; 356cb93a386Sopenharmony_ci sk_sp<SkSurface> fSurface; 357cb93a386Sopenharmony_ci SkTLazy<SkRuntimeShaderBuilder> fBuilder; 358cb93a386Sopenharmony_ci}; 359cb93a386Sopenharmony_ci 360cb93a386Sopenharmony_ciclass TestBlend { 361cb93a386Sopenharmony_cipublic: 362cb93a386Sopenharmony_ci TestBlend(skiatest::Reporter* r, sk_sp<SkSurface> surface) 363cb93a386Sopenharmony_ci : fReporter(r), fSurface(std::move(surface)) {} 364cb93a386Sopenharmony_ci 365cb93a386Sopenharmony_ci void build(const char* src) { 366cb93a386Sopenharmony_ci auto [effect, errorText] = SkRuntimeEffect::MakeForBlender(SkString(src)); 367cb93a386Sopenharmony_ci if (!effect) { 368cb93a386Sopenharmony_ci REPORT_FAILURE(fReporter, "effect", 369cb93a386Sopenharmony_ci SkStringPrintf("Effect didn't compile: %s", errorText.c_str())); 370cb93a386Sopenharmony_ci return; 371cb93a386Sopenharmony_ci } 372cb93a386Sopenharmony_ci fBuilder.init(std::move(effect)); 373cb93a386Sopenharmony_ci } 374cb93a386Sopenharmony_ci 375cb93a386Sopenharmony_ci SkRuntimeBlendBuilder::BuilderUniform uniform(const char* name) { 376cb93a386Sopenharmony_ci return fBuilder->uniform(name); 377cb93a386Sopenharmony_ci } 378cb93a386Sopenharmony_ci 379cb93a386Sopenharmony_ci SkRuntimeBlendBuilder::BuilderChild child(const char* name) { 380cb93a386Sopenharmony_ci return fBuilder->child(name); 381cb93a386Sopenharmony_ci } 382cb93a386Sopenharmony_ci 383cb93a386Sopenharmony_ci void test(std::array<GrColor, 4> expected, PreTestFn preTestCallback = nullptr) { 384cb93a386Sopenharmony_ci auto blender = fBuilder->makeBlender(); 385cb93a386Sopenharmony_ci if (!blender) { 386cb93a386Sopenharmony_ci REPORT_FAILURE(fReporter, "blender", SkString("Effect didn't produce a blender")); 387cb93a386Sopenharmony_ci return; 388cb93a386Sopenharmony_ci } 389cb93a386Sopenharmony_ci 390cb93a386Sopenharmony_ci SkCanvas* canvas = fSurface->getCanvas(); 391cb93a386Sopenharmony_ci SkPaint paint; 392cb93a386Sopenharmony_ci paint.setBlender(std::move(blender)); 393cb93a386Sopenharmony_ci paint.setColor(SK_ColorGRAY); 394cb93a386Sopenharmony_ci 395cb93a386Sopenharmony_ci paint_canvas(canvas, &paint, preTestCallback); 396cb93a386Sopenharmony_ci 397cb93a386Sopenharmony_ci verify_2x2_surface_results(fReporter, fBuilder->effect(), fSurface.get(), expected); 398cb93a386Sopenharmony_ci } 399cb93a386Sopenharmony_ci 400cb93a386Sopenharmony_ci void test(GrColor expected, PreTestFn preTestCallback = nullptr) { 401cb93a386Sopenharmony_ci this->test({expected, expected, expected, expected}, preTestCallback); 402cb93a386Sopenharmony_ci } 403cb93a386Sopenharmony_ci 404cb93a386Sopenharmony_ciprivate: 405cb93a386Sopenharmony_ci skiatest::Reporter* fReporter; 406cb93a386Sopenharmony_ci sk_sp<SkSurface> fSurface; 407cb93a386Sopenharmony_ci SkTLazy<SkRuntimeBlendBuilder> fBuilder; 408cb93a386Sopenharmony_ci}; 409cb93a386Sopenharmony_ci 410cb93a386Sopenharmony_ci// Produces a 2x2 bitmap shader, with opaque colors: 411cb93a386Sopenharmony_ci// [ Red, Green ] 412cb93a386Sopenharmony_ci// [ Blue, White ] 413cb93a386Sopenharmony_cistatic sk_sp<SkShader> make_RGBW_shader() { 414cb93a386Sopenharmony_ci SkBitmap bmp; 415cb93a386Sopenharmony_ci bmp.allocPixels(SkImageInfo::Make(2, 2, kRGBA_8888_SkColorType, kPremul_SkAlphaType)); 416cb93a386Sopenharmony_ci SkIRect topLeft = SkIRect::MakeWH(1, 1); 417cb93a386Sopenharmony_ci bmp.pixmap().erase(SK_ColorRED, topLeft); 418cb93a386Sopenharmony_ci bmp.pixmap().erase(SK_ColorGREEN, topLeft.makeOffset(1, 0)); 419cb93a386Sopenharmony_ci bmp.pixmap().erase(SK_ColorBLUE, topLeft.makeOffset(0, 1)); 420cb93a386Sopenharmony_ci bmp.pixmap().erase(SK_ColorWHITE, topLeft.makeOffset(1, 1)); 421cb93a386Sopenharmony_ci return bmp.makeShader(SkSamplingOptions()); 422cb93a386Sopenharmony_ci} 423cb93a386Sopenharmony_ci 424cb93a386Sopenharmony_cistatic void test_RuntimeEffect_Shaders(skiatest::Reporter* r, GrRecordingContext* rContext) { 425cb93a386Sopenharmony_ci SkImageInfo info = SkImageInfo::Make(2, 2, kRGBA_8888_SkColorType, kPremul_SkAlphaType); 426cb93a386Sopenharmony_ci sk_sp<SkSurface> surface = rContext 427cb93a386Sopenharmony_ci ? SkSurface::MakeRenderTarget(rContext, SkBudgeted::kNo, info) 428cb93a386Sopenharmony_ci : SkSurface::MakeRaster(info); 429cb93a386Sopenharmony_ci REPORTER_ASSERT(r, surface); 430cb93a386Sopenharmony_ci TestEffect effect(r, surface); 431cb93a386Sopenharmony_ci 432cb93a386Sopenharmony_ci using float4 = std::array<float, 4>; 433cb93a386Sopenharmony_ci using int4 = std::array<int, 4>; 434cb93a386Sopenharmony_ci 435cb93a386Sopenharmony_ci // Local coords 436cb93a386Sopenharmony_ci effect.build("half4 main(float2 p) { return half4(half2(p - 0.5), 0, 1); }"); 437cb93a386Sopenharmony_ci effect.test({0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF}); 438cb93a386Sopenharmony_ci 439cb93a386Sopenharmony_ci // Use of a simple uniform. (Draw twice with two values to ensure it's updated). 440cb93a386Sopenharmony_ci effect.build("uniform float4 gColor; half4 main(float2 p) { return half4(gColor); }"); 441cb93a386Sopenharmony_ci effect.uniform("gColor") = float4{ 0.0f, 0.25f, 0.75f, 1.0f }; 442cb93a386Sopenharmony_ci effect.test(0xFFBF4000); 443cb93a386Sopenharmony_ci effect.uniform("gColor") = float4{ 1.0f, 0.0f, 0.0f, 0.498f }; 444cb93a386Sopenharmony_ci effect.test(0x7F0000FF); // Tests that we don't clamp to valid premul 445cb93a386Sopenharmony_ci 446cb93a386Sopenharmony_ci // Same, with integer uniforms 447cb93a386Sopenharmony_ci effect.build("uniform int4 gColor; half4 main(float2 p) { return half4(gColor) / 255.0; }"); 448cb93a386Sopenharmony_ci effect.uniform("gColor") = int4{ 0x00, 0x40, 0xBF, 0xFF }; 449cb93a386Sopenharmony_ci effect.test(0xFFBF4000); 450cb93a386Sopenharmony_ci effect.uniform("gColor") = int4{ 0xFF, 0x00, 0x00, 0x7F }; 451cb93a386Sopenharmony_ci effect.test(0x7F0000FF); // Tests that we don't clamp to valid premul 452cb93a386Sopenharmony_ci 453cb93a386Sopenharmony_ci // Test sk_FragCoord (device coords). Rotate the canvas to be sure we're seeing device coords. 454cb93a386Sopenharmony_ci // Since the surface is 2x2, we should see (0,0), (1,0), (0,1), (1,1). Multiply by 0.498 to 455cb93a386Sopenharmony_ci // make sure we're not saturating unexpectedly. 456cb93a386Sopenharmony_ci effect.build( 457cb93a386Sopenharmony_ci "half4 main(float2 p) { return half4(0.498 * (half2(sk_FragCoord.xy) - 0.5), 0, 1); }"); 458cb93a386Sopenharmony_ci effect.test({0xFF000000, 0xFF00007F, 0xFF007F00, 0xFF007F7F}, 459cb93a386Sopenharmony_ci [](SkCanvas* canvas, SkPaint*) { canvas->rotate(45.0f); }); 460cb93a386Sopenharmony_ci 461cb93a386Sopenharmony_ci // Runtime effects should use relaxed precision rules by default 462cb93a386Sopenharmony_ci effect.build("half4 main(float2 p) { return float4(p - 0.5, 0, 1); }"); 463cb93a386Sopenharmony_ci effect.test({0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF}); 464cb93a386Sopenharmony_ci 465cb93a386Sopenharmony_ci // ... and support *returning* float4 (aka vec4), not just half4 466cb93a386Sopenharmony_ci effect.build("float4 main(float2 p) { return float4(p - 0.5, 0, 1); }"); 467cb93a386Sopenharmony_ci effect.test({0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF}); 468cb93a386Sopenharmony_ci effect.build("vec4 main(float2 p) { return float4(p - 0.5, 0, 1); }"); 469cb93a386Sopenharmony_ci effect.test({0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF}); 470cb93a386Sopenharmony_ci 471cb93a386Sopenharmony_ci // Mutating coords should work. (skbug.com/10918) 472cb93a386Sopenharmony_ci effect.build("vec4 main(vec2 p) { p -= 0.5; return vec4(p, 0, 1); }"); 473cb93a386Sopenharmony_ci effect.test({0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF}); 474cb93a386Sopenharmony_ci effect.build("void moveCoords(inout vec2 p) { p -= 0.5; }" 475cb93a386Sopenharmony_ci "vec4 main(vec2 p) { moveCoords(p); return vec4(p, 0, 1); }"); 476cb93a386Sopenharmony_ci effect.test({0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF}); 477cb93a386Sopenharmony_ci 478cb93a386Sopenharmony_ci // 479cb93a386Sopenharmony_ci // Sampling children 480cb93a386Sopenharmony_ci // 481cb93a386Sopenharmony_ci 482cb93a386Sopenharmony_ci // Sampling a null child should return the paint color 483cb93a386Sopenharmony_ci effect.build("uniform shader child;" 484cb93a386Sopenharmony_ci "half4 main(float2 p) { return child.eval(p); }"); 485cb93a386Sopenharmony_ci effect.child("child") = nullptr; 486cb93a386Sopenharmony_ci effect.test(0xFF00FFFF, 487cb93a386Sopenharmony_ci [](SkCanvas*, SkPaint* paint) { paint->setColor4f({1.0f, 1.0f, 0.0f, 1.0f}); }); 488cb93a386Sopenharmony_ci 489cb93a386Sopenharmony_ci sk_sp<SkShader> rgbwShader = make_RGBW_shader(); 490cb93a386Sopenharmony_ci 491cb93a386Sopenharmony_ci // Sampling a simple child at our coordinates 492cb93a386Sopenharmony_ci effect.build("uniform shader child;" 493cb93a386Sopenharmony_ci "half4 main(float2 p) { return child.eval(p); }"); 494cb93a386Sopenharmony_ci effect.child("child") = rgbwShader; 495cb93a386Sopenharmony_ci effect.test({0xFF0000FF, 0xFF00FF00, 0xFFFF0000, 0xFFFFFFFF}); 496cb93a386Sopenharmony_ci 497cb93a386Sopenharmony_ci // Sampling with explicit coordinates (reflecting about the diagonal) 498cb93a386Sopenharmony_ci effect.build("uniform shader child;" 499cb93a386Sopenharmony_ci "half4 main(float2 p) { return child.eval(p.yx); }"); 500cb93a386Sopenharmony_ci effect.child("child") = rgbwShader; 501cb93a386Sopenharmony_ci effect.test({0xFF0000FF, 0xFFFF0000, 0xFF00FF00, 0xFFFFFFFF}); 502cb93a386Sopenharmony_ci 503cb93a386Sopenharmony_ci // Bind an image shader, but don't use it - ensure that we don't assert or generate bad shaders. 504cb93a386Sopenharmony_ci // (skbug.com/12429) 505cb93a386Sopenharmony_ci effect.build("uniform shader child;" 506cb93a386Sopenharmony_ci "half4 main(float2 p) { return half4(0, 1, 0, 1); }"); 507cb93a386Sopenharmony_ci effect.child("child") = rgbwShader; 508cb93a386Sopenharmony_ci effect.test(0xFF00FF00); 509cb93a386Sopenharmony_ci 510cb93a386Sopenharmony_ci // 511cb93a386Sopenharmony_ci // Helper functions 512cb93a386Sopenharmony_ci // 513cb93a386Sopenharmony_ci 514cb93a386Sopenharmony_ci // Test case for inlining in the pipeline-stage and fragment-shader passes (skbug.com/10526): 515cb93a386Sopenharmony_ci effect.build("float2 helper(float2 x) { return x + 1; }" 516cb93a386Sopenharmony_ci "half4 main(float2 p) { float2 v = helper(p); return half4(half2(v), 0, 1); }"); 517cb93a386Sopenharmony_ci effect.test(0xFF00FFFF); 518cb93a386Sopenharmony_ci} 519cb93a386Sopenharmony_ci 520cb93a386Sopenharmony_ciDEF_TEST(SkRuntimeEffectSimple, r) { 521cb93a386Sopenharmony_ci test_RuntimeEffect_Shaders(r, nullptr); 522cb93a386Sopenharmony_ci} 523cb93a386Sopenharmony_ci 524cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRuntimeEffectSimple_GPU, r, ctxInfo) { 525cb93a386Sopenharmony_ci test_RuntimeEffect_Shaders(r, ctxInfo.directContext()); 526cb93a386Sopenharmony_ci} 527cb93a386Sopenharmony_ci 528cb93a386Sopenharmony_cistatic void test_RuntimeEffect_Blenders(skiatest::Reporter* r, GrRecordingContext* rContext) { 529cb93a386Sopenharmony_ci SkImageInfo info = SkImageInfo::Make(2, 2, kRGBA_8888_SkColorType, kPremul_SkAlphaType); 530cb93a386Sopenharmony_ci sk_sp<SkSurface> surface = rContext 531cb93a386Sopenharmony_ci ? SkSurface::MakeRenderTarget(rContext, SkBudgeted::kNo, info) 532cb93a386Sopenharmony_ci : SkSurface::MakeRaster(info); 533cb93a386Sopenharmony_ci REPORTER_ASSERT(r, surface); 534cb93a386Sopenharmony_ci TestBlend effect(r, surface); 535cb93a386Sopenharmony_ci 536cb93a386Sopenharmony_ci using float2 = std::array<float, 2>; 537cb93a386Sopenharmony_ci using float4 = std::array<float, 4>; 538cb93a386Sopenharmony_ci using int4 = std::array<int, 4>; 539cb93a386Sopenharmony_ci 540cb93a386Sopenharmony_ci // Use of a simple uniform. (Draw twice with two values to ensure it's updated). 541cb93a386Sopenharmony_ci effect.build("uniform float4 gColor; half4 main(half4 s, half4 d) { return half4(gColor); }"); 542cb93a386Sopenharmony_ci effect.uniform("gColor") = float4{ 0.0f, 0.25f, 0.75f, 1.0f }; 543cb93a386Sopenharmony_ci effect.test(0xFFBF4000); 544cb93a386Sopenharmony_ci effect.uniform("gColor") = float4{ 1.0f, 0.0f, 0.0f, 0.498f }; 545cb93a386Sopenharmony_ci effect.test(0x7F0000FF); // We don't clamp here either 546cb93a386Sopenharmony_ci 547cb93a386Sopenharmony_ci // Same, with integer uniforms 548cb93a386Sopenharmony_ci effect.build("uniform int4 gColor;" 549cb93a386Sopenharmony_ci "half4 main(half4 s, half4 d) { return half4(gColor) / 255.0; }"); 550cb93a386Sopenharmony_ci effect.uniform("gColor") = int4{ 0x00, 0x40, 0xBF, 0xFF }; 551cb93a386Sopenharmony_ci effect.test(0xFFBF4000); 552cb93a386Sopenharmony_ci effect.uniform("gColor") = int4{ 0xFF, 0x00, 0x00, 0x7F }; 553cb93a386Sopenharmony_ci effect.test(0x7F0000FF); // We don't clamp here either 554cb93a386Sopenharmony_ci 555cb93a386Sopenharmony_ci // Verify that mutating the source and destination colors is allowed 556cb93a386Sopenharmony_ci effect.build("half4 main(half4 s, half4 d) { s += d; d += s; return half4(1); }"); 557cb93a386Sopenharmony_ci effect.test(0xFFFFFFFF); 558cb93a386Sopenharmony_ci 559cb93a386Sopenharmony_ci // Verify that we can write out the source color (ignoring the dest color) 560cb93a386Sopenharmony_ci // This is equivalent to the kSrc blend mode. 561cb93a386Sopenharmony_ci effect.build("half4 main(half4 s, half4 d) { return s; }"); 562cb93a386Sopenharmony_ci effect.test(0xFF888888); 563cb93a386Sopenharmony_ci 564cb93a386Sopenharmony_ci // Fill the destination with a variety of colors (using the RGBW shader) 565cb93a386Sopenharmony_ci SkPaint rgbwPaint; 566cb93a386Sopenharmony_ci rgbwPaint.setShader(make_RGBW_shader()); 567cb93a386Sopenharmony_ci rgbwPaint.setBlendMode(SkBlendMode::kSrc); 568cb93a386Sopenharmony_ci surface->getCanvas()->drawPaint(rgbwPaint); 569cb93a386Sopenharmony_ci 570cb93a386Sopenharmony_ci // Verify that we can read back the dest color exactly as-is (ignoring the source color) 571cb93a386Sopenharmony_ci // This is equivalent to the kDst blend mode. 572cb93a386Sopenharmony_ci effect.build("half4 main(half4 s, half4 d) { return d; }"); 573cb93a386Sopenharmony_ci effect.test({0xFF0000FF, 0xFF00FF00, 0xFFFF0000, 0xFFFFFFFF}); 574cb93a386Sopenharmony_ci 575cb93a386Sopenharmony_ci // Verify that we can invert the destination color (including the alpha channel). 576cb93a386Sopenharmony_ci // The expected outputs are the exact inverse of the previous test. 577cb93a386Sopenharmony_ci effect.build("half4 main(half4 s, half4 d) { return half4(1) - d; }"); 578cb93a386Sopenharmony_ci effect.test({0x00FFFF00, 0x00FF00FF, 0x0000FFFF, 0x00000000}); 579cb93a386Sopenharmony_ci 580cb93a386Sopenharmony_ci // Verify that color values are clamped to 0 and 1. 581cb93a386Sopenharmony_ci effect.build("half4 main(half4 s, half4 d) { return half4(-1); }"); 582cb93a386Sopenharmony_ci effect.test(0x00000000); 583cb93a386Sopenharmony_ci effect.build("half4 main(half4 s, half4 d) { return half4(2); }"); 584cb93a386Sopenharmony_ci effect.test(0xFFFFFFFF); 585cb93a386Sopenharmony_ci 586cb93a386Sopenharmony_ci // 587cb93a386Sopenharmony_ci // Sampling children 588cb93a386Sopenharmony_ci // 589cb93a386Sopenharmony_ci 590cb93a386Sopenharmony_ci // Sampling a null shader/color filter should return the paint color. 591cb93a386Sopenharmony_ci effect.build("uniform shader child;" 592cb93a386Sopenharmony_ci "half4 main(half4 s, half4 d) { return child.eval(s.rg); }"); 593cb93a386Sopenharmony_ci effect.child("child") = nullptr; 594cb93a386Sopenharmony_ci effect.test(0xFF00FFFF, 595cb93a386Sopenharmony_ci [](SkCanvas*, SkPaint* paint) { paint->setColor4f({1.0f, 1.0f, 0.0f, 1.0f}); }); 596cb93a386Sopenharmony_ci 597cb93a386Sopenharmony_ci effect.build("uniform colorFilter child;" 598cb93a386Sopenharmony_ci "half4 main(half4 s, half4 d) { return child.eval(s); }"); 599cb93a386Sopenharmony_ci effect.child("child") = nullptr; 600cb93a386Sopenharmony_ci effect.test(0xFF00FFFF, 601cb93a386Sopenharmony_ci [](SkCanvas*, SkPaint* paint) { paint->setColor4f({1.0f, 1.0f, 0.0f, 1.0f}); }); 602cb93a386Sopenharmony_ci 603cb93a386Sopenharmony_ci // Sampling a null blender should do a src-over blend. Draw 50% black over RGBW to verify this. 604cb93a386Sopenharmony_ci surface->getCanvas()->drawPaint(rgbwPaint); 605cb93a386Sopenharmony_ci effect.build("uniform blender child;" 606cb93a386Sopenharmony_ci "half4 main(half4 s, half4 d) { return child.eval(s, d); }"); 607cb93a386Sopenharmony_ci effect.child("child") = nullptr; 608cb93a386Sopenharmony_ci effect.test({0xFF000080, 0xFF008000, 0xFF800000, 0xFF808080}, 609cb93a386Sopenharmony_ci [](SkCanvas*, SkPaint* paint) { paint->setColor4f({0.0f, 0.0f, 0.0f, 0.497f}); }); 610cb93a386Sopenharmony_ci 611cb93a386Sopenharmony_ci // Sampling a shader at various coordinates 612cb93a386Sopenharmony_ci effect.build("uniform shader child;" 613cb93a386Sopenharmony_ci "uniform half2 pos;" 614cb93a386Sopenharmony_ci "half4 main(half4 s, half4 d) { return child.eval(pos); }"); 615cb93a386Sopenharmony_ci effect.child("child") = make_RGBW_shader(); 616cb93a386Sopenharmony_ci effect.uniform("pos") = float2{0, 0}; 617cb93a386Sopenharmony_ci effect.test(0xFF0000FF); 618cb93a386Sopenharmony_ci 619cb93a386Sopenharmony_ci effect.uniform("pos") = float2{1, 0}; 620cb93a386Sopenharmony_ci effect.test(0xFF00FF00); 621cb93a386Sopenharmony_ci 622cb93a386Sopenharmony_ci effect.uniform("pos") = float2{0, 1}; 623cb93a386Sopenharmony_ci effect.test(0xFFFF0000); 624cb93a386Sopenharmony_ci 625cb93a386Sopenharmony_ci effect.uniform("pos") = float2{1, 1}; 626cb93a386Sopenharmony_ci effect.test(0xFFFFFFFF); 627cb93a386Sopenharmony_ci 628cb93a386Sopenharmony_ci // Sampling a color filter 629cb93a386Sopenharmony_ci effect.build("uniform colorFilter child;" 630cb93a386Sopenharmony_ci "half4 main(half4 s, half4 d) { return child.eval(half4(1)); }"); 631cb93a386Sopenharmony_ci effect.child("child") = SkColorFilters::Blend(0xFF012345, SkBlendMode::kSrc); 632cb93a386Sopenharmony_ci effect.test(0xFF452301); 633cb93a386Sopenharmony_ci 634cb93a386Sopenharmony_ci // Sampling a built-in blender 635cb93a386Sopenharmony_ci surface->getCanvas()->drawPaint(rgbwPaint); 636cb93a386Sopenharmony_ci effect.build("uniform blender child;" 637cb93a386Sopenharmony_ci "half4 main(half4 s, half4 d) { return child.eval(s, d); }"); 638cb93a386Sopenharmony_ci effect.child("child") = SkBlender::Mode(SkBlendMode::kPlus); 639cb93a386Sopenharmony_ci effect.test({0xFF4523FF, 0xFF45FF01, 0xFFFF2301, 0xFFFFFFFF}, 640cb93a386Sopenharmony_ci [](SkCanvas*, SkPaint* paint) { paint->setColor(0xFF012345); }); 641cb93a386Sopenharmony_ci 642cb93a386Sopenharmony_ci // Sampling a runtime-effect blender 643cb93a386Sopenharmony_ci surface->getCanvas()->drawPaint(rgbwPaint); 644cb93a386Sopenharmony_ci effect.build("uniform blender child;" 645cb93a386Sopenharmony_ci "half4 main(half4 s, half4 d) { return child.eval(s, d); }"); 646cb93a386Sopenharmony_ci effect.child("child") = SkBlenders::Arithmetic(0, 1, 1, 0, /*enforcePremul=*/false); 647cb93a386Sopenharmony_ci effect.test({0xFF4523FF, 0xFF45FF01, 0xFFFF2301, 0xFFFFFFFF}, 648cb93a386Sopenharmony_ci [](SkCanvas*, SkPaint* paint) { paint->setColor(0xFF012345); }); 649cb93a386Sopenharmony_ci} 650cb93a386Sopenharmony_ci 651cb93a386Sopenharmony_ciDEF_TEST(SkRuntimeEffect_Blender_CPU, r) { 652cb93a386Sopenharmony_ci test_RuntimeEffect_Blenders(r, /*rContext=*/nullptr); 653cb93a386Sopenharmony_ci} 654cb93a386Sopenharmony_ci 655cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRuntimeEffect_Blender_GPU, r, ctxInfo) { 656cb93a386Sopenharmony_ci test_RuntimeEffect_Blenders(r, ctxInfo.directContext()); 657cb93a386Sopenharmony_ci} 658cb93a386Sopenharmony_ci 659cb93a386Sopenharmony_ciDEF_TEST(SkRuntimeShaderBuilderReuse, r) { 660cb93a386Sopenharmony_ci const char* kSource = R"( 661cb93a386Sopenharmony_ci uniform half x; 662cb93a386Sopenharmony_ci half4 main(float2 p) { return half4(x); } 663cb93a386Sopenharmony_ci )"; 664cb93a386Sopenharmony_ci 665cb93a386Sopenharmony_ci sk_sp<SkRuntimeEffect> effect = SkRuntimeEffect::MakeForShader(SkString(kSource)).effect; 666cb93a386Sopenharmony_ci REPORTER_ASSERT(r, effect); 667cb93a386Sopenharmony_ci 668cb93a386Sopenharmony_ci // Test passes if this sequence doesn't assert. skbug.com/10667 669cb93a386Sopenharmony_ci SkRuntimeShaderBuilder b(std::move(effect)); 670cb93a386Sopenharmony_ci b.uniform("x") = 0.0f; 671cb93a386Sopenharmony_ci auto shader_0 = b.makeShader(/*localMatrix=*/nullptr, /*isOpaque=*/false); 672cb93a386Sopenharmony_ci 673cb93a386Sopenharmony_ci b.uniform("x") = 1.0f; 674cb93a386Sopenharmony_ci auto shader_1 = b.makeShader(/*localMatrix=*/nullptr, /*isOpaque=*/true); 675cb93a386Sopenharmony_ci} 676cb93a386Sopenharmony_ci 677cb93a386Sopenharmony_ciDEF_TEST(SkRuntimeBlendBuilderReuse, r) { 678cb93a386Sopenharmony_ci const char* kSource = R"( 679cb93a386Sopenharmony_ci uniform half x; 680cb93a386Sopenharmony_ci half4 main(half4 s, half4 d) { return half4(x); } 681cb93a386Sopenharmony_ci )"; 682cb93a386Sopenharmony_ci 683cb93a386Sopenharmony_ci sk_sp<SkRuntimeEffect> effect = SkRuntimeEffect::MakeForBlender(SkString(kSource)).effect; 684cb93a386Sopenharmony_ci REPORTER_ASSERT(r, effect); 685cb93a386Sopenharmony_ci 686cb93a386Sopenharmony_ci // We should be able to construct multiple SkBlenders in a row without asserting. 687cb93a386Sopenharmony_ci SkRuntimeBlendBuilder b(std::move(effect)); 688cb93a386Sopenharmony_ci for (float x = 0.0f; x <= 2.0f; x += 2.0f) { 689cb93a386Sopenharmony_ci b.uniform("x") = x; 690cb93a386Sopenharmony_ci sk_sp<SkBlender> blender = b.makeBlender(); 691cb93a386Sopenharmony_ci } 692cb93a386Sopenharmony_ci} 693cb93a386Sopenharmony_ci 694cb93a386Sopenharmony_ciDEF_TEST(SkRuntimeShaderBuilderSetUniforms, r) { 695cb93a386Sopenharmony_ci const char* kSource = R"( 696cb93a386Sopenharmony_ci uniform half x; 697cb93a386Sopenharmony_ci uniform vec2 offset; 698cb93a386Sopenharmony_ci half4 main(float2 p) { return half4(x); } 699cb93a386Sopenharmony_ci )"; 700cb93a386Sopenharmony_ci 701cb93a386Sopenharmony_ci sk_sp<SkRuntimeEffect> effect = SkRuntimeEffect::MakeForShader(SkString(kSource)).effect; 702cb93a386Sopenharmony_ci REPORTER_ASSERT(r, effect); 703cb93a386Sopenharmony_ci 704cb93a386Sopenharmony_ci SkRuntimeShaderBuilder b(std::move(effect)); 705cb93a386Sopenharmony_ci 706cb93a386Sopenharmony_ci // Test passes if this sequence doesn't assert. 707cb93a386Sopenharmony_ci float x = 1.0f; 708cb93a386Sopenharmony_ci REPORTER_ASSERT(r, b.uniform("x").set(&x, 1)); 709cb93a386Sopenharmony_ci 710cb93a386Sopenharmony_ci // add extra value to ensure that set doesn't try to use sizeof(array) 711cb93a386Sopenharmony_ci float origin[] = { 2.0f, 3.0f, 4.0f }; 712cb93a386Sopenharmony_ci REPORTER_ASSERT(r, b.uniform("offset").set<float>(origin, 2)); 713cb93a386Sopenharmony_ci 714cb93a386Sopenharmony_ci#ifndef SK_DEBUG 715cb93a386Sopenharmony_ci REPORTER_ASSERT(r, !b.uniform("offset").set<float>(origin, 1)); 716cb93a386Sopenharmony_ci REPORTER_ASSERT(r, !b.uniform("offset").set<float>(origin, 3)); 717cb93a386Sopenharmony_ci#endif 718cb93a386Sopenharmony_ci 719cb93a386Sopenharmony_ci auto shader = b.makeShader(/*localMatrix=*/nullptr, /*isOpaque=*/false); 720cb93a386Sopenharmony_ci} 721cb93a386Sopenharmony_ci 722cb93a386Sopenharmony_ciDEF_TEST(SkRuntimeEffectThreaded, r) { 723cb93a386Sopenharmony_ci // SkRuntimeEffect uses a single compiler instance, but it's mutex locked. 724cb93a386Sopenharmony_ci // This tests that we can safely use it from more than one thread, and also 725cb93a386Sopenharmony_ci // that programs don't refer to shared structures owned by the compiler. 726cb93a386Sopenharmony_ci // skbug.com/10589 727cb93a386Sopenharmony_ci static constexpr char kSource[] = "half4 main(float2 p) { return sk_FragCoord.xyxy; }"; 728cb93a386Sopenharmony_ci 729cb93a386Sopenharmony_ci std::thread threads[16]; 730cb93a386Sopenharmony_ci for (auto& thread : threads) { 731cb93a386Sopenharmony_ci thread = std::thread([r]() { 732cb93a386Sopenharmony_ci SkRuntimeEffect::Options options; 733cb93a386Sopenharmony_ci SkRuntimeEffectPriv::EnableFragCoord(&options); 734cb93a386Sopenharmony_ci auto [effect, error] = SkRuntimeEffect::MakeForShader(SkString(kSource), options); 735cb93a386Sopenharmony_ci REPORTER_ASSERT(r, effect); 736cb93a386Sopenharmony_ci }); 737cb93a386Sopenharmony_ci } 738cb93a386Sopenharmony_ci 739cb93a386Sopenharmony_ci for (auto& thread : threads) { 740cb93a386Sopenharmony_ci thread.join(); 741cb93a386Sopenharmony_ci } 742cb93a386Sopenharmony_ci} 743cb93a386Sopenharmony_ci 744cb93a386Sopenharmony_ciDEF_TEST(SkRuntimeColorFilterSingleColor, r) { 745cb93a386Sopenharmony_ci // Test runtime colorfilters support filterColor4f(). 746cb93a386Sopenharmony_ci auto [effect, err] = 747cb93a386Sopenharmony_ci SkRuntimeEffect::MakeForColorFilter(SkString{"half4 main(half4 c) { return c*c; }"}); 748cb93a386Sopenharmony_ci REPORTER_ASSERT(r, effect); 749cb93a386Sopenharmony_ci REPORTER_ASSERT(r, err.isEmpty()); 750cb93a386Sopenharmony_ci 751cb93a386Sopenharmony_ci sk_sp<SkColorFilter> cf = effect->makeColorFilter(SkData::MakeEmpty()); 752cb93a386Sopenharmony_ci REPORTER_ASSERT(r, cf); 753cb93a386Sopenharmony_ci 754cb93a386Sopenharmony_ci SkColor4f c = cf->filterColor4f({0.25, 0.5, 0.75, 1.0}, 755cb93a386Sopenharmony_ci sk_srgb_singleton(), sk_srgb_singleton()); 756cb93a386Sopenharmony_ci REPORTER_ASSERT(r, c.fR == 0.0625f); 757cb93a386Sopenharmony_ci REPORTER_ASSERT(r, c.fG == 0.25f); 758cb93a386Sopenharmony_ci REPORTER_ASSERT(r, c.fB == 0.5625f); 759cb93a386Sopenharmony_ci REPORTER_ASSERT(r, c.fA == 1.0f); 760cb93a386Sopenharmony_ci} 761cb93a386Sopenharmony_ci 762cb93a386Sopenharmony_cistatic void test_RuntimeEffectStructNameReuse(skiatest::Reporter* r, GrRecordingContext* rContext) { 763cb93a386Sopenharmony_ci // Test that two different runtime effects can reuse struct names in a single paint operation 764cb93a386Sopenharmony_ci auto [childEffect, err] = SkRuntimeEffect::MakeForShader(SkString( 765cb93a386Sopenharmony_ci "uniform shader paint;" 766cb93a386Sopenharmony_ci "struct S { half4 rgba; };" 767cb93a386Sopenharmony_ci "void process(inout S s) { s.rgba.rgb *= 0.5; }" 768cb93a386Sopenharmony_ci "half4 main(float2 p) { S s; s.rgba = paint.eval(p); process(s); return s.rgba; }" 769cb93a386Sopenharmony_ci )); 770cb93a386Sopenharmony_ci REPORTER_ASSERT(r, childEffect, "%s\n", err.c_str()); 771cb93a386Sopenharmony_ci sk_sp<SkShader> nullChild = nullptr; 772cb93a386Sopenharmony_ci sk_sp<SkShader> child = childEffect->makeShader(/*uniforms=*/nullptr, &nullChild, 773cb93a386Sopenharmony_ci /*childCount=*/1, /*localMatrix=*/nullptr, 774cb93a386Sopenharmony_ci /*isOpaque=*/false); 775cb93a386Sopenharmony_ci 776cb93a386Sopenharmony_ci SkImageInfo info = SkImageInfo::Make(2, 2, kRGBA_8888_SkColorType, kPremul_SkAlphaType); 777cb93a386Sopenharmony_ci sk_sp<SkSurface> surface = rContext 778cb93a386Sopenharmony_ci ? SkSurface::MakeRenderTarget(rContext, SkBudgeted::kNo, info) 779cb93a386Sopenharmony_ci : SkSurface::MakeRaster(info); 780cb93a386Sopenharmony_ci REPORTER_ASSERT(r, surface); 781cb93a386Sopenharmony_ci 782cb93a386Sopenharmony_ci TestEffect effect(r, surface); 783cb93a386Sopenharmony_ci effect.build( 784cb93a386Sopenharmony_ci "uniform shader child;" 785cb93a386Sopenharmony_ci "struct S { float2 coord; };" 786cb93a386Sopenharmony_ci "void process(inout S s) { s.coord = s.coord.yx; }" 787cb93a386Sopenharmony_ci "half4 main(float2 p) { S s; s.coord = p; process(s); return child.eval(s.coord); " 788cb93a386Sopenharmony_ci "}"); 789cb93a386Sopenharmony_ci effect.child("child") = child; 790cb93a386Sopenharmony_ci effect.test(0xFF00407F, [](SkCanvas*, SkPaint* paint) { 791cb93a386Sopenharmony_ci paint->setColor4f({0.99608f, 0.50196f, 0.0f, 1.0f}); 792cb93a386Sopenharmony_ci }); 793cb93a386Sopenharmony_ci} 794cb93a386Sopenharmony_ci 795cb93a386Sopenharmony_ciDEF_TEST(SkRuntimeStructNameReuse, r) { 796cb93a386Sopenharmony_ci test_RuntimeEffectStructNameReuse(r, nullptr); 797cb93a386Sopenharmony_ci} 798cb93a386Sopenharmony_ci 799cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRuntimeStructNameReuse_GPU, r, ctxInfo) { 800cb93a386Sopenharmony_ci test_RuntimeEffectStructNameReuse(r, ctxInfo.directContext()); 801cb93a386Sopenharmony_ci} 802cb93a386Sopenharmony_ci 803cb93a386Sopenharmony_ciDEF_TEST(SkRuntimeColorFilterFlags, r) { 804cb93a386Sopenharmony_ci { // Here's a non-trivial filter that doesn't change alpha. 805cb93a386Sopenharmony_ci auto [effect, err] = SkRuntimeEffect::MakeForColorFilter(SkString{ 806cb93a386Sopenharmony_ci "half4 main(half4 color) { return color + half4(1,1,1,0); }"}); 807cb93a386Sopenharmony_ci REPORTER_ASSERT(r, effect && err.isEmpty()); 808cb93a386Sopenharmony_ci sk_sp<SkColorFilter> filter = effect->makeColorFilter(SkData::MakeEmpty()); 809cb93a386Sopenharmony_ci REPORTER_ASSERT(r, filter && filter->isAlphaUnchanged()); 810cb93a386Sopenharmony_ci } 811cb93a386Sopenharmony_ci 812cb93a386Sopenharmony_ci { // Here's one that definitely changes alpha. 813cb93a386Sopenharmony_ci auto [effect, err] = SkRuntimeEffect::MakeForColorFilter(SkString{ 814cb93a386Sopenharmony_ci "half4 main(half4 color) { return color + half4(0,0,0,4); }"}); 815cb93a386Sopenharmony_ci REPORTER_ASSERT(r, effect && err.isEmpty()); 816cb93a386Sopenharmony_ci sk_sp<SkColorFilter> filter = effect->makeColorFilter(SkData::MakeEmpty()); 817cb93a386Sopenharmony_ci REPORTER_ASSERT(r, filter && !filter->isAlphaUnchanged()); 818cb93a386Sopenharmony_ci } 819cb93a386Sopenharmony_ci} 820cb93a386Sopenharmony_ci 821cb93a386Sopenharmony_ciDEF_TEST(SkRuntimeShaderSampleCoords, r) { 822cb93a386Sopenharmony_ci // This test verifies that we detect calls to sample where the coords are the same as those 823cb93a386Sopenharmony_ci // passed to main. In those cases, it's safe to turn the "explicit" sampling into "passthrough" 824cb93a386Sopenharmony_ci // sampling. This optimization is implemented very conservatively. 825cb93a386Sopenharmony_ci // 826cb93a386Sopenharmony_ci // It also checks that we correctly set the "referencesSampleCoords" bit on the runtime effect 827cb93a386Sopenharmony_ci // FP, depending on how the coords parameter to main is used. 828cb93a386Sopenharmony_ci 829cb93a386Sopenharmony_ci auto test = [&](const char* src, bool expectExplicit, bool expectReferencesSampleCoords) { 830cb93a386Sopenharmony_ci auto [effect, err] = 831cb93a386Sopenharmony_ci SkRuntimeEffect::MakeForShader(SkStringPrintf("uniform shader child; %s", src)); 832cb93a386Sopenharmony_ci REPORTER_ASSERT(r, effect); 833cb93a386Sopenharmony_ci 834cb93a386Sopenharmony_ci auto child = GrFragmentProcessor::MakeColor({ 1, 1, 1, 1 }); 835cb93a386Sopenharmony_ci auto fp = GrSkSLFP::Make(effect, "test_fp", /*inputFP=*/nullptr, GrSkSLFP::OptFlags::kNone, 836cb93a386Sopenharmony_ci "child", std::move(child)); 837cb93a386Sopenharmony_ci REPORTER_ASSERT(r, fp); 838cb93a386Sopenharmony_ci 839cb93a386Sopenharmony_ci REPORTER_ASSERT(r, fp->childProcessor(0)->sampleUsage().isExplicit() == expectExplicit); 840cb93a386Sopenharmony_ci REPORTER_ASSERT(r, fp->usesSampleCoords() == expectReferencesSampleCoords); 841cb93a386Sopenharmony_ci }; 842cb93a386Sopenharmony_ci 843cb93a386Sopenharmony_ci // Cases where our optimization is valid, and works: 844cb93a386Sopenharmony_ci 845cb93a386Sopenharmony_ci // Direct use of passed-in coords. Here, the only use of sample coords is for a sample call 846cb93a386Sopenharmony_ci // converted to passthrough, so referenceSampleCoords is *false*, despite appearing in main. 847cb93a386Sopenharmony_ci test("half4 main(float2 xy) { return child.eval(xy); }", false, false); 848cb93a386Sopenharmony_ci // Sample with passed-in coords, read (but don't write) sample coords elsewhere 849cb93a386Sopenharmony_ci test("half4 main(float2 xy) { return child.eval(xy) + sin(xy.x); }", false, true); 850cb93a386Sopenharmony_ci 851cb93a386Sopenharmony_ci // Cases where our optimization is not valid, and does not happen: 852cb93a386Sopenharmony_ci 853cb93a386Sopenharmony_ci // Sampling with values completely unrelated to passed-in coords 854cb93a386Sopenharmony_ci test("half4 main(float2 xy) { return child.eval(float2(0, 0)); }", true, false); 855cb93a386Sopenharmony_ci // Use of expression involving passed in coords 856cb93a386Sopenharmony_ci test("half4 main(float2 xy) { return child.eval(xy * 0.5); }", true, true); 857cb93a386Sopenharmony_ci // Use of coords after modification 858cb93a386Sopenharmony_ci test("half4 main(float2 xy) { xy *= 2; return child.eval(xy); }", true, true); 859cb93a386Sopenharmony_ci // Use of coords after modification via out-param call 860cb93a386Sopenharmony_ci test("void adjust(inout float2 xy) { xy *= 2; }" 861cb93a386Sopenharmony_ci "half4 main(float2 xy) { adjust(xy); return child.eval(xy); }", true, true); 862cb93a386Sopenharmony_ci 863cb93a386Sopenharmony_ci // There should (must) not be any false-positive cases. There are false-negatives. 864cb93a386Sopenharmony_ci // In all of these cases, our optimization would be valid, but does not happen: 865cb93a386Sopenharmony_ci 866cb93a386Sopenharmony_ci // Direct use of passed-in coords, modified after use 867cb93a386Sopenharmony_ci test("half4 main(float2 xy) { half4 c = child.eval(xy); xy *= 2; return c; }", true, true); 868cb93a386Sopenharmony_ci // Passed-in coords copied to a temp variable 869cb93a386Sopenharmony_ci test("half4 main(float2 xy) { float2 p = xy; return child.eval(p); }", true, true); 870cb93a386Sopenharmony_ci // Use of coords passed to helper function 871cb93a386Sopenharmony_ci test("half4 helper(float2 xy) { return child.eval(xy); }" 872cb93a386Sopenharmony_ci "half4 main(float2 xy) { return helper(xy); }", true, true); 873cb93a386Sopenharmony_ci} 874cb93a386Sopenharmony_ci 875cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_ALL_CONTEXTS(GrSkSLFP_Specialized, r, ctxInfo) { 876cb93a386Sopenharmony_ci struct FpAndKey { 877cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> fp; 878cb93a386Sopenharmony_ci SkTArray<uint32_t, true> key; 879cb93a386Sopenharmony_ci }; 880cb93a386Sopenharmony_ci 881cb93a386Sopenharmony_ci // Constant color, but with an 'specialize' option that decides if the color is inserted in the 882cb93a386Sopenharmony_ci // SkSL as a literal, or left as a uniform 883cb93a386Sopenharmony_ci auto make_color_fp = [&](SkPMColor4f color, bool specialize) { 884cb93a386Sopenharmony_ci auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, R"( 885cb93a386Sopenharmony_ci uniform half4 color; 886cb93a386Sopenharmony_ci half4 main(float2 xy) { return color; } 887cb93a386Sopenharmony_ci )"); 888cb93a386Sopenharmony_ci FpAndKey result; 889cb93a386Sopenharmony_ci result.fp = GrSkSLFP::Make(std::move(effect), "color_fp", /*inputFP=*/nullptr, 890cb93a386Sopenharmony_ci GrSkSLFP::OptFlags::kNone, 891cb93a386Sopenharmony_ci "color", GrSkSLFP::SpecializeIf(specialize, color)); 892cb93a386Sopenharmony_ci GrProcessorKeyBuilder builder(&result.key); 893cb93a386Sopenharmony_ci result.fp->addToKey(*ctxInfo.directContext()->priv().caps()->shaderCaps(), &builder); 894cb93a386Sopenharmony_ci builder.flush(); 895cb93a386Sopenharmony_ci return result; 896cb93a386Sopenharmony_ci }; 897cb93a386Sopenharmony_ci 898cb93a386Sopenharmony_ci FpAndKey uRed = make_color_fp({1, 0, 0, 1}, false), 899cb93a386Sopenharmony_ci uGreen = make_color_fp({0, 1, 0, 1}, false), 900cb93a386Sopenharmony_ci sRed = make_color_fp({1, 0, 0, 1}, true), 901cb93a386Sopenharmony_ci sGreen = make_color_fp({0, 1, 0, 1}, true); 902cb93a386Sopenharmony_ci 903cb93a386Sopenharmony_ci // uRed and uGreen should have the same key - they just have different uniforms 904cb93a386Sopenharmony_ci SkASSERT(uRed.key == uGreen.key); 905cb93a386Sopenharmony_ci // sRed and sGreen should have keys that are different from the uniform case, and each other 906cb93a386Sopenharmony_ci SkASSERT(sRed.key != uRed.key); 907cb93a386Sopenharmony_ci SkASSERT(sGreen.key != uRed.key); 908cb93a386Sopenharmony_ci SkASSERT(sRed.key != sGreen.key); 909cb93a386Sopenharmony_ci} 910cb93a386Sopenharmony_ci 911cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrSkSLFP_UniformArray, r, ctxInfo) { 912cb93a386Sopenharmony_ci // Make a fill-context to draw into. 913cb93a386Sopenharmony_ci GrDirectContext* directContext = ctxInfo.directContext(); 914cb93a386Sopenharmony_ci SkImageInfo info = SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType); 915cb93a386Sopenharmony_ci std::unique_ptr<skgpu::SurfaceFillContext> testCtx = 916cb93a386Sopenharmony_ci directContext->priv().makeSFC(info, SkBackingFit::kExact); 917cb93a386Sopenharmony_ci 918cb93a386Sopenharmony_ci // Make an effect that takes a uniform array as input. 919cb93a386Sopenharmony_ci static constexpr std::array<float, 4> kRed {1.0f, 0.0f, 0.0f, 1.0f}; 920cb93a386Sopenharmony_ci static constexpr std::array<float, 4> kGreen{0.0f, 1.0f, 0.0f, 1.0f}; 921cb93a386Sopenharmony_ci static constexpr std::array<float, 4> kBlue {0.0f, 0.0f, 1.0f, 1.0f}; 922cb93a386Sopenharmony_ci static constexpr std::array<float, 4> kGray {0.499f, 0.499f, 0.499f, 1.0f}; 923cb93a386Sopenharmony_ci 924cb93a386Sopenharmony_ci for (const auto& colorArray : {kRed, kGreen, kBlue, kGray}) { 925cb93a386Sopenharmony_ci // Compile our runtime effect. 926cb93a386Sopenharmony_ci auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, R"( 927cb93a386Sopenharmony_ci uniform half color[4]; 928cb93a386Sopenharmony_ci half4 main(float2 xy) { return half4(color[0], color[1], color[2], color[3]); } 929cb93a386Sopenharmony_ci )"); 930cb93a386Sopenharmony_ci // Render our shader into the fill-context with our various input colors. 931cb93a386Sopenharmony_ci testCtx->fillWithFP(GrSkSLFP::Make(std::move(effect), "test_fp", 932cb93a386Sopenharmony_ci /*inputFP=*/nullptr, 933cb93a386Sopenharmony_ci GrSkSLFP::OptFlags::kNone, 934cb93a386Sopenharmony_ci "color", SkMakeSpan(colorArray))); 935cb93a386Sopenharmony_ci // Read our color back and ensure it matches. 936cb93a386Sopenharmony_ci GrColor actual; 937cb93a386Sopenharmony_ci GrPixmap pixmap(info, &actual, sizeof(GrColor)); 938cb93a386Sopenharmony_ci if (!testCtx->readPixels(directContext, pixmap, /*srcPt=*/{0, 0})) { 939cb93a386Sopenharmony_ci REPORT_FAILURE(r, "readPixels", SkString("readPixels failed")); 940cb93a386Sopenharmony_ci break; 941cb93a386Sopenharmony_ci } 942cb93a386Sopenharmony_ci if (actual != GrColorPackRGBA(255 * colorArray[0], 255 * colorArray[1], 943cb93a386Sopenharmony_ci 255 * colorArray[2], 255 * colorArray[3])) { 944cb93a386Sopenharmony_ci REPORT_FAILURE(r, "Uniform array didn't match expectations", 945cb93a386Sopenharmony_ci SkStringPrintf("\n" 946cb93a386Sopenharmony_ci "Expected: [ %g %g %g %g ]\n" 947cb93a386Sopenharmony_ci "Got : [ %08x ]\n", 948cb93a386Sopenharmony_ci colorArray[0], colorArray[1], 949cb93a386Sopenharmony_ci colorArray[2], colorArray[3], 950cb93a386Sopenharmony_ci actual)); 951cb93a386Sopenharmony_ci break; 952cb93a386Sopenharmony_ci } 953cb93a386Sopenharmony_ci } 954cb93a386Sopenharmony_ci} 955