blob: 3d0bd1618621453ef8473e1ef9a0e3a375c1fbf2 [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"
Michael Ludwig898bbfa2019-08-02 15:21:23 -040021#include "include/effects/SkImageFilters.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050022#include "include/effects/SkTableColorFilter.h"
23#include "include/gpu/GrContext.h"
kkinnunendc0f4082015-01-26 00:14:26 -080024
mtkleindbfd7ab2016-09-01 11:24:54 -070025constexpr int kTestRectSize = 50;
26constexpr int kDetectorGreenValue = 50;
kkinnunendc0f4082015-01-26 00:14:26 -080027
28// Below are few functions to install "detector" color filters. The filter is there to assert that
29// the color value it sees is the expected. It will trigger only with kDetectorGreenValue, and
30// turn that value into full green. The idea is that if an optimization incorrectly changes
31// kDetectorGreenValue and then the incorrect value is observable by some part of the drawing
32// pipeline, that pixel will remain empty.
33
reedd053ce92016-03-22 10:17:23 -070034static sk_sp<SkColorFilter> make_detector_color_filter() {
kkinnunendc0f4082015-01-26 00:14:26 -080035 uint8_t tableA[256] = { 0, };
36 uint8_t tableR[256] = { 0, };
37 uint8_t tableG[256] = { 0, };
38 uint8_t tableB[256] = { 0, };
39 tableA[255] = 255;
40 tableG[kDetectorGreenValue] = 255;
reedd053ce92016-03-22 10:17:23 -070041 return SkTableColorFilter::MakeARGB(tableA, tableR, tableG, tableB);
kkinnunendc0f4082015-01-26 00:14:26 -080042}
43
44// This detector detects that color filter phase of the pixel pipeline receives the correct value.
45static void install_detector_color_filter(SkPaint* drawPaint) {
reedd053ce92016-03-22 10:17:23 -070046 drawPaint->setColorFilter(make_detector_color_filter());
kkinnunendc0f4082015-01-26 00:14:26 -080047}
48
49// This detector detects that image filter phase of the pixel pipeline receives the correct value.
50static void install_detector_image_filter(SkPaint* drawPaint) {
Michael Ludwig898bbfa2019-08-02 15:21:23 -040051 drawPaint->setImageFilter(SkImageFilters::ColorFilter(
52 make_detector_color_filter(), drawPaint->refImageFilter()));
kkinnunendc0f4082015-01-26 00:14:26 -080053}
54
55static void no_detector_install(SkPaint*) {
56}
57
58typedef void(*InstallDetectorFunc)(SkPaint*);
59
60
61// Draws an pattern that can be optimized by alpha folding outer savelayer alpha value to
62// inner draw. Since we know that folding will happen to the inner draw, install a detector
63// to make sure that optimization does not change anything observable.
64static void draw_save_layer_draw_rect_restore_sequence(SkCanvas* canvas, SkColor shapeColor,
65 InstallDetectorFunc installDetector) {
66 SkRect targetRect(SkRect::MakeWH(SkIntToScalar(kTestRectSize), SkIntToScalar(kTestRectSize)));
67 SkPaint layerPaint;
68 layerPaint.setColor(SkColorSetARGB(128, 0, 0, 0));
69 canvas->saveLayer(&targetRect, &layerPaint);
70 SkPaint drawPaint;
71 drawPaint.setColor(shapeColor);
72 installDetector(&drawPaint);
73 canvas->drawRect(targetRect, drawPaint);
74 canvas->restore();
75}
76
77// Draws an pattern that can be optimized by alpha folding outer savelayer alpha value to
78// inner draw. A variant where the draw is not uniform color.
79static void draw_save_layer_draw_bitmap_restore_sequence(SkCanvas* canvas, SkColor shapeColor,
80 InstallDetectorFunc installDetector) {
81 SkBitmap bitmap;
82 bitmap.allocN32Pixels(kTestRectSize, kTestRectSize);
83 bitmap.eraseColor(shapeColor);
84 {
85 // Make the bitmap non-uniform color, so that it can not be optimized as uniform drawRect.
86 SkCanvas canvas(bitmap);
87 SkPaint p;
88 p.setColor(SK_ColorWHITE);
89 SkASSERT(shapeColor != SK_ColorWHITE);
90 canvas.drawRect(SkRect::MakeWH(SkIntToScalar(7), SkIntToScalar(7)), p);
kkinnunendc0f4082015-01-26 00:14:26 -080091 }
92
93 SkRect targetRect(SkRect::MakeWH(SkIntToScalar(kTestRectSize), SkIntToScalar(kTestRectSize)));
94 SkPaint layerPaint;
95 layerPaint.setColor(SkColorSetARGB(129, 0, 0, 0));
96 canvas->saveLayer(&targetRect, &layerPaint);
97 SkPaint drawPaint;
98 installDetector(&drawPaint);
99 canvas->drawBitmap(bitmap, SkIntToScalar(0), SkIntToScalar(0), &drawPaint);
100 canvas->restore();
101}
102
103// Draws an pattern that can be optimized by alpha folding outer savelayer alpha value to
104// inner savelayer. We know that alpha folding happens to inner savelayer, so add detector there.
105static void draw_svg_opacity_and_filter_layer_sequence(SkCanvas* canvas, SkColor shapeColor,
106 InstallDetectorFunc installDetector) {
107
108 SkRect targetRect(SkRect::MakeWH(SkIntToScalar(kTestRectSize), SkIntToScalar(kTestRectSize)));
reedca2622b2016-03-18 07:25:55 -0700109 sk_sp<SkPicture> shape;
kkinnunendc0f4082015-01-26 00:14:26 -0800110 {
111 SkPictureRecorder recorder;
112 SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kTestRectSize + 2),
113 SkIntToScalar(kTestRectSize + 2));
114 SkPaint shapePaint;
115 shapePaint.setColor(shapeColor);
116 canvas->drawRect(targetRect, shapePaint);
reedca2622b2016-03-18 07:25:55 -0700117 shape = recorder.finishRecordingAsPicture();
kkinnunendc0f4082015-01-26 00:14:26 -0800118 }
119
120 SkPaint layerPaint;
121 layerPaint.setColor(SkColorSetARGB(130, 0, 0, 0));
122 canvas->saveLayer(&targetRect, &layerPaint);
123 canvas->save();
124 canvas->clipRect(targetRect);
125 SkPaint drawPaint;
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400126 drawPaint.setImageFilter(SkImageFilters::Picture(shape));
kkinnunendc0f4082015-01-26 00:14:26 -0800127 installDetector(&drawPaint);
128 canvas->saveLayer(&targetRect, &drawPaint);
129 canvas->restore();
130 canvas->restore();
131 canvas->restore();
132}
133
134// Draws two columns of rectangles. The test is correct when:
135// - Left and right columns always identical
136// - First 3 rows are green, with a white dent in the middle row
137// - Next 6 rows are green, with a grey dent in the middle row
138// (the grey dent is from the color filter removing everything but the "good" green, see below)
139// - Last 6 rows are grey
140DEF_SIMPLE_GM(recordopts, canvas, (kTestRectSize+1)*2, (kTestRectSize+1)*15) {
Robert Phillips9882dae2019-03-04 11:00:10 -0500141 GrContext* context = canvas->getGrContext();
kkinnunendc0f4082015-01-26 00:14:26 -0800142 canvas->clear(SK_ColorTRANSPARENT);
143
144 typedef void (*TestVariantSequence)(SkCanvas*, SkColor, InstallDetectorFunc);
145 TestVariantSequence funcs[] = {
146 draw_save_layer_draw_rect_restore_sequence,
147 draw_save_layer_draw_bitmap_restore_sequence,
148 draw_svg_opacity_and_filter_layer_sequence,
149 };
150
151 // Draw layer-related sequences that can be optimized by folding the opacity layer alpha to
152 // the inner draw operation. This tries to trigger the optimization, and relies on gm diffs
153 // to keep the color value correct over time.
154
155 // Draws two green rects side by side: one is without the optimization, the other is with
156 // the optimization applied.
157
158 SkColor shapeColor = SkColorSetARGB(255, 0, 255, 0);
159 for (size_t k = 0; k < SK_ARRAY_COUNT(funcs); ++k) {
160 canvas->save();
161
162 TestVariantSequence drawTestSequence = funcs[k];
163 drawTestSequence(canvas, shapeColor, no_detector_install);
Robert Phillips9882dae2019-03-04 11:00:10 -0500164 if (context) {
165 context->flush();
166 }
kkinnunendc0f4082015-01-26 00:14:26 -0800167 canvas->translate(SkIntToScalar(kTestRectSize) + SkIntToScalar(1), SkIntToScalar(0));
168 {
169 SkPictureRecorder recorder;
170 drawTestSequence(recorder.beginRecording(SkIntToScalar(kTestRectSize),
171 SkIntToScalar(kTestRectSize)),
172 shapeColor, no_detector_install);
reedca2622b2016-03-18 07:25:55 -0700173 recorder.finishRecordingAsPicture()->playback(canvas);
Robert Phillips9882dae2019-03-04 11:00:10 -0500174 if (context) {
175 context->flush();
176 }
kkinnunendc0f4082015-01-26 00:14:26 -0800177 }
178 canvas->restore();
179 canvas->translate(SkIntToScalar(0), SkIntToScalar(kTestRectSize) + SkIntToScalar(1));
180 }
181
182 // Draw the same layer related sequences, but manipulate the sequences so that the result is
183 // incorrect if the alpha is folded or folded incorrectly. These test the observable state
184 // throughout the pixel pipeline, and thus may turn off the optimizations (this is why we
185 // trigger the optimizations above).
186
187 // Draws two green rects side by side: one is without the optimization, the other is with
188 // the possibility that optimization is applied.
189 // At the end, draws the same patterns in translucent black. This tests that the detectors
190 // work, eg. that if the value the detector sees is wrong, the resulting image shows this.
191 SkColor shapeColors[] = {
192 SkColorSetARGB(255, 0, kDetectorGreenValue, 0),
robertphillipsb644e9a2015-01-26 05:39:26 -0800193 SkColorSetARGB(255, 0, (kDetectorGreenValue + 1), 0) // This tests that detectors work.
kkinnunendc0f4082015-01-26 00:14:26 -0800194 };
195
196 InstallDetectorFunc detectorInstallFuncs[] = {
197 install_detector_image_filter,
198 install_detector_color_filter
199 };
200
201 for (size_t i = 0; i < SK_ARRAY_COUNT(shapeColors); ++i) {
202 shapeColor = shapeColors[i];
brianosman42a41492016-06-23 11:40:14 -0700203 for (size_t j = 0; j < SK_ARRAY_COUNT(detectorInstallFuncs); ++j) {
kkinnunendc0f4082015-01-26 00:14:26 -0800204 InstallDetectorFunc detectorInstallFunc = detectorInstallFuncs[j];
205 for (size_t k = 0; k < SK_ARRAY_COUNT(funcs); ++k) {
206 TestVariantSequence drawTestSequence = funcs[k];
207 canvas->save();
208 drawTestSequence(canvas, shapeColor, detectorInstallFunc);
Robert Phillips9882dae2019-03-04 11:00:10 -0500209 if (context) {
210 context->flush();
211 }
kkinnunendc0f4082015-01-26 00:14:26 -0800212 canvas->translate(SkIntToScalar(kTestRectSize) + SkIntToScalar(1), SkIntToScalar(0));
213 {
214 SkPictureRecorder recorder;
215 drawTestSequence(recorder.beginRecording(SkIntToScalar(kTestRectSize),
216 SkIntToScalar(kTestRectSize)),
217 shapeColor, detectorInstallFunc);
reedca2622b2016-03-18 07:25:55 -0700218 recorder.finishRecordingAsPicture()->playback(canvas);
Robert Phillips9882dae2019-03-04 11:00:10 -0500219 if (context) {
220 context->flush();
221 }
kkinnunendc0f4082015-01-26 00:14:26 -0800222 }
223
224 canvas->restore();
225 canvas->translate(SkIntToScalar(0), SkIntToScalar(kTestRectSize) + SkIntToScalar(1));
226 }
227
228 }
229 }
230}