• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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