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