1 /*
2 * Copyright 2016 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 "include/core/SkBitmap.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColor.h"
11 #include "include/core/SkColorSpace.h"
12 #include "include/core/SkImageInfo.h"
13 #include "include/core/SkPaint.h"
14 #include "include/core/SkRect.h"
15 #include "include/core/SkRefCnt.h"
16 #include "include/core/SkSurface.h"
17 #include "include/core/SkTypes.h"
18 #include "include/gpu/GrBackendSurface.h"
19 #include "include/gpu/GrContext.h"
20 #include "include/gpu/GrContextOptions.h"
21 #include "include/private/GrTypesPriv.h"
22 #include "include/private/SkColorData.h"
23 #include "src/core/SkAutoPixmapStorage.h"
24 #include "src/gpu/GrCaps.h"
25 #include "src/gpu/GrColor.h"
26 #include "src/gpu/GrContextPriv.h"
27 #include "src/gpu/GrRenderTargetContext.h"
28 #include "tests/Test.h"
29 #include "tools/gpu/GrContextFactory.h"
30
31 #include <cstdint>
32 #include <cstring>
33 #include <memory>
34
check_rect(GrRenderTargetContext * rtc,const SkIRect & rect,uint32_t expectedValue,uint32_t * actualValue,int * failX,int * failY)35 static bool check_rect(GrRenderTargetContext* rtc, const SkIRect& rect, uint32_t expectedValue,
36 uint32_t* actualValue, int* failX, int* failY) {
37 int w = rect.width();
38 int h = rect.height();
39
40 SkImageInfo dstInfo = SkImageInfo::Make(w, h, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
41
42 SkAutoPixmapStorage readback;
43 readback.alloc(dstInfo);
44
45 readback.erase(~expectedValue);
46 if (!rtc->readPixels(readback.info(), readback.writable_addr(), readback.rowBytes(),
47 {rect.fLeft, rect.fTop})) {
48 return false;
49 }
50
51 for (int y = 0; y < h; ++y) {
52 for (int x = 0; x < w; ++x) {
53 uint32_t pixel = readback.addr32()[y * w + x];
54 if (pixel != expectedValue) {
55 *actualValue = pixel;
56 *failX = x + rect.fLeft;
57 *failY = y + rect.fTop;
58 return false;
59 }
60 }
61 }
62 return true;
63 }
64
newRTC(GrContext * context,int w,int h)65 sk_sp<GrRenderTargetContext> newRTC(GrContext* context, int w, int h) {
66 return context->priv().makeDeferredRenderTargetContext(SkBackingFit::kExact, w, h,
67 GrColorType::kRGBA_8888, nullptr);
68 }
69
clear_op_test(skiatest::Reporter * reporter,GrContext * context)70 static void clear_op_test(skiatest::Reporter* reporter, GrContext* context) {
71 static const int kW = 10;
72 static const int kH = 10;
73
74 SkIRect fullRect = SkIRect::MakeWH(kW, kH);
75 sk_sp<GrRenderTargetContext> rtContext;
76
77 // A rectangle that is inset by one on all sides and the 1-pixel wide rectangles that surround
78 // it.
79 SkIRect mid1Rect = SkIRect::MakeXYWH(1, 1, kW-2, kH-2);
80 SkIRect outerLeftEdge = SkIRect::MakeXYWH(0, 0, 1, kH);
81 SkIRect outerTopEdge = SkIRect::MakeXYWH(0, 0, kW, 1);
82 SkIRect outerRightEdge = SkIRect::MakeXYWH(kW-1, 0, 1, kH);
83 SkIRect outerBottomEdge = SkIRect::MakeXYWH(0, kH-1, kW, 1);
84
85 // A rectangle that is inset by two on all sides and the 1-pixel wide rectangles that surround
86 // it.
87 SkIRect mid2Rect = SkIRect::MakeXYWH(2, 2, kW-4, kH-4);
88 SkIRect innerLeftEdge = SkIRect::MakeXYWH(1, 1, 1, kH-2);
89 SkIRect innerTopEdge = SkIRect::MakeXYWH(1, 1, kW-2, 1);
90 SkIRect innerRightEdge = SkIRect::MakeXYWH(kW-2, 1, 1, kH-2);
91 SkIRect innerBottomEdge = SkIRect::MakeXYWH(1, kH-2, kW-2, 1);
92
93 uint32_t actualValue;
94 int failX, failY;
95
96 static const GrColor kColor1 = 0xABCDEF01;
97 static const GrColor kColor2 = ~kColor1;
98 static const SkPMColor4f kColor1f = SkPMColor4f::FromBytes_RGBA(kColor1);
99 static const SkPMColor4f kColor2f = SkPMColor4f::FromBytes_RGBA(kColor2);
100
101 rtContext = newRTC(context, kW, kH);
102 SkASSERT(rtContext);
103
104 // Check a full clear
105 rtContext->clear(&fullRect, kColor1f, GrRenderTargetContext::CanClearFullscreen::kNo);
106 if (!check_rect(rtContext.get(), fullRect, kColor1, &actualValue, &failX, &failY)) {
107 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
108 failX, failY);
109 }
110
111 rtContext = newRTC(context, kW, kH);
112 SkASSERT(rtContext);
113
114 // Check two full clears, same color
115 rtContext->clear(&fullRect, kColor1f, GrRenderTargetContext::CanClearFullscreen::kNo);
116 rtContext->clear(&fullRect, kColor1f, GrRenderTargetContext::CanClearFullscreen::kNo);
117 if (!check_rect(rtContext.get(), fullRect, kColor1, &actualValue, &failX, &failY)) {
118 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
119 failX, failY);
120 }
121
122 rtContext = newRTC(context, kW, kH);
123 SkASSERT(rtContext);
124
125 // Check two full clears, different colors
126 rtContext->clear(&fullRect, kColor1f, GrRenderTargetContext::CanClearFullscreen::kNo);
127 rtContext->clear(&fullRect, kColor2f, GrRenderTargetContext::CanClearFullscreen::kNo);
128 if (!check_rect(rtContext.get(), fullRect, kColor2, &actualValue, &failX, &failY)) {
129 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor2, actualValue,
130 failX, failY);
131 }
132
133 rtContext = newRTC(context, kW, kH);
134 SkASSERT(rtContext);
135
136 // Test a full clear followed by a same color inset clear
137 rtContext->clear(&fullRect, kColor1f, GrRenderTargetContext::CanClearFullscreen::kNo);
138 rtContext->clear(&mid1Rect, kColor1f, GrRenderTargetContext::CanClearFullscreen::kNo);
139 if (!check_rect(rtContext.get(), fullRect, kColor1, &actualValue, &failX, &failY)) {
140 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
141 failX, failY);
142 }
143
144 rtContext = newRTC(context, kW, kH);
145 SkASSERT(rtContext);
146
147 // Test a inset clear followed by same color full clear
148 rtContext->clear(&mid1Rect, kColor1f, GrRenderTargetContext::CanClearFullscreen::kNo);
149 rtContext->clear(&fullRect, kColor1f, GrRenderTargetContext::CanClearFullscreen::kNo);
150 if (!check_rect(rtContext.get(), fullRect, kColor1, &actualValue, &failX, &failY)) {
151 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
152 failX, failY);
153 }
154
155 rtContext = newRTC(context, kW, kH);
156 SkASSERT(rtContext);
157
158 // Test a full clear followed by a different color inset clear
159 rtContext->clear(&fullRect, kColor1f, GrRenderTargetContext::CanClearFullscreen::kNo);
160 rtContext->clear(&mid1Rect, kColor2f, GrRenderTargetContext::CanClearFullscreen::kNo);
161 if (!check_rect(rtContext.get(), mid1Rect, kColor2, &actualValue, &failX, &failY)) {
162 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor2, actualValue,
163 failX, failY);
164 }
165 if (!check_rect(rtContext.get(), outerLeftEdge, kColor1, &actualValue, &failX, &failY) ||
166 !check_rect(rtContext.get(), outerTopEdge, kColor1, &actualValue, &failX, &failY) ||
167 !check_rect(rtContext.get(), outerRightEdge, kColor1, &actualValue, &failX, &failY) ||
168 !check_rect(rtContext.get(), outerBottomEdge, kColor1, &actualValue, &failX, &failY)) {
169 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
170 failX, failY);
171 }
172
173 rtContext = newRTC(context, kW, kH);
174 SkASSERT(rtContext);
175
176 // Test a inset clear followed by a different full clear
177 rtContext->clear(&mid1Rect, kColor2f, GrRenderTargetContext::CanClearFullscreen::kNo);
178 rtContext->clear(&fullRect, kColor1f, GrRenderTargetContext::CanClearFullscreen::kNo);
179 if (!check_rect(rtContext.get(), fullRect, kColor1, &actualValue, &failX, &failY)) {
180 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
181 failX, failY);
182 }
183
184 rtContext = newRTC(context, kW, kH);
185 SkASSERT(rtContext);
186
187 // Check three nested clears from largest to smallest where outermost and innermost are same
188 // color.
189 rtContext->clear(&fullRect, kColor1f, GrRenderTargetContext::CanClearFullscreen::kNo);
190 rtContext->clear(&mid1Rect, kColor2f, GrRenderTargetContext::CanClearFullscreen::kNo);
191 rtContext->clear(&mid2Rect, kColor1f, GrRenderTargetContext::CanClearFullscreen::kNo);
192 if (!check_rect(rtContext.get(), mid2Rect, kColor1, &actualValue, &failX, &failY)) {
193 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
194 failX, failY);
195 }
196 if (!check_rect(rtContext.get(), innerLeftEdge, kColor2, &actualValue, &failX, &failY) ||
197 !check_rect(rtContext.get(), innerTopEdge, kColor2, &actualValue, &failX, &failY) ||
198 !check_rect(rtContext.get(), innerRightEdge, kColor2, &actualValue, &failX, &failY) ||
199 !check_rect(rtContext.get(), innerBottomEdge, kColor2, &actualValue, &failX, &failY)) {
200 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor2, actualValue,
201 failX, failY);
202 }
203 if (!check_rect(rtContext.get(), outerLeftEdge, kColor1, &actualValue, &failX, &failY) ||
204 !check_rect(rtContext.get(), outerTopEdge, kColor1, &actualValue, &failX, &failY) ||
205 !check_rect(rtContext.get(), outerRightEdge, kColor1, &actualValue, &failX, &failY) ||
206 !check_rect(rtContext.get(), outerBottomEdge, kColor1, &actualValue, &failX, &failY)) {
207 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
208 failX, failY);
209 }
210
211 rtContext = newRTC(context, kW, kH);
212 SkASSERT(rtContext);
213
214 // Swap the order of the second two clears in the above test.
215 rtContext->clear(&fullRect, kColor1f, GrRenderTargetContext::CanClearFullscreen::kNo);
216 rtContext->clear(&mid2Rect, kColor1f, GrRenderTargetContext::CanClearFullscreen::kNo);
217 rtContext->clear(&mid1Rect, kColor2f, GrRenderTargetContext::CanClearFullscreen::kNo);
218 if (!check_rect(rtContext.get(), mid1Rect, kColor2, &actualValue, &failX, &failY)) {
219 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor2, actualValue,
220 failX, failY);
221 }
222 if (!check_rect(rtContext.get(), outerLeftEdge, kColor1, &actualValue, &failX, &failY) ||
223 !check_rect(rtContext.get(), outerTopEdge, kColor1, &actualValue, &failX, &failY) ||
224 !check_rect(rtContext.get(), outerRightEdge, kColor1, &actualValue, &failX, &failY) ||
225 !check_rect(rtContext.get(), outerBottomEdge, kColor1, &actualValue, &failX, &failY)) {
226 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
227 failX, failY);
228 }
229 }
230
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ClearOp,reporter,ctxInfo)231 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ClearOp, reporter, ctxInfo) {
232 // Regular clear
233 clear_op_test(reporter, ctxInfo.grContext());
234
235 // Force drawing for clears
236 GrContextOptions options(ctxInfo.options());
237 options.fUseDrawInsteadOfClear = GrContextOptions::Enable::kYes;
238 sk_gpu_test::GrContextFactory workaroundFactory(options);
239 clear_op_test(reporter, workaroundFactory.get(ctxInfo.type()));
240 }
241
fullscreen_clear_with_layer_test(skiatest::Reporter * reporter,GrContext * context)242 void fullscreen_clear_with_layer_test(skiatest::Reporter* reporter, GrContext* context) {
243 const SkImageInfo ii = SkImageInfo::Make(400, 77, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
244
245 sk_sp<SkSurface> surf = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, ii);
246 SkCanvas* canvas = surf->getCanvas();
247
248 SkPaint paints[2];
249 paints[0].setColor(SK_ColorGREEN);
250 paints[1].setColor(SK_ColorGRAY);
251
252 static const int kLeftX = 158;
253 static const int kMidX = 258;
254 static const int kRightX = 383;
255 static const int kTopY = 26;
256 static const int kBotY = 51;
257
258 const SkRect rects[2] = {
259 { kLeftX, kTopY, kMidX, kBotY },
260 { kMidX, kTopY, kRightX, kBotY },
261 };
262
263 for (int i = 0; i < 2; ++i) {
264 // the bounds parameter is required to cause a full screen clear
265 canvas->saveLayer(&rects[i], nullptr);
266 canvas->drawRect(rects[i], paints[i]);
267 canvas->restore();
268 }
269
270 SkBitmap bm;
271 bm.allocPixels(ii, 0);
272
273 SkAssertResult(surf->readPixels(bm, 0, 0));
274
275 bool isCorrect = true;
276 for (int y = kTopY; isCorrect && y < kBotY; ++y) {
277 const uint32_t* sl = bm.getAddr32(0, y);
278
279 for (int x = kLeftX; x < kMidX; ++x) {
280 if (SK_ColorGREEN != sl[x]) {
281 isCorrect = false;
282 break;
283 }
284 }
285
286 for (int x = kMidX; x < kRightX; ++x) {
287 if (SK_ColorGRAY != sl[x]) {
288 isCorrect = false;
289 break;
290 }
291 }
292 }
293
294 REPORTER_ASSERT(reporter, isCorrect);
295 }
296 // From crbug.com/768134
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(FullScreenClearWithLayers,reporter,ctxInfo)297 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(FullScreenClearWithLayers, reporter, ctxInfo) {
298 // Regular clear
299 fullscreen_clear_with_layer_test(reporter, ctxInfo.grContext());
300
301 // Use draws for clears
302 GrContextOptions options(ctxInfo.options());
303 options.fUseDrawInsteadOfClear = GrContextOptions::Enable::kYes;
304 sk_gpu_test::GrContextFactory workaroundFactory(options);
305 fullscreen_clear_with_layer_test(reporter, workaroundFactory.get(ctxInfo.type()));
306 }
307