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