blob: be44d2039388231253d693591a690fd79473baff [file] [log] [blame]
Zepeng Hu94007012020-07-22 14:37:46 +00001/*
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
35static constexpr int kMaxWidth = 64;
36static constexpr int kMaxHeight = 64;
37static constexpr int kSampleCount = 1;
38
39static SkSurfaceProps gen_fuzzed_surface_props(Fuzz* fuzz) {
40 SkPixelGeometry pixel;
41 fuzz->nextEnum(&pixel, kBGR_V_SkPixelGeometry);
42 return SkSurfaceProps(0x0, pixel);
43}
44
45static 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
55static 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
124static 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
158static 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
173static 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
183static bool draw_ddl(sk_sp<SkSurface> surface, sk_sp<SkDeferredDisplayList> ddl) {
184 return surface->draw(std::move(ddl));
185}
186
187using SurfaceAndChar = std::tuple<sk_sp<SkSurface>, SkSurfaceCharacterization>;
188static 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
204DEF_FUZZ(CreateDDL, fuzz) {
205 SkColorType surfaceType;
206 GrSurfaceOrigin origin;
207 fuzz->nextEnum(&surfaceType, SkColorType::kLastEnum_SkColorType);
208 fuzz->nextEnum(&origin, GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin);
Robert Phillips32df8f82020-07-31 13:21:07 -0400209
Zepeng Hu94007012020-07-22 14:37:46 +0000210 sk_gpu_test::GrContextFactory factory;
Robert Phillips32df8f82020-07-31 13:21:07 -0400211 auto ctxInfo = factory.getContextInfo(sk_gpu_test::GrContextFactory::kGL_ContextType);
212
Zepeng Hu94007012020-07-22 14:37:46 +0000213 GrDirectContext* dContext = ctxInfo.directContext();
Robert Phillips32df8f82020-07-31 13:21:07 -0400214 if (!dContext) {
215 SkDebugf("Context creation failed");
216 return;
217 }
Zepeng Hu94007012020-07-22 14:37:46 +0000218
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}