Flutter Engine
The Flutter Engine
FuzzPrecompile.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2023 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 "fuzz/Fuzz.h"
9
13#include "include/core/SkFont.h"
23#include "modules/skcms/skcms.h"
39#include "tools/ToolUtils.h"
42
43using namespace skgpu::graphite;
44
45namespace {
46
47SkBlendMode random_blend_mode(Fuzz* fuzz) {
48 uint32_t temp;
49 fuzz->next(&temp);
50 return (SkBlendMode) (temp % kSkBlendModeCount);
51}
52
53SkColor random_opaque_skcolor(Fuzz* fuzz) {
55 fuzz->next(&color);
56 return 0xff000000 | color;
57}
58
59SkColor4f random_color4f(Fuzz* fuzz) {
60 bool makeOpaque;
61 fuzz->next(&makeOpaque);
62
64 fuzz->nextRange(&color.fR, 0, 1);
65 fuzz->nextRange(&color.fG, 0, 1);
66 fuzz->nextRange(&color.fB, 0, 1);
67 if (makeOpaque) {
68 color.fA = 1.0;
69 } else {
70 fuzz->nextRange(&color.fA, 0, 1);
71 }
72
73 return color;
74}
75
78 path.moveTo(0, 0);
79 path.lineTo(8, 2);
80 path.lineTo(16, 0);
81 path.lineTo(14, 8);
82 path.lineTo(16, 16);
83 path.lineTo(8, 14);
84 path.lineTo(0, 16);
85 path.lineTo(2, 8);
86 path.close();
87 return path.detach();
88}
89
90//--------------------------------------------------------------------------------------------------
91// color spaces
92
93const skcms_TransferFunction& random_transfer_function(Fuzz* fuzz) {
94 static constexpr skcms_TransferFunction gTransferFunctions[] = {
101 };
102
103 uint32_t xferFunction;
104 fuzz->next(&xferFunction);
105 xferFunction %= std::size(gTransferFunctions);
106 return gTransferFunctions[xferFunction];
107}
108
109const skcms_Matrix3x3& random_gamut(Fuzz* fuzz) {
110 static constexpr skcms_Matrix3x3 gGamuts[] = {
116 };
117
118 uint32_t gamut;
119 fuzz->next(&gamut);
120 gamut %= std::size(gGamuts);
121 return gGamuts[gamut];
122}
123
124enum class ColorSpaceType {
125 kNone,
126 kSRGB,
127 kSRGBLinear,
128 kRGB,
129
130 kLast = kRGB
131};
132
133static constexpr int kColorSpaceTypeCount = static_cast<int>(ColorSpaceType::kLast) + 1;
134
135sk_sp<SkColorSpace> create_colorspace(Fuzz* fuzz, ColorSpaceType csType) {
136 switch (csType) {
138 return nullptr;
139 case ColorSpaceType::kSRGB:
140 return SkColorSpace::MakeSRGB();
141 case ColorSpaceType::kSRGBLinear:
143 case ColorSpaceType::kRGB:
144 return SkColorSpace::MakeRGB(random_transfer_function(fuzz), random_gamut(fuzz));
145 }
146
148}
149
150sk_sp<SkColorSpace> create_random_colorspace(Fuzz* fuzz) {
151 uint32_t temp;
152 fuzz->next(&temp);
153 ColorSpaceType csType = (ColorSpaceType) (temp % kColorSpaceTypeCount);
154
155 return create_colorspace(fuzz, csType);
156}
157
158//--------------------------------------------------------------------------------------------------
159// color filters
160
161enum class ColorFilterType {
162 kNone,
163 kBlend,
164 kMatrix,
165 kHSLAMatrix,
166 // TODO: add more color filters
167
168 kLast = kHSLAMatrix
169};
170
171static constexpr int kColorFilterTypeCount = static_cast<int>(ColorFilterType::kLast) + 1;
172
173std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_blend_colorfilter(
174 Fuzz* fuzz) {
175
177
178 // SkColorFilters::Blend is clever and can weed out noop color filters. Loop until we get
179 // a valid color filter.
180 while (!cf && !fuzz->exhausted()) {
181 cf = SkColorFilters::Blend(random_color4f(fuzz),
182 create_random_colorspace(fuzz),
183 random_blend_mode(fuzz));
184 }
185
187
188 return { cf, o };
189}
190
191std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_matrix_colorfilter() {
195
196 return { cf, o };
197}
198
199std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_hsla_matrix_colorfilter() {
203
204 return { cf, o };
205}
206
207std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_colorfilter(
208 Fuzz* fuzz,
209 ColorFilterType type,
210 int depth) {
211 if (depth <= 0) {
212 return {};
213 }
214
215 switch (type) {
217 return { nullptr, nullptr };
218 case ColorFilterType::kBlend:
219 return create_blend_colorfilter(fuzz);
220 case ColorFilterType::kMatrix:
221 return create_matrix_colorfilter();
222 case ColorFilterType::kHSLAMatrix:
223 return create_hsla_matrix_colorfilter();
224 }
225
227}
228
229std::pair<sk_sp<SkColorFilter>, sk_sp<PrecompileColorFilter>> create_random_colorfilter(
230 Fuzz* fuzz,
231 int depth) {
232
233 uint32_t temp;
234 fuzz->next(&temp);
235 ColorFilterType cf = (ColorFilterType) (temp % kColorFilterTypeCount);
236
237 return create_colorfilter(fuzz, cf, depth);
238}
239
240//--------------------------------------------------------------------------------------------------
241std::pair<SkPaint, PaintOptions> create_random_paint(Fuzz* fuzz, int depth) {
242 if (depth <= 0) {
243 return {};
244 }
245
247 paint.setColor(random_opaque_skcolor(fuzz));
248
249 PaintOptions paintOptions;
250
251 {
252 auto [cf, o] = create_random_colorfilter(fuzz, depth - 1);
253 SkASSERT_RELEASE(!cf == !o);
254
255 if (cf) {
256 paint.setColorFilter(std::move(cf));
257 paintOptions.setColorFilters({o});
258 }
259 }
260
261 return { paint, paintOptions };
262}
263
264//--------------------------------------------------------------------------------------------------
265void check_draw(Context* context,
266 Recorder* recorder,
267 const SkPaint& paint,
268 DrawTypeFlags dt,
269 const SkPath& path) {
270 int before = context->priv().globalCache()->numGraphicsPipelines();
271
272 {
273 // TODO: vary the colorType of the target surface too
274 SkImageInfo ii = SkImageInfo::Make(16, 16,
277
278 sk_sp<SkSurface> surf = SkSurfaces::RenderTarget(recorder, ii);
279 SkCanvas* canvas = surf->getCanvas();
280
281 switch (dt) {
283 canvas->drawRect(SkRect::MakeWH(16, 16), paint);
284 canvas->drawPath(path, paint);
285 break;
286 default:
287 SkASSERT_RELEASE(false);
288 break;
289 }
290
291 std::unique_ptr<skgpu::graphite::Recording> recording = recorder->snap();
292 context->insertRecording({ recording.get() });
293 context->submit(SyncToCpu::kYes);
294 }
295
296 int after = context->priv().globalCache()->numGraphicsPipelines();
297
298 // Actually using the SkPaint with the specified type of draw shouldn't have caused
299 // any additional compilation
300 SkASSERT_RELEASE(before == after);
301}
302
303void fuzz_graphite(Fuzz* fuzz, Context* context, int depth = 9) {
304 auto recorder = context->makeRecorder();
306
309
310 std::unique_ptr<RuntimeEffectDictionary> rtDict = std::make_unique<RuntimeEffectDictionary>();
311 KeyContext precompileKeyContext(recorder->priv().caps(),
312 dict,
313 rtDict.get(),
314 ci,
315 /* dstTexture= */ nullptr,
316 /* dstOffset= */ {0, 0});
317
318 auto dstTexInfo = recorder->priv().caps()->getDefaultSampledTextureInfo(kRGBA_8888_SkColorType,
322 // Use Budgeted::kYes to avoid immediately instantiating the TextureProxy. This test doesn't
323 // require full resources.
324 sk_sp<TextureProxy> fakeDstTexture = TextureProxy::Make(recorder->priv().caps(),
325 recorder->priv().resourceProvider(),
326 SkISize::Make(1, 1),
327 dstTexInfo,
328 "FuzzPrecompileFakeDstTexture",
330 constexpr SkIPoint fakeDstOffset = SkIPoint::Make(0, 0);
331
334
336 : Layout::kStd140;
337
339 PipelineDataGatherer gatherer(layout);
340
341 auto [paint, paintOptions] = create_random_paint(fuzz, depth);
342
343 constexpr Coverage coverageOptions[3] = {
344 Coverage::kNone, Coverage::kSingleChannel, Coverage::kLCD};
345 uint32_t temp;
346 fuzz->next(&temp);
347 Coverage coverage = coverageOptions[temp % 3];
348
350 const SkBlenderBase* blender = as_BB(paint.getBlender());
351 if (blender) {
352 dstReadReq = GetDstReadRequirement(recorder->priv().caps(),
353 blender->asBlendMode(),
354 coverage);
355 }
356 bool needsDstSample = dstReadReq == DstReadRequirement::kTextureCopy ||
357 dstReadReq == DstReadRequirement::kTextureSample;
358 sk_sp<TextureProxy> curDst = needsDstSample ? fakeDstTexture : nullptr;
359
360 auto [paintID, uData, tData] = ExtractPaintData(recorder.get(),
361 &gatherer,
362 &builder,
363 layout,
364 {},
366 /* primitiveBlender= */ nullptr,
367 /* clipShader= */ nullptr,
368 dstReadReq,
369 /* skipColorXform= */ false),
370 {},
371 curDst,
372 fakeDstOffset,
373 ci);
374
375 std::vector<UniquePaintParamsID> precompileIDs;
376 paintOptions.priv().buildCombinations(precompileKeyContext,
377 &gatherer,
379 /* withPrimitiveBlender= */ false,
380 coverage,
381 [&](UniquePaintParamsID id,
383 bool /* withPrimitiveBlender */,
384 Coverage) {
385 precompileIDs.push_back(id);
386 });
387
388 // The specific key generated by ExtractPaintData should be one of the
389 // combinations generated by the combination system.
390 auto result = std::find(precompileIDs.begin(), precompileIDs.end(), paintID);
391
392#ifdef SK_DEBUG
393 if (result == precompileIDs.end()) {
394 SkDebugf("From paint: ");
395 dict->dump(paintID);
396
397 SkDebugf("From combination builder:");
398 for (auto iter : precompileIDs) {
399 dict->dump(iter);
400 }
401 }
402#endif
403
404 SkASSERT_RELEASE(result != precompileIDs.end());
405
406 {
407 context->priv().globalCache()->resetGraphicsPipelines();
408
409 int before = context->priv().globalCache()->numGraphicsPipelines();
410 Precompile(context, paintOptions, kDrawType);
411 int after = context->priv().globalCache()->numGraphicsPipelines();
412
413 SkASSERT_RELEASE(before == 0);
414 SkASSERT_RELEASE(after > before);
415
416 check_draw(context, recorder.get(), paint, kDrawType, path);
417 }
418}
419
420} // anonymous namespace
421
424
425 skgpu::ContextType contextType;
426#if defined(SK_METAL)
427 contextType = skgpu::ContextType::kMetal;
428#elif defined(SK_VULKAN)
429 contextType = skgpu::ContextType::kVulkan;
430#else
431 contextType = skgpu::ContextType::kMock;
432#endif
433
434 skiatest::graphite::ContextInfo ctxInfo = factory.getContextInfo(contextType);
435 skgpu::graphite::Context* context = ctxInfo.fContext;
436 if (!context) {
437 return;
438 }
439
440 fuzz_graphite(fuzz, context);
441}
DEF_FUZZ(Precompile, fuzz)
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
#define SkUNREACHABLE
Definition: SkAssert.h:135
#define SkASSERT_RELEASE(cond)
Definition: SkAssert.h:100
static constexpr int kSkBlendModeCount
Definition: SkBlendMode.h:76
SkBlendMode
Definition: SkBlendMode.h:38
SkBlenderBase * as_BB(SkBlender *blend)
Definition: SkBlenderBase.h:69
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
uint32_t SkColor
Definition: SkColor.h:37
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
@ kJPEG_Full_SkYUVColorSpace
describes full range
Definition: SkImageInfo.h:69
int find(T *array, int N, T item)
GLenum type
Definition: Fuzz.h:24
void next(T *t)
Definition: Fuzz.h:64
void nextRange(T *, Min, Max)
Definition: Fuzz.h:119
bool exhausted() const
Definition: Fuzz.h:39
virtual std::optional< SkBlendMode > asBlendMode() const
Definition: SkBlenderBase.h:45
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
void drawPath(const SkPath &path, const SkPaint &paint)
Definition: SkCanvas.cpp:1747
static sk_sp< SkColorFilter > Blend(const SkColor4f &c, sk_sp< SkColorSpace >, SkBlendMode mode)
static sk_sp< SkColorFilter > Matrix(const SkColorMatrix &)
static sk_sp< SkColorFilter > HSLAMatrix(const SkColorMatrix &)
static SkColorMatrix RGBtoYUV(SkYUVColorSpace)
static sk_sp< SkColorSpace > MakeSRGB()
static sk_sp< SkColorSpace > MakeRGB(const skcms_TransferFunction &transferFn, const skcms_Matrix3x3 &toXYZ)
static sk_sp< SkColorSpace > MakeSRGBLinear()
Definition: SkPath.h:59
SkCanvas * getCanvas()
Definition: SkSurface.cpp:82
virtual TextureInfo getDefaultSampledTextureInfo(SkColorType, Mipmapped mipmapped, Protected, Renderable) const =0
const GlobalCache * globalCache() const
Definition: ContextPriv.h:40
const ShaderCodeDictionary * shaderCodeDictionary() const
Definition: ContextPriv.h:34
BackendApi backend() const
Definition: Context.cpp:130
std::unique_ptr< Recorder > makeRecorder(const RecorderOptions &={})
Definition: Context.cpp:132
bool submit(SyncToCpu=SyncToCpu::kNo)
Definition: Context.cpp:162
bool insertRecording(const InsertRecordingInfo &)
Definition: Context.cpp:156
void buildCombinations(const KeyContext &keyContext, PipelineDataGatherer *gatherer, DrawTypeFlags drawTypes, bool withPrimitiveBlender, Coverage coverage, const ProcessCombination &processCombination) const
void setColorFilters(SkSpan< const sk_sp< PrecompileColorFilter > > colorFilters)
const Caps * caps() const
Definition: RecorderPriv.h:31
ResourceProvider * resourceProvider()
Definition: RecorderPriv.h:33
std::unique_ptr< Recording > snap()
Definition: Recorder.cpp:159
ContextInfo getContextInfo(skgpu::ContextType)
const Paint & paint
Definition: color_source.cc:38
static const skcms_Matrix3x3 gGamuts[]
Definition: colorspace.cpp:27
DlColor color
@ kMetal
Definition: embedder.h:85
GAsyncResult * result
SK_API sk_sp< SkDocument > Make(SkWStream *dst, const SkSerialProcs *=nullptr, std::function< void(const SkPicture *)> onEndPage=nullptr)
static constexpr skcms_Matrix3x3 kSRGB
Definition: SkColorSpace.h:67
static constexpr skcms_Matrix3x3 kAdobeRGB
Definition: SkColorSpace.h:77
static constexpr skcms_Matrix3x3 kXYZ
Definition: SkColorSpace.h:99
static constexpr skcms_Matrix3x3 kRec2020
Definition: SkColorSpace.h:93
static constexpr skcms_Matrix3x3 kDisplayP3
Definition: SkColorSpace.h:87
static constexpr skcms_TransferFunction kRec2020
Definition: SkColorSpace.h:54
static constexpr skcms_TransferFunction k2Dot2
Definition: SkColorSpace.h:48
static constexpr skcms_TransferFunction kSRGB
Definition: SkColorSpace.h:45
static constexpr skcms_TransferFunction kHLG
Definition: SkColorSpace.h:60
static constexpr skcms_TransferFunction kPQ
Definition: SkColorSpace.h:57
static constexpr skcms_TransferFunction kLinear
Definition: SkColorSpace.h:51
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
@ kNone
Definition: layer.h:53
@ kSRGB
Definition: image.h:17
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
SK_API sk_sp< PrecompileColorFilter > HSLAMatrix()
SK_API sk_sp< PrecompileColorFilter > Matrix()
DstReadRequirement GetDstReadRequirement(const Caps *caps, std::optional< SkBlendMode > blendMode, Coverage coverage)
void Precompile(Context *context, const PaintOptions &paintOptions, DrawTypeFlags drawTypes=kMostCommon)
DstReadRequirement
Definition: Caps.h:64
std::tuple< UniquePaintParamsID, const UniformDataBlock *, const TextureDataBlock * > ExtractPaintData(Recorder *recorder, PipelineDataGatherer *gatherer, PaintParamsKeyBuilder *builder, const Layout layout, const SkM44 &local2Dev, const PaintParams &p, const Geometry &geometry, sk_sp< TextureProxy > dstTexture, SkIPoint dstOffset, const SkColorInfo &targetColorInfo)
ContextType
Definition: ContextType.h:19
@ kVulkan
ANGLE on Metal ES 3 context.
@ kMock
Dawn on OpenGL ES.
static SkPath make_path()
static constexpr SkIPoint Make(int32_t x, int32_t y)
Definition: SkPoint_impl.h:38
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609
skgpu::graphite::Context * fContext