xref: /aosp_15_r20/external/skia/tests/SurfaceSemaphoreTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2017 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/SkBitmap.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColor.h"
12 #include "include/core/SkColorSpace.h"
13 #include "include/core/SkColorType.h"
14 #include "include/core/SkImage.h"
15 #include "include/core/SkImageInfo.h"
16 #include "include/core/SkPaint.h"
17 #include "include/core/SkRect.h"
18 #include "include/core/SkRefCnt.h"
19 #include "include/core/SkString.h"
20 #include "include/core/SkSurface.h"
21 #include "include/core/SkTypes.h"
22 #include "include/gpu/GpuTypes.h"
23 #include "include/gpu/ganesh/GrBackendSemaphore.h"
24 #include "include/gpu/ganesh/GrBackendSurface.h"
25 #include "include/gpu/ganesh/GrDirectContext.h"
26 #include "include/gpu/ganesh/GrTypes.h"
27 #include "include/gpu/ganesh/SkImageGanesh.h"
28 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
29 #include "include/private/base/SkTemplates.h"
30 #include "src/gpu/ganesh/GrCaps.h"
31 #include "src/gpu/ganesh/GrDirectContextPriv.h"
32 #include "tests/CtsEnforcement.h"
33 #include "tests/Test.h"
34 #include "tools/gpu/ContextType.h"
35 #include "tools/gpu/TestContext.h"
36 
37 #include <cstring>
38 #include <cstdint>
39 #include <initializer_list>
40 
41 #ifdef SK_GL
42 #include "include/gpu/ganesh/gl/GrGLFunctions.h"
43 #include "include/gpu/ganesh/gl/GrGLInterface.h"
44 #include "include/gpu/ganesh/gl/GrGLTypes.h"
45 #include "src/gpu/ganesh/gl/GrGLGpu.h"
46 #include "src/gpu/ganesh/gl/GrGLUtil.h"
47 #endif
48 
49 #ifdef SK_VULKAN
50 #include "include/gpu/ganesh/vk/GrVkBackendSemaphore.h"
51 #include "include/gpu/ganesh/vk/GrVkBackendSurface.h"
52 #include "src/gpu/ganesh/vk/GrVkCommandPool.h"
53 #include "src/gpu/ganesh/vk/GrVkGpu.h"
54 #include "src/gpu/ganesh/vk/GrVkUtil.h"
55 
56 #include <vulkan/vulkan_core.h>
57 
58 namespace skgpu { struct VulkanInterface; }
59 
60 #ifdef VK_USE_PLATFORM_WIN32_KHR
61 // windows wants to define this as CreateSemaphoreA or CreateSemaphoreW
62 #undef CreateSemaphore
63 #endif
64 #endif
65 
66 using namespace skia_private;
67 
68 struct GrContextOptions;
69 
70 static const int MAIN_W = 8, MAIN_H = 16;
71 static const int CHILD_W = 16, CHILD_H = 16;
72 
check_pixels(skiatest::Reporter * reporter,const SkBitmap & bitmap)73 void check_pixels(skiatest::Reporter* reporter, const SkBitmap& bitmap) {
74     const uint32_t* canvasPixels = static_cast<const uint32_t*>(bitmap.getPixels());
75 
76     bool failureFound = false;
77     SkPMColor expectedPixel;
78     for (int cy = 0; cy < CHILD_H && !failureFound; ++cy) {
79         for (int cx = 0; cx < CHILD_W && !failureFound; ++cx) {
80             SkPMColor canvasPixel = canvasPixels[cy * CHILD_W + cx];
81             if (cy < CHILD_H / 2) {
82                 if (cx < CHILD_W / 2) {
83                     expectedPixel = 0xFF0000FF; // Red
84                 } else {
85                     expectedPixel = 0xFFFF0000; // Blue
86                 }
87             } else {
88                 expectedPixel = 0xFF00FF00; // Green
89             }
90             if (expectedPixel != canvasPixel) {
91                 failureFound = true;
92                 ERRORF(reporter, "Wrong color at %d, %d. Got 0x%08x when we expected 0x%08x",
93                        cx, cy, canvasPixel, expectedPixel);
94             }
95         }
96     }
97 }
98 
draw_child(skiatest::Reporter * reporter,const sk_gpu_test::ContextInfo & childInfo,const GrBackendTexture & backendTexture,const GrBackendSemaphore & semaphore)99 void draw_child(skiatest::Reporter* reporter,
100                 const sk_gpu_test::ContextInfo& childInfo,
101                 const GrBackendTexture& backendTexture,
102                 const GrBackendSemaphore& semaphore) {
103 
104     childInfo.testContext()->makeCurrent();
105 
106     const SkImageInfo childII = SkImageInfo::Make(CHILD_W, CHILD_H, kRGBA_8888_SkColorType,
107                                                   kPremul_SkAlphaType);
108 
109     auto childDContext = childInfo.directContext();
110     sk_sp<SkSurface> childSurface(SkSurfaces::RenderTarget(
111             childDContext, skgpu::Budgeted::kNo, childII, 0, kTopLeft_GrSurfaceOrigin, nullptr));
112 
113     sk_sp<SkImage> childImage = SkImages::BorrowTextureFrom(childDContext,
114                                                             backendTexture,
115                                                             kTopLeft_GrSurfaceOrigin,
116                                                             kRGBA_8888_SkColorType,
117                                                             kPremul_SkAlphaType,
118                                                             nullptr,
119                                                             nullptr,
120                                                             nullptr);
121 
122     SkCanvas* childCanvas = childSurface->getCanvas();
123     childCanvas->clear(SK_ColorRED);
124 
125     childSurface->wait(1, &semaphore);
126 
127     childCanvas->drawImage(childImage, CHILD_W/2, 0);
128 
129     SkPaint paint;
130     paint.setColor(SK_ColorGREEN);
131     SkIRect rect = SkIRect::MakeLTRB(0, CHILD_H/2, CHILD_W, CHILD_H);
132     childCanvas->drawIRect(rect, paint);
133 
134     // read pixels
135     SkBitmap bitmap;
136     bitmap.allocPixels(childII);
137     childSurface->readPixels(bitmap, 0, 0);
138 
139     check_pixels(reporter, bitmap);
140 }
141 
142 enum class FlushType { kSurface, kImage, kContext };
143 
surface_semaphore_test(skiatest::Reporter * reporter,const sk_gpu_test::ContextInfo & mainInfo,const sk_gpu_test::ContextInfo & childInfo1,const sk_gpu_test::ContextInfo & childInfo2,FlushType flushType)144 void surface_semaphore_test(skiatest::Reporter* reporter,
145                             const sk_gpu_test::ContextInfo& mainInfo,
146                             const sk_gpu_test::ContextInfo& childInfo1,
147                             const sk_gpu_test::ContextInfo& childInfo2,
148                             FlushType flushType) {
149     auto mainCtx = mainInfo.directContext();
150     if (!mainCtx->priv().caps()->backendSemaphoreSupport()) {
151         return;
152     }
153 
154     const SkImageInfo ii = SkImageInfo::Make(MAIN_W, MAIN_H, kRGBA_8888_SkColorType,
155                                              kPremul_SkAlphaType);
156 
157     sk_sp<SkSurface> mainSurface(SkSurfaces::RenderTarget(
158             mainCtx, skgpu::Budgeted::kNo, ii, 0, kTopLeft_GrSurfaceOrigin, nullptr));
159     SkCanvas* mainCanvas = mainSurface->getCanvas();
160     auto blueSurface = mainSurface->makeSurface(ii);
161     blueSurface->getCanvas()->clear(SK_ColorBLUE);
162     auto blueImage = blueSurface->makeImageSnapshot();
163     blueSurface.reset();
164     mainCanvas->drawImage(blueImage, 0, 0);
165 
166     AutoTArray<GrBackendSemaphore> semaphores(2);
167 #ifdef SK_VULKAN
168     if (GrBackendApi::kVulkan == mainInfo.backend()) {
169         // Initialize the secondary semaphore instead of having Ganesh create one internally
170         GrVkGpu* gpu = static_cast<GrVkGpu*>(mainCtx->priv().getGpu());
171         VkDevice device = gpu->device();
172 
173         VkSemaphore vkSem;
174 
175         VkSemaphoreCreateInfo createInfo;
176         createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
177         createInfo.pNext = nullptr;
178         createInfo.flags = 0;
179         GR_VK_CALL_ERRCHECK(gpu, CreateSemaphore(device, &createInfo, nullptr, &vkSem));
180 
181         semaphores[1] = GrBackendSemaphores::MakeVk(vkSem);
182     }
183 #endif
184 
185     GrFlushInfo info;
186     info.fNumSemaphores = 2;
187     info.fSignalSemaphores = semaphores.get();
188     switch (flushType) {
189         case FlushType::kSurface:
190             mainCtx->flush(mainSurface.get(), SkSurfaces::BackendSurfaceAccess::kNoAccess, info);
191             break;
192         case FlushType::kImage:
193             mainCtx->flush(blueImage, info);
194             break;
195         case FlushType::kContext:
196             mainCtx->flush(info);
197             break;
198     }
199     mainCtx->submit();
200 
201     GrBackendTexture backendTexture = SkSurfaces::GetBackendTexture(
202             mainSurface.get(), SkSurface::BackendHandleAccess::kFlushRead);
203 
204     draw_child(reporter, childInfo1, backendTexture, semaphores[0]);
205 
206 #ifdef SK_VULKAN
207     if (GrBackendApi::kVulkan == mainInfo.backend()) {
208         // In Vulkan we need to make sure we are sending the correct VkImageLayout in with the
209         // backendImage. After the first child draw the layout gets changed to SHADER_READ, so
210         // we just manually set that here.
211         GrBackendTextures::SetVkImageLayout(&backendTexture,
212                                             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
213     }
214 #endif
215 
216     draw_child(reporter, childInfo2, backendTexture, semaphores[1]);
217 }
218 
DEF_GANESH_TEST(SurfaceSemaphores,reporter,options,CtsEnforcement::kApiLevel_T)219 DEF_GANESH_TEST(SurfaceSemaphores, reporter, options, CtsEnforcement::kApiLevel_T) {
220 #if defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_MAC)
221     static constexpr auto kNativeGLType = skgpu::ContextType::kGL;
222 #else
223     static constexpr auto kNativeGLType = skgpu::ContextType::kGLES;
224 #endif
225 
226     for (int typeInt = 0; typeInt < skgpu::kContextTypeCount; ++typeInt) {
227         for (auto flushType : {FlushType::kSurface, FlushType::kImage, FlushType::kContext}) {
228             skgpu::ContextType contextType = static_cast<skgpu::ContextType>(typeInt);
229 #ifdef SK_GL
230             // Use "native" instead of explicitly trying OpenGL and OpenGL ES. Do not use GLES on
231             // desktop since tests do not account for not fixing http://skbug.com/2809
232             if (contextType == skgpu::ContextType::kGL ||
233                 contextType == skgpu::ContextType::kGLES) {
234                 if (contextType != kNativeGLType) {
235                     continue;
236                 }
237             }
238 #else
239             sk_ignore_unused_variable(kNativeGLType);  // Do something to avoid unused variable
240 #endif
241             sk_gpu_test::GrContextFactory factory(options);
242             sk_gpu_test::ContextInfo ctxInfo = factory.getContextInfo(contextType);
243             if (!skgpu::IsRenderingContext(contextType)) {
244                 continue;
245             }
246             skiatest::ReporterContext ctx(reporter, SkString(skgpu::ContextTypeName(contextType)));
247             if (ctxInfo.directContext()) {
248                 sk_gpu_test::ContextInfo child1 =
249                         factory.getSharedContextInfo(ctxInfo.directContext(), 0);
250                 sk_gpu_test::ContextInfo child2 =
251                         factory.getSharedContextInfo(ctxInfo.directContext(), 1);
252                 if (!child1.directContext() || !child2.directContext()) {
253                     continue;
254                 }
255 
256                 surface_semaphore_test(reporter, ctxInfo, child1, child2, flushType);
257             }
258         }
259     }
260 }
261 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(EmptySurfaceSemaphoreTest,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)262 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(EmptySurfaceSemaphoreTest,
263                                        reporter,
264                                        ctxInfo,
265                                        CtsEnforcement::kApiLevel_T) {
266     auto ctx = ctxInfo.directContext();
267     if (!ctx->priv().caps()->backendSemaphoreSupport()) {
268         // For example, the GL backend does not support these.
269         return;
270     }
271 
272     const SkImageInfo ii = SkImageInfo::Make(MAIN_W, MAIN_H, kRGBA_8888_SkColorType,
273                                              kPremul_SkAlphaType);
274 
275     sk_sp<SkSurface> mainSurface(SkSurfaces::RenderTarget(
276             ctx, skgpu::Budgeted::kNo, ii, 0, kTopLeft_GrSurfaceOrigin, nullptr));
277 
278     // Flush surface once without semaphores to make sure there is no pending IO for it.
279     ctx->flushAndSubmit(mainSurface.get(), GrSyncCpu::kNo);
280 
281     GrBackendSemaphore semaphore;
282     GrFlushInfo flushInfo;
283     flushInfo.fNumSemaphores = 1;
284     flushInfo.fSignalSemaphores = &semaphore;
285     GrSemaphoresSubmitted submitted =
286             ctx->flush(mainSurface.get(), SkSurfaces::BackendSurfaceAccess::kNoAccess, flushInfo);
287     REPORTER_ASSERT(reporter, GrSemaphoresSubmitted::kYes == submitted);
288     ctx->submit();
289 
290 #ifdef SK_VULKAN
291     if (GrBackendApi::kVulkan == ctxInfo.backend()) {
292         GrVkGpu* gpu = static_cast<GrVkGpu*>(ctx->priv().getGpu());
293         const skgpu::VulkanInterface* interface = gpu->vkInterface();
294         VkDevice device = gpu->device();
295         VkQueue queue = gpu->queue();
296         GrVkCommandPool* cmdPool = gpu->cmdPool();
297         VkCommandBuffer cmdBuffer;
298 
299         // Create Command Buffer
300         const VkCommandBufferAllocateInfo cmdInfo = {
301             VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,   // sType
302             nullptr,                                          // pNext
303             cmdPool->vkCommandPool(),                         // commandPool
304             VK_COMMAND_BUFFER_LEVEL_PRIMARY,                  // level
305             1                                                 // bufferCount
306         };
307 
308         VkResult err = GR_VK_CALL(interface, AllocateCommandBuffers(device, &cmdInfo, &cmdBuffer));
309         if (err) {
310             return;
311         }
312 
313         VkCommandBufferBeginInfo cmdBufferBeginInfo;
314         memset(&cmdBufferBeginInfo, 0, sizeof(VkCommandBufferBeginInfo));
315         cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
316         cmdBufferBeginInfo.pNext = nullptr;
317         cmdBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
318         cmdBufferBeginInfo.pInheritanceInfo = nullptr;
319 
320         GR_VK_CALL_ERRCHECK(gpu, BeginCommandBuffer(cmdBuffer, &cmdBufferBeginInfo));
321         GR_VK_CALL_ERRCHECK(gpu, EndCommandBuffer(cmdBuffer));
322 
323         VkFenceCreateInfo fenceInfo;
324         VkFence fence;
325 
326         memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
327         fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
328         err = GR_VK_CALL(interface, CreateFence(device, &fenceInfo, nullptr, &fence));
329         SkASSERT(!err);
330 
331         VkPipelineStageFlags waitStages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
332         VkSubmitInfo submitInfo;
333         memset(&submitInfo, 0, sizeof(VkSubmitInfo));
334         submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
335         submitInfo.pNext = nullptr;
336         submitInfo.waitSemaphoreCount = 1;
337         VkSemaphore vkSem = GrBackendSemaphores::GetVkSemaphore(semaphore);
338         submitInfo.pWaitSemaphores = &vkSem;
339         submitInfo.pWaitDstStageMask = &waitStages;
340         submitInfo.commandBufferCount = 1;
341         submitInfo.pCommandBuffers = &cmdBuffer;
342         submitInfo.signalSemaphoreCount = 0;
343         submitInfo.pSignalSemaphores = nullptr;
344         GR_VK_CALL_ERRCHECK(gpu, QueueSubmit(queue, 1, &submitInfo, fence));
345 
346         err = GR_VK_CALL(interface, WaitForFences(device, 1, &fence, true, 3000000000));
347 
348         REPORTER_ASSERT(reporter, err != VK_TIMEOUT);
349 
350         GR_VK_CALL(interface, DestroyFence(device, fence, nullptr));
351         GR_VK_CALL(interface, DestroySemaphore(device, vkSem, nullptr));
352         // If the above test fails the wait semaphore will never be signaled which can cause the
353         // device to hang when tearing down (even if just tearing down GL). So we Fail here to
354         // kill things.
355         if (err == VK_TIMEOUT) {
356             SK_ABORT("Waiting on semaphore indefinitely");
357         }
358     }
359 #endif
360 }
361