xref: /aosp_15_r20/external/skia/fuzz/FuzzDDLThreading.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2021 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "fuzz/Fuzz.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "fuzz/FuzzCommon.h"
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkExecutor.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrDirectContext.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/SkImageGanesh.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/SkSurfaceGanesh.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDeque.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMutex.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTemplates.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkThreadID.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/chromium/GrDeferredDisplayList.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/chromium/GrDeferredDisplayListRecorder.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/chromium/GrPromiseImageTexture.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/chromium/SkImageChromium.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTaskGroup.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/image/SkImage_Ganesh.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "tools/gpu/GrContextFactory.h"
29*c8dee2aaSAndroid Build Coastguard Worker 
30*c8dee2aaSAndroid Build Coastguard Worker #include <atomic>
31*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
32*c8dee2aaSAndroid Build Coastguard Worker #include <queue>
33*c8dee2aaSAndroid Build Coastguard Worker 
34*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
35*c8dee2aaSAndroid Build Coastguard Worker using ContextType = sk_gpu_test::GrContextFactory::ContextType;
36*c8dee2aaSAndroid Build Coastguard Worker 
37*c8dee2aaSAndroid Build Coastguard Worker // be careful: `foo(make_fuzz_t<T>(f), make_fuzz_t<U>(f))` is undefined.
38*c8dee2aaSAndroid Build Coastguard Worker // In fact, all make_fuzz_foo() functions have this potential problem.
39*c8dee2aaSAndroid Build Coastguard Worker // Use sequence points!
40*c8dee2aaSAndroid Build Coastguard Worker template <typename T>
make_fuzz_t(Fuzz * fuzz)41*c8dee2aaSAndroid Build Coastguard Worker inline T make_fuzz_t(Fuzz* fuzz) {
42*c8dee2aaSAndroid Build Coastguard Worker     T t;
43*c8dee2aaSAndroid Build Coastguard Worker     fuzz->next(&t);
44*c8dee2aaSAndroid Build Coastguard Worker     return t;
45*c8dee2aaSAndroid Build Coastguard Worker }
46*c8dee2aaSAndroid Build Coastguard Worker 
47*c8dee2aaSAndroid Build Coastguard Worker class DDLFuzzer;
48*c8dee2aaSAndroid Build Coastguard Worker 
49*c8dee2aaSAndroid Build Coastguard Worker // This class stores the state of a given promise image owned by the fuzzer. It acts as the
50*c8dee2aaSAndroid Build Coastguard Worker // context for the callback procs of the promise image.
51*c8dee2aaSAndroid Build Coastguard Worker class PromiseImageInfo : public SkNVRefCnt<PromiseImageInfo> {
52*c8dee2aaSAndroid Build Coastguard Worker public:
53*c8dee2aaSAndroid Build Coastguard Worker     enum class State : int {
54*c8dee2aaSAndroid Build Coastguard Worker         kInitial,
55*c8dee2aaSAndroid Build Coastguard Worker         kTriedToFulfill,
56*c8dee2aaSAndroid Build Coastguard Worker         kDone
57*c8dee2aaSAndroid Build Coastguard Worker     };
58*c8dee2aaSAndroid Build Coastguard Worker 
59*c8dee2aaSAndroid Build Coastguard Worker     PromiseImageInfo() = default;
~PromiseImageInfo()60*c8dee2aaSAndroid Build Coastguard Worker     ~PromiseImageInfo() {
61*c8dee2aaSAndroid Build Coastguard Worker         // If we hit this, then the image or the texture will outlive this object which is bad.
62*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT_RELEASE(!fImage || fImage->unique());
63*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT_RELEASE(!fTexture || fTexture->unique());
64*c8dee2aaSAndroid Build Coastguard Worker         fImage.reset();
65*c8dee2aaSAndroid Build Coastguard Worker         fTexture.reset();
66*c8dee2aaSAndroid Build Coastguard Worker         State s = fState;
67*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT_RELEASE(!fDrawn || s == State::kDone);
68*c8dee2aaSAndroid Build Coastguard Worker     }
69*c8dee2aaSAndroid Build Coastguard Worker 
70*c8dee2aaSAndroid Build Coastguard Worker     // Make noncopyable
71*c8dee2aaSAndroid Build Coastguard Worker     PromiseImageInfo(PromiseImageInfo&) = delete;
72*c8dee2aaSAndroid Build Coastguard Worker     PromiseImageInfo& operator=(PromiseImageInfo&) = delete;
73*c8dee2aaSAndroid Build Coastguard Worker 
74*c8dee2aaSAndroid Build Coastguard Worker     DDLFuzzer* fFuzzer = nullptr;
75*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkImage> fImage;
76*c8dee2aaSAndroid Build Coastguard Worker     // At the moment, the atomicity of this isn't used because all our promise image callbacks
77*c8dee2aaSAndroid Build Coastguard Worker     // happen on the same thread. See the TODO below about them unreffing them off the GPU thread.
78*c8dee2aaSAndroid Build Coastguard Worker     std::atomic<State> fState{State::kInitial};
79*c8dee2aaSAndroid Build Coastguard Worker     std::atomic<bool> fDrawn{false};
80*c8dee2aaSAndroid Build Coastguard Worker 
81*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<GrPromiseImageTexture> fTexture;
82*c8dee2aaSAndroid Build Coastguard Worker };
83*c8dee2aaSAndroid Build Coastguard Worker 
84*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kPromiseImageCount = 8;
85*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkISize kPromiseImageSize{16, 16};
86*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kPromiseImagesPerDDL = 4;
87*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kRecordingThreadCount = 4;
88*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kIterationCount = 10000;
89*c8dee2aaSAndroid Build Coastguard Worker 
90*c8dee2aaSAndroid Build Coastguard Worker // A one-shot runner object for fuzzing our DDL threading. It creates an array of promise images,
91*c8dee2aaSAndroid Build Coastguard Worker // and concurrently records DDLs that reference them, playing each DDL back on the GPU thread.
92*c8dee2aaSAndroid Build Coastguard Worker // The backing textures for promise images may be recycled into a pool, or not, for each case
93*c8dee2aaSAndroid Build Coastguard Worker // as determined by the fuzzing data.
94*c8dee2aaSAndroid Build Coastguard Worker class DDLFuzzer {
95*c8dee2aaSAndroid Build Coastguard Worker public:
96*c8dee2aaSAndroid Build Coastguard Worker     DDLFuzzer(Fuzz*, ContextType);
97*c8dee2aaSAndroid Build Coastguard Worker     DDLFuzzer() = delete;
98*c8dee2aaSAndroid Build Coastguard Worker     // Make noncopyable
99*c8dee2aaSAndroid Build Coastguard Worker     DDLFuzzer(DDLFuzzer&) = delete;
100*c8dee2aaSAndroid Build Coastguard Worker     DDLFuzzer& operator=(DDLFuzzer&) = delete;
101*c8dee2aaSAndroid Build Coastguard Worker 
102*c8dee2aaSAndroid Build Coastguard Worker     void run();
103*c8dee2aaSAndroid Build Coastguard Worker 
104*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<GrPromiseImageTexture> fulfillPromiseImage(PromiseImageInfo&);
105*c8dee2aaSAndroid Build Coastguard Worker     void releasePromiseImage(PromiseImageInfo&);
106*c8dee2aaSAndroid Build Coastguard Worker private:
107*c8dee2aaSAndroid Build Coastguard Worker     void initPromiseImage(int index);
108*c8dee2aaSAndroid Build Coastguard Worker     void recordAndPlayDDL();
isOnGPUThread() const109*c8dee2aaSAndroid Build Coastguard Worker     bool isOnGPUThread() const { return SkGetThreadID() == fGpuThread; }
isOnMainThread() const110*c8dee2aaSAndroid Build Coastguard Worker     bool isOnMainThread() const { return SkGetThreadID() == fMainThread; }
111*c8dee2aaSAndroid Build Coastguard Worker 
112*c8dee2aaSAndroid Build Coastguard Worker     Fuzz* fFuzz = nullptr;
113*c8dee2aaSAndroid Build Coastguard Worker     GrDirectContext* fContext = nullptr;
114*c8dee2aaSAndroid Build Coastguard Worker     AutoTArray<PromiseImageInfo> fPromiseImages{kPromiseImageCount};
115*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkSurface> fSurface;
116*c8dee2aaSAndroid Build Coastguard Worker     GrSurfaceCharacterization fSurfaceCharacterization;
117*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<SkExecutor> fGpuExecutor = SkExecutor::MakeFIFOThreadPool(1, false);
118*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<SkExecutor> fRecordingExecutor =
119*c8dee2aaSAndroid Build Coastguard Worker         SkExecutor::MakeFIFOThreadPool(kRecordingThreadCount, false);
120*c8dee2aaSAndroid Build Coastguard Worker     SkTaskGroup fGpuTaskGroup{*fGpuExecutor};
121*c8dee2aaSAndroid Build Coastguard Worker     SkTaskGroup fRecordingTaskGroup{*fRecordingExecutor};
122*c8dee2aaSAndroid Build Coastguard Worker     SkThreadID fGpuThread = kIllegalThreadID;
123*c8dee2aaSAndroid Build Coastguard Worker     SkThreadID fMainThread = SkGetThreadID();
124*c8dee2aaSAndroid Build Coastguard Worker     std::queue<sk_sp<GrPromiseImageTexture>> fReusableTextures;
125*c8dee2aaSAndroid Build Coastguard Worker     sk_gpu_test::GrContextFactory fContextFactory;
126*c8dee2aaSAndroid Build Coastguard Worker };
127*c8dee2aaSAndroid Build Coastguard Worker 
DDLFuzzer(Fuzz * fuzz,ContextType contextType)128*c8dee2aaSAndroid Build Coastguard Worker DDLFuzzer::DDLFuzzer(Fuzz* fuzz, ContextType contextType) : fFuzz(fuzz) {
129*c8dee2aaSAndroid Build Coastguard Worker     sk_gpu_test::ContextInfo ctxInfo = fContextFactory.getContextInfo(contextType);
130*c8dee2aaSAndroid Build Coastguard Worker     sk_gpu_test::TestContext* testCtx = ctxInfo.testContext();
131*c8dee2aaSAndroid Build Coastguard Worker     fContext = ctxInfo.directContext();
132*c8dee2aaSAndroid Build Coastguard Worker     if (!fContext) {
133*c8dee2aaSAndroid Build Coastguard Worker         return;
134*c8dee2aaSAndroid Build Coastguard Worker     }
135*c8dee2aaSAndroid Build Coastguard Worker     SkISize canvasSize = kPromiseImageSize;
136*c8dee2aaSAndroid Build Coastguard Worker     canvasSize.fWidth *= kPromiseImagesPerDDL;
137*c8dee2aaSAndroid Build Coastguard Worker     SkImageInfo ii = SkImageInfo::Make(canvasSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
138*c8dee2aaSAndroid Build Coastguard Worker     fSurface = SkSurfaces::RenderTarget(fContext, skgpu::Budgeted::kNo, ii);
139*c8dee2aaSAndroid Build Coastguard Worker     if (!fSurface || !fSurface->characterize(&fSurfaceCharacterization)) {
140*c8dee2aaSAndroid Build Coastguard Worker         return;
141*c8dee2aaSAndroid Build Coastguard Worker     }
142*c8dee2aaSAndroid Build Coastguard Worker 
143*c8dee2aaSAndroid Build Coastguard Worker     testCtx->makeNotCurrent();
144*c8dee2aaSAndroid Build Coastguard Worker     fGpuTaskGroup.add([&]{
145*c8dee2aaSAndroid Build Coastguard Worker         testCtx->makeCurrent();
146*c8dee2aaSAndroid Build Coastguard Worker         fGpuThread = SkGetThreadID();
147*c8dee2aaSAndroid Build Coastguard Worker     });
148*c8dee2aaSAndroid Build Coastguard Worker     fGpuTaskGroup.wait();
149*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < kPromiseImageCount; ++i) {
150*c8dee2aaSAndroid Build Coastguard Worker         this->initPromiseImage(i);
151*c8dee2aaSAndroid Build Coastguard Worker     }
152*c8dee2aaSAndroid Build Coastguard Worker }
153*c8dee2aaSAndroid Build Coastguard Worker 
fulfillPromiseImage(PromiseImageInfo & promiseImage)154*c8dee2aaSAndroid Build Coastguard Worker sk_sp<GrPromiseImageTexture> DDLFuzzer::fulfillPromiseImage(PromiseImageInfo& promiseImage) {
155*c8dee2aaSAndroid Build Coastguard Worker     using State = PromiseImageInfo::State;
156*c8dee2aaSAndroid Build Coastguard Worker     if (!this->isOnGPUThread()) {
157*c8dee2aaSAndroid Build Coastguard Worker         fFuzz->signalBug();
158*c8dee2aaSAndroid Build Coastguard Worker     }
159*c8dee2aaSAndroid Build Coastguard Worker     bool success = make_fuzz_t<bool>(fFuzz);
160*c8dee2aaSAndroid Build Coastguard Worker     State prior = promiseImage.fState.exchange(State::kTriedToFulfill, std::memory_order_relaxed);
161*c8dee2aaSAndroid Build Coastguard Worker     if (prior != State::kInitial || promiseImage.fTexture != nullptr) {
162*c8dee2aaSAndroid Build Coastguard Worker         fFuzz->signalBug();
163*c8dee2aaSAndroid Build Coastguard Worker     }
164*c8dee2aaSAndroid Build Coastguard Worker     if (!success) {
165*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
166*c8dee2aaSAndroid Build Coastguard Worker     }
167*c8dee2aaSAndroid Build Coastguard Worker 
168*c8dee2aaSAndroid Build Coastguard Worker     // Try reusing an existing texture if we can and if the fuzzer wills it.
169*c8dee2aaSAndroid Build Coastguard Worker     if (!fReusableTextures.empty() && make_fuzz_t<bool>(fFuzz)) {
170*c8dee2aaSAndroid Build Coastguard Worker         promiseImage.fTexture = std::move(fReusableTextures.front());
171*c8dee2aaSAndroid Build Coastguard Worker         fReusableTextures.pop();
172*c8dee2aaSAndroid Build Coastguard Worker         return promiseImage.fTexture;
173*c8dee2aaSAndroid Build Coastguard Worker     }
174*c8dee2aaSAndroid Build Coastguard Worker 
175*c8dee2aaSAndroid Build Coastguard Worker     bool finishedBECreate = false;
176*c8dee2aaSAndroid Build Coastguard Worker     auto markFinished = [](void* context) {
177*c8dee2aaSAndroid Build Coastguard Worker         *(bool*)context = true;
178*c8dee2aaSAndroid Build Coastguard Worker     };
179*c8dee2aaSAndroid Build Coastguard Worker 
180*c8dee2aaSAndroid Build Coastguard Worker     GrBackendTexture backendTex =
181*c8dee2aaSAndroid Build Coastguard Worker             fContext->createBackendTexture(kPromiseImageSize.width(),
182*c8dee2aaSAndroid Build Coastguard Worker                                            kPromiseImageSize.height(),
183*c8dee2aaSAndroid Build Coastguard Worker                                            kRGBA_8888_SkColorType,
184*c8dee2aaSAndroid Build Coastguard Worker                                            SkColors::kRed,
185*c8dee2aaSAndroid Build Coastguard Worker                                            skgpu::Mipmapped::kNo,
186*c8dee2aaSAndroid Build Coastguard Worker                                            GrRenderable::kYes,
187*c8dee2aaSAndroid Build Coastguard Worker                                            GrProtected::kNo,
188*c8dee2aaSAndroid Build Coastguard Worker                                            markFinished,
189*c8dee2aaSAndroid Build Coastguard Worker                                            &finishedBECreate,
190*c8dee2aaSAndroid Build Coastguard Worker                                            /*label=*/"DDLFuzzer_FulFillPromiseImage");
191*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT_RELEASE(backendTex.isValid());
192*c8dee2aaSAndroid Build Coastguard Worker     while (!finishedBECreate) {
193*c8dee2aaSAndroid Build Coastguard Worker         fContext->checkAsyncWorkCompletion();
194*c8dee2aaSAndroid Build Coastguard Worker     }
195*c8dee2aaSAndroid Build Coastguard Worker 
196*c8dee2aaSAndroid Build Coastguard Worker     promiseImage.fTexture = GrPromiseImageTexture::Make(backendTex);
197*c8dee2aaSAndroid Build Coastguard Worker 
198*c8dee2aaSAndroid Build Coastguard Worker     return promiseImage.fTexture;
199*c8dee2aaSAndroid Build Coastguard Worker }
200*c8dee2aaSAndroid Build Coastguard Worker 
releasePromiseImage(PromiseImageInfo & promiseImage)201*c8dee2aaSAndroid Build Coastguard Worker void DDLFuzzer::releasePromiseImage(PromiseImageInfo& promiseImage) {
202*c8dee2aaSAndroid Build Coastguard Worker     using State = PromiseImageInfo::State;
203*c8dee2aaSAndroid Build Coastguard Worker     // TODO: This requirement will go away when we unref promise images off the GPU thread.
204*c8dee2aaSAndroid Build Coastguard Worker     if (!this->isOnGPUThread()) {
205*c8dee2aaSAndroid Build Coastguard Worker         fFuzz->signalBug();
206*c8dee2aaSAndroid Build Coastguard Worker     }
207*c8dee2aaSAndroid Build Coastguard Worker 
208*c8dee2aaSAndroid Build Coastguard Worker     State old = promiseImage.fState.exchange(State::kDone, std::memory_order_relaxed);
209*c8dee2aaSAndroid Build Coastguard Worker     if (promiseImage.fDrawn && old != State::kTriedToFulfill) {
210*c8dee2aaSAndroid Build Coastguard Worker         fFuzz->signalBug();
211*c8dee2aaSAndroid Build Coastguard Worker     }
212*c8dee2aaSAndroid Build Coastguard Worker 
213*c8dee2aaSAndroid Build Coastguard Worker     // If we failed to fulfill, then nothing to be done.
214*c8dee2aaSAndroid Build Coastguard Worker     if (!promiseImage.fTexture) {
215*c8dee2aaSAndroid Build Coastguard Worker         return;
216*c8dee2aaSAndroid Build Coastguard Worker     }
217*c8dee2aaSAndroid Build Coastguard Worker 
218*c8dee2aaSAndroid Build Coastguard Worker     bool reuse = make_fuzz_t<bool>(fFuzz);
219*c8dee2aaSAndroid Build Coastguard Worker     if (reuse) {
220*c8dee2aaSAndroid Build Coastguard Worker         fReusableTextures.push(std::move(promiseImage.fTexture));
221*c8dee2aaSAndroid Build Coastguard Worker     } else {
222*c8dee2aaSAndroid Build Coastguard Worker         fContext->deleteBackendTexture(promiseImage.fTexture->backendTexture());
223*c8dee2aaSAndroid Build Coastguard Worker     }
224*c8dee2aaSAndroid Build Coastguard Worker     promiseImage.fTexture = nullptr;
225*c8dee2aaSAndroid Build Coastguard Worker }
226*c8dee2aaSAndroid Build Coastguard Worker 
fuzz_promise_image_fulfill(void * ctxIn)227*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<GrPromiseImageTexture> fuzz_promise_image_fulfill(void* ctxIn) {
228*c8dee2aaSAndroid Build Coastguard Worker     PromiseImageInfo& fuzzPromiseImage = *(PromiseImageInfo*)ctxIn;
229*c8dee2aaSAndroid Build Coastguard Worker     return fuzzPromiseImage.fFuzzer->fulfillPromiseImage(fuzzPromiseImage);
230*c8dee2aaSAndroid Build Coastguard Worker }
231*c8dee2aaSAndroid Build Coastguard Worker 
fuzz_promise_image_release(void * ctxIn)232*c8dee2aaSAndroid Build Coastguard Worker static void fuzz_promise_image_release(void* ctxIn) {
233*c8dee2aaSAndroid Build Coastguard Worker     PromiseImageInfo& fuzzPromiseImage = *(PromiseImageInfo*)ctxIn;
234*c8dee2aaSAndroid Build Coastguard Worker     fuzzPromiseImage.fFuzzer->releasePromiseImage(fuzzPromiseImage);
235*c8dee2aaSAndroid Build Coastguard Worker }
236*c8dee2aaSAndroid Build Coastguard Worker 
initPromiseImage(int index)237*c8dee2aaSAndroid Build Coastguard Worker void DDLFuzzer::initPromiseImage(int index) {
238*c8dee2aaSAndroid Build Coastguard Worker     PromiseImageInfo& promiseImage = fPromiseImages[index];
239*c8dee2aaSAndroid Build Coastguard Worker     promiseImage.fFuzzer = this;
240*c8dee2aaSAndroid Build Coastguard Worker     GrBackendFormat backendFmt = fContext->defaultBackendFormat(kRGBA_8888_SkColorType,
241*c8dee2aaSAndroid Build Coastguard Worker                                                                 GrRenderable::kYes);
242*c8dee2aaSAndroid Build Coastguard Worker     promiseImage.fImage = SkImages::PromiseTextureFrom(fContext->threadSafeProxy(),
243*c8dee2aaSAndroid Build Coastguard Worker                                                        backendFmt,
244*c8dee2aaSAndroid Build Coastguard Worker                                                        kPromiseImageSize,
245*c8dee2aaSAndroid Build Coastguard Worker                                                        skgpu::Mipmapped::kNo,
246*c8dee2aaSAndroid Build Coastguard Worker                                                        kTopLeft_GrSurfaceOrigin,
247*c8dee2aaSAndroid Build Coastguard Worker                                                        kRGBA_8888_SkColorType,
248*c8dee2aaSAndroid Build Coastguard Worker                                                        kUnpremul_SkAlphaType,
249*c8dee2aaSAndroid Build Coastguard Worker                                                        SkColorSpace::MakeSRGB(),
250*c8dee2aaSAndroid Build Coastguard Worker                                                        &fuzz_promise_image_fulfill,
251*c8dee2aaSAndroid Build Coastguard Worker                                                        &fuzz_promise_image_release,
252*c8dee2aaSAndroid Build Coastguard Worker                                                        &promiseImage);
253*c8dee2aaSAndroid Build Coastguard Worker }
254*c8dee2aaSAndroid Build Coastguard Worker 
recordAndPlayDDL()255*c8dee2aaSAndroid Build Coastguard Worker void DDLFuzzer::recordAndPlayDDL() {
256*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!this->isOnGPUThread() && !this->isOnMainThread());
257*c8dee2aaSAndroid Build Coastguard Worker     GrDeferredDisplayListRecorder recorder(fSurfaceCharacterization);
258*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas* canvas = recorder.getCanvas();
259*c8dee2aaSAndroid Build Coastguard Worker     // Draw promise images in a strip
260*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < kPromiseImagesPerDDL; i++) {
261*c8dee2aaSAndroid Build Coastguard Worker         int xOffset = i * kPromiseImageSize.width();
262*c8dee2aaSAndroid Build Coastguard Worker         int j;
263*c8dee2aaSAndroid Build Coastguard Worker         // Pick random promise images to draw.
264*c8dee2aaSAndroid Build Coastguard Worker         fFuzz->nextRange(&j, 0, kPromiseImageCount - 1);
265*c8dee2aaSAndroid Build Coastguard Worker         fPromiseImages[j].fDrawn = true;
266*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawImage(fPromiseImages[j].fImage, xOffset, 0);
267*c8dee2aaSAndroid Build Coastguard Worker     }
268*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<GrDeferredDisplayList> ddl = recorder.detach();
269*c8dee2aaSAndroid Build Coastguard Worker     fGpuTaskGroup.add([ddl{std::move(ddl)}, this] {
270*c8dee2aaSAndroid Build Coastguard Worker         bool success = skgpu::ganesh::DrawDDL(fSurface, std::move(ddl));
271*c8dee2aaSAndroid Build Coastguard Worker         if (!success) {
272*c8dee2aaSAndroid Build Coastguard Worker             fFuzz->signalBug();
273*c8dee2aaSAndroid Build Coastguard Worker         }
274*c8dee2aaSAndroid Build Coastguard Worker     });
275*c8dee2aaSAndroid Build Coastguard Worker }
276*c8dee2aaSAndroid Build Coastguard Worker 
run()277*c8dee2aaSAndroid Build Coastguard Worker void DDLFuzzer::run() {
278*c8dee2aaSAndroid Build Coastguard Worker     if (!fSurface) {
279*c8dee2aaSAndroid Build Coastguard Worker         return;
280*c8dee2aaSAndroid Build Coastguard Worker     }
281*c8dee2aaSAndroid Build Coastguard Worker     fRecordingTaskGroup.batch(kIterationCount, [this](int i) { this->recordAndPlayDDL(); });
282*c8dee2aaSAndroid Build Coastguard Worker     fRecordingTaskGroup.wait();
283*c8dee2aaSAndroid Build Coastguard Worker 
284*c8dee2aaSAndroid Build Coastguard Worker     fGpuTaskGroup.add([this] { fContext->flushAndSubmit(fSurface.get(), GrSyncCpu::kYes); });
285*c8dee2aaSAndroid Build Coastguard Worker 
286*c8dee2aaSAndroid Build Coastguard Worker     fGpuTaskGroup.wait();
287*c8dee2aaSAndroid Build Coastguard Worker 
288*c8dee2aaSAndroid Build Coastguard Worker     fGpuTaskGroup.add([this] {
289*c8dee2aaSAndroid Build Coastguard Worker         while (!fReusableTextures.empty()) {
290*c8dee2aaSAndroid Build Coastguard Worker             sk_sp<GrPromiseImageTexture> gpuTexture = std::move(fReusableTextures.front());
291*c8dee2aaSAndroid Build Coastguard Worker             fContext->deleteBackendTexture(gpuTexture->backendTexture());
292*c8dee2aaSAndroid Build Coastguard Worker             fReusableTextures.pop();
293*c8dee2aaSAndroid Build Coastguard Worker         }
294*c8dee2aaSAndroid Build Coastguard Worker         fContextFactory.destroyContexts();
295*c8dee2aaSAndroid Build Coastguard Worker         // TODO: Release promise images not on the GPU thread.
296*c8dee2aaSAndroid Build Coastguard Worker         fPromiseImages.reset(0);
297*c8dee2aaSAndroid Build Coastguard Worker     });
298*c8dee2aaSAndroid Build Coastguard Worker     fGpuTaskGroup.wait();
299*c8dee2aaSAndroid Build Coastguard Worker }
300*c8dee2aaSAndroid Build Coastguard Worker 
DEF_FUZZ(DDLThreadingGL,fuzz)301*c8dee2aaSAndroid Build Coastguard Worker DEF_FUZZ(DDLThreadingGL, fuzz) {
302*c8dee2aaSAndroid Build Coastguard Worker     DDLFuzzer(fuzz, skgpu::ContextType::kGL).run();
303*c8dee2aaSAndroid Build Coastguard Worker }
304