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