|  | // 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<SkImage> make_image(sk_sp<SkRuntimeEffect> effect, | 
|  | const SkImageInfo& info) { | 
|  | sk_sp<SkSurface> 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 |