xref: /aosp_15_r20/external/skia/tests/ClearTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2016 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkAlphaType.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorType.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPixmap.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurfaceProps.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/GpuTypes.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrContextOptions.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrDirectContext.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/SkSurfaceGanesh.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkColorData.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/gpu/ganesh/GrTypesPriv.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkAutoPixmapStorage.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/SkBackingFit.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrCaps.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrColor.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrDirectContextPriv.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/SurfaceDrawContext.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/ClearOp.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrOp.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/OpsTask.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "tests/CtsEnforcement.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
39*c8dee2aaSAndroid Build Coastguard Worker 
40*c8dee2aaSAndroid Build Coastguard Worker #include <array>
41*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
42*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
43*c8dee2aaSAndroid Build Coastguard Worker 
44*c8dee2aaSAndroid Build Coastguard Worker class GrRecordingContext;
45*c8dee2aaSAndroid Build Coastguard Worker 
46*c8dee2aaSAndroid Build Coastguard Worker using SurfaceDrawContext = skgpu::ganesh::SurfaceDrawContext;
47*c8dee2aaSAndroid Build Coastguard Worker using ClearOp = skgpu::ganesh::ClearOp;
48*c8dee2aaSAndroid Build Coastguard Worker 
pixel_matches(const SkPixmap & pm,int x,int y,uint32_t expectedValue,uint32_t * actualValue,int * failX,int * failY)49*c8dee2aaSAndroid Build Coastguard Worker static bool pixel_matches(const SkPixmap& pm, int x, int y, uint32_t expectedValue,
50*c8dee2aaSAndroid Build Coastguard Worker                           uint32_t* actualValue, int* failX, int* failY) {
51*c8dee2aaSAndroid Build Coastguard Worker     uint32_t pixel = pm.addr32()[y * pm.width() + x];
52*c8dee2aaSAndroid Build Coastguard Worker     if (pixel != expectedValue) {
53*c8dee2aaSAndroid Build Coastguard Worker         *actualValue = pixel;
54*c8dee2aaSAndroid Build Coastguard Worker         *failX = x;
55*c8dee2aaSAndroid Build Coastguard Worker         *failY = y;
56*c8dee2aaSAndroid Build Coastguard Worker         return false;
57*c8dee2aaSAndroid Build Coastguard Worker     }
58*c8dee2aaSAndroid Build Coastguard Worker 
59*c8dee2aaSAndroid Build Coastguard Worker     return true;
60*c8dee2aaSAndroid Build Coastguard Worker }
61*c8dee2aaSAndroid Build Coastguard Worker 
check_rect(GrDirectContext * dContext,SurfaceDrawContext * sdc,const SkIRect & rect,uint32_t expectedValue,uint32_t * actualValue,int * failX,int * failY)62*c8dee2aaSAndroid Build Coastguard Worker static bool check_rect(GrDirectContext* dContext,
63*c8dee2aaSAndroid Build Coastguard Worker                        SurfaceDrawContext* sdc,
64*c8dee2aaSAndroid Build Coastguard Worker                        const SkIRect& rect,
65*c8dee2aaSAndroid Build Coastguard Worker                        uint32_t expectedValue,
66*c8dee2aaSAndroid Build Coastguard Worker                        uint32_t* actualValue,
67*c8dee2aaSAndroid Build Coastguard Worker                        int* failX,
68*c8dee2aaSAndroid Build Coastguard Worker                        int* failY) {
69*c8dee2aaSAndroid Build Coastguard Worker     int w = sdc->width();
70*c8dee2aaSAndroid Build Coastguard Worker     int h = sdc->height();
71*c8dee2aaSAndroid Build Coastguard Worker 
72*c8dee2aaSAndroid Build Coastguard Worker     SkImageInfo dstInfo = SkImageInfo::Make(w, h, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
73*c8dee2aaSAndroid Build Coastguard Worker 
74*c8dee2aaSAndroid Build Coastguard Worker     SkAutoPixmapStorage readback;
75*c8dee2aaSAndroid Build Coastguard Worker     readback.alloc(dstInfo);
76*c8dee2aaSAndroid Build Coastguard Worker 
77*c8dee2aaSAndroid Build Coastguard Worker     readback.erase(~expectedValue);
78*c8dee2aaSAndroid Build Coastguard Worker     if (!sdc->readPixels(dContext, readback, {0, 0})) {
79*c8dee2aaSAndroid Build Coastguard Worker         return false;
80*c8dee2aaSAndroid Build Coastguard Worker     }
81*c8dee2aaSAndroid Build Coastguard Worker 
82*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(rect.fTop < rect.fBottom && rect.fLeft < rect.fRight);
83*c8dee2aaSAndroid Build Coastguard Worker     for (int y = rect.fTop; y < rect.fBottom; ++y) {
84*c8dee2aaSAndroid Build Coastguard Worker         for (int x = rect.fLeft; x < rect.fRight; ++x) {
85*c8dee2aaSAndroid Build Coastguard Worker             if (!pixel_matches(readback, x, y, expectedValue, actualValue, failX, failY)) {
86*c8dee2aaSAndroid Build Coastguard Worker                 return false;
87*c8dee2aaSAndroid Build Coastguard Worker             }
88*c8dee2aaSAndroid Build Coastguard Worker         }
89*c8dee2aaSAndroid Build Coastguard Worker     }
90*c8dee2aaSAndroid Build Coastguard Worker     return true;
91*c8dee2aaSAndroid Build Coastguard Worker }
92*c8dee2aaSAndroid Build Coastguard Worker 
93*c8dee2aaSAndroid Build Coastguard Worker // Check a 1-pixel wide ring 'inset' from the outer edge
check_ring(GrDirectContext * dContext,SurfaceDrawContext * sdc,int inset,uint32_t expectedValue,uint32_t * actualValue,int * failX,int * failY)94*c8dee2aaSAndroid Build Coastguard Worker static bool check_ring(GrDirectContext* dContext,
95*c8dee2aaSAndroid Build Coastguard Worker                        SurfaceDrawContext* sdc,
96*c8dee2aaSAndroid Build Coastguard Worker                        int inset,
97*c8dee2aaSAndroid Build Coastguard Worker                        uint32_t expectedValue,
98*c8dee2aaSAndroid Build Coastguard Worker                        uint32_t* actualValue,
99*c8dee2aaSAndroid Build Coastguard Worker                        int* failX,
100*c8dee2aaSAndroid Build Coastguard Worker                        int* failY) {
101*c8dee2aaSAndroid Build Coastguard Worker     int w = sdc->width();
102*c8dee2aaSAndroid Build Coastguard Worker     int h = sdc->height();
103*c8dee2aaSAndroid Build Coastguard Worker 
104*c8dee2aaSAndroid Build Coastguard Worker     SkImageInfo dstInfo = SkImageInfo::Make(w, h, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
105*c8dee2aaSAndroid Build Coastguard Worker 
106*c8dee2aaSAndroid Build Coastguard Worker     SkAutoPixmapStorage readback;
107*c8dee2aaSAndroid Build Coastguard Worker     readback.alloc(dstInfo);
108*c8dee2aaSAndroid Build Coastguard Worker 
109*c8dee2aaSAndroid Build Coastguard Worker     readback.erase(~expectedValue);
110*c8dee2aaSAndroid Build Coastguard Worker     if (!sdc->readPixels(dContext, readback, {0, 0})) {
111*c8dee2aaSAndroid Build Coastguard Worker         return false;
112*c8dee2aaSAndroid Build Coastguard Worker     }
113*c8dee2aaSAndroid Build Coastguard Worker 
114*c8dee2aaSAndroid Build Coastguard Worker     for (int y = inset; y < h-inset; ++y) {
115*c8dee2aaSAndroid Build Coastguard Worker         if (!pixel_matches(readback, inset, y, expectedValue, actualValue, failX, failY) ||
116*c8dee2aaSAndroid Build Coastguard Worker             !pixel_matches(readback, w-1-inset, y, expectedValue, actualValue, failX, failY)) {
117*c8dee2aaSAndroid Build Coastguard Worker             return false;
118*c8dee2aaSAndroid Build Coastguard Worker         }
119*c8dee2aaSAndroid Build Coastguard Worker     }
120*c8dee2aaSAndroid Build Coastguard Worker     for (int x = inset+1; x < w-inset-1; ++x) {
121*c8dee2aaSAndroid Build Coastguard Worker         if (!pixel_matches(readback, x, inset, expectedValue, actualValue, failX, failY) ||
122*c8dee2aaSAndroid Build Coastguard Worker             !pixel_matches(readback, x, h-1-inset, expectedValue, actualValue, failX, failY)) {
123*c8dee2aaSAndroid Build Coastguard Worker             return false;
124*c8dee2aaSAndroid Build Coastguard Worker         }
125*c8dee2aaSAndroid Build Coastguard Worker     }
126*c8dee2aaSAndroid Build Coastguard Worker 
127*c8dee2aaSAndroid Build Coastguard Worker     return true;
128*c8dee2aaSAndroid Build Coastguard Worker }
129*c8dee2aaSAndroid Build Coastguard Worker 
newSDC(GrRecordingContext * rContext,int w,int h)130*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SurfaceDrawContext> newSDC(GrRecordingContext* rContext, int w, int h) {
131*c8dee2aaSAndroid Build Coastguard Worker     return SurfaceDrawContext::Make(rContext, GrColorType::kRGBA_8888, nullptr,
132*c8dee2aaSAndroid Build Coastguard Worker                                     SkBackingFit::kExact, {w, h}, SkSurfaceProps(),
133*c8dee2aaSAndroid Build Coastguard Worker                                     /*label=*/{});
134*c8dee2aaSAndroid Build Coastguard Worker }
135*c8dee2aaSAndroid Build Coastguard Worker 
clear_op_test(skiatest::Reporter * reporter,GrDirectContext * dContext)136*c8dee2aaSAndroid Build Coastguard Worker static void clear_op_test(skiatest::Reporter* reporter, GrDirectContext* dContext) {
137*c8dee2aaSAndroid Build Coastguard Worker     static const int kW = 10;
138*c8dee2aaSAndroid Build Coastguard Worker     static const int kH = 10;
139*c8dee2aaSAndroid Build Coastguard Worker 
140*c8dee2aaSAndroid Build Coastguard Worker     SkIRect fullRect = SkIRect::MakeWH(kW, kH);
141*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<SurfaceDrawContext> sdc;
142*c8dee2aaSAndroid Build Coastguard Worker 
143*c8dee2aaSAndroid Build Coastguard Worker     // A rectangle that is inset by one on all sides and the 1-pixel wide rectangles that surround
144*c8dee2aaSAndroid Build Coastguard Worker     // it.
145*c8dee2aaSAndroid Build Coastguard Worker     SkIRect mid1Rect = SkIRect::MakeXYWH(1, 1, kW-2, kH-2);
146*c8dee2aaSAndroid Build Coastguard Worker 
147*c8dee2aaSAndroid Build Coastguard Worker     // A rectangle that is inset by two on all sides and the 1-pixel wide rectangles that surround
148*c8dee2aaSAndroid Build Coastguard Worker     // it.
149*c8dee2aaSAndroid Build Coastguard Worker     SkIRect mid2Rect = SkIRect::MakeXYWH(2, 2, kW-4, kH-4);
150*c8dee2aaSAndroid Build Coastguard Worker 
151*c8dee2aaSAndroid Build Coastguard Worker     uint32_t actualValue;
152*c8dee2aaSAndroid Build Coastguard Worker     int failX, failY;
153*c8dee2aaSAndroid Build Coastguard Worker 
154*c8dee2aaSAndroid Build Coastguard Worker     static const GrColor kColor1 = 0xABCDEF01;
155*c8dee2aaSAndroid Build Coastguard Worker     static const GrColor kColor2 = ~kColor1;
156*c8dee2aaSAndroid Build Coastguard Worker     static const SkPMColor4f kColor1f = SkPMColor4f::FromBytes_RGBA(kColor1);
157*c8dee2aaSAndroid Build Coastguard Worker     static const SkPMColor4f kColor2f = SkPMColor4f::FromBytes_RGBA(kColor2);
158*c8dee2aaSAndroid Build Coastguard Worker 
159*c8dee2aaSAndroid Build Coastguard Worker     sdc = newSDC(dContext, kW, kH);
160*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(sdc);
161*c8dee2aaSAndroid Build Coastguard Worker 
162*c8dee2aaSAndroid Build Coastguard Worker     // Check a full clear
163*c8dee2aaSAndroid Build Coastguard Worker     sdc->clear(fullRect, kColor1f);
164*c8dee2aaSAndroid Build Coastguard Worker     if (!check_rect(dContext, sdc.get(), fullRect, kColor1, &actualValue, &failX, &failY)) {
165*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
166*c8dee2aaSAndroid Build Coastguard Worker                failX, failY);
167*c8dee2aaSAndroid Build Coastguard Worker     }
168*c8dee2aaSAndroid Build Coastguard Worker 
169*c8dee2aaSAndroid Build Coastguard Worker     sdc = newSDC(dContext, kW, kH);
170*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(sdc);
171*c8dee2aaSAndroid Build Coastguard Worker 
172*c8dee2aaSAndroid Build Coastguard Worker     // Check two full clears, same color
173*c8dee2aaSAndroid Build Coastguard Worker     sdc->clear(fullRect, kColor1f);
174*c8dee2aaSAndroid Build Coastguard Worker     sdc->clear(fullRect, kColor1f);
175*c8dee2aaSAndroid Build Coastguard Worker     if (!check_rect(dContext, sdc.get(), fullRect, kColor1, &actualValue, &failX, &failY)) {
176*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
177*c8dee2aaSAndroid Build Coastguard Worker                failX, failY);
178*c8dee2aaSAndroid Build Coastguard Worker     }
179*c8dee2aaSAndroid Build Coastguard Worker 
180*c8dee2aaSAndroid Build Coastguard Worker     sdc = newSDC(dContext, kW, kH);
181*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(sdc);
182*c8dee2aaSAndroid Build Coastguard Worker 
183*c8dee2aaSAndroid Build Coastguard Worker     // Check two full clears, different colors
184*c8dee2aaSAndroid Build Coastguard Worker     sdc->clear(fullRect, kColor1f);
185*c8dee2aaSAndroid Build Coastguard Worker     sdc->clear(fullRect, kColor2f);
186*c8dee2aaSAndroid Build Coastguard Worker     if (!check_rect(dContext, sdc.get(), fullRect, kColor2, &actualValue, &failX, &failY)) {
187*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor2, actualValue,
188*c8dee2aaSAndroid Build Coastguard Worker                failX, failY);
189*c8dee2aaSAndroid Build Coastguard Worker     }
190*c8dee2aaSAndroid Build Coastguard Worker 
191*c8dee2aaSAndroid Build Coastguard Worker     sdc = newSDC(dContext, kW, kH);
192*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(sdc);
193*c8dee2aaSAndroid Build Coastguard Worker 
194*c8dee2aaSAndroid Build Coastguard Worker     // Test a full clear followed by a same color inset clear
195*c8dee2aaSAndroid Build Coastguard Worker     sdc->clear(fullRect, kColor1f);
196*c8dee2aaSAndroid Build Coastguard Worker     sdc->clear(mid1Rect, kColor1f);
197*c8dee2aaSAndroid Build Coastguard Worker     if (!check_rect(dContext, sdc.get(), fullRect, kColor1, &actualValue, &failX, &failY)) {
198*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
199*c8dee2aaSAndroid Build Coastguard Worker                failX, failY);
200*c8dee2aaSAndroid Build Coastguard Worker     }
201*c8dee2aaSAndroid Build Coastguard Worker 
202*c8dee2aaSAndroid Build Coastguard Worker     sdc = newSDC(dContext, kW, kH);
203*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(sdc);
204*c8dee2aaSAndroid Build Coastguard Worker 
205*c8dee2aaSAndroid Build Coastguard Worker     // Test a inset clear followed by same color full clear
206*c8dee2aaSAndroid Build Coastguard Worker     sdc->clear(mid1Rect, kColor1f);
207*c8dee2aaSAndroid Build Coastguard Worker     sdc->clear(fullRect, kColor1f);
208*c8dee2aaSAndroid Build Coastguard Worker     if (!check_rect(dContext, sdc.get(), fullRect, kColor1, &actualValue, &failX, &failY)) {
209*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
210*c8dee2aaSAndroid Build Coastguard Worker                failX, failY);
211*c8dee2aaSAndroid Build Coastguard Worker     }
212*c8dee2aaSAndroid Build Coastguard Worker 
213*c8dee2aaSAndroid Build Coastguard Worker     sdc = newSDC(dContext, kW, kH);
214*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(sdc);
215*c8dee2aaSAndroid Build Coastguard Worker 
216*c8dee2aaSAndroid Build Coastguard Worker     // Test a full clear followed by a different color inset clear
217*c8dee2aaSAndroid Build Coastguard Worker     sdc->clear(fullRect, kColor1f);
218*c8dee2aaSAndroid Build Coastguard Worker     sdc->clear(mid1Rect, kColor2f);
219*c8dee2aaSAndroid Build Coastguard Worker     if (!check_rect(dContext, sdc.get(), mid1Rect, kColor2, &actualValue, &failX, &failY)) {
220*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor2, actualValue,
221*c8dee2aaSAndroid Build Coastguard Worker                failX, failY);
222*c8dee2aaSAndroid Build Coastguard Worker     }
223*c8dee2aaSAndroid Build Coastguard Worker 
224*c8dee2aaSAndroid Build Coastguard Worker     if (!check_ring(dContext, sdc.get(), /*inset=*/ 0, kColor1, &actualValue, &failX, &failY)) {
225*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
226*c8dee2aaSAndroid Build Coastguard Worker                failX, failY);
227*c8dee2aaSAndroid Build Coastguard Worker     }
228*c8dee2aaSAndroid Build Coastguard Worker 
229*c8dee2aaSAndroid Build Coastguard Worker     sdc = newSDC(dContext, kW, kH);
230*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(sdc);
231*c8dee2aaSAndroid Build Coastguard Worker 
232*c8dee2aaSAndroid Build Coastguard Worker     // Test a inset clear followed by a different full clear
233*c8dee2aaSAndroid Build Coastguard Worker     sdc->clear(mid1Rect, kColor2f);
234*c8dee2aaSAndroid Build Coastguard Worker     sdc->clear(fullRect, kColor1f);
235*c8dee2aaSAndroid Build Coastguard Worker     if (!check_rect(dContext, sdc.get(), fullRect, kColor1, &actualValue, &failX, &failY)) {
236*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
237*c8dee2aaSAndroid Build Coastguard Worker                failX, failY);
238*c8dee2aaSAndroid Build Coastguard Worker     }
239*c8dee2aaSAndroid Build Coastguard Worker 
240*c8dee2aaSAndroid Build Coastguard Worker     sdc = newSDC(dContext, kW, kH);
241*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(sdc);
242*c8dee2aaSAndroid Build Coastguard Worker 
243*c8dee2aaSAndroid Build Coastguard Worker     // Check three nested clears from largest to smallest where outermost and innermost are same
244*c8dee2aaSAndroid Build Coastguard Worker     // color.
245*c8dee2aaSAndroid Build Coastguard Worker     sdc->clear(fullRect, kColor1f);
246*c8dee2aaSAndroid Build Coastguard Worker     sdc->clear(mid1Rect, kColor2f);
247*c8dee2aaSAndroid Build Coastguard Worker     sdc->clear(mid2Rect, kColor1f);
248*c8dee2aaSAndroid Build Coastguard Worker     if (!check_rect(dContext, sdc.get(), mid2Rect, kColor1, &actualValue, &failX, &failY)) {
249*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
250*c8dee2aaSAndroid Build Coastguard Worker                failX, failY);
251*c8dee2aaSAndroid Build Coastguard Worker     }
252*c8dee2aaSAndroid Build Coastguard Worker 
253*c8dee2aaSAndroid Build Coastguard Worker     if (!check_ring(dContext, sdc.get(), /*inset=*/ 1, kColor2, &actualValue, &failX, &failY)) {
254*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor2, actualValue,
255*c8dee2aaSAndroid Build Coastguard Worker                failX, failY);
256*c8dee2aaSAndroid Build Coastguard Worker     }
257*c8dee2aaSAndroid Build Coastguard Worker 
258*c8dee2aaSAndroid Build Coastguard Worker     if (!check_ring(dContext, sdc.get(), /*inset=*/ 0, kColor1, &actualValue, &failX, &failY)) {
259*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
260*c8dee2aaSAndroid Build Coastguard Worker                failX, failY);
261*c8dee2aaSAndroid Build Coastguard Worker     }
262*c8dee2aaSAndroid Build Coastguard Worker 
263*c8dee2aaSAndroid Build Coastguard Worker     sdc = newSDC(dContext, kW, kH);
264*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(sdc);
265*c8dee2aaSAndroid Build Coastguard Worker 
266*c8dee2aaSAndroid Build Coastguard Worker     // Swap the order of the second two clears in the above test.
267*c8dee2aaSAndroid Build Coastguard Worker     sdc->clear(fullRect, kColor1f);
268*c8dee2aaSAndroid Build Coastguard Worker     sdc->clear(mid2Rect, kColor1f);
269*c8dee2aaSAndroid Build Coastguard Worker     sdc->clear(mid1Rect, kColor2f);
270*c8dee2aaSAndroid Build Coastguard Worker     if (!check_rect(dContext, sdc.get(), mid1Rect, kColor2, &actualValue, &failX, &failY)) {
271*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor2, actualValue,
272*c8dee2aaSAndroid Build Coastguard Worker                failX, failY);
273*c8dee2aaSAndroid Build Coastguard Worker     }
274*c8dee2aaSAndroid Build Coastguard Worker     if (!check_ring(dContext, sdc.get(), /*inset=*/ 0, kColor1, &actualValue, &failX, &failY)) {
275*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
276*c8dee2aaSAndroid Build Coastguard Worker                failX, failY);
277*c8dee2aaSAndroid Build Coastguard Worker     }
278*c8dee2aaSAndroid Build Coastguard Worker 
279*c8dee2aaSAndroid Build Coastguard Worker     // Clear calls need to remain ClearOps for the following combining-tests to work as expected
280*c8dee2aaSAndroid Build Coastguard Worker     if (!dContext->priv().caps()->performColorClearsAsDraws() &&
281*c8dee2aaSAndroid Build Coastguard Worker         !dContext->priv().caps()->performStencilClearsAsDraws() &&
282*c8dee2aaSAndroid Build Coastguard Worker         !dContext->priv().caps()->performPartialClearsAsDraws()) {
283*c8dee2aaSAndroid Build Coastguard Worker         static constexpr SkIRect kScissorRect = SkIRect::MakeXYWH(1, 1, kW-1, kH-1);
284*c8dee2aaSAndroid Build Coastguard Worker 
285*c8dee2aaSAndroid Build Coastguard Worker         // Try combining a pure-color clear w/ a combined stencil & color clear
286*c8dee2aaSAndroid Build Coastguard Worker         // (re skbug.com/10963)
287*c8dee2aaSAndroid Build Coastguard Worker         {
288*c8dee2aaSAndroid Build Coastguard Worker             sdc = newSDC(dContext, kW, kH);
289*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(sdc);
290*c8dee2aaSAndroid Build Coastguard Worker 
291*c8dee2aaSAndroid Build Coastguard Worker             sdc->clearStencilClip(kScissorRect, true);
292*c8dee2aaSAndroid Build Coastguard Worker             // This color clear can combine w/ the preceding stencil clear
293*c8dee2aaSAndroid Build Coastguard Worker             sdc->clear(kScissorRect, SK_PMColor4fWHITE);
294*c8dee2aaSAndroid Build Coastguard Worker 
295*c8dee2aaSAndroid Build Coastguard Worker             // This should combine w/ the prior combined clear and overwrite the color
296*c8dee2aaSAndroid Build Coastguard Worker             sdc->clear(kScissorRect, SK_PMColor4fBLACK);
297*c8dee2aaSAndroid Build Coastguard Worker 
298*c8dee2aaSAndroid Build Coastguard Worker             auto opsTask = sdc->getOpsTask();
299*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, opsTask->numOpChains() == 1);
300*c8dee2aaSAndroid Build Coastguard Worker 
301*c8dee2aaSAndroid Build Coastguard Worker             const ClearOp& clearOp = opsTask->getChain(0)->cast<ClearOp>();
302*c8dee2aaSAndroid Build Coastguard Worker 
303*c8dee2aaSAndroid Build Coastguard Worker             constexpr std::array<float, 4> kExpected { 0, 0, 0, 1 };
304*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, clearOp.color() == kExpected);
305*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, clearOp.stencilInsideMask());
306*c8dee2aaSAndroid Build Coastguard Worker 
307*c8dee2aaSAndroid Build Coastguard Worker             dContext->flushAndSubmit();
308*c8dee2aaSAndroid Build Coastguard Worker         }
309*c8dee2aaSAndroid Build Coastguard Worker 
310*c8dee2aaSAndroid Build Coastguard Worker         // Try combining a pure-stencil clear w/ a combined stencil & color clear
311*c8dee2aaSAndroid Build Coastguard Worker         // (re skbug.com/10963)
312*c8dee2aaSAndroid Build Coastguard Worker         {
313*c8dee2aaSAndroid Build Coastguard Worker             sdc = newSDC(dContext, kW, kH);
314*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(sdc);
315*c8dee2aaSAndroid Build Coastguard Worker 
316*c8dee2aaSAndroid Build Coastguard Worker             sdc->clearStencilClip(kScissorRect, true);
317*c8dee2aaSAndroid Build Coastguard Worker             // This color clear can combine w/ the preceding stencil clear
318*c8dee2aaSAndroid Build Coastguard Worker             sdc->clear(kScissorRect, SK_PMColor4fWHITE);
319*c8dee2aaSAndroid Build Coastguard Worker 
320*c8dee2aaSAndroid Build Coastguard Worker             // This should combine w/ the prior combined clear and overwrite the 'insideStencilMask'
321*c8dee2aaSAndroid Build Coastguard Worker             // field
322*c8dee2aaSAndroid Build Coastguard Worker             sdc->clearStencilClip(kScissorRect, false);
323*c8dee2aaSAndroid Build Coastguard Worker 
324*c8dee2aaSAndroid Build Coastguard Worker             auto opsTask = sdc->getOpsTask();
325*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, opsTask->numOpChains() == 1);
326*c8dee2aaSAndroid Build Coastguard Worker 
327*c8dee2aaSAndroid Build Coastguard Worker             const ClearOp& clearOp = opsTask->getChain(0)->cast<ClearOp>();
328*c8dee2aaSAndroid Build Coastguard Worker 
329*c8dee2aaSAndroid Build Coastguard Worker             constexpr std::array<float, 4> kExpected { 1, 1, 1, 1 };
330*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, clearOp.color() == kExpected);
331*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !clearOp.stencilInsideMask());
332*c8dee2aaSAndroid Build Coastguard Worker 
333*c8dee2aaSAndroid Build Coastguard Worker             dContext->flushAndSubmit();
334*c8dee2aaSAndroid Build Coastguard Worker         }
335*c8dee2aaSAndroid Build Coastguard Worker     }
336*c8dee2aaSAndroid Build Coastguard Worker }
337*c8dee2aaSAndroid Build Coastguard Worker 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ClearOp,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)338*c8dee2aaSAndroid Build Coastguard Worker DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ClearOp, reporter, ctxInfo, CtsEnforcement::kApiLevel_T) {
339*c8dee2aaSAndroid Build Coastguard Worker     // Regular clear
340*c8dee2aaSAndroid Build Coastguard Worker     clear_op_test(reporter, ctxInfo.directContext());
341*c8dee2aaSAndroid Build Coastguard Worker 
342*c8dee2aaSAndroid Build Coastguard Worker     // Force drawing for clears
343*c8dee2aaSAndroid Build Coastguard Worker     GrContextOptions options(ctxInfo.options());
344*c8dee2aaSAndroid Build Coastguard Worker     options.fUseDrawInsteadOfClear = GrContextOptions::Enable::kYes;
345*c8dee2aaSAndroid Build Coastguard Worker     sk_gpu_test::GrContextFactory workaroundFactory(options);
346*c8dee2aaSAndroid Build Coastguard Worker     clear_op_test(reporter, workaroundFactory.get(ctxInfo.type()));
347*c8dee2aaSAndroid Build Coastguard Worker }
348*c8dee2aaSAndroid Build Coastguard Worker 
fullscreen_clear_with_layer_test(skiatest::Reporter * reporter,GrRecordingContext * rContext)349*c8dee2aaSAndroid Build Coastguard Worker void fullscreen_clear_with_layer_test(skiatest::Reporter* reporter, GrRecordingContext* rContext) {
350*c8dee2aaSAndroid Build Coastguard Worker     const SkImageInfo ii = SkImageInfo::Make(400, 77, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
351*c8dee2aaSAndroid Build Coastguard Worker 
352*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkSurface> surf = SkSurfaces::RenderTarget(rContext, skgpu::Budgeted::kYes, ii);
353*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas* canvas = surf->getCanvas();
354*c8dee2aaSAndroid Build Coastguard Worker 
355*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paints[2];
356*c8dee2aaSAndroid Build Coastguard Worker     paints[0].setColor(SK_ColorGREEN);
357*c8dee2aaSAndroid Build Coastguard Worker     paints[1].setColor(SK_ColorGRAY);
358*c8dee2aaSAndroid Build Coastguard Worker 
359*c8dee2aaSAndroid Build Coastguard Worker     static const int kLeftX = 158;
360*c8dee2aaSAndroid Build Coastguard Worker     static const int kMidX = 258;
361*c8dee2aaSAndroid Build Coastguard Worker     static const int kRightX = 383;
362*c8dee2aaSAndroid Build Coastguard Worker     static const int kTopY = 26;
363*c8dee2aaSAndroid Build Coastguard Worker     static const int kBotY = 51;
364*c8dee2aaSAndroid Build Coastguard Worker 
365*c8dee2aaSAndroid Build Coastguard Worker     const SkRect rects[2] = {
366*c8dee2aaSAndroid Build Coastguard Worker         { kLeftX, kTopY, kMidX, kBotY },
367*c8dee2aaSAndroid Build Coastguard Worker         { kMidX, kTopY, kRightX, kBotY },
368*c8dee2aaSAndroid Build Coastguard Worker     };
369*c8dee2aaSAndroid Build Coastguard Worker 
370*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < 2; ++i) {
371*c8dee2aaSAndroid Build Coastguard Worker         // the bounds parameter is required to cause a full screen clear
372*c8dee2aaSAndroid Build Coastguard Worker         canvas->saveLayer(&rects[i], nullptr);
373*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawRect(rects[i], paints[i]);
374*c8dee2aaSAndroid Build Coastguard Worker         canvas->restore();
375*c8dee2aaSAndroid Build Coastguard Worker     }
376*c8dee2aaSAndroid Build Coastguard Worker 
377*c8dee2aaSAndroid Build Coastguard Worker     SkBitmap bm;
378*c8dee2aaSAndroid Build Coastguard Worker     bm.allocPixels(ii, 0);
379*c8dee2aaSAndroid Build Coastguard Worker 
380*c8dee2aaSAndroid Build Coastguard Worker     SkAssertResult(surf->readPixels(bm, 0, 0));
381*c8dee2aaSAndroid Build Coastguard Worker 
382*c8dee2aaSAndroid Build Coastguard Worker     bool isCorrect = true;
383*c8dee2aaSAndroid Build Coastguard Worker     for (int y = kTopY; isCorrect && y < kBotY; ++y) {
384*c8dee2aaSAndroid Build Coastguard Worker         const uint32_t* sl = bm.getAddr32(0, y);
385*c8dee2aaSAndroid Build Coastguard Worker 
386*c8dee2aaSAndroid Build Coastguard Worker         for (int x = kLeftX; x < kMidX; ++x) {
387*c8dee2aaSAndroid Build Coastguard Worker             if (SK_ColorGREEN != sl[x]) {
388*c8dee2aaSAndroid Build Coastguard Worker                 isCorrect = false;
389*c8dee2aaSAndroid Build Coastguard Worker                 break;
390*c8dee2aaSAndroid Build Coastguard Worker             }
391*c8dee2aaSAndroid Build Coastguard Worker         }
392*c8dee2aaSAndroid Build Coastguard Worker 
393*c8dee2aaSAndroid Build Coastguard Worker         for (int x = kMidX; x < kRightX; ++x) {
394*c8dee2aaSAndroid Build Coastguard Worker             if (SK_ColorGRAY != sl[x]) {
395*c8dee2aaSAndroid Build Coastguard Worker                 isCorrect = false;
396*c8dee2aaSAndroid Build Coastguard Worker                 break;
397*c8dee2aaSAndroid Build Coastguard Worker             }
398*c8dee2aaSAndroid Build Coastguard Worker         }
399*c8dee2aaSAndroid Build Coastguard Worker     }
400*c8dee2aaSAndroid Build Coastguard Worker 
401*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, isCorrect);
402*c8dee2aaSAndroid Build Coastguard Worker }
403*c8dee2aaSAndroid Build Coastguard Worker // From crbug.com/768134
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(FullScreenClearWithLayers,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)404*c8dee2aaSAndroid Build Coastguard Worker DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(FullScreenClearWithLayers,
405*c8dee2aaSAndroid Build Coastguard Worker                                        reporter,
406*c8dee2aaSAndroid Build Coastguard Worker                                        ctxInfo,
407*c8dee2aaSAndroid Build Coastguard Worker                                        CtsEnforcement::kApiLevel_T) {
408*c8dee2aaSAndroid Build Coastguard Worker     // Regular clear
409*c8dee2aaSAndroid Build Coastguard Worker     fullscreen_clear_with_layer_test(reporter, ctxInfo.directContext());
410*c8dee2aaSAndroid Build Coastguard Worker 
411*c8dee2aaSAndroid Build Coastguard Worker     // Use draws for clears
412*c8dee2aaSAndroid Build Coastguard Worker     GrContextOptions options(ctxInfo.options());
413*c8dee2aaSAndroid Build Coastguard Worker     options.fUseDrawInsteadOfClear = GrContextOptions::Enable::kYes;
414*c8dee2aaSAndroid Build Coastguard Worker     sk_gpu_test::GrContextFactory workaroundFactory(options);
415*c8dee2aaSAndroid Build Coastguard Worker     fullscreen_clear_with_layer_test(reporter, workaroundFactory.get(ctxInfo.type()));
416*c8dee2aaSAndroid Build Coastguard Worker }
417