/* * Copyright 2022 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "tests/Test.h" #if defined(SK_GRAPHITE) #include "include/core/SkColorSpace.h" #include "include/effects/SkRuntimeEffect.h" #include "src/gpu/graphite/ContextPriv.h" #include "src/gpu/graphite/FactoryFunctions.h" #include "src/gpu/graphite/KeyContext.h" #include "src/gpu/graphite/PaintOptionsPriv.h" #include "src/gpu/graphite/Precompile.h" #include "src/gpu/graphite/RuntimeEffectDictionary.h" #include using namespace::skgpu::graphite; namespace { // The default PaintOptions should create a single combination with a solid color shader and // kSrcOver blending void empty_test(const KeyContext& keyContext, skiatest::Reporter* reporter) { PaintOptions paintOptions; REPORTER_ASSERT(reporter, paintOptions.priv().numCombinations() == 1); std::vector precompileIDs; paintOptions.priv().buildCombinations(keyContext, /* addPrimitiveBlender= */ false, [&](UniquePaintParamsID id) { precompileIDs.push_back(id); }); SkASSERT(precompileIDs.size() == 1); } // A PaintOptions will supply a default solid color shader if needed. void no_shader_option_test(const KeyContext& keyContext, skiatest::Reporter* reporter) { SkBlendMode blendModes[] = { SkBlendMode::kSrcOver }; PaintOptions paintOptions; paintOptions.setBlendModes(blendModes); REPORTER_ASSERT(reporter, paintOptions.priv().numCombinations() == 1); std::vector precompileIDs; paintOptions.priv().buildCombinations(keyContext, /* addPrimitiveBlender= */ false, [&](UniquePaintParamsID id) { precompileIDs.push_back(id); }); SkASSERT(precompileIDs.size() == 1); } // A default kSrcOver blend mode will be supplied if no other blend options are added void no_blend_mode_option_test(const KeyContext& keyContext, skiatest::Reporter* reporter) { PaintOptions paintOptions; paintOptions.setShaders({ PrecompileShaders::Color() }); REPORTER_ASSERT(reporter, paintOptions.priv().numCombinations() == 1); std::vector precompileIDs; paintOptions.priv().buildCombinations(keyContext, /* addPrimitiveBlender= */ false, [&](UniquePaintParamsID id) { precompileIDs.push_back(id); }); SkASSERT(precompileIDs.size() == 1); } void big_test(const KeyContext& keyContext, skiatest::Reporter* reporter) { // paintOptions (17) // |- sweepGrad_0 (2) | blendShader_0 (15) // | 0: kSrc (1) // | 1: (dsts) linearGrad_0 (2) | solid_0 (1) // | 2: (srcs) linearGrad_1 (2) | blendShader_1 (3) // | 0: kDst (1) // | 1: (dsts) radGrad_0 (2) | solid_1 (1) // | 2: (srcs) imageShader_0 (1) // | // |- 4-built-in-blend-modes (just 1 since all are PorterDuff) PaintOptions paintOptions; // first, shaders. First top-level option (sweepGrad_0) sk_sp sweepGrad_0 = PrecompileShaders::SweepGradient(); std::array blendModes{ SkBlendMode::kSrc }; std::vector moreBlendModes{ SkBlendMode::kDst }; // Second top-level option (blendShader_0) auto blendShader_0 = PrecompileShaders::Blend( SkSpan(blendModes), // std::array { // initializer_list PrecompileShaders::LinearGradient(), PrecompileShaders::Color() }, { PrecompileShaders::LinearGradient(), PrecompileShaders::Blend( SkSpan(moreBlendModes),// std::vector { PrecompileShaders::RadialGradient(), PrecompileShaders::Color() }, { PrecompileShaders::Image() }) }); paintOptions.setShaders({ sweepGrad_0, blendShader_0 }); SkBlendMode evenMoreBlendModes[] = { SkBlendMode::kSrcOver, SkBlendMode::kSrc, SkBlendMode::kDstOver, SkBlendMode::kDst }; // now, blend modes paintOptions.setBlendModes(evenMoreBlendModes); // c array REPORTER_ASSERT(reporter, paintOptions.priv().numCombinations() == 17); std::vector precompileIDs; paintOptions.priv().buildCombinations(keyContext, /* addPrimitiveBlender= */ false, [&](UniquePaintParamsID id) { precompileIDs.push_back(id); }); SkASSERT(precompileIDs.size() == 17); } template std::vector> create_runtime_combos( skiatest::Reporter* reporter, SkRuntimeEffect::Result effectFactory(SkString), sk_sp precompileFactory(sk_sp, SkSpan childOptions), const char* redCode, const char* greenCode, const char* combineCode) { auto [redEffect, error1] = effectFactory(SkString(redCode)); REPORTER_ASSERT(reporter, redEffect, "%s", error1.c_str()); auto [greenEffect, error2] = effectFactory(SkString(greenCode)); REPORTER_ASSERT(reporter, greenEffect, "%s", error2.c_str()); auto [combineEffect, error3] = effectFactory(SkString(combineCode)); REPORTER_ASSERT(reporter, combineEffect, "%s", error3.c_str()); sk_sp red = precompileFactory(redEffect, {}); REPORTER_ASSERT(reporter, red); sk_sp green = precompileFactory(greenEffect, {}); REPORTER_ASSERT(reporter, green); sk_sp combine = precompileFactory(combineEffect, { { red, green }, { green, red } }); REPORTER_ASSERT(reporter, combine); return { combine }; } void runtime_effect_test(const KeyContext& keyContext, skiatest::Reporter* reporter) { // paintOptions (8) // |- combineShader (2) // | 0: redShader | greenShader // | 1: greenShader | redShader // | // |- combineColorFilter (2) // | 0: redColorFilter | greenColorFilter // | 1: greenColorFilter | redColorFilter // | // |- combineBlender (2) // | 0: redBlender | greenBlender // | 1: greenBlender | redBlender PaintOptions paintOptions; // shaders { static const char* kRedS = R"( half4 main(vec2 fragcoord) { return half4(.5, 0, 0, .5); } )"; static const char* kGreenS = R"( half4 main(vec2 fragcoord) { return half4(0, .5, 0, .5); } )"; static const char* kCombineS = R"( uniform shader first; uniform shader second; half4 main(vec2 fragcoords) { return first.eval(fragcoords) + second.eval(fragcoords); } )"; std::vector> combinations = create_runtime_combos(reporter, SkRuntimeEffect::MakeForShader, MakePrecompileShader, kRedS, kGreenS, kCombineS); paintOptions.setShaders(combinations); } // color filters { static const char* kRedCF = R"( half4 main(half4 color) { return half4(.5, 0, 0, .5); } )"; static const char* kGreenCF = R"( half4 main(half4 color) { return half4(0, .5, 0, .5); } )"; static const char* kCombineCF = R"( uniform colorFilter first; uniform colorFilter second; half4 main(half4 color) { return first.eval(color) + second.eval(color); } )"; std::vector> combinations = create_runtime_combos(reporter, SkRuntimeEffect::MakeForColorFilter, MakePrecompileColorFilter, kRedCF, kGreenCF, kCombineCF); paintOptions.setColorFilters(combinations); } // blenders { static const char* kRedB = R"( half4 main(half4 src, half4 dst) { return half4(.5, 0, 0, .5); } )"; static const char* kGreenB = R"( half4 main(half4 src, half4 dst) { return half4(0, .5, 0, .5); } )"; static const char* kCombineB = R"( uniform blender first; uniform blender second; half4 main(half4 src, half4 dst) { return first.eval(src, dst) + second.eval(src, dst); } )"; std::vector> combinations = create_runtime_combos(reporter, SkRuntimeEffect::MakeForBlender, MakePrecompileBlender, kRedB, kGreenB, kCombineB); paintOptions.setBlenders(combinations); } REPORTER_ASSERT(reporter, paintOptions.priv().numCombinations() == 8); std::vector precompileIDs; paintOptions.priv().buildCombinations(keyContext, /* addPrimitiveBlender= */ false, [&](UniquePaintParamsID id) { precompileIDs.push_back(id); }); SkASSERT(precompileIDs.size() == 8); } } // anonymous namespace DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(CombinationBuilderTest, reporter, context) { ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary(); auto rtEffectDict = std::make_unique(); SkColorInfo ci(kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr); KeyContext keyContext(dict, rtEffectDict.get(), ci); empty_test(keyContext, reporter); no_shader_option_test(keyContext, reporter); no_blend_mode_option_test(keyContext, reporter); big_test(keyContext, reporter); runtime_effect_test(keyContext, reporter); } #endif // SK_GRAPHITE