xref: /aosp_15_r20/external/skia/fuzz/FuzzCreateDDL.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2020 Google, LLC
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/SkCanvas.h"
9 #include "include/core/SkPaint.h"
10 #include "include/core/SkSurface.h"
11 #include "include/gpu/ganesh/GrDirectContext.h"
12 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
13 #include "include/private/chromium/GrDeferredDisplayList.h"
14 #include "include/private/chromium/GrDeferredDisplayListRecorder.h"
15 #include "include/private/chromium/GrSurfaceCharacterization.h"
16 #include "include/private/gpu/ganesh/GrTypesPriv.h"
17 #include "src/gpu/ganesh/GrShaderCaps.h"
18 #include "src/gpu/ganesh/GrUtil.h"
19 #include "tools/gpu/GrContextFactory.h"
20 
21 #include "fuzz/Fuzz.h"
22 
23 #include <tuple>
24 
25 /**
26  * The fuzzer aims to fuzz the use of GrDeferredDisplayList. It mainly consists of
27  * three parts.
28  * 1. In create_surface_characterization, (make_characterization) Create GrSurfaceCharacterization
29  * by using GrDirectContext of ContextType::kGL as it can be applied on all platform, and
30  * (make_surface) create a GPU backend surface of the same GrDirectContext
31  * 2. (make_ddl) Create GrDeferredDisplayListRecorder from the GrSurfaceCharacterization, and test
32  * the recoder's corresponding canvas.
33  * 3. (make_ddl, draw_ddl) Create GrDeferredDisplayList from the SkDeferredDisplayRecorder and draw
34  * the ddl on a GPU backend surface.
35  */
36 
37 static constexpr int kMaxWidth = 64;
38 static constexpr int kMaxHeight = 64;
39 static constexpr int kSampleCount = 1;
40 
gen_fuzzed_surface_props(Fuzz * fuzz)41 static SkSurfaceProps gen_fuzzed_surface_props(Fuzz* fuzz) {
42     SkPixelGeometry pixel;
43     fuzz->nextEnum(&pixel, kBGR_V_SkPixelGeometry);
44     return SkSurfaceProps(0x0, pixel);
45 }
46 
gen_fuzzed_skpaint(Fuzz * fuzz)47 static SkPaint gen_fuzzed_skpaint(Fuzz* fuzz) {
48     float R, G, B, Alpha;
49     fuzz->nextRange(&R, -1, 2);
50     fuzz->nextRange(&G, -1, 2);
51     fuzz->nextRange(&B, -1, 2);
52     fuzz->nextRange(&Alpha, 0, 1);
53     SkColor4f color = {R, G, B, Alpha};
54     return SkPaint(color);
55 }
56 
gen_fuzzed_imageinfo(Fuzz * fuzz,SkColorType surfaceType)57 static SkImageInfo gen_fuzzed_imageinfo(Fuzz* fuzz, SkColorType surfaceType) {
58     int width, height;
59     fuzz->nextRange(&width, 1, kMaxWidth);
60     fuzz->nextRange(&height, 1, kMaxHeight);
61     SkAlphaType alphaType;
62     fuzz->nextEnum(&alphaType, SkAlphaType::kLastEnum_SkAlphaType);
63     skcms_TransferFunction skcmsFn;
64     uint8_t skcms;
65     fuzz->nextRange(&skcms, 0, 5);
66     switch (skcms) {
67         case 0: {
68             skcmsFn = SkNamedTransferFn::kSRGB;
69             break;
70         }
71         case 1: {
72             skcmsFn = SkNamedTransferFn::k2Dot2;
73             break;
74         }
75         case 2: {
76             skcmsFn = SkNamedTransferFn::kHLG;
77             break;
78         }
79         case 3: {
80             skcmsFn = SkNamedTransferFn::kLinear;
81             break;
82         }
83         case 4: {
84             skcmsFn = SkNamedTransferFn::kPQ;
85             break;
86         }
87         case 5: {
88             skcmsFn = SkNamedTransferFn::kRec2020;
89             break;
90         }
91         default:
92             SkASSERT(false);
93             break;
94     }
95     skcms_Matrix3x3 skcmsMat;
96     fuzz->nextRange(&skcms, 0, 4);
97     switch (skcms) {
98         case 0: {
99             skcmsMat = SkNamedGamut::kAdobeRGB;
100             break;
101         }
102         case 1: {
103             skcmsMat = SkNamedGamut::kDisplayP3;
104             break;
105         }
106         case 2: {
107             skcmsMat = SkNamedGamut::kRec2020;
108             break;
109         }
110         case 3: {
111             skcmsMat = SkNamedGamut::kSRGB;
112             break;
113         }
114         case 4: {
115             skcmsMat = SkNamedGamut::kXYZ;
116             break;
117         }
118         default:
119             SkASSERT(false);
120             break;
121     }
122     return SkImageInfo::Make(width, height, surfaceType, alphaType,
123                              SkColorSpace::MakeRGB(skcmsFn, skcmsMat));
124 }
125 
make_characterization(Fuzz * fuzz,GrDirectContext * dContext,SkImageInfo & ii,SkColorType surfaceType,GrSurfaceOrigin origin)126 static GrSurfaceCharacterization make_characterization(Fuzz* fuzz, GrDirectContext* dContext,
127                                                        SkImageInfo& ii, SkColorType surfaceType,
128                                                        GrSurfaceOrigin origin) {
129     if (!dContext->colorTypeSupportedAsSurface(surfaceType)) {
130         SkDebugf("Couldn't create backend texture in the backend %s",
131                  GrBackendApiToStr(dContext->backend()));
132         return {};
133     }
134 
135     GrBackendFormat backendFormat = dContext->defaultBackendFormat(surfaceType,
136                                                                    GrRenderable::kYes);
137     if (!backendFormat.isValid()) {
138         SkDebugf("Color Type is not supported in the backend %s",
139                  GrBackendApiToStr(dContext->backend()));
140         return {};
141     }
142     GrProtected protect = GrProtected::kNo;
143 #ifdef SK_VULKAN
144     fuzz->nextEnum(&protect, GrProtected::kYes);
145 #endif
146     GrSurfaceCharacterization c;
147     size_t maxResourceBytes = dContext->getResourceCacheLimit();
148     c = dContext->threadSafeProxy()->createCharacterization(maxResourceBytes,
149                                                             ii,
150                                                             backendFormat,
151                                                             kSampleCount,
152                                                             origin,
153                                                             gen_fuzzed_surface_props(fuzz),
154                                                             skgpu::Mipmapped::kYes,
155                                                             false,
156                                                             true,
157                                                             protect);
158     if (!c.isValid()) {
159         SkDebugf("Could not create Characterization in the backend %s",
160                  GrBackendApiToStr(dContext->backend()));
161         return {};
162     }
163     return c;
164 }
165 
make_ddl(Fuzz * fuzz,GrDirectContext * dContext,const GrSurfaceCharacterization & c)166 static sk_sp<GrDeferredDisplayList> make_ddl(Fuzz* fuzz, GrDirectContext* dContext,
167                                              const GrSurfaceCharacterization& c) {
168     GrDeferredDisplayListRecorder r(c);
169     SkCanvas* canvas = r.getCanvas();
170     if (!canvas) {
171         SkDebugf("Could not create canvas for backend %s", GrBackendApiToStr(dContext->backend()));
172         return nullptr;
173     }
174     // For now we only draw a rect into the DDL. This will be scaled up to draw more varied content.
175     SkRect tile;
176     fuzz->next(&tile);
177     canvas->drawRect(tile, gen_fuzzed_skpaint(fuzz));
178     return r.detach();
179 }
180 
make_surface(Fuzz * fuzz,GrDirectContext * dContext,const SkImageInfo & ii,GrSurfaceOrigin origin)181 static sk_sp<SkSurface> make_surface(Fuzz* fuzz, GrDirectContext* dContext, const SkImageInfo& ii,
182                                      GrSurfaceOrigin origin) {
183     skgpu::Budgeted budgeted;
184     fuzz->nextEnum(&budgeted, skgpu::Budgeted::kYes);
185     SkSurfaceProps surfaceProps = gen_fuzzed_surface_props(fuzz);
186     auto surface =
187             SkSurfaces::RenderTarget(dContext, budgeted, ii, kSampleCount, origin, &surfaceProps);
188     return surface;
189 }
190 
draw_ddl(sk_sp<SkSurface> surface,sk_sp<const GrDeferredDisplayList> ddl)191 static bool draw_ddl(sk_sp<SkSurface> surface, sk_sp<const GrDeferredDisplayList> ddl) {
192     return skgpu::ganesh::DrawDDL(std::move(surface), std::move(ddl));
193 }
194 
195 using SurfaceAndChar = std::tuple<sk_sp<SkSurface>, GrSurfaceCharacterization>;
create_surface_and_characterization(Fuzz * fuzz,GrDirectContext * dContext,SkColorType surfaceType,GrSurfaceOrigin origin)196 static SurfaceAndChar create_surface_and_characterization(Fuzz* fuzz, GrDirectContext* dContext,
197                                                           SkColorType surfaceType,
198                                                           GrSurfaceOrigin origin) {
199     SkImageInfo ii = gen_fuzzed_imageinfo(fuzz, surfaceType);
200     GrSurfaceCharacterization c = make_characterization(fuzz, dContext, ii, surfaceType, origin);
201     if (!c.isValid()) {
202        return {};
203     }
204 
205     auto surface = make_surface(fuzz, dContext, ii, origin);
206     if (!surface) {
207         return {};
208     }
209     return {surface, c};
210 }
211 
DEF_FUZZ(CreateDDL,fuzz)212 DEF_FUZZ(CreateDDL, fuzz) {
213     SkColorType surfaceType;
214     GrSurfaceOrigin origin;
215     fuzz->nextEnum(&surfaceType, SkColorType::kLastEnum_SkColorType);
216     fuzz->nextEnum(&origin, GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin);
217 
218     sk_gpu_test::GrContextFactory factory;
219     auto ctxInfo = factory.getContextInfo(skgpu::ContextType::kGL);
220 
221     GrDirectContext* dContext = ctxInfo.directContext();
222     if (!dContext) {
223         SkDebugf("Context creation failed");
224         return;
225     }
226 
227     auto[surface, c] = create_surface_and_characterization(fuzz, dContext, surfaceType, origin);
228     if (!surface || !c.isValid()) {
229         return;
230     }
231 
232     sk_sp<GrDeferredDisplayList> ddl = make_ddl(fuzz, dContext, c);
233     if (!ddl) {
234         SkDebugf("Could not create ddl %s", GrBackendApiToStr(dContext->backend()));
235         return;
236     }
237     if (!draw_ddl(std::move(surface), std::move(ddl))) {
238         SkDebugf("Could not draw ddl in the backend");
239     }
240     return;
241 }
242