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 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 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 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->contextPriv().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->contextPriv().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->flushAndSignalSemaphores(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 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 213 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(EmptySurfaceSemaphoreTest, reporter, ctxInfo) { 214 GrContext* ctx = ctxInfo.grContext(); 215 if (!ctx->contextPriv().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->contextPriv().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->contextPriv().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