• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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