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 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); 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