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