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