blob: 1110fddbd25a18155f77d386c0bb3c6ff5a09aad [file] [log] [blame]
bsalomone63ffef2016-02-05 07:17:34 -08001/*
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
Ben Wagnerb607a8f2018-03-12 13:46:21 -04008#include "SkTypes.h"
Ben Wagner1a462bd2018-03-12 13:46:21 -04009
Ben Wagner501c17c2018-03-12 20:04:31 +000010#if SK_SUPPORT_GPU
Ben Wagnerb607a8f2018-03-12 13:46:21 -040011#include "GrColor.h"
Ben Wagner501c17c2018-03-12 20:04:31 +000012#include "GrContext.h"
Ben Wagnerb607a8f2018-03-12 13:46:21 -040013#include "GrContextFactory.h"
14#include "GrContextOptions.h"
15#include "GrContextPriv.h"
Ben Wagner501c17c2018-03-12 20:04:31 +000016#include "GrRenderTargetContext.h"
Ben Wagnerb607a8f2018-03-12 13:46:21 -040017#include "GrTypes.h"
18#include "SkBitmap.h"
Ben Wagner501c17c2018-03-12 20:04:31 +000019#include "SkCanvas.h"
Ben Wagnerb607a8f2018-03-12 13:46:21 -040020#include "SkColor.h"
21#include "SkColorSpace.h"
22#include "SkImageInfo.h"
23#include "SkPaint.h"
24#include "SkRect.h"
25#include "SkRefCnt.h"
Ben Wagner501c17c2018-03-12 20:04:31 +000026#include "SkSurface.h"
Ben Wagnerb607a8f2018-03-12 13:46:21 -040027#include "Test.h"
28
29#include <cstring>
30#include <memory>
Robert Phillipsdbfecd02017-10-18 15:44:08 -040031
Brian Osman11052242016-10-27 14:47:55 -040032static bool check_rect(GrRenderTargetContext* rtc, const SkIRect& rect, uint32_t expectedValue,
bsalomone63ffef2016-02-05 07:17:34 -080033 uint32_t* actualValue, int* failX, int* failY) {
bsalomone63ffef2016-02-05 07:17:34 -080034 int w = rect.width();
35 int h = rect.height();
Ben Wagner7ecc5962016-11-02 17:07:33 -040036 std::unique_ptr<uint32_t[]> pixels(new uint32_t[w * h]);
bsalomone63ffef2016-02-05 07:17:34 -080037 memset(pixels.get(), ~expectedValue, sizeof(uint32_t) * w * h);
Robert Phillips301431d2017-03-29 12:08:49 -040038
39 SkImageInfo dstInfo = SkImageInfo::Make(w, h, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
40
41 if (!rtc->readPixels(dstInfo, pixels.get(), 0, rect.fLeft, rect.fTop)) {
42 return false;
43 }
44
bsalomone63ffef2016-02-05 07:17:34 -080045 for (int y = 0; y < h; ++y) {
46 for (int x = 0; x < w; ++x) {
47 uint32_t pixel = pixels.get()[y * w + x];
48 if (pixel != expectedValue) {
49 *actualValue = pixel;
50 *failX = x + rect.fLeft;
51 *failY = y + rect.fTop;
52 return false;
53 }
54 }
55 }
56 return true;
57}
58
Robert Phillipse4d45bf2017-06-02 14:53:40 -040059sk_sp<GrRenderTargetContext> newRTC(GrContext* context, int w, int h) {
Robert Phillips0c4b7b12018-03-06 08:20:37 -050060 return context->contextPriv().makeDeferredRenderTargetContext(
61 SkBackingFit::kExact, w, h,
62 kRGBA_8888_GrPixelConfig, nullptr);
bsalomone63ffef2016-02-05 07:17:34 -080063}
64
Brian Salomon43f8bf02017-10-18 08:33:29 -040065static void clear_op_test(skiatest::Reporter* reporter, GrContext* context) {
bsalomone63ffef2016-02-05 07:17:34 -080066 static const int kW = 10;
67 static const int kH = 10;
68
69 SkIRect fullRect = SkIRect::MakeWH(kW, kH);
Brian Osman11052242016-10-27 14:47:55 -040070 sk_sp<GrRenderTargetContext> rtContext;
bsalomone63ffef2016-02-05 07:17:34 -080071
72 // A rectangle that is inset by one on all sides and the 1-pixel wide rectangles that surround
73 // it.
74 SkIRect mid1Rect = SkIRect::MakeXYWH(1, 1, kW-2, kH-2);
75 SkIRect outerLeftEdge = SkIRect::MakeXYWH(0, 0, 1, kH);
76 SkIRect outerTopEdge = SkIRect::MakeXYWH(0, 0, kW, 1);
77 SkIRect outerRightEdge = SkIRect::MakeXYWH(kW-1, 0, 1, kH);
78 SkIRect outerBottomEdge = SkIRect::MakeXYWH(0, kH-1, kW, 1);
79
80 // A rectangle that is inset by two on all sides and the 1-pixel wide rectangles that surround
81 // it.
82 SkIRect mid2Rect = SkIRect::MakeXYWH(2, 2, kW-4, kH-4);
83 SkIRect innerLeftEdge = SkIRect::MakeXYWH(1, 1, 1, kH-2);
84 SkIRect innerTopEdge = SkIRect::MakeXYWH(1, 1, kW-2, 1);
85 SkIRect innerRightEdge = SkIRect::MakeXYWH(kW-2, 1, 1, kH-2);
86 SkIRect innerBottomEdge = SkIRect::MakeXYWH(1, kH-2, kW-2, 1);
87
88 uint32_t actualValue;
89 int failX, failY;
90
91 static const GrColor kColor1 = 0xABCDEF01;
92 static const GrColor kColor2 = ~kColor1;
93
Robert Phillipse4d45bf2017-06-02 14:53:40 -040094 rtContext = newRTC(context, kW, kH);
95 SkASSERT(rtContext);
96
bsalomone63ffef2016-02-05 07:17:34 -080097 // Check a full clear
Chris Dalton344e9032017-12-11 15:42:09 -070098 rtContext->clear(&fullRect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
Brian Osman11052242016-10-27 14:47:55 -040099 if (!check_rect(rtContext.get(), fullRect, kColor1, &actualValue, &failX, &failY)) {
bsalomone63ffef2016-02-05 07:17:34 -0800100 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
101 failX, failY);
102 }
103
Robert Phillipse4d45bf2017-06-02 14:53:40 -0400104 rtContext = newRTC(context, kW, kH);
105 SkASSERT(rtContext);
106
bsalomone63ffef2016-02-05 07:17:34 -0800107 // Check two full clears, same color
Chris Dalton344e9032017-12-11 15:42:09 -0700108 rtContext->clear(&fullRect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
109 rtContext->clear(&fullRect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
Brian Osman11052242016-10-27 14:47:55 -0400110 if (!check_rect(rtContext.get(), fullRect, kColor1, &actualValue, &failX, &failY)) {
bsalomone63ffef2016-02-05 07:17:34 -0800111 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
112 failX, failY);
113 }
114
Robert Phillipse4d45bf2017-06-02 14:53:40 -0400115 rtContext = newRTC(context, kW, kH);
116 SkASSERT(rtContext);
117
bsalomone63ffef2016-02-05 07:17:34 -0800118 // Check two full clears, different colors
Chris Dalton344e9032017-12-11 15:42:09 -0700119 rtContext->clear(&fullRect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
120 rtContext->clear(&fullRect, kColor2, GrRenderTargetContext::CanClearFullscreen::kNo);
Brian Osman11052242016-10-27 14:47:55 -0400121 if (!check_rect(rtContext.get(), fullRect, kColor2, &actualValue, &failX, &failY)) {
bsalomone63ffef2016-02-05 07:17:34 -0800122 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor2, actualValue,
123 failX, failY);
124 }
125
Robert Phillipse4d45bf2017-06-02 14:53:40 -0400126 rtContext = newRTC(context, kW, kH);
127 SkASSERT(rtContext);
128
bsalomone63ffef2016-02-05 07:17:34 -0800129 // Test a full clear followed by a same color inset clear
Chris Dalton344e9032017-12-11 15:42:09 -0700130 rtContext->clear(&fullRect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
131 rtContext->clear(&mid1Rect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
Brian Osman11052242016-10-27 14:47:55 -0400132 if (!check_rect(rtContext.get(), fullRect, kColor1, &actualValue, &failX, &failY)) {
bsalomone63ffef2016-02-05 07:17:34 -0800133 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
134 failX, failY);
135 }
136
Robert Phillipse4d45bf2017-06-02 14:53:40 -0400137 rtContext = newRTC(context, kW, kH);
138 SkASSERT(rtContext);
139
bsalomone63ffef2016-02-05 07:17:34 -0800140 // Test a inset clear followed by same color full clear
Chris Dalton344e9032017-12-11 15:42:09 -0700141 rtContext->clear(&mid1Rect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
142 rtContext->clear(&fullRect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
Brian Osman11052242016-10-27 14:47:55 -0400143 if (!check_rect(rtContext.get(), fullRect, kColor1, &actualValue, &failX, &failY)) {
bsalomone63ffef2016-02-05 07:17:34 -0800144 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
145 failX, failY);
146 }
147
Robert Phillipse4d45bf2017-06-02 14:53:40 -0400148 rtContext = newRTC(context, kW, kH);
149 SkASSERT(rtContext);
150
bsalomone63ffef2016-02-05 07:17:34 -0800151 // Test a full clear followed by a different color inset clear
Chris Dalton344e9032017-12-11 15:42:09 -0700152 rtContext->clear(&fullRect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
153 rtContext->clear(&mid1Rect, kColor2, GrRenderTargetContext::CanClearFullscreen::kNo);
Brian Osman11052242016-10-27 14:47:55 -0400154 if (!check_rect(rtContext.get(), mid1Rect, kColor2, &actualValue, &failX, &failY)) {
bsalomone63ffef2016-02-05 07:17:34 -0800155 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor2, actualValue,
156 failX, failY);
157 }
Brian Osman11052242016-10-27 14:47:55 -0400158 if (!check_rect(rtContext.get(), outerLeftEdge, kColor1, &actualValue, &failX, &failY) ||
159 !check_rect(rtContext.get(), outerTopEdge, kColor1, &actualValue, &failX, &failY) ||
160 !check_rect(rtContext.get(), outerRightEdge, kColor1, &actualValue, &failX, &failY) ||
161 !check_rect(rtContext.get(), outerBottomEdge, kColor1, &actualValue, &failX, &failY)) {
bsalomone63ffef2016-02-05 07:17:34 -0800162 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
163 failX, failY);
164 }
165
Robert Phillipse4d45bf2017-06-02 14:53:40 -0400166 rtContext = newRTC(context, kW, kH);
167 SkASSERT(rtContext);
168
bsalomone63ffef2016-02-05 07:17:34 -0800169 // Test a inset clear followed by a different full clear
Chris Dalton344e9032017-12-11 15:42:09 -0700170 rtContext->clear(&mid1Rect, kColor2, GrRenderTargetContext::CanClearFullscreen::kNo);
171 rtContext->clear(&fullRect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
Brian Osman11052242016-10-27 14:47:55 -0400172 if (!check_rect(rtContext.get(), fullRect, kColor1, &actualValue, &failX, &failY)) {
bsalomone63ffef2016-02-05 07:17:34 -0800173 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
174 failX, failY);
175 }
176
Robert Phillipse4d45bf2017-06-02 14:53:40 -0400177 rtContext = newRTC(context, kW, kH);
178 SkASSERT(rtContext);
179
bsalomone63ffef2016-02-05 07:17:34 -0800180 // Check three nested clears from largest to smallest where outermost and innermost are same
181 // color.
Chris Dalton344e9032017-12-11 15:42:09 -0700182 rtContext->clear(&fullRect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
183 rtContext->clear(&mid1Rect, kColor2, GrRenderTargetContext::CanClearFullscreen::kNo);
184 rtContext->clear(&mid2Rect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
Brian Osman11052242016-10-27 14:47:55 -0400185 if (!check_rect(rtContext.get(), mid2Rect, kColor1, &actualValue, &failX, &failY)) {
bsalomone63ffef2016-02-05 07:17:34 -0800186 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
187 failX, failY);
188 }
Brian Osman11052242016-10-27 14:47:55 -0400189 if (!check_rect(rtContext.get(), innerLeftEdge, kColor2, &actualValue, &failX, &failY) ||
190 !check_rect(rtContext.get(), innerTopEdge, kColor2, &actualValue, &failX, &failY) ||
191 !check_rect(rtContext.get(), innerRightEdge, kColor2, &actualValue, &failX, &failY) ||
192 !check_rect(rtContext.get(), innerBottomEdge, kColor2, &actualValue, &failX, &failY)) {
bsalomone63ffef2016-02-05 07:17:34 -0800193 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor2, actualValue,
194 failX, failY);
195 }
Brian Osman11052242016-10-27 14:47:55 -0400196 if (!check_rect(rtContext.get(), outerLeftEdge, kColor1, &actualValue, &failX, &failY) ||
197 !check_rect(rtContext.get(), outerTopEdge, kColor1, &actualValue, &failX, &failY) ||
198 !check_rect(rtContext.get(), outerRightEdge, kColor1, &actualValue, &failX, &failY) ||
199 !check_rect(rtContext.get(), outerBottomEdge, kColor1, &actualValue, &failX, &failY)) {
bsalomone63ffef2016-02-05 07:17:34 -0800200 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
201 failX, failY);
202 }
203
Robert Phillipse4d45bf2017-06-02 14:53:40 -0400204 rtContext = newRTC(context, kW, kH);
205 SkASSERT(rtContext);
206
bsalomone63ffef2016-02-05 07:17:34 -0800207 // Swap the order of the second two clears in the above test.
Chris Dalton344e9032017-12-11 15:42:09 -0700208 rtContext->clear(&fullRect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
209 rtContext->clear(&mid2Rect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
210 rtContext->clear(&mid1Rect, kColor2, GrRenderTargetContext::CanClearFullscreen::kNo);
Brian Osman11052242016-10-27 14:47:55 -0400211 if (!check_rect(rtContext.get(), mid1Rect, kColor2, &actualValue, &failX, &failY)) {
bsalomone63ffef2016-02-05 07:17:34 -0800212 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor2, actualValue,
213 failX, failY);
214 }
Brian Osman11052242016-10-27 14:47:55 -0400215 if (!check_rect(rtContext.get(), outerLeftEdge, kColor1, &actualValue, &failX, &failY) ||
216 !check_rect(rtContext.get(), outerTopEdge, kColor1, &actualValue, &failX, &failY) ||
217 !check_rect(rtContext.get(), outerRightEdge, kColor1, &actualValue, &failX, &failY) ||
218 !check_rect(rtContext.get(), outerBottomEdge, kColor1, &actualValue, &failX, &failY)) {
bsalomone63ffef2016-02-05 07:17:34 -0800219 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
220 failX, failY);
221 }
222}
Brian Salomon43f8bf02017-10-18 08:33:29 -0400223
224DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ClearOp, reporter, ctxInfo) {
225 clear_op_test(reporter, ctxInfo.grContext());
226 if (ctxInfo.backend() == kOpenGL_GrBackend) {
227 GrContextOptions options(ctxInfo.options());
228 options.fUseDrawInsteadOfGLClear = GrContextOptions::Enable::kYes;
229 sk_gpu_test::GrContextFactory workaroundFactory(options);
230 clear_op_test(reporter, workaroundFactory.get(ctxInfo.type()));
231 }
232}
233
Brian Salomon43f8bf02017-10-18 08:33:29 -0400234void fullscreen_clear_with_layer_test(skiatest::Reporter* reporter, GrContext* context) {
235 const SkImageInfo ii = SkImageInfo::Make(400, 77, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
236
237 sk_sp<SkSurface> surf = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, ii);
238 SkCanvas* canvas = surf->getCanvas();
239
240 SkPaint paints[2];
241 paints[0].setColor(SK_ColorGREEN);
242 paints[1].setColor(SK_ColorGRAY);
243
244 static const int kLeftX = 158;
245 static const int kMidX = 258;
246 static const int kRightX = 383;
247 static const int kTopY = 26;
248 static const int kBotY = 51;
249
250 const SkRect rects[2] = {
251 { kLeftX, kTopY, kMidX, kBotY },
252 { kMidX, kTopY, kRightX, kBotY },
253 };
254
255 for (int i = 0; i < 2; ++i) {
256 // the bounds parameter is required to cause a full screen clear
257 canvas->saveLayer(&rects[i], nullptr);
258 canvas->drawRect(rects[i], paints[i]);
259 canvas->restore();
260 }
261
262 SkBitmap bm;
263 bm.allocPixels(ii, 0);
264
265 SkAssertResult(surf->readPixels(bm, 0, 0));
266
267 bool isCorrect = true;
268 for (int y = kTopY; isCorrect && y < kBotY; ++y) {
269 const uint32_t* sl = bm.getAddr32(0, y);
270
271 for (int x = kLeftX; x < kMidX; ++x) {
272 if (SK_ColorGREEN != sl[x]) {
273 isCorrect = false;
274 break;
275 }
276 }
277
278 for (int x = kMidX; x < kRightX; ++x) {
279 if (SK_ColorGRAY != sl[x]) {
280 isCorrect = false;
281 break;
282 }
283 }
284 }
285
286 REPORTER_ASSERT(reporter, isCorrect);
287}
288// From crbug.com/768134
289DEF_GPUTEST_FOR_RENDERING_CONTEXTS(FullScreenClearWithLayers, reporter, ctxInfo) {
290 fullscreen_clear_with_layer_test(reporter, ctxInfo.grContext());
291 if (ctxInfo.backend() == kOpenGL_GrBackend) {
292 GrContextOptions options(ctxInfo.options());
293 options.fUseDrawInsteadOfGLClear = GrContextOptions::Enable::kYes;
294 sk_gpu_test::GrContextFactory workaroundFactory(options);
295 fullscreen_clear_with_layer_test(reporter, workaroundFactory.get(ctxInfo.type()));
296 }
297}
298
299#endif