| /* |
| * 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" |
| |
| #ifdef SK_GRAPHITE_ENABLED |
| |
| #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 <array> |
| |
| 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<UniquePaintParamsID> 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<UniquePaintParamsID> 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<UniquePaintParamsID> 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<PrecompileShader> sweepGrad_0 = PrecompileShaders::SweepGradient(); |
| |
| std::array<SkBlendMode, 1> blendModes{ SkBlendMode::kSrc }; |
| |
| std::vector<SkBlendMode> moreBlendModes{ SkBlendMode::kDst }; |
| |
| // Second top-level option (blendShader_0) |
| auto blendShader_0 = PrecompileShaders::Blend( |
| SkSpan<SkBlendMode>(blendModes), // std::array |
| { // initializer_list |
| PrecompileShaders::LinearGradient(), |
| PrecompileShaders::Color() |
| }, |
| { |
| PrecompileShaders::LinearGradient(), |
| PrecompileShaders::Blend( |
| SkSpan<SkBlendMode>(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<UniquePaintParamsID> precompileIDs; |
| paintOptions.priv().buildCombinations(keyContext, |
| /* addPrimitiveBlender= */ false, |
| [&](UniquePaintParamsID id) { |
| precompileIDs.push_back(id); |
| }); |
| |
| SkASSERT(precompileIDs.size() == 17); |
| } |
| |
| template <typename T> |
| std::vector<sk_sp<T>> create_runtime_combos( |
| skiatest::Reporter* reporter, |
| SkRuntimeEffect::Result effectFactory(SkString), |
| sk_sp<T> precompileFactory(sk_sp<SkRuntimeEffect>, |
| SkSpan<const PrecompileChildOptions> 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<T> red = precompileFactory(redEffect, {}); |
| REPORTER_ASSERT(reporter, red); |
| |
| sk_sp<T> green = precompileFactory(greenEffect, {}); |
| REPORTER_ASSERT(reporter, green); |
| |
| sk_sp<T> 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<sk_sp<PrecompileShader>> combinations = |
| create_runtime_combos<PrecompileShader>(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<sk_sp<PrecompileColorFilter>> combinations = |
| create_runtime_combos<PrecompileColorFilter>(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<sk_sp<PrecompileBlender>> combinations = |
| create_runtime_combos<PrecompileBlender>(reporter, |
| SkRuntimeEffect::MakeForBlender, |
| MakePrecompileBlender, |
| kRedB, |
| kGreenB, |
| kCombineB); |
| paintOptions.setBlenders(combinations); |
| } |
| |
| REPORTER_ASSERT(reporter, paintOptions.priv().numCombinations() == 8); |
| |
| std::vector<UniquePaintParamsID> 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<RuntimeEffectDictionary>(); |
| |
| 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_ENABLED |