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