xref: /aosp_15_r20/external/skia/tests/GrFinishedFlushTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2019 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 "include/core/SkAlphaType.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorType.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/GpuTypes.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrDirectContext.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrTypes.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/SkSurfaceGanesh.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrCaps.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrDirectContextPriv.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "tests/CtsEnforcement.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "tools/gpu/FenceSync.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "tools/gpu/ManagedBackendTexture.h"
29*c8dee2aaSAndroid Build Coastguard Worker 
30*c8dee2aaSAndroid Build Coastguard Worker #include <chrono>
31*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
32*c8dee2aaSAndroid Build Coastguard Worker 
33*c8dee2aaSAndroid Build Coastguard Worker struct GrContextOptions;
34*c8dee2aaSAndroid Build Coastguard Worker 
35*c8dee2aaSAndroid Build Coastguard Worker using namespace sk_gpu_test;
36*c8dee2aaSAndroid Build Coastguard Worker 
testing_finished_proc(void * ctx)37*c8dee2aaSAndroid Build Coastguard Worker static void testing_finished_proc(void* ctx) {
38*c8dee2aaSAndroid Build Coastguard Worker     int* count = (int*)ctx;
39*c8dee2aaSAndroid Build Coastguard Worker     *count += 1;
40*c8dee2aaSAndroid Build Coastguard Worker }
41*c8dee2aaSAndroid Build Coastguard Worker 
busy_wait_for_callback(int * count,int expectedValue,GrDirectContext * dContext,skiatest::Reporter * reporter)42*c8dee2aaSAndroid Build Coastguard Worker static void busy_wait_for_callback(int* count, int expectedValue, GrDirectContext* dContext,
43*c8dee2aaSAndroid Build Coastguard Worker                                    skiatest::Reporter* reporter) {
44*c8dee2aaSAndroid Build Coastguard Worker     // Busy waiting should detect that the work is done.
45*c8dee2aaSAndroid Build Coastguard Worker     auto begin = std::chrono::steady_clock::now();
46*c8dee2aaSAndroid Build Coastguard Worker     auto end = begin;
47*c8dee2aaSAndroid Build Coastguard Worker     do {
48*c8dee2aaSAndroid Build Coastguard Worker         dContext->checkAsyncWorkCompletion();
49*c8dee2aaSAndroid Build Coastguard Worker         end = std::chrono::steady_clock::now();
50*c8dee2aaSAndroid Build Coastguard Worker     } while (*count != expectedValue && (end - begin) < std::chrono::seconds(1));
51*c8dee2aaSAndroid Build Coastguard Worker     if (*count != expectedValue) {
52*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "Expected count failed to reach %d within 1 second of busy waiting.",
53*c8dee2aaSAndroid Build Coastguard Worker                expectedValue);
54*c8dee2aaSAndroid Build Coastguard Worker     }
55*c8dee2aaSAndroid Build Coastguard Worker }
56*c8dee2aaSAndroid Build Coastguard Worker 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(FlushFinishedProcTest,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)57*c8dee2aaSAndroid Build Coastguard Worker DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(FlushFinishedProcTest,
58*c8dee2aaSAndroid Build Coastguard Worker                                        reporter,
59*c8dee2aaSAndroid Build Coastguard Worker                                        ctxInfo,
60*c8dee2aaSAndroid Build Coastguard Worker                                        CtsEnforcement::kApiLevel_T) {
61*c8dee2aaSAndroid Build Coastguard Worker     auto dContext = ctxInfo.directContext();
62*c8dee2aaSAndroid Build Coastguard Worker 
63*c8dee2aaSAndroid Build Coastguard Worker     SkImageInfo info =
64*c8dee2aaSAndroid Build Coastguard Worker             SkImageInfo::Make(8, 8, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
65*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkSurface> surface = SkSurfaces::RenderTarget(dContext, skgpu::Budgeted::kNo, info);
66*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas* canvas = surface->getCanvas();
67*c8dee2aaSAndroid Build Coastguard Worker 
68*c8dee2aaSAndroid Build Coastguard Worker     canvas->clear(SK_ColorGREEN);
69*c8dee2aaSAndroid Build Coastguard Worker     auto image = surface->makeImageSnapshot();
70*c8dee2aaSAndroid Build Coastguard Worker 
71*c8dee2aaSAndroid Build Coastguard Worker     dContext->flush();
72*c8dee2aaSAndroid Build Coastguard Worker     dContext->submit(GrSyncCpu::kYes);
73*c8dee2aaSAndroid Build Coastguard Worker 
74*c8dee2aaSAndroid Build Coastguard Worker     int count = 0;
75*c8dee2aaSAndroid Build Coastguard Worker 
76*c8dee2aaSAndroid Build Coastguard Worker     GrFlushInfo flushInfoFinishedProc;
77*c8dee2aaSAndroid Build Coastguard Worker     flushInfoFinishedProc.fFinishedProc = testing_finished_proc;
78*c8dee2aaSAndroid Build Coastguard Worker     flushInfoFinishedProc.fFinishedContext = (void*)&count;
79*c8dee2aaSAndroid Build Coastguard Worker     // There is no work on the surface so flushing may immediately call the finished proc.
80*c8dee2aaSAndroid Build Coastguard Worker     dContext->flush(surface.get(), flushInfoFinishedProc);
81*c8dee2aaSAndroid Build Coastguard Worker     dContext->submit();
82*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, count == 0 || count == 1);
83*c8dee2aaSAndroid Build Coastguard Worker     // Busy waiting should detect that the work is done.
84*c8dee2aaSAndroid Build Coastguard Worker     busy_wait_for_callback(&count, 1, dContext, reporter);
85*c8dee2aaSAndroid Build Coastguard Worker 
86*c8dee2aaSAndroid Build Coastguard Worker     canvas->clear(SK_ColorRED);
87*c8dee2aaSAndroid Build Coastguard Worker 
88*c8dee2aaSAndroid Build Coastguard Worker     dContext->flush(surface.get(), flushInfoFinishedProc);
89*c8dee2aaSAndroid Build Coastguard Worker     dContext->submit(GrSyncCpu::kNo);
90*c8dee2aaSAndroid Build Coastguard Worker 
91*c8dee2aaSAndroid Build Coastguard Worker     bool expectAsyncCallback = dContext->priv().caps()->finishedProcAsyncCallbackSupport();
92*c8dee2aaSAndroid Build Coastguard Worker     if (expectAsyncCallback) {
93*c8dee2aaSAndroid Build Coastguard Worker         // On Vulkan the command buffer we just submitted may or may not have finished immediately
94*c8dee2aaSAndroid Build Coastguard Worker         // so the finish proc may not have been called.
95*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, count == 1 || count == 2);
96*c8dee2aaSAndroid Build Coastguard Worker     } else {
97*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, count == 2);
98*c8dee2aaSAndroid Build Coastguard Worker     }
99*c8dee2aaSAndroid Build Coastguard Worker     dContext->flush();
100*c8dee2aaSAndroid Build Coastguard Worker     dContext->submit(GrSyncCpu::kYes);
101*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, count == 2);
102*c8dee2aaSAndroid Build Coastguard Worker 
103*c8dee2aaSAndroid Build Coastguard Worker     // Test flushing via the SkImage
104*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawImage(image, 0, 0);
105*c8dee2aaSAndroid Build Coastguard Worker     dContext->flush(image, flushInfoFinishedProc);
106*c8dee2aaSAndroid Build Coastguard Worker     dContext->submit(GrSyncCpu::kNo);
107*c8dee2aaSAndroid Build Coastguard Worker     if (expectAsyncCallback) {
108*c8dee2aaSAndroid Build Coastguard Worker         // On Vulkan the command buffer we just submitted may or may not have finished immediately
109*c8dee2aaSAndroid Build Coastguard Worker         // so the finish proc may not have been called.
110*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, count == 2 || count == 3);
111*c8dee2aaSAndroid Build Coastguard Worker     } else {
112*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, count == 3);
113*c8dee2aaSAndroid Build Coastguard Worker     }
114*c8dee2aaSAndroid Build Coastguard Worker     dContext->flush();
115*c8dee2aaSAndroid Build Coastguard Worker     dContext->submit(GrSyncCpu::kYes);
116*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, count == 3);
117*c8dee2aaSAndroid Build Coastguard Worker 
118*c8dee2aaSAndroid Build Coastguard Worker     // Test flushing via the GrDirectContext
119*c8dee2aaSAndroid Build Coastguard Worker     canvas->clear(SK_ColorBLUE);
120*c8dee2aaSAndroid Build Coastguard Worker     dContext->flush(flushInfoFinishedProc);
121*c8dee2aaSAndroid Build Coastguard Worker     dContext->submit(GrSyncCpu::kNo);
122*c8dee2aaSAndroid Build Coastguard Worker     if (expectAsyncCallback) {
123*c8dee2aaSAndroid Build Coastguard Worker         // On Vulkan the command buffer we just submitted may or may not have finished immediately
124*c8dee2aaSAndroid Build Coastguard Worker         // so the finish proc may not have been called.
125*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, count == 3 || count == 4);
126*c8dee2aaSAndroid Build Coastguard Worker     } else {
127*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, count == 4);
128*c8dee2aaSAndroid Build Coastguard Worker     }
129*c8dee2aaSAndroid Build Coastguard Worker     dContext->flush();
130*c8dee2aaSAndroid Build Coastguard Worker     dContext->submit(GrSyncCpu::kYes);
131*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, count == 4);
132*c8dee2aaSAndroid Build Coastguard Worker 
133*c8dee2aaSAndroid Build Coastguard Worker     // There is no work on the surface so flushing may immediately call the finished proc.
134*c8dee2aaSAndroid Build Coastguard Worker     dContext->flush(flushInfoFinishedProc);
135*c8dee2aaSAndroid Build Coastguard Worker     dContext->submit(GrSyncCpu::kNo);
136*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, count == 4 || count == 5);
137*c8dee2aaSAndroid Build Coastguard Worker     busy_wait_for_callback(&count, 5, dContext, reporter);
138*c8dee2aaSAndroid Build Coastguard Worker 
139*c8dee2aaSAndroid Build Coastguard Worker     count = 0;
140*c8dee2aaSAndroid Build Coastguard Worker     int count2 = 0;
141*c8dee2aaSAndroid Build Coastguard Worker     canvas->clear(SK_ColorGREEN);
142*c8dee2aaSAndroid Build Coastguard Worker     dContext->flush(surface.get(), flushInfoFinishedProc);
143*c8dee2aaSAndroid Build Coastguard Worker     dContext->submit(GrSyncCpu::kNo);
144*c8dee2aaSAndroid Build Coastguard Worker     // There is no work to be flushed here so this will return immediately, but make sure the
145*c8dee2aaSAndroid Build Coastguard Worker     // finished call from this proc isn't called till the previous surface flush also is finished.
146*c8dee2aaSAndroid Build Coastguard Worker     flushInfoFinishedProc.fFinishedContext = (void*)&count2;
147*c8dee2aaSAndroid Build Coastguard Worker     dContext->flush(flushInfoFinishedProc);
148*c8dee2aaSAndroid Build Coastguard Worker     dContext->submit(GrSyncCpu::kNo);
149*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, count <= 1 && count2 <= count);
150*c8dee2aaSAndroid Build Coastguard Worker 
151*c8dee2aaSAndroid Build Coastguard Worker     dContext->flush();
152*c8dee2aaSAndroid Build Coastguard Worker     dContext->submit(GrSyncCpu::kYes);
153*c8dee2aaSAndroid Build Coastguard Worker 
154*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, count == 1);
155*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, count == count2);
156*c8dee2aaSAndroid Build Coastguard Worker }
157*c8dee2aaSAndroid Build Coastguard Worker 
158*c8dee2aaSAndroid Build Coastguard Worker 
abandon_context(void * context)159*c8dee2aaSAndroid Build Coastguard Worker static void abandon_context(void* context) {
160*c8dee2aaSAndroid Build Coastguard Worker     ((GrDirectContext*)context)->abandonContext();
161*c8dee2aaSAndroid Build Coastguard Worker }
162*c8dee2aaSAndroid Build Coastguard Worker 
async_callback(void * c,std::unique_ptr<const SkImage::AsyncReadResult> result)163*c8dee2aaSAndroid Build Coastguard Worker static void async_callback(void* c, std::unique_ptr<const SkImage::AsyncReadResult> result) {
164*c8dee2aaSAndroid Build Coastguard Worker     // We don't actually care about the results so just drop them without doing anything.
165*c8dee2aaSAndroid Build Coastguard Worker }
166*c8dee2aaSAndroid Build Coastguard Worker 
167*c8dee2aaSAndroid Build Coastguard Worker // This test checks that calls to the async read pixels callback can safely be made even if the
168*c8dee2aaSAndroid Build Coastguard Worker // context has been abandoned previously. Specifically there was a bug where the client buffer
169*c8dee2aaSAndroid Build Coastguard Worker // manager stored on the GrDirectContext was accessed in the async callback after it was deleted.
170*c8dee2aaSAndroid Build Coastguard Worker // This bug is detected on ASAN bots running non GL backends (GL isn't affected purely based on
171*c8dee2aaSAndroid Build Coastguard Worker // how we call finish callbacks during abandon).
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(FinishedAsyncProcWhenAbandonedTest,reporter,ctxInfo,CtsEnforcement::kApiLevel_U)172*c8dee2aaSAndroid Build Coastguard Worker DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(FinishedAsyncProcWhenAbandonedTest,
173*c8dee2aaSAndroid Build Coastguard Worker                                        reporter,
174*c8dee2aaSAndroid Build Coastguard Worker                                        ctxInfo,
175*c8dee2aaSAndroid Build Coastguard Worker                                        CtsEnforcement::kApiLevel_U) {
176*c8dee2aaSAndroid Build Coastguard Worker     auto dContext = ctxInfo.directContext();
177*c8dee2aaSAndroid Build Coastguard Worker 
178*c8dee2aaSAndroid Build Coastguard Worker     SkImageInfo info =
179*c8dee2aaSAndroid Build Coastguard Worker             SkImageInfo::Make(8, 8, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
180*c8dee2aaSAndroid Build Coastguard Worker 
181*c8dee2aaSAndroid Build Coastguard Worker     auto mbet = sk_gpu_test::ManagedBackendTexture::MakeFromInfo(
182*c8dee2aaSAndroid Build Coastguard Worker             dContext, info, skgpu::Mipmapped::kNo, GrRenderable::kYes);
183*c8dee2aaSAndroid Build Coastguard Worker     if (!mbet) {
184*c8dee2aaSAndroid Build Coastguard Worker         return;
185*c8dee2aaSAndroid Build Coastguard Worker     }
186*c8dee2aaSAndroid Build Coastguard Worker 
187*c8dee2aaSAndroid Build Coastguard Worker     auto surface = SkSurfaces::WrapBackendTexture(dContext,
188*c8dee2aaSAndroid Build Coastguard Worker                                                   mbet->texture(),
189*c8dee2aaSAndroid Build Coastguard Worker                                                   kTopLeft_GrSurfaceOrigin,
190*c8dee2aaSAndroid Build Coastguard Worker                                                   /*sample count*/ 1,
191*c8dee2aaSAndroid Build Coastguard Worker                                                   kRGBA_8888_SkColorType,
192*c8dee2aaSAndroid Build Coastguard Worker                                                   /*color space*/ nullptr,
193*c8dee2aaSAndroid Build Coastguard Worker                                                   /*surface props*/ nullptr,
194*c8dee2aaSAndroid Build Coastguard Worker                                                   sk_gpu_test::ManagedBackendTexture::ReleaseProc,
195*c8dee2aaSAndroid Build Coastguard Worker                                                   mbet->releaseContext(nullptr, nullptr));
196*c8dee2aaSAndroid Build Coastguard Worker 
197*c8dee2aaSAndroid Build Coastguard Worker     if (!surface) {
198*c8dee2aaSAndroid Build Coastguard Worker         return;
199*c8dee2aaSAndroid Build Coastguard Worker     }
200*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas* canvas = surface->getCanvas();
201*c8dee2aaSAndroid Build Coastguard Worker     canvas->clear(SK_ColorGREEN);
202*c8dee2aaSAndroid Build Coastguard Worker 
203*c8dee2aaSAndroid Build Coastguard Worker     // To trigger bug we must have a finish callback that abanonds the context before an asyc
204*c8dee2aaSAndroid Build Coastguard Worker     // read callbck on the same command buffer. So we add the abandon callback first and flush
205*c8dee2aaSAndroid Build Coastguard Worker     // then add the asyc to enforce this order.
206*c8dee2aaSAndroid Build Coastguard Worker     GrFlushInfo flushInfo;
207*c8dee2aaSAndroid Build Coastguard Worker     flushInfo.fFinishedProc = abandon_context;
208*c8dee2aaSAndroid Build Coastguard Worker     flushInfo.fFinishedContext = dContext;
209*c8dee2aaSAndroid Build Coastguard Worker 
210*c8dee2aaSAndroid Build Coastguard Worker     dContext->flush(flushInfo);
211*c8dee2aaSAndroid Build Coastguard Worker 
212*c8dee2aaSAndroid Build Coastguard Worker     surface->asyncRescaleAndReadPixels(info,
213*c8dee2aaSAndroid Build Coastguard Worker                                        SkIRect::MakeWH(8, 8),
214*c8dee2aaSAndroid Build Coastguard Worker                                        SkImage::RescaleGamma::kSrc,
215*c8dee2aaSAndroid Build Coastguard Worker                                        SkImage::RescaleMode::kNearest,
216*c8dee2aaSAndroid Build Coastguard Worker                                        async_callback,
217*c8dee2aaSAndroid Build Coastguard Worker                                        nullptr);
218*c8dee2aaSAndroid Build Coastguard Worker 
219*c8dee2aaSAndroid Build Coastguard Worker     surface.reset();
220*c8dee2aaSAndroid Build Coastguard Worker 
221*c8dee2aaSAndroid Build Coastguard Worker     dContext->flushAndSubmit(GrSyncCpu::kYes);
222*c8dee2aaSAndroid Build Coastguard Worker }
223