blob: f6b4a9ceeddc55b29e7cac59cc4406676ee298d0 [file] [log] [blame]
brianosmane5824b92016-02-26 11:57:23 -08001/*
2 * Copyright 2015 Google Inc.
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
8#include "gm.h"
9
10#include "Resources.h"
11#include "SkGradientShader.h"
reed6644d932016-06-10 11:41:47 -070012#include "SkPM4fPriv.h"
brianosmane5824b92016-02-26 11:57:23 -080013
brianosman490452e2016-09-13 08:24:56 -070014DEF_SIMPLE_GM(gamma, canvas, 850, 200) {
brianosmane5824b92016-02-26 11:57:23 -080015 SkPaint p;
16 const SkScalar sz = 50.0f;
17 const int szInt = SkScalarTruncToInt(sz);
brianosman7a99a0a2016-08-30 07:08:07 -070018 const SkScalar tx = sz + 15.0f;
brianosmane5824b92016-02-26 11:57:23 -080019 const SkRect r = SkRect::MakeXYWH(0, 0, sz, sz);
20 SkShader::TileMode rpt = SkShader::kRepeat_TileMode;
brianosman52ede1d2016-06-20 08:25:02 -070021 auto srgbColorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
brianosmane5824b92016-02-26 11:57:23 -080022
23 SkBitmap ditherBmp;
24 ditherBmp.allocN32Pixels(2, 2);
25 SkPMColor* pixels = reinterpret_cast<SkPMColor*>(ditherBmp.getPixels());
26 pixels[0] = pixels[3] = SkPackARGB32(0xFF, 0xFF, 0xFF, 0xFF);
27 pixels[1] = pixels[2] = SkPackARGB32(0xFF, 0, 0, 0);
28
29 SkBitmap linearGreyBmp;
brianosman52ede1d2016-06-20 08:25:02 -070030 SkImageInfo linearGreyInfo = SkImageInfo::MakeN32(szInt, szInt, kOpaque_SkAlphaType, nullptr);
brianosmane5824b92016-02-26 11:57:23 -080031 linearGreyBmp.allocPixels(linearGreyInfo);
32 linearGreyBmp.eraseARGB(0xFF, 0x7F, 0x7F, 0x7F);
33
34 SkBitmap srgbGreyBmp;
35 SkImageInfo srgbGreyInfo = SkImageInfo::MakeN32(szInt, szInt, kOpaque_SkAlphaType,
brianosman52ede1d2016-06-20 08:25:02 -070036 srgbColorSpace);
brianosmane5824b92016-02-26 11:57:23 -080037 srgbGreyBmp.allocPixels(srgbGreyInfo);
brianosman33f6b3f2016-06-02 05:49:21 -070038 // 0xBC = 255 * linear_to_srgb(0.5f)
brianosmane5824b92016-02-26 11:57:23 -080039 srgbGreyBmp.eraseARGB(0xFF, 0xBC, 0xBC, 0xBC);
40
brianosman33f6b3f2016-06-02 05:49:21 -070041 SkBitmap mipmapBmp;
reed6644d932016-06-10 11:41:47 -070042 SkImageInfo mipmapInfo = SkImageInfo::Make(2, 2, kN32_SkColorType, kOpaque_SkAlphaType,
brianosman52ede1d2016-06-20 08:25:02 -070043 srgbColorSpace);
brianosman33f6b3f2016-06-02 05:49:21 -070044 mipmapBmp.allocPixels(mipmapInfo);
45 SkPMColor* mipmapPixels = reinterpret_cast<SkPMColor*>(mipmapBmp.getPixels());
reed6644d932016-06-10 11:41:47 -070046 unsigned s25 = 0x89; // 255 * linear_to_srgb(0.25f)
47 unsigned s75 = 0xE1; // 255 * linear_to_srgb(0.75f)
48 mipmapPixels[0] = mipmapPixels[3] = SkPackARGB32(0xFF, s25, s25, s25);
49 mipmapPixels[1] = mipmapPixels[2] = SkPackARGB32(0xFF, s75, s75, s75);
brianosman33f6b3f2016-06-02 05:49:21 -070050
brianosmane5824b92016-02-26 11:57:23 -080051 SkPaint textPaint;
brianosman7a99a0a2016-08-30 07:08:07 -070052 textPaint.setAntiAlias(true);
brianosmane5824b92016-02-26 11:57:23 -080053 textPaint.setColor(SK_ColorWHITE);
brianosman7a99a0a2016-08-30 07:08:07 -070054 sk_tool_utils::set_portable_typeface(&textPaint);
brianosmane5824b92016-02-26 11:57:23 -080055
56 // Helpers:
57 auto advance = [&]() {
58 canvas->translate(tx, 0);
59 p.reset();
60 };
61
62 auto nextRect = [&](const char* label, const char* label2) {
63 canvas->drawRect(r, p);
64 canvas->drawText(label, strlen(label), 0, sz + textPaint.getFontSpacing(), textPaint);
65 if (label2) {
66 canvas->drawText(label2, strlen(label2), 0, sz + 2 * textPaint.getFontSpacing(),
67 textPaint);
68 }
69 advance();
70 };
71
72 auto nextBitmap = [&](const SkBitmap& bmp, const char* label) {
73 canvas->drawBitmap(bmp, 0, 0);
74 canvas->drawText(label, strlen(label), 0, sz + textPaint.getFontSpacing(), textPaint);
75 advance();
76 };
77
78 auto nextXferRect = [&](SkColor srcColor, SkXfermode::Mode mode, SkColor dstColor) {
79 p.setColor(dstColor);
80 canvas->drawRect(r, p);
81 p.setColor(srcColor);
82 p.setXfermodeMode(mode);
83 canvas->drawRect(r, p);
84
85 SkString srcText = SkStringPrintf("%08X", srcColor);
86 SkString dstText = SkStringPrintf("%08X", dstColor);
87 canvas->drawText(srcText.c_str(), srcText.size(), 0, sz + textPaint.getFontSpacing(),
88 textPaint);
89 const char* modeName = SkXfermode::ModeName(mode);
90 canvas->drawText(modeName, strlen(modeName), 0, sz + 2 * textPaint.getFontSpacing(),
91 textPaint);
92 canvas->drawText(dstText.c_str(), dstText.size(), 0, sz + 3 * textPaint.getFontSpacing(),
93 textPaint);
94 advance();
95 };
96
97 // Necessary for certain Xfermode tests to work (ie some of them output white @ 50% alpha):
98 canvas->clear(SK_ColorBLACK);
99
100 // *Everything* should be perceptually 50% grey. Only the first rectangle
101 // is guaranteed to draw that way, though.
102 canvas->save();
103
104 // Black/white dither, pixel perfect. This is ground truth.
reed2ad1aa62016-03-09 09:50:50 -0800105 p.setShader(SkShader::MakeBitmapShader(ditherBmp, rpt, rpt));
brianosmane5824b92016-02-26 11:57:23 -0800106 p.setFilterQuality(SkFilterQuality::kNone_SkFilterQuality);
107 nextRect("Dither", "Reference");
108
109 // Black/white dither, sampled at half-texel offset. Tests bilerp.
110 // NOTE: We need to apply a non-identity scale and/or rotation to trick
111 // the raster pipeline into *not* snapping to nearest.
112 SkMatrix offsetMatrix = SkMatrix::Concat(
113 SkMatrix::MakeScale(-1.0f), SkMatrix::MakeTrans(0.5f, 0.0f));
reed2ad1aa62016-03-09 09:50:50 -0800114 p.setShader(SkShader::MakeBitmapShader(ditherBmp, rpt, rpt, &offsetMatrix));
brianosmane5824b92016-02-26 11:57:23 -0800115 p.setFilterQuality(SkFilterQuality::kMedium_SkFilterQuality);
116 nextRect("Dither", "Bilerp");
117
118 // Black/white dither, scaled down by 2x. Tests minification.
119 SkMatrix scaleMatrix = SkMatrix::MakeScale(0.5f);
reed2ad1aa62016-03-09 09:50:50 -0800120 p.setShader(SkShader::MakeBitmapShader(ditherBmp, rpt, rpt, &scaleMatrix));
brianosmane5824b92016-02-26 11:57:23 -0800121 p.setFilterQuality(SkFilterQuality::kMedium_SkFilterQuality);
122 nextRect("Dither", "Scale");
123
brianosman33f6b3f2016-06-02 05:49:21 -0700124 // 25%/75% dither, scaled down by 2x. Tests ALL aspects of minification. Specifically, are
125 // sRGB sources decoded to linear before computing mipmaps?
126 p.setShader(SkShader::MakeBitmapShader(mipmapBmp, rpt, rpt, &scaleMatrix));
127 p.setFilterQuality(SkFilterQuality::kMedium_SkFilterQuality);
128 nextRect("MipMaps", 0);
129
brianosman7a99a0a2016-08-30 07:08:07 -0700130 // 50% grey via paint color. Paint color (SkColor) is specified to be sRGB!
131 p.setColor(0xffbcbcbc);
brianosmane5824b92016-02-26 11:57:23 -0800132 nextRect("Color", 0);
133
brianosman490452e2016-09-13 08:24:56 -0700134 {
135 // Black -> White gradient, scaled to sample just the middle.
136 // Tests gradient interpolation.
137 SkPoint points[2] = {
138 SkPoint::Make(0 - (sz * 10), 0),
139 SkPoint::Make(sz + (sz * 10), 0)
140 };
141 SkColor colors[2] = { SK_ColorBLACK, SK_ColorWHITE };
142 p.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 2,
143 SkShader::kClamp_TileMode));
144 nextRect("Gradient", "Interpolation");
145 }
146
147 {
148 // Shallow gradient around 50% (perceptual) gray. Endpoints are SkColor, so sRGB.
149 // Tests gamma-correction of gradient stops before interpolation in two-stop case
150 SkPoint points[2] = {
151 SkPoint::Make(0, 0),
152 SkPoint::Make(sz, 0)
153 };
154 SkColor colors[2] = { 0xffbbbbbb, 0xffbdbdbd };
155 p.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 2,
156 SkShader::kClamp_TileMode));
157 nextRect("Gradient", "Endpoints");
158 }
159
160 {
161 // Shallow 3-stop gradient around 50% (perceptual) gray. Endpoints are SkColor, so sRGB.
162 // Tests gamma-correction of gradient stops before interpolation in three-stop case
163 SkPoint points[2] = {
164 SkPoint::Make(0, 0),
165 SkPoint::Make(sz, 0)
166 };
167 SkColor colors[3] = { 0xffbbbbbb, 0xffbdbdbd, 0xffbbbbbb };
168 p.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 3,
169 SkShader::kClamp_TileMode));
170 nextRect("Gradient", "3-Stop");
171 }
172
173 {
174 // Shallow N-stop gradient around 50% (perceptual) gray. Endpoints are SkColor, so sRGB.
175 // Tests gamma-correction of gradient stops before interpolation in texture implementation
176 SkPoint points[2] = {
177 SkPoint::Make(0, 0),
178 SkPoint::Make(sz, 0)
179 };
180 SkColor colors[5] = { 0xffbbbbbb, 0xffbdbdbd, 0xffbbbbbb, 0xffbdbdbd, 0xffbbbbbb };
181 p.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 5,
182 SkShader::kClamp_TileMode));
183 nextRect("Gradient", "Texture");
184 }
brianosmane5824b92016-02-26 11:57:23 -0800185
186 // 50% grey from linear bitmap, with drawBitmap
187 nextBitmap(linearGreyBmp, "Lnr BMP");
188
189 // 50% grey from sRGB bitmap, with drawBitmap
190 nextBitmap(srgbGreyBmp, "sRGB BMP");
191
192 // Bitmap wrapped in a shader (linear):
reed2ad1aa62016-03-09 09:50:50 -0800193 p.setShader(SkShader::MakeBitmapShader(linearGreyBmp, rpt, rpt));
brianosmane5824b92016-02-26 11:57:23 -0800194 p.setFilterQuality(SkFilterQuality::kMedium_SkFilterQuality);
195 nextRect("Lnr BMP", "Shader");
196
197 // Bitmap wrapped in a shader (sRGB):
reed2ad1aa62016-03-09 09:50:50 -0800198 p.setShader(SkShader::MakeBitmapShader(srgbGreyBmp, rpt, rpt));
brianosmane5824b92016-02-26 11:57:23 -0800199 p.setFilterQuality(SkFilterQuality::kMedium_SkFilterQuality);
200 nextRect("sRGB BMP", "Shader");
201
202 // Carriage return.
203 canvas->restore();
204 canvas->translate(0, 2 * sz);
205
brianosmane5824b92016-02-26 11:57:23 -0800206 // Xfermode tests, all done off-screen so certain modes work...
207
208 canvas->saveLayer(nullptr, nullptr);
209
210 nextXferRect(0x7fffffff, SkXfermode::kSrcOver_Mode, SK_ColorBLACK);
211 nextXferRect(0x7f000000, SkXfermode::kSrcOver_Mode, SK_ColorWHITE);
212
213 nextXferRect(SK_ColorBLACK, SkXfermode::kDstOver_Mode, 0x7fffffff);
214 nextXferRect(SK_ColorWHITE, SkXfermode::kSrcIn_Mode, 0x7fff00ff);
215 nextXferRect(0x7fff00ff, SkXfermode::kDstIn_Mode, SK_ColorWHITE);
brianosmane5824b92016-02-26 11:57:23 -0800216
brianosman7a99a0a2016-08-30 07:08:07 -0700217 // 0x89 = 255 * linear_to_srgb(0.25)
218 nextXferRect(0xff898989, SkXfermode::kPlus_Mode, 0xff898989);
219
220 // 0xDB = 255 * linear_to_srgb(sqrt(0.5))
221 nextXferRect(0xffdbdbdb, SkXfermode::kModulate_Mode, 0xffdbdbdb);
brianosmane5824b92016-02-26 11:57:23 -0800222
223 canvas->restore();
brianosmane5824b92016-02-26 11:57:23 -0800224}