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 37static const int MAIN_W = 8, MAIN_H = 16; 38static const int CHILD_W = 16, CHILD_H = 16; 39 40void 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 66void 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 110enum class FlushType { kSurface, kImage, kContext }; 111 112void 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 188DEF_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 230DEF_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