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