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/SkCanvas.h" 10cb93a386Sopenharmony_ci#include "include/core/SkColorFilter.h" 11cb93a386Sopenharmony_ci#include "include/core/SkData.h" 12cb93a386Sopenharmony_ci#include "include/core/SkPaint.h" 13cb93a386Sopenharmony_ci#include "include/core/SkSurface.h" 14cb93a386Sopenharmony_ci#include "include/effects/SkRuntimeEffect.h" 15cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h" 16cb93a386Sopenharmony_ci#include "include/sksl/DSLRuntimeEffects.h" 17cb93a386Sopenharmony_ci#include "src/core/SkRuntimeEffectPriv.h" 18cb93a386Sopenharmony_ci#include "src/core/SkTLazy.h" 19cb93a386Sopenharmony_ci#include "src/gpu/GrColor.h" 20cb93a386Sopenharmony_ci#include "src/sksl/SkSLCompiler.h" 21cb93a386Sopenharmony_ci#include "tests/Test.h" 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ci#include <algorithm> 24cb93a386Sopenharmony_ci#include <thread> 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ciusing namespace SkSL::dsl; 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_ciclass DSLTestEffect { 29cb93a386Sopenharmony_cipublic: 30cb93a386Sopenharmony_ci DSLTestEffect(skiatest::Reporter* r, sk_sp<SkSurface> surface) 31cb93a386Sopenharmony_ci : fReporter(r) 32cb93a386Sopenharmony_ci , fCaps(SkSL::ShaderCapsFactory::Standalone()) 33cb93a386Sopenharmony_ci , fCompiler(std::make_unique<SkSL::Compiler>(fCaps.get())) 34cb93a386Sopenharmony_ci , fSurface(std::move(surface)) {} 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_ci void start() { 37cb93a386Sopenharmony_ci StartRuntimeShader(fCompiler.get()); 38cb93a386Sopenharmony_ci } 39cb93a386Sopenharmony_ci 40cb93a386Sopenharmony_ci void end(bool expectSuccess = true) { 41cb93a386Sopenharmony_ci SkRuntimeEffect::Options options; 42cb93a386Sopenharmony_ci SkRuntimeEffectPriv::EnableFragCoord(&options); 43cb93a386Sopenharmony_ci sk_sp<SkRuntimeEffect> effect = EndRuntimeShader(options); 44cb93a386Sopenharmony_ci REPORTER_ASSERT(fReporter, effect ? expectSuccess : !expectSuccess); 45cb93a386Sopenharmony_ci if (effect) { 46cb93a386Sopenharmony_ci fBuilder.init(std::move(effect)); 47cb93a386Sopenharmony_ci } 48cb93a386Sopenharmony_ci } 49cb93a386Sopenharmony_ci 50cb93a386Sopenharmony_ci SkRuntimeShaderBuilder::BuilderUniform uniform(skstd::string_view name) { 51cb93a386Sopenharmony_ci return fBuilder->uniform(SkString(name).c_str()); 52cb93a386Sopenharmony_ci } 53cb93a386Sopenharmony_ci 54cb93a386Sopenharmony_ci SkRuntimeShaderBuilder::BuilderChild child(skstd::string_view name) { 55cb93a386Sopenharmony_ci return fBuilder->child(SkString(name).c_str()); 56cb93a386Sopenharmony_ci } 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_ci using PreTestFn = std::function<void(SkCanvas*, SkPaint*)>; 59cb93a386Sopenharmony_ci 60cb93a386Sopenharmony_ci void test(GrColor TL, GrColor TR, GrColor BL, GrColor BR, 61cb93a386Sopenharmony_ci PreTestFn preTestCallback = nullptr) { 62cb93a386Sopenharmony_ci auto shader = fBuilder->makeShader(nullptr, false); 63cb93a386Sopenharmony_ci if (!shader) { 64cb93a386Sopenharmony_ci REPORT_FAILURE(fReporter, "shader", SkString("Effect didn't produce a shader")); 65cb93a386Sopenharmony_ci return; 66cb93a386Sopenharmony_ci } 67cb93a386Sopenharmony_ci 68cb93a386Sopenharmony_ci SkCanvas* canvas = fSurface->getCanvas(); 69cb93a386Sopenharmony_ci SkPaint paint; 70cb93a386Sopenharmony_ci paint.setShader(std::move(shader)); 71cb93a386Sopenharmony_ci paint.setBlendMode(SkBlendMode::kSrc); 72cb93a386Sopenharmony_ci 73cb93a386Sopenharmony_ci canvas->save(); 74cb93a386Sopenharmony_ci if (preTestCallback) { 75cb93a386Sopenharmony_ci preTestCallback(canvas, &paint); 76cb93a386Sopenharmony_ci } 77cb93a386Sopenharmony_ci canvas->drawPaint(paint); 78cb93a386Sopenharmony_ci canvas->restore(); 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_ci GrColor actual[4]; 81cb93a386Sopenharmony_ci SkImageInfo info = fSurface->imageInfo(); 82cb93a386Sopenharmony_ci if (!fSurface->readPixels(info, actual, info.minRowBytes(), 0, 0)) { 83cb93a386Sopenharmony_ci REPORT_FAILURE(fReporter, "readPixels", SkString("readPixels failed")); 84cb93a386Sopenharmony_ci return; 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci 87cb93a386Sopenharmony_ci GrColor expected[4] = {TL, TR, BL, BR}; 88cb93a386Sopenharmony_ci if (0 != memcmp(actual, expected, sizeof(actual))) { 89cb93a386Sopenharmony_ci REPORT_FAILURE(fReporter, "Runtime effect didn't match expectations", 90cb93a386Sopenharmony_ci SkStringPrintf("\n" 91cb93a386Sopenharmony_ci "Expected: [ %08x %08x %08x %08x ]\n" 92cb93a386Sopenharmony_ci "Got : [ %08x %08x %08x %08x ]\n" 93cb93a386Sopenharmony_ci "SkSL:\n%s\n", 94cb93a386Sopenharmony_ci TL, TR, BL, BR, actual[0], actual[1], actual[2], 95cb93a386Sopenharmony_ci actual[3], fBuilder->effect()->source().c_str())); 96cb93a386Sopenharmony_ci } 97cb93a386Sopenharmony_ci } 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ci void test(GrColor expected, PreTestFn preTestCallback = nullptr) { 100cb93a386Sopenharmony_ci this->test(expected, expected, expected, expected, preTestCallback); 101cb93a386Sopenharmony_ci } 102cb93a386Sopenharmony_ci 103cb93a386Sopenharmony_ciprivate: 104cb93a386Sopenharmony_ci skiatest::Reporter* fReporter; 105cb93a386Sopenharmony_ci SkSL::ShaderCapsPointer fCaps; 106cb93a386Sopenharmony_ci std::unique_ptr<SkSL::Compiler> fCompiler; 107cb93a386Sopenharmony_ci sk_sp<SkSurface> fSurface; 108cb93a386Sopenharmony_ci SkTLazy<SkRuntimeShaderBuilder> fBuilder; 109cb93a386Sopenharmony_ci}; 110cb93a386Sopenharmony_ci 111cb93a386Sopenharmony_cistatic void test_RuntimeEffect_Shaders(skiatest::Reporter* r, GrRecordingContext* rContext) { 112cb93a386Sopenharmony_ci SkImageInfo info = SkImageInfo::Make(2, 2, kRGBA_8888_SkColorType, kPremul_SkAlphaType); 113cb93a386Sopenharmony_ci sk_sp<SkSurface> surface = rContext 114cb93a386Sopenharmony_ci ? SkSurface::MakeRenderTarget(rContext, SkBudgeted::kNo, info) 115cb93a386Sopenharmony_ci : SkSurface::MakeRaster(info); 116cb93a386Sopenharmony_ci REPORTER_ASSERT(r, surface); 117cb93a386Sopenharmony_ci using float4 = std::array<float, 4>; 118cb93a386Sopenharmony_ci using int4 = std::array<int, 4>; 119cb93a386Sopenharmony_ci DSLTestEffect effect(r, surface); 120cb93a386Sopenharmony_ci 121cb93a386Sopenharmony_ci // Local coords 122cb93a386Sopenharmony_ci { 123cb93a386Sopenharmony_ci effect.start(); 124cb93a386Sopenharmony_ci Parameter p(kFloat2_Type, "p"); 125cb93a386Sopenharmony_ci Function(kHalf4_Type, "main", p).define( 126cb93a386Sopenharmony_ci Return(Half4(Half2(p - 0.5), 0, 1)) 127cb93a386Sopenharmony_ci ); 128cb93a386Sopenharmony_ci effect.end(); 129cb93a386Sopenharmony_ci effect.test(0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF); 130cb93a386Sopenharmony_ci } 131cb93a386Sopenharmony_ci 132cb93a386Sopenharmony_ci // Use of a simple uniform. (Draw twice with two values to ensure it's updated). 133cb93a386Sopenharmony_ci { 134cb93a386Sopenharmony_ci effect.start(); 135cb93a386Sopenharmony_ci GlobalVar gColor(kUniform_Modifier, kFloat4_Type); 136cb93a386Sopenharmony_ci Declare(gColor); 137cb93a386Sopenharmony_ci Parameter p(kFloat2_Type, "p"); 138cb93a386Sopenharmony_ci Function(kHalf4_Type, "main", p).define( 139cb93a386Sopenharmony_ci Return(Half4(gColor)) 140cb93a386Sopenharmony_ci ); 141cb93a386Sopenharmony_ci effect.end(); 142cb93a386Sopenharmony_ci effect.uniform(SkString(gColor.name()).c_str()) = float4{ 0.0f, 0.25f, 0.75f, 1.0f }; 143cb93a386Sopenharmony_ci effect.test(0xFFBF4000); 144cb93a386Sopenharmony_ci effect.uniform(SkString(gColor.name()).c_str()) = float4{ 1.0f, 0.0f, 0.0f, 0.498f }; 145cb93a386Sopenharmony_ci effect.test(0x7F0000FF); // Tests that we don't clamp to valid premul 146cb93a386Sopenharmony_ci } 147cb93a386Sopenharmony_ci 148cb93a386Sopenharmony_ci // Same, with integer uniforms 149cb93a386Sopenharmony_ci { 150cb93a386Sopenharmony_ci effect.start(); 151cb93a386Sopenharmony_ci GlobalVar gColor(kUniform_Modifier, kInt4_Type); 152cb93a386Sopenharmony_ci Declare(gColor); 153cb93a386Sopenharmony_ci Parameter p(kFloat2_Type, "p"); 154cb93a386Sopenharmony_ci Function(kHalf4_Type, "main", p).define( 155cb93a386Sopenharmony_ci Return(Half4(gColor) / 255) 156cb93a386Sopenharmony_ci ); 157cb93a386Sopenharmony_ci effect.end(); 158cb93a386Sopenharmony_ci effect.uniform(SkString(gColor.name()).c_str()) = int4{ 0x00, 0x40, 0xBF, 0xFF }; 159cb93a386Sopenharmony_ci effect.test(0xFFBF4000); 160cb93a386Sopenharmony_ci effect.uniform(SkString(gColor.name()).c_str()) = int4{ 0xFF, 0x00, 0x00, 0x7F }; 161cb93a386Sopenharmony_ci effect.test(0x7F0000FF); // Tests that we don't clamp to valid premul 162cb93a386Sopenharmony_ci } 163cb93a386Sopenharmony_ci 164cb93a386Sopenharmony_ci // Test sk_FragCoord (device coords). Rotate the canvas to be sure we're seeing device coords. 165cb93a386Sopenharmony_ci // Since the surface is 2x2, we should see (0,0), (1,0), (0,1), (1,1). Multiply by 0.498 to 166cb93a386Sopenharmony_ci // make sure we're not saturating unexpectedly. 167cb93a386Sopenharmony_ci { 168cb93a386Sopenharmony_ci effect.start(); 169cb93a386Sopenharmony_ci Parameter p(kFloat2_Type, "p"); 170cb93a386Sopenharmony_ci Function(kHalf4_Type, "main", p).define( 171cb93a386Sopenharmony_ci Return(Half4(0.498 * (Half2(Swizzle(sk_FragCoord(), X, Y)) - 0.5), 0, 1)) 172cb93a386Sopenharmony_ci ); 173cb93a386Sopenharmony_ci effect.end(); 174cb93a386Sopenharmony_ci effect.test(0xFF000000, 0xFF00007F, 0xFF007F00, 0xFF007F7F, 175cb93a386Sopenharmony_ci [](SkCanvas* canvas, SkPaint*) { canvas->rotate(45.0f); }); 176cb93a386Sopenharmony_ci } 177cb93a386Sopenharmony_ci 178cb93a386Sopenharmony_ci // Runtime effects should use relaxed precision rules by default 179cb93a386Sopenharmony_ci { 180cb93a386Sopenharmony_ci effect.start(); 181cb93a386Sopenharmony_ci Parameter p(kFloat2_Type, "p"); 182cb93a386Sopenharmony_ci Function(kHalf4_Type, "main", p).define( 183cb93a386Sopenharmony_ci Return(Float4(p - 0.5, 0, 1)) 184cb93a386Sopenharmony_ci ); 185cb93a386Sopenharmony_ci effect.end(); 186cb93a386Sopenharmony_ci effect.test(0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF); 187cb93a386Sopenharmony_ci } 188cb93a386Sopenharmony_ci 189cb93a386Sopenharmony_ci // ... and support *returning* float4, not just half4 190cb93a386Sopenharmony_ci { 191cb93a386Sopenharmony_ci effect.start(); 192cb93a386Sopenharmony_ci Parameter p(kFloat2_Type, "p"); 193cb93a386Sopenharmony_ci Function(kFloat4_Type, "main", p).define( 194cb93a386Sopenharmony_ci Return(Float4(p - 0.5, 0, 1)) 195cb93a386Sopenharmony_ci ); 196cb93a386Sopenharmony_ci effect.end(); 197cb93a386Sopenharmony_ci effect.test(0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF); 198cb93a386Sopenharmony_ci } 199cb93a386Sopenharmony_ci 200cb93a386Sopenharmony_ci // Test error reporting. We put this before a couple of successful tests to ensure that a 201cb93a386Sopenharmony_ci // failure doesn't leave us in a broken state. 202cb93a386Sopenharmony_ci { 203cb93a386Sopenharmony_ci class SimpleErrorReporter : public SkSL::ErrorReporter { 204cb93a386Sopenharmony_ci public: 205cb93a386Sopenharmony_ci void handleError(skstd::string_view msg, SkSL::PositionInfo pos) override { 206cb93a386Sopenharmony_ci fMsg += msg; 207cb93a386Sopenharmony_ci } 208cb93a386Sopenharmony_ci 209cb93a386Sopenharmony_ci SkSL::String fMsg; 210cb93a386Sopenharmony_ci } errorReporter; 211cb93a386Sopenharmony_ci effect.start(); 212cb93a386Sopenharmony_ci SetErrorReporter(&errorReporter); 213cb93a386Sopenharmony_ci Parameter p(kFloat2_Type, "p"); 214cb93a386Sopenharmony_ci Function(kHalf4_Type, "main", p).define( 215cb93a386Sopenharmony_ci Return(1) // Error, type mismatch 216cb93a386Sopenharmony_ci ); 217cb93a386Sopenharmony_ci effect.end(false); 218cb93a386Sopenharmony_ci REPORTER_ASSERT(r, errorReporter.fMsg == "expected 'half4', but found 'int'"); 219cb93a386Sopenharmony_ci } 220cb93a386Sopenharmony_ci 221cb93a386Sopenharmony_ci // Mutating coords should work. (skbug.com/10918) 222cb93a386Sopenharmony_ci { 223cb93a386Sopenharmony_ci effect.start(); 224cb93a386Sopenharmony_ci Parameter p(kFloat2_Type, "p"); 225cb93a386Sopenharmony_ci Function(kFloat4_Type, "main", p).define( 226cb93a386Sopenharmony_ci p -= 0.5, 227cb93a386Sopenharmony_ci Return(Float4(p, 0, 1)) 228cb93a386Sopenharmony_ci ); 229cb93a386Sopenharmony_ci effect.end(); 230cb93a386Sopenharmony_ci effect.test(0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF); 231cb93a386Sopenharmony_ci } 232cb93a386Sopenharmony_ci { 233cb93a386Sopenharmony_ci effect.start(); 234cb93a386Sopenharmony_ci Parameter p1(kInOut_Modifier, kFloat2_Type, "p"); 235cb93a386Sopenharmony_ci Function moveCoords(kVoid_Type, "moveCoords", p1); 236cb93a386Sopenharmony_ci moveCoords.define( 237cb93a386Sopenharmony_ci p1 -= 0.5 238cb93a386Sopenharmony_ci ); 239cb93a386Sopenharmony_ci Parameter p2(kFloat2_Type, "p"); 240cb93a386Sopenharmony_ci Function(kFloat4_Type, "main", p2).define( 241cb93a386Sopenharmony_ci moveCoords(p2), 242cb93a386Sopenharmony_ci Return(Float4(p2, 0, 1)) 243cb93a386Sopenharmony_ci ); 244cb93a386Sopenharmony_ci effect.end(); 245cb93a386Sopenharmony_ci effect.test(0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF); 246cb93a386Sopenharmony_ci } 247cb93a386Sopenharmony_ci 248cb93a386Sopenharmony_ci // 249cb93a386Sopenharmony_ci // Sampling children 250cb93a386Sopenharmony_ci // 251cb93a386Sopenharmony_ci 252cb93a386Sopenharmony_ci // Sampling a null child should return the paint color 253cb93a386Sopenharmony_ci { 254cb93a386Sopenharmony_ci effect.start(); 255cb93a386Sopenharmony_ci GlobalVar child(kUniform_Modifier, kShader_Type, "child"); 256cb93a386Sopenharmony_ci Declare(child); 257cb93a386Sopenharmony_ci Parameter p2(kFloat2_Type, "p"); 258cb93a386Sopenharmony_ci Function(kFloat4_Type, "main", p2).define( 259cb93a386Sopenharmony_ci Return(child.eval(p2)) 260cb93a386Sopenharmony_ci ); 261cb93a386Sopenharmony_ci effect.end(); 262cb93a386Sopenharmony_ci effect.child(child.name()) = nullptr; 263cb93a386Sopenharmony_ci effect.test(0xFF00FFFF, 264cb93a386Sopenharmony_ci [](SkCanvas*, SkPaint* paint) { paint->setColor4f({1.0f, 1.0f, 0.0f, 1.0f}); }); 265cb93a386Sopenharmony_ci } 266cb93a386Sopenharmony_ci} 267cb93a386Sopenharmony_ci 268cb93a386Sopenharmony_ciDEF_TEST(DSLRuntimeEffectSimple, r) { 269cb93a386Sopenharmony_ci test_RuntimeEffect_Shaders(r, nullptr); 270cb93a386Sopenharmony_ci} 271cb93a386Sopenharmony_ci 272cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(DSLRuntimeEffectSimple_GPU, r, ctxInfo) { 273cb93a386Sopenharmony_ci test_RuntimeEffect_Shaders(r, ctxInfo.directContext()); 274cb93a386Sopenharmony_ci} 275