| /* | |
| * Copyright 2025 Google LLC | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "tests/graphite/precompile/AndroidRuntimeEffectManager.h" | |
| #include "include/core/SkString.h" | |
| #include "include/effects/SkRuntimeEffect.h" | |
| namespace { | |
| // Note: passing in a name to 'makeEffect' is a difference from Android's factory functions. | |
| sk_sp<SkRuntimeEffect> makeEffect(const SkString& sksl, const char* name) { | |
| SkRuntimeEffect::Options options; | |
| options.fName = name; | |
| auto [effect, error] = SkRuntimeEffect::MakeForShader(sksl, options); | |
| if (!effect) { | |
| SkDebugf("%s\n", error.c_str()); | |
| } | |
| return effect; | |
| } | |
| } // anonymous namespace | |
| // All the SkSL snippets in this constructor are just stubs for the Android code. | |
| // For Skia's testing purposes they only need to match the real code wrt: | |
| // name | |
| // number of child shaders | |
| // access method for child shaders (direct sample "eval(xy)" vs indirect "eval(modified-xy)") | |
| RuntimeEffectManager::RuntimeEffectManager() { | |
| static const SkString kBlurFilter_MixEffectCode(R"( | |
| uniform shader img1; | |
| uniform shader img2; | |
| half4 main(float2 xy) { | |
| return half4(mix(img1.eval(xy), img2.eval(xy), 0.5)).rgb1; | |
| } | |
| )"); | |
| static const SkString kEdgeExtensionEffectCode(R"( | |
| uniform shader img; | |
| vec4 main(vec2 xy) { | |
| float3 sample = img.eval(0.115 * xy).rgb; | |
| return float4(sample, 1.0); | |
| } | |
| )"); | |
| static const SkString kGainmapEffectCode(R"( | |
| uniform shader img1; | |
| uniform shader img2; | |
| vec4 main(vec2 xy) { | |
| float3 sample = img1.eval(xy).rgb + img2.eval(xy).rgb; | |
| return float4(sample, 1.0); | |
| } | |
| )"); | |
| static const SkString kKawaseBlurDualFilterV2_QuarterResDownSampleBlurEffectCode(R"( | |
| uniform shader img; | |
| half4 main(float2 xy) { | |
| half3 c = img.eval(0.6 * xy).rgb; | |
| return half4(c * 0.5, 1.0); | |
| } | |
| )"); | |
| static const SkString kKawaseBlurDualFilterV2_HalfResDownSampleBlurEffectCode(R"( | |
| uniform shader img; | |
| half4 main(float2 xy) { | |
| half3 c = img.eval(0.55 * xy).rgb; | |
| return half4(c, 1.0); | |
| } | |
| )"); | |
| static const SkString kKawaseBlurDualFilterV2_UpSampleBlurEffectCode(R"( | |
| uniform shader img; | |
| half4 main(float2 xy) { | |
| half3 c = img.eval(0.55 * xy).rgb; | |
| return half4(c, 1.0); | |
| } | |
| )"); | |
| static const SkString kKawaseBlurEffectCode(R"( | |
| uniform shader img; | |
| half4 main(float2 xy) { | |
| half3 c = img.eval(0.55 * xy).rgb; | |
| return half4(c, 1.0); | |
| } | |
| )"); | |
| static const SkString kLutEffectCode(R"( | |
| uniform shader img; | |
| uniform shader lut; | |
| half4 main(float2 xy) { | |
| half3 c = img.eval(xy).rgb; | |
| float rV = lut.eval(vec2(255, 0)).r; | |
| float gV = lut.eval(vec2(128, 0)).r; | |
| float bV = lut.eval(vec2(64, 0)).r; | |
| return half4(rV+c.r, gV+c.g, bV+c.b, 1.0); | |
| } | |
| )"); | |
| static const SkString kMouriMap_CrossTalkAndChunk16x16EffectCode(R"( | |
| uniform shader img; | |
| vec4 main(vec2 xy) { | |
| float3 linear = img.eval(0.25 * xy).rgb; | |
| return float4(linear, 1.0); | |
| } | |
| )"); | |
| static const SkString kMouriMap_Chunk8x8EffectCode(R"( | |
| uniform shader img; | |
| vec4 main(vec2 xy) { | |
| return float4(img.eval(0.33 * xy).rgb, 1.0); | |
| } | |
| )"); | |
| static const SkString kMouriMap_BlurEffectCode(R"( | |
| uniform shader img; | |
| vec4 main(vec2 xy) { | |
| return float4(img.eval(0.4 * xy).rgb, 0.0); | |
| } | |
| )"); | |
| static const SkString kMouriMap_TonemapEffectCode(R"( | |
| uniform shader image; | |
| uniform shader lux; | |
| vec4 main(vec2 xy) { | |
| float tmp = lux.eval(xy * 0.4).r; | |
| float4 rgba = image.eval(xy); | |
| float3 linear = rgba.rgb * tmp; | |
| return float4(linear, rgba.a); | |
| } | |
| )"); | |
| static const SkString kStretchEffectCode(R"( | |
| uniform shader image; | |
| vec4 main(vec2 xy) { | |
| float4 rgba = image.eval(0.5 * xy); | |
| return rgba; | |
| } | |
| )"); | |
| static const SkString kBoxShadowEffectCode(R"( | |
| vec4 main(vec2 xy) { | |
| return float4(.5, .7, .9, .95); | |
| } | |
| )"); | |
| #define M(id) f##id = makeEffect(k##id##Code, "RE_" #id); | |
| SK_ALL_ANDROID_KNOWN_EFFECTS(M) | |
| #undef M | |
| } | |
| namespace { | |
| SkString to_str(ui::Dataspace ds) { | |
| switch (ds) { | |
| case ui::Dataspace::UNKNOWN: return SkString("UNKNOWN"); | |
| case ui::Dataspace::SRGB: return SkString("SRGB"); | |
| case ui::Dataspace::BT2020: return SkString("BT2020"); | |
| case ui::Dataspace::BT2020_ITU_PQ: return SkString("BT2020_ITU_PQ"); | |
| case ui::Dataspace::BT2020_HLG: return SkString("BT2020_HLG"); | |
| case ui::Dataspace::DISPLAY_P3: return SkString("DISPLAY_P3"); | |
| case ui::Dataspace::V0_SRGB: return SkString("V0_SRGB"); | |
| } | |
| return SkStringPrintf("0x%x", static_cast<uint32_t>(ds)); | |
| } | |
| const char* to_str(shaders::LinearEffect::SkSLType type) { | |
| switch (type) { | |
| case shaders::LinearEffect::SkSLType::Shader: return "Shader"; | |
| case shaders::LinearEffect::SkSLType::ColorFilter: return "ColorFilter"; | |
| } | |
| SkUNREACHABLE; | |
| } | |
| } // anonymous namespace | |
| sk_sp<SkRuntimeEffect> RuntimeEffectManager::getOrCreateLinearRuntimeEffect( | |
| const shaders::LinearEffect& linearEffect) { | |
| SkString name = SkStringPrintf("RE_LinearEffect_%s__%s__%s__%s__%s", | |
| to_str(linearEffect.inputDataspace).c_str(), | |
| to_str(linearEffect.outputDataspace).c_str(), | |
| linearEffect.undoPremultipliedAlpha ? "true" : "false", | |
| to_str(linearEffect.fakeOutputDataspace).c_str(), | |
| to_str(linearEffect.type)); | |
| auto result = fLinearEffects.find(name.c_str()); | |
| if (result != fLinearEffects.end()) { | |
| return result->second; | |
| } | |
| // Each code snippet must be unique, otherwise Skia will internally find a match | |
| // and uniquify things. To avoid this we just add an arbitrary alpha constant | |
| // to the code. | |
| static float arbitraryAlpha = 0.051f; | |
| SkString linearEffectCode = SkStringPrintf( | |
| "uniform shader child;" | |
| "vec4 main(vec2 xy) {" | |
| "float3 linear = child.eval(xy).rgb;" | |
| "return float4(linear, %f);" | |
| "}", | |
| arbitraryAlpha); | |
| arbitraryAlpha += 0.05f; | |
| sk_sp<SkRuntimeEffect> effect = makeEffect(linearEffectCode, name.c_str()); | |
| fLinearEffects.insert({ name.c_str(), effect }); | |
| return effect; | |
| } |