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