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