// Copyright 2024 Google LLC. // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. #include "tools/fiddle/examples.h" REG_FIDDLE(SkSL_RawImageShaders, 384, 128, false, 0) { static sk_sp make_image(sk_sp effect, const SkImageInfo& info) { sk_sp surface = SkSurfaces::Raster(info); SkCanvas* canvas = surface->getCanvas(); auto shader = effect->makeShader(/*uniforms=*/ nullptr, /*children=*/ {}); if (!shader) { return nullptr; } SkPaint paint; paint.setShader(std::move(shader)); paint.setBlendMode(SkBlendMode::kSrc); canvas->drawPaint(paint); return surface->makeImageSnapshot(); } void draw(SkCanvas* canvas) { // Make a hemispherical normal map image: auto imageInfo = SkImageInfo::MakeN32Premul(128, 128); auto imageShader = SkRuntimeEffect::MakeForShader(SkString(R"( vec4 main(vec2 p) { p = (p / 128) * 2 - 1; float len2 = dot(p, p); vec3 v = (len2 > 1) ? vec3(0, 0, 1) : vec3(p, sqrt(1 - len2)); return (v * 0.5 + 0.5).xyz1; })")).effect; auto normalImage = make_image(imageShader, imageInfo); // Make a simple lighting effect: auto litEffect = SkRuntimeEffect::MakeForShader(SkString(R"( uniform shader normals; vec4 main(vec2 p) { vec3 n = normalize(normals.eval(p).xyz * 2 - 1); vec3 l = normalize(vec3(-1, -1, 0.5)); return saturate(dot(n, l)).xxx1; })")).effect; SkRuntimeShaderBuilder builder(litEffect); SkPaint paint; // FIRST: Draw the lighting to our (not color managed) canvas. // This is our CORRECT, reference result: builder.child("normals") = normalImage->makeShader(SkSamplingOptions{}); paint.setShader(builder.makeShader()); canvas->drawRect({0,0,128,128}, paint); // Make an offscreen surface with a wide gamut: auto rec2020 = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kRec2020); auto info = SkImageInfo::Make(128, 128, kRGBA_F16_SkColorType, kPremul_SkAlphaType, rec2020); auto surface = SkSurfaces::Raster(info); // SECOND: Draw the lighting to the offscreen surface. Color management // changes the normals, producing INCORRECT (wrong direction) lighting: surface->getCanvas()->drawPaint(paint); canvas->drawImage(surface->makeImageSnapshot(), 128, 0); // THIRD: Convert the normals to a raw image shader. This ignores color // management for that image, so we get CORRECT lighting again: builder.child("normals") = normalImage->makeRawShader(SkSamplingOptions{}); paint.setShader(builder.makeShader()); surface->getCanvas()->drawPaint(paint); canvas->drawImage(surface->makeImageSnapshot(), 256, 0); } } // END FIDDLE