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