blob: 83e30cf5f28c9cb96bc4e6e5fe4ddfe75acde7d1 [file] [log] [blame]
kkinnunendc0f4082015-01-26 00:14:26 -08001/*
2 * Copyright 2014 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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -04009#include "include/core/SkBitmap.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkCanvas.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040011#include "include/core/SkColor.h"
12#include "include/core/SkColorFilter.h"
13#include "include/core/SkImageFilter.h"
14#include "include/core/SkPaint.h"
15#include "include/core/SkPicture.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "include/core/SkPictureRecorder.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040017#include "include/core/SkRect.h"
18#include "include/core/SkRefCnt.h"
19#include "include/core/SkScalar.h"
20#include "include/core/SkTypes.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "include/effects/SkColorFilterImageFilter.h"
22#include "include/effects/SkPictureImageFilter.h"
23#include "include/effects/SkTableColorFilter.h"
24#include "include/gpu/GrContext.h"
kkinnunendc0f4082015-01-26 00:14:26 -080025
mtkleindbfd7ab2016-09-01 11:24:54 -070026constexpr int kTestRectSize = 50;
27constexpr int kDetectorGreenValue = 50;
kkinnunendc0f4082015-01-26 00:14:26 -080028
29// Below are few functions to install "detector" color filters. The filter is there to assert that
30// the color value it sees is the expected. It will trigger only with kDetectorGreenValue, and
31// turn that value into full green. The idea is that if an optimization incorrectly changes
32// kDetectorGreenValue and then the incorrect value is observable by some part of the drawing
33// pipeline, that pixel will remain empty.
34
reedd053ce92016-03-22 10:17:23 -070035static sk_sp<SkColorFilter> make_detector_color_filter() {
kkinnunendc0f4082015-01-26 00:14:26 -080036 uint8_t tableA[256] = { 0, };
37 uint8_t tableR[256] = { 0, };
38 uint8_t tableG[256] = { 0, };
39 uint8_t tableB[256] = { 0, };
40 tableA[255] = 255;
41 tableG[kDetectorGreenValue] = 255;
reedd053ce92016-03-22 10:17:23 -070042 return SkTableColorFilter::MakeARGB(tableA, tableR, tableG, tableB);
kkinnunendc0f4082015-01-26 00:14:26 -080043}
44
45// This detector detects that color filter phase of the pixel pipeline receives the correct value.
46static void install_detector_color_filter(SkPaint* drawPaint) {
reedd053ce92016-03-22 10:17:23 -070047 drawPaint->setColorFilter(make_detector_color_filter());
kkinnunendc0f4082015-01-26 00:14:26 -080048}
49
50// This detector detects that image filter phase of the pixel pipeline receives the correct value.
51static void install_detector_image_filter(SkPaint* drawPaint) {
Mike Reed693fdbd2017-01-12 10:13:40 -050052 drawPaint->setImageFilter(SkColorFilterImageFilter::Make(make_detector_color_filter(),
53 drawPaint->refImageFilter()));
kkinnunendc0f4082015-01-26 00:14:26 -080054}
55
56static void no_detector_install(SkPaint*) {
57}
58
59typedef void(*InstallDetectorFunc)(SkPaint*);
60
61
62// Draws an pattern that can be optimized by alpha folding outer savelayer alpha value to
63// inner draw. Since we know that folding will happen to the inner draw, install a detector
64// to make sure that optimization does not change anything observable.
65static void draw_save_layer_draw_rect_restore_sequence(SkCanvas* canvas, SkColor shapeColor,
66 InstallDetectorFunc installDetector) {
67 SkRect targetRect(SkRect::MakeWH(SkIntToScalar(kTestRectSize), SkIntToScalar(kTestRectSize)));
68 SkPaint layerPaint;
69 layerPaint.setColor(SkColorSetARGB(128, 0, 0, 0));
70 canvas->saveLayer(&targetRect, &layerPaint);
71 SkPaint drawPaint;
72 drawPaint.setColor(shapeColor);
73 installDetector(&drawPaint);
74 canvas->drawRect(targetRect, drawPaint);
75 canvas->restore();
76}
77
78// Draws an pattern that can be optimized by alpha folding outer savelayer alpha value to
79// inner draw. A variant where the draw is not uniform color.
80static void draw_save_layer_draw_bitmap_restore_sequence(SkCanvas* canvas, SkColor shapeColor,
81 InstallDetectorFunc installDetector) {
82 SkBitmap bitmap;
83 bitmap.allocN32Pixels(kTestRectSize, kTestRectSize);
84 bitmap.eraseColor(shapeColor);
85 {
86 // Make the bitmap non-uniform color, so that it can not be optimized as uniform drawRect.
87 SkCanvas canvas(bitmap);
88 SkPaint p;
89 p.setColor(SK_ColorWHITE);
90 SkASSERT(shapeColor != SK_ColorWHITE);
91 canvas.drawRect(SkRect::MakeWH(SkIntToScalar(7), SkIntToScalar(7)), p);
kkinnunendc0f4082015-01-26 00:14:26 -080092 }
93
94 SkRect targetRect(SkRect::MakeWH(SkIntToScalar(kTestRectSize), SkIntToScalar(kTestRectSize)));
95 SkPaint layerPaint;
96 layerPaint.setColor(SkColorSetARGB(129, 0, 0, 0));
97 canvas->saveLayer(&targetRect, &layerPaint);
98 SkPaint drawPaint;
99 installDetector(&drawPaint);
100 canvas->drawBitmap(bitmap, SkIntToScalar(0), SkIntToScalar(0), &drawPaint);
101 canvas->restore();
102}
103
104// Draws an pattern that can be optimized by alpha folding outer savelayer alpha value to
105// inner savelayer. We know that alpha folding happens to inner savelayer, so add detector there.
106static void draw_svg_opacity_and_filter_layer_sequence(SkCanvas* canvas, SkColor shapeColor,
107 InstallDetectorFunc installDetector) {
108
109 SkRect targetRect(SkRect::MakeWH(SkIntToScalar(kTestRectSize), SkIntToScalar(kTestRectSize)));
reedca2622b2016-03-18 07:25:55 -0700110 sk_sp<SkPicture> shape;
kkinnunendc0f4082015-01-26 00:14:26 -0800111 {
112 SkPictureRecorder recorder;
113 SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kTestRectSize + 2),
114 SkIntToScalar(kTestRectSize + 2));
115 SkPaint shapePaint;
116 shapePaint.setColor(shapeColor);
117 canvas->drawRect(targetRect, shapePaint);
reedca2622b2016-03-18 07:25:55 -0700118 shape = recorder.finishRecordingAsPicture();
kkinnunendc0f4082015-01-26 00:14:26 -0800119 }
120
121 SkPaint layerPaint;
122 layerPaint.setColor(SkColorSetARGB(130, 0, 0, 0));
123 canvas->saveLayer(&targetRect, &layerPaint);
124 canvas->save();
125 canvas->clipRect(targetRect);
126 SkPaint drawPaint;
robertphillips5ff17b12016-03-28 13:13:42 -0700127 drawPaint.setImageFilter(SkPictureImageFilter::Make(shape));
kkinnunendc0f4082015-01-26 00:14:26 -0800128 installDetector(&drawPaint);
129 canvas->saveLayer(&targetRect, &drawPaint);
130 canvas->restore();
131 canvas->restore();
132 canvas->restore();
133}
134
135// Draws two columns of rectangles. The test is correct when:
136// - Left and right columns always identical
137// - First 3 rows are green, with a white dent in the middle row
138// - Next 6 rows are green, with a grey dent in the middle row
139// (the grey dent is from the color filter removing everything but the "good" green, see below)
140// - Last 6 rows are grey
141DEF_SIMPLE_GM(recordopts, canvas, (kTestRectSize+1)*2, (kTestRectSize+1)*15) {
Robert Phillips9882dae2019-03-04 11:00:10 -0500142 GrContext* context = canvas->getGrContext();
kkinnunendc0f4082015-01-26 00:14:26 -0800143 canvas->clear(SK_ColorTRANSPARENT);
144
145 typedef void (*TestVariantSequence)(SkCanvas*, SkColor, InstallDetectorFunc);
146 TestVariantSequence funcs[] = {
147 draw_save_layer_draw_rect_restore_sequence,
148 draw_save_layer_draw_bitmap_restore_sequence,
149 draw_svg_opacity_and_filter_layer_sequence,
150 };
151
152 // Draw layer-related sequences that can be optimized by folding the opacity layer alpha to
153 // the inner draw operation. This tries to trigger the optimization, and relies on gm diffs
154 // to keep the color value correct over time.
155
156 // Draws two green rects side by side: one is without the optimization, the other is with
157 // the optimization applied.
158
159 SkColor shapeColor = SkColorSetARGB(255, 0, 255, 0);
160 for (size_t k = 0; k < SK_ARRAY_COUNT(funcs); ++k) {
161 canvas->save();
162
163 TestVariantSequence drawTestSequence = funcs[k];
164 drawTestSequence(canvas, shapeColor, no_detector_install);
Robert Phillips9882dae2019-03-04 11:00:10 -0500165 if (context) {
166 context->flush();
167 }
kkinnunendc0f4082015-01-26 00:14:26 -0800168 canvas->translate(SkIntToScalar(kTestRectSize) + SkIntToScalar(1), SkIntToScalar(0));
169 {
170 SkPictureRecorder recorder;
171 drawTestSequence(recorder.beginRecording(SkIntToScalar(kTestRectSize),
172 SkIntToScalar(kTestRectSize)),
173 shapeColor, no_detector_install);
reedca2622b2016-03-18 07:25:55 -0700174 recorder.finishRecordingAsPicture()->playback(canvas);
Robert Phillips9882dae2019-03-04 11:00:10 -0500175 if (context) {
176 context->flush();
177 }
kkinnunendc0f4082015-01-26 00:14:26 -0800178 }
179 canvas->restore();
180 canvas->translate(SkIntToScalar(0), SkIntToScalar(kTestRectSize) + SkIntToScalar(1));
181 }
182
183 // Draw the same layer related sequences, but manipulate the sequences so that the result is
184 // incorrect if the alpha is folded or folded incorrectly. These test the observable state
185 // throughout the pixel pipeline, and thus may turn off the optimizations (this is why we
186 // trigger the optimizations above).
187
188 // Draws two green rects side by side: one is without the optimization, the other is with
189 // the possibility that optimization is applied.
190 // At the end, draws the same patterns in translucent black. This tests that the detectors
191 // work, eg. that if the value the detector sees is wrong, the resulting image shows this.
192 SkColor shapeColors[] = {
193 SkColorSetARGB(255, 0, kDetectorGreenValue, 0),
robertphillipsb644e9a2015-01-26 05:39:26 -0800194 SkColorSetARGB(255, 0, (kDetectorGreenValue + 1), 0) // This tests that detectors work.
kkinnunendc0f4082015-01-26 00:14:26 -0800195 };
196
197 InstallDetectorFunc detectorInstallFuncs[] = {
198 install_detector_image_filter,
199 install_detector_color_filter
200 };
201
202 for (size_t i = 0; i < SK_ARRAY_COUNT(shapeColors); ++i) {
203 shapeColor = shapeColors[i];
brianosman42a41492016-06-23 11:40:14 -0700204 for (size_t j = 0; j < SK_ARRAY_COUNT(detectorInstallFuncs); ++j) {
kkinnunendc0f4082015-01-26 00:14:26 -0800205 InstallDetectorFunc detectorInstallFunc = detectorInstallFuncs[j];
206 for (size_t k = 0; k < SK_ARRAY_COUNT(funcs); ++k) {
207 TestVariantSequence drawTestSequence = funcs[k];
208 canvas->save();
209 drawTestSequence(canvas, shapeColor, detectorInstallFunc);
Robert Phillips9882dae2019-03-04 11:00:10 -0500210 if (context) {
211 context->flush();
212 }
kkinnunendc0f4082015-01-26 00:14:26 -0800213 canvas->translate(SkIntToScalar(kTestRectSize) + SkIntToScalar(1), SkIntToScalar(0));
214 {
215 SkPictureRecorder recorder;
216 drawTestSequence(recorder.beginRecording(SkIntToScalar(kTestRectSize),
217 SkIntToScalar(kTestRectSize)),
218 shapeColor, detectorInstallFunc);
reedca2622b2016-03-18 07:25:55 -0700219 recorder.finishRecordingAsPicture()->playback(canvas);
Robert Phillips9882dae2019-03-04 11:00:10 -0500220 if (context) {
221 context->flush();
222 }
kkinnunendc0f4082015-01-26 00:14:26 -0800223 }
224
225 canvas->restore();
226 canvas->translate(SkIntToScalar(0), SkIntToScalar(kTestRectSize) + SkIntToScalar(1));
227 }
228
229 }
230 }
231}