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