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