blob: 58577020a15ce01104b051200ed8e68ee66c2fdf [file] [log] [blame]
Ethan Nicholasa70693b2019-03-04 13:07:36 -05001/*
2 * Copyright 2019 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
9#include "include/core/SkCanvas.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040010#include "include/core/SkColorFilter.h"
11#include "include/core/SkData.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "include/core/SkImage.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040013#include "include/core/SkPaint.h"
14#include "include/core/SkRefCnt.h"
15#include "include/core/SkSize.h"
16#include "include/core/SkString.h"
Brian Osmanee426f22020-01-02 11:55:24 -050017#include "include/effects/SkRuntimeEffect.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "tools/Resources.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040019
20#include <stddef.h>
21#include <utility>
22
Mike Kleina0f54522020-10-14 16:31:36 -050023const char* gNoop = R"(
Brian Osman91292e92020-11-04 15:40:50 -050024 uniform shader input;
Mike Kleina0f54522020-10-14 16:31:36 -050025 half4 main() {
26 return sample(input);
27 }
28)";
29
Brian Osman5240e182020-08-12 10:22:34 -040030const char* gLumaSrc = R"(
Brian Osman91292e92020-11-04 15:40:50 -050031 uniform shader input;
Brian Osman767f4442020-08-13 16:59:48 -040032 half4 main() {
33 return dot(sample(input).rgb, half3(0.3, 0.6, 0.1)).000r;
Ethan Nicholasa70693b2019-03-04 13:07:36 -050034 }
35)";
36
Brian Osman5240e182020-08-12 10:22:34 -040037const char* gLumaSrcWithCoords = R"(
Brian Osman91292e92020-11-04 15:40:50 -050038 uniform shader input;
Brian Osman767f4442020-08-13 16:59:48 -040039 half4 main(float2 p) {
40 return dot(sample(input).rgb, half3(0.3, 0.6, 0.1)).000r;
Brian Osman5240e182020-08-12 10:22:34 -040041 }
42)";
43
Mike Kleina0f54522020-10-14 16:31:36 -050044// Build up the same effect with increasingly complex control flow syntax.
45// All of these are semantically equivalent and can be reduced in principle to one basic block.
46
47// Simplest to run; hardest to write?
48const char* gTernary = R"(
Brian Osman91292e92020-11-04 15:40:50 -050049 uniform shader input;
Mike Klein7485ffc2020-10-14 14:05:50 -050050 half4 main() {
51 half4 color = sample(input);
Mike Kleina0f54522020-10-14 16:31:36 -050052 half luma = dot(color.rgb, half3(0.3, 0.6, 0.1));
Mike Klein7485ffc2020-10-14 14:05:50 -050053
Mike Kleina0f54522020-10-14 16:31:36 -050054 half scale = luma < 0.33333 ? 0.5
55 : luma < 0.66666 ? (0.166666 + 2.0 * (luma - 0.33333)) / luma
56 : /* else */ (0.833333 + 0.5 * (luma - 0.66666)) / luma;
57 return half4(color.rgb * scale, color.a);
58 }
59)";
60
61// Uses conditional if statements but no early return.
62const char* gIfs = R"(
Brian Osman91292e92020-11-04 15:40:50 -050063 uniform shader input;
Mike Kleina0f54522020-10-14 16:31:36 -050064 half4 main() {
65 half4 color = sample(input);
Mike Klein7485ffc2020-10-14 14:05:50 -050066 half luma = dot(color.rgb, half3(0.3, 0.6, 0.1));
67
68 half scale = 0;
Mike Kleina0f54522020-10-14 16:31:36 -050069 if (luma < 0.33333) {
70 scale = 0.5;
71 } else if (luma < 0.66666) {
72 scale = (0.166666 + 2.0 * (luma - 0.33333)) / luma;
73 } else {
74 scale = (0.833333 + 0.5 * (luma - 0.66666)) / luma;
75 }
76 return half4(color.rgb * scale, color.a);
77 }
78)";
Mike Klein7485ffc2020-10-14 14:05:50 -050079
Mike Kleina0f54522020-10-14 16:31:36 -050080// Distilled from AOSP tone mapping shaders, more like what people tend to write.
81const char* gEarlyReturn = R"(
Brian Osman91292e92020-11-04 15:40:50 -050082 uniform shader input;
Mike Kleina0f54522020-10-14 16:31:36 -050083 half4 main() {
84 half4 color = sample(input);
85 half luma = dot(color.rgb, half3(0.3, 0.6, 0.1));
86
87 half scale = 0;
Mike Klein7485ffc2020-10-14 14:05:50 -050088 if (luma < 0.33333) {
89 return half4(color.rgb * 0.5, color.a);
90 } else if (luma < 0.66666) {
91 scale = 0.166666 + 2.0 * (luma - 0.33333);
92 } else {
93 scale = 0.833333 + 0.5 * (luma - 0.66666);
94 }
Mike Klein7485ffc2020-10-14 14:05:50 -050095 return half4(color.rgb * (scale/luma), color.a);
96 }
97)";
98
99
Mike Kleina0f54522020-10-14 16:31:36 -0500100DEF_SIMPLE_GM(runtimecolorfilter, canvas, 256 * 3, 256 * 2) {
101 sk_sp<SkImage> img = GetResourceAsImage("images/mandrill_256.png");
Ethan Nicholasa70693b2019-03-04 13:07:36 -0500102
Mike Kleina0f54522020-10-14 16:31:36 -0500103 auto draw_filter = [&](const char* src) {
104 auto [effect, err] = SkRuntimeEffect::Make(SkString(src));
105 if (!effect) {
106 SkDebugf("%s\n%s\n", src, err.c_str());
107 }
Ethan Nicholas63d7ee32020-08-17 10:57:12 -0400108 SkASSERT(effect);
Brian Osman5240e182020-08-12 10:22:34 -0400109 SkPaint p;
Brian Osman767f4442020-08-13 16:59:48 -0400110 sk_sp<SkColorFilter> input = nullptr;
111 p.setColorFilter(effect->makeColorFilter(nullptr, &input, 1));
Brian Osman5240e182020-08-12 10:22:34 -0400112 canvas->drawImage(img, 0, 0, &p);
Mike Kleina0f54522020-10-14 16:31:36 -0500113 canvas->translate(256, 0);
114 };
115
116 for (const char* src : { gNoop, gLumaSrc, gLumaSrcWithCoords}) {
117 draw_filter(src);
118 }
119 canvas->translate(-256*3, 256);
120 for (const char* src : { gTernary, gIfs, gEarlyReturn}) {
121 draw_filter(src);
Brian Osman5240e182020-08-12 10:22:34 -0400122 }
Ethan Nicholasa70693b2019-03-04 13:07:36 -0500123}