VulkanWindowContext.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. /*
  2. * Copyright 2015 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. #include "tools/sk_app/VulkanWindowContext.h"
  8. #include "include/core/SkSurface.h"
  9. #include "include/gpu/GrBackendSemaphore.h"
  10. #include "include/gpu/GrBackendSurface.h"
  11. #include "include/gpu/GrContext.h"
  12. #include "src/core/SkAutoMalloc.h"
  13. #include "include/gpu/vk/GrVkExtensions.h"
  14. #include "include/gpu/vk/GrVkTypes.h"
  15. #include "src/gpu/vk/GrVkImage.h"
  16. #include "src/gpu/vk/GrVkUtil.h"
  17. #ifdef VK_USE_PLATFORM_WIN32_KHR
  18. // windows wants to define this as CreateSemaphoreA or CreateSemaphoreW
  19. #undef CreateSemaphore
  20. #endif
  21. #define GET_PROC(F) f ## F = (PFN_vk ## F) fGetInstanceProcAddr(fInstance, "vk" #F)
  22. #define GET_DEV_PROC(F) f ## F = (PFN_vk ## F) fGetDeviceProcAddr(fDevice, "vk" #F)
  23. namespace sk_app {
  24. VulkanWindowContext::VulkanWindowContext(const DisplayParams& params,
  25. CreateVkSurfaceFn createVkSurface,
  26. CanPresentFn canPresent,
  27. PFN_vkGetInstanceProcAddr instProc,
  28. PFN_vkGetDeviceProcAddr devProc)
  29. : WindowContext(params)
  30. , fCreateVkSurfaceFn(createVkSurface)
  31. , fCanPresentFn(canPresent)
  32. , fSurface(VK_NULL_HANDLE)
  33. , fSwapchain(VK_NULL_HANDLE)
  34. , fImages(nullptr)
  35. , fImageLayouts(nullptr)
  36. , fSurfaces(nullptr)
  37. , fBackbuffers(nullptr) {
  38. fGetInstanceProcAddr = instProc;
  39. fGetDeviceProcAddr = devProc;
  40. this->initializeContext();
  41. }
  42. void VulkanWindowContext::initializeContext() {
  43. // any config code here (particularly for msaa)?
  44. PFN_vkGetInstanceProcAddr getInstanceProc = fGetInstanceProcAddr;
  45. PFN_vkGetDeviceProcAddr getDeviceProc = fGetDeviceProcAddr;
  46. auto getProc = [getInstanceProc, getDeviceProc](const char* proc_name,
  47. VkInstance instance, VkDevice device) {
  48. if (device != VK_NULL_HANDLE) {
  49. return getDeviceProc(device, proc_name);
  50. }
  51. return getInstanceProc(instance, proc_name);
  52. };
  53. GrVkBackendContext backendContext;
  54. GrVkExtensions extensions;
  55. VkPhysicalDeviceFeatures2 features;
  56. if (!sk_gpu_test::CreateVkBackendContext(getProc, &backendContext, &extensions, &features,
  57. &fDebugCallback, &fPresentQueueIndex, fCanPresentFn)) {
  58. sk_gpu_test::FreeVulkanFeaturesStructs(&features);
  59. return;
  60. }
  61. if (!extensions.hasExtension(VK_KHR_SURFACE_EXTENSION_NAME, 25) ||
  62. !extensions.hasExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, 68)) {
  63. sk_gpu_test::FreeVulkanFeaturesStructs(&features);
  64. return;
  65. }
  66. fInstance = backendContext.fInstance;
  67. fPhysicalDevice = backendContext.fPhysicalDevice;
  68. fDevice = backendContext.fDevice;
  69. fGraphicsQueueIndex = backendContext.fGraphicsQueueIndex;
  70. fGraphicsQueue = backendContext.fQueue;
  71. PFN_vkGetPhysicalDeviceProperties localGetPhysicalDeviceProperties =
  72. reinterpret_cast<PFN_vkGetPhysicalDeviceProperties>(
  73. backendContext.fGetProc("vkGetPhysicalDeviceProperties",
  74. backendContext.fInstance,
  75. VK_NULL_HANDLE));
  76. if (!localGetPhysicalDeviceProperties) {
  77. sk_gpu_test::FreeVulkanFeaturesStructs(&features);
  78. return;
  79. }
  80. VkPhysicalDeviceProperties physDeviceProperties;
  81. localGetPhysicalDeviceProperties(backendContext.fPhysicalDevice, &physDeviceProperties);
  82. uint32_t physDevVersion = physDeviceProperties.apiVersion;
  83. fInterface.reset(new GrVkInterface(backendContext.fGetProc, fInstance, fDevice,
  84. backendContext.fInstanceVersion, physDevVersion,
  85. &extensions));
  86. GET_PROC(DestroyInstance);
  87. if (fDebugCallback != VK_NULL_HANDLE) {
  88. GET_PROC(DestroyDebugReportCallbackEXT);
  89. }
  90. GET_PROC(DestroySurfaceKHR);
  91. GET_PROC(GetPhysicalDeviceSurfaceSupportKHR);
  92. GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR);
  93. GET_PROC(GetPhysicalDeviceSurfaceFormatsKHR);
  94. GET_PROC(GetPhysicalDeviceSurfacePresentModesKHR);
  95. GET_DEV_PROC(DeviceWaitIdle);
  96. GET_DEV_PROC(QueueWaitIdle);
  97. GET_DEV_PROC(DestroyDevice);
  98. GET_DEV_PROC(CreateSwapchainKHR);
  99. GET_DEV_PROC(DestroySwapchainKHR);
  100. GET_DEV_PROC(GetSwapchainImagesKHR);
  101. GET_DEV_PROC(AcquireNextImageKHR);
  102. GET_DEV_PROC(QueuePresentKHR);
  103. GET_DEV_PROC(GetDeviceQueue);
  104. fContext = GrContext::MakeVulkan(backendContext, fDisplayParams.fGrContextOptions);
  105. fSurface = fCreateVkSurfaceFn(fInstance);
  106. if (VK_NULL_HANDLE == fSurface) {
  107. this->destroyContext();
  108. sk_gpu_test::FreeVulkanFeaturesStructs(&features);
  109. return;
  110. }
  111. VkBool32 supported;
  112. VkResult res = fGetPhysicalDeviceSurfaceSupportKHR(fPhysicalDevice, fPresentQueueIndex,
  113. fSurface, &supported);
  114. if (VK_SUCCESS != res) {
  115. this->destroyContext();
  116. sk_gpu_test::FreeVulkanFeaturesStructs(&features);
  117. return;
  118. }
  119. if (!this->createSwapchain(-1, -1, fDisplayParams)) {
  120. this->destroyContext();
  121. sk_gpu_test::FreeVulkanFeaturesStructs(&features);
  122. return;
  123. }
  124. // create presentQueue
  125. fGetDeviceQueue(fDevice, fPresentQueueIndex, 0, &fPresentQueue);
  126. sk_gpu_test::FreeVulkanFeaturesStructs(&features);
  127. }
  128. bool VulkanWindowContext::createSwapchain(int width, int height,
  129. const DisplayParams& params) {
  130. // check for capabilities
  131. VkSurfaceCapabilitiesKHR caps;
  132. VkResult res = fGetPhysicalDeviceSurfaceCapabilitiesKHR(fPhysicalDevice, fSurface, &caps);
  133. if (VK_SUCCESS != res) {
  134. return false;
  135. }
  136. uint32_t surfaceFormatCount;
  137. res = fGetPhysicalDeviceSurfaceFormatsKHR(fPhysicalDevice, fSurface, &surfaceFormatCount,
  138. nullptr);
  139. if (VK_SUCCESS != res) {
  140. return false;
  141. }
  142. SkAutoMalloc surfaceFormatAlloc(surfaceFormatCount * sizeof(VkSurfaceFormatKHR));
  143. VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)surfaceFormatAlloc.get();
  144. res = fGetPhysicalDeviceSurfaceFormatsKHR(fPhysicalDevice, fSurface, &surfaceFormatCount,
  145. surfaceFormats);
  146. if (VK_SUCCESS != res) {
  147. return false;
  148. }
  149. uint32_t presentModeCount;
  150. res = fGetPhysicalDeviceSurfacePresentModesKHR(fPhysicalDevice, fSurface, &presentModeCount,
  151. nullptr);
  152. if (VK_SUCCESS != res) {
  153. return false;
  154. }
  155. SkAutoMalloc presentModeAlloc(presentModeCount * sizeof(VkPresentModeKHR));
  156. VkPresentModeKHR* presentModes = (VkPresentModeKHR*)presentModeAlloc.get();
  157. res = fGetPhysicalDeviceSurfacePresentModesKHR(fPhysicalDevice, fSurface, &presentModeCount,
  158. presentModes);
  159. if (VK_SUCCESS != res) {
  160. return false;
  161. }
  162. VkExtent2D extent = caps.currentExtent;
  163. // use the hints
  164. if (extent.width == (uint32_t)-1) {
  165. extent.width = width;
  166. extent.height = height;
  167. }
  168. // clamp width; to protect us from broken hints
  169. if (extent.width < caps.minImageExtent.width) {
  170. extent.width = caps.minImageExtent.width;
  171. } else if (extent.width > caps.maxImageExtent.width) {
  172. extent.width = caps.maxImageExtent.width;
  173. }
  174. // clamp height
  175. if (extent.height < caps.minImageExtent.height) {
  176. extent.height = caps.minImageExtent.height;
  177. } else if (extent.height > caps.maxImageExtent.height) {
  178. extent.height = caps.maxImageExtent.height;
  179. }
  180. fWidth = (int)extent.width;
  181. fHeight = (int)extent.height;
  182. uint32_t imageCount = caps.minImageCount + 2;
  183. if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) {
  184. // Application must settle for fewer images than desired:
  185. imageCount = caps.maxImageCount;
  186. }
  187. VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
  188. VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
  189. VK_IMAGE_USAGE_TRANSFER_DST_BIT;
  190. SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags);
  191. SkASSERT(caps.supportedTransforms & caps.currentTransform);
  192. SkASSERT(caps.supportedCompositeAlpha & (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
  193. VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR));
  194. VkCompositeAlphaFlagBitsKHR composite_alpha =
  195. (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) ?
  196. VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR :
  197. VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
  198. // Pick our surface format.
  199. VkFormat surfaceFormat = VK_FORMAT_UNDEFINED;
  200. VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
  201. for (uint32_t i = 0; i < surfaceFormatCount; ++i) {
  202. VkFormat localFormat = surfaceFormats[i].format;
  203. if (GrVkFormatIsSupported(localFormat)) {
  204. surfaceFormat = localFormat;
  205. colorSpace = surfaceFormats[i].colorSpace;
  206. break;
  207. }
  208. }
  209. fDisplayParams = params;
  210. fSampleCount = params.fMSAASampleCount;
  211. fStencilBits = 8;
  212. if (VK_FORMAT_UNDEFINED == surfaceFormat) {
  213. return false;
  214. }
  215. SkColorType colorType;
  216. switch (surfaceFormat) {
  217. case VK_FORMAT_R8G8B8A8_UNORM: // fall through
  218. case VK_FORMAT_R8G8B8A8_SRGB:
  219. colorType = kRGBA_8888_SkColorType;
  220. break;
  221. case VK_FORMAT_B8G8R8A8_UNORM: // fall through
  222. colorType = kBGRA_8888_SkColorType;
  223. break;
  224. default:
  225. return false;
  226. }
  227. // If mailbox mode is available, use it, as it is the lowest-latency non-
  228. // tearing mode. If not, fall back to FIFO which is always available.
  229. VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR;
  230. bool hasImmediate = false;
  231. for (uint32_t i = 0; i < presentModeCount; ++i) {
  232. // use mailbox
  233. if (VK_PRESENT_MODE_MAILBOX_KHR == presentModes[i]) {
  234. mode = VK_PRESENT_MODE_MAILBOX_KHR;
  235. }
  236. if (VK_PRESENT_MODE_IMMEDIATE_KHR == presentModes[i]) {
  237. hasImmediate = true;
  238. }
  239. }
  240. if (params.fDisableVsync && hasImmediate) {
  241. mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
  242. }
  243. VkSwapchainCreateInfoKHR swapchainCreateInfo;
  244. memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR));
  245. swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
  246. swapchainCreateInfo.surface = fSurface;
  247. swapchainCreateInfo.minImageCount = imageCount;
  248. swapchainCreateInfo.imageFormat = surfaceFormat;
  249. swapchainCreateInfo.imageColorSpace = colorSpace;
  250. swapchainCreateInfo.imageExtent = extent;
  251. swapchainCreateInfo.imageArrayLayers = 1;
  252. swapchainCreateInfo.imageUsage = usageFlags;
  253. uint32_t queueFamilies[] = { fGraphicsQueueIndex, fPresentQueueIndex };
  254. if (fGraphicsQueueIndex != fPresentQueueIndex) {
  255. swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
  256. swapchainCreateInfo.queueFamilyIndexCount = 2;
  257. swapchainCreateInfo.pQueueFamilyIndices = queueFamilies;
  258. } else {
  259. swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
  260. swapchainCreateInfo.queueFamilyIndexCount = 0;
  261. swapchainCreateInfo.pQueueFamilyIndices = nullptr;
  262. }
  263. swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
  264. swapchainCreateInfo.compositeAlpha = composite_alpha;
  265. swapchainCreateInfo.presentMode = mode;
  266. swapchainCreateInfo.clipped = true;
  267. swapchainCreateInfo.oldSwapchain = fSwapchain;
  268. res = fCreateSwapchainKHR(fDevice, &swapchainCreateInfo, nullptr, &fSwapchain);
  269. if (VK_SUCCESS != res) {
  270. return false;
  271. }
  272. // destroy the old swapchain
  273. if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) {
  274. fDeviceWaitIdle(fDevice);
  275. this->destroyBuffers();
  276. fDestroySwapchainKHR(fDevice, swapchainCreateInfo.oldSwapchain, nullptr);
  277. }
  278. this->createBuffers(swapchainCreateInfo.imageFormat, colorType);
  279. return true;
  280. }
  281. void VulkanWindowContext::createBuffers(VkFormat format, SkColorType colorType) {
  282. fGetSwapchainImagesKHR(fDevice, fSwapchain, &fImageCount, nullptr);
  283. SkASSERT(fImageCount);
  284. fImages = new VkImage[fImageCount];
  285. fGetSwapchainImagesKHR(fDevice, fSwapchain, &fImageCount, fImages);
  286. // set up initial image layouts and create surfaces
  287. fImageLayouts = new VkImageLayout[fImageCount];
  288. fSurfaces = new sk_sp<SkSurface>[fImageCount];
  289. for (uint32_t i = 0; i < fImageCount; ++i) {
  290. fImageLayouts[i] = VK_IMAGE_LAYOUT_UNDEFINED;
  291. GrVkImageInfo info;
  292. info.fImage = fImages[i];
  293. info.fAlloc = GrVkAlloc();
  294. info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  295. info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
  296. info.fFormat = format;
  297. info.fLevelCount = 1;
  298. info.fCurrentQueueFamily = fPresentQueueIndex;
  299. if (fSampleCount == 1) {
  300. GrBackendRenderTarget backendRT(fWidth, fHeight, fSampleCount, info);
  301. fSurfaces[i] = SkSurface::MakeFromBackendRenderTarget(
  302. fContext.get(), backendRT, kTopLeft_GrSurfaceOrigin, colorType,
  303. fDisplayParams.fColorSpace, &fDisplayParams.fSurfaceProps);
  304. } else {
  305. GrBackendTexture backendTexture(fWidth, fHeight, info);
  306. fSurfaces[i] = SkSurface::MakeFromBackendTexture(
  307. fContext.get(), backendTexture, kTopLeft_GrSurfaceOrigin, fSampleCount,
  308. colorType, fDisplayParams.fColorSpace, &fDisplayParams.fSurfaceProps);
  309. }
  310. }
  311. // set up the backbuffers
  312. VkSemaphoreCreateInfo semaphoreInfo;
  313. memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo));
  314. semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
  315. semaphoreInfo.pNext = nullptr;
  316. semaphoreInfo.flags = 0;
  317. // we create one additional backbuffer structure here, because we want to
  318. // give the command buffers they contain a chance to finish before we cycle back
  319. fBackbuffers = new BackbufferInfo[fImageCount + 1];
  320. for (uint32_t i = 0; i < fImageCount + 1; ++i) {
  321. fBackbuffers[i].fImageIndex = -1;
  322. GR_VK_CALL_ERRCHECK(fInterface,
  323. CreateSemaphore(fDevice, &semaphoreInfo,
  324. nullptr, &fBackbuffers[i].fRenderSemaphore));
  325. }
  326. fCurrentBackbufferIndex = fImageCount;
  327. }
  328. void VulkanWindowContext::destroyBuffers() {
  329. if (fBackbuffers) {
  330. for (uint32_t i = 0; i < fImageCount + 1; ++i) {
  331. fBackbuffers[i].fImageIndex = -1;
  332. GR_VK_CALL(fInterface,
  333. DestroySemaphore(fDevice,
  334. fBackbuffers[i].fRenderSemaphore,
  335. nullptr));
  336. }
  337. }
  338. delete[] fBackbuffers;
  339. fBackbuffers = nullptr;
  340. // Does this actually free the surfaces?
  341. delete[] fSurfaces;
  342. fSurfaces = nullptr;
  343. delete[] fImageLayouts;
  344. fImageLayouts = nullptr;
  345. delete[] fImages;
  346. fImages = nullptr;
  347. }
  348. VulkanWindowContext::~VulkanWindowContext() {
  349. this->destroyContext();
  350. }
  351. void VulkanWindowContext::destroyContext() {
  352. if (this->isValid()) {
  353. fQueueWaitIdle(fPresentQueue);
  354. fDeviceWaitIdle(fDevice);
  355. this->destroyBuffers();
  356. if (VK_NULL_HANDLE != fSwapchain) {
  357. fDestroySwapchainKHR(fDevice, fSwapchain, nullptr);
  358. fSwapchain = VK_NULL_HANDLE;
  359. }
  360. if (VK_NULL_HANDLE != fSurface) {
  361. fDestroySurfaceKHR(fInstance, fSurface, nullptr);
  362. fSurface = VK_NULL_HANDLE;
  363. }
  364. }
  365. fContext.reset();
  366. fInterface.reset();
  367. if (VK_NULL_HANDLE != fDevice) {
  368. fDestroyDevice(fDevice, nullptr);
  369. fDevice = VK_NULL_HANDLE;
  370. }
  371. #ifdef SK_ENABLE_VK_LAYERS
  372. if (fDebugCallback != VK_NULL_HANDLE) {
  373. fDestroyDebugReportCallbackEXT(fInstance, fDebugCallback, nullptr);
  374. }
  375. #endif
  376. fPhysicalDevice = VK_NULL_HANDLE;
  377. if (VK_NULL_HANDLE != fInstance) {
  378. fDestroyInstance(fInstance, nullptr);
  379. fInstance = VK_NULL_HANDLE;
  380. }
  381. }
  382. VulkanWindowContext::BackbufferInfo* VulkanWindowContext::getAvailableBackbuffer() {
  383. SkASSERT(fBackbuffers);
  384. ++fCurrentBackbufferIndex;
  385. if (fCurrentBackbufferIndex > fImageCount) {
  386. fCurrentBackbufferIndex = 0;
  387. }
  388. BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex;
  389. return backbuffer;
  390. }
  391. sk_sp<SkSurface> VulkanWindowContext::getBackbufferSurface() {
  392. BackbufferInfo* backbuffer = this->getAvailableBackbuffer();
  393. SkASSERT(backbuffer);
  394. // semaphores should be in unsignaled state
  395. VkSemaphoreCreateInfo semaphoreInfo;
  396. memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo));
  397. semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
  398. semaphoreInfo.pNext = nullptr;
  399. semaphoreInfo.flags = 0;
  400. VkSemaphore semaphore;
  401. GR_VK_CALL_ERRCHECK(fInterface, CreateSemaphore(fDevice, &semaphoreInfo,
  402. nullptr, &semaphore));
  403. // acquire the image
  404. VkResult res = fAcquireNextImageKHR(fDevice, fSwapchain, UINT64_MAX,
  405. semaphore, VK_NULL_HANDLE,
  406. &backbuffer->fImageIndex);
  407. if (VK_ERROR_SURFACE_LOST_KHR == res) {
  408. // need to figure out how to create a new vkSurface without the platformData*
  409. // maybe use attach somehow? but need a Window
  410. GR_VK_CALL(fInterface, DestroySemaphore(fDevice, semaphore, nullptr));
  411. return nullptr;
  412. }
  413. if (VK_ERROR_OUT_OF_DATE_KHR == res) {
  414. // tear swapchain down and try again
  415. if (!this->createSwapchain(-1, -1, fDisplayParams)) {
  416. GR_VK_CALL(fInterface, DestroySemaphore(fDevice, semaphore, nullptr));
  417. return nullptr;
  418. }
  419. backbuffer = this->getAvailableBackbuffer();
  420. // acquire the image
  421. res = fAcquireNextImageKHR(fDevice, fSwapchain, UINT64_MAX,
  422. semaphore, VK_NULL_HANDLE,
  423. &backbuffer->fImageIndex);
  424. if (VK_SUCCESS != res) {
  425. GR_VK_CALL(fInterface, DestroySemaphore(fDevice, semaphore, nullptr));
  426. return nullptr;
  427. }
  428. }
  429. SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get();
  430. GrBackendSemaphore beSemaphore;
  431. beSemaphore.initVulkan(semaphore);
  432. surface->wait(1, &beSemaphore);
  433. return sk_ref_sp(surface);
  434. }
  435. void VulkanWindowContext::swapBuffers() {
  436. BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex;
  437. SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get();
  438. GrBackendSemaphore beSemaphore;
  439. beSemaphore.initVulkan(backbuffer->fRenderSemaphore);
  440. GrFlushInfo info;
  441. info.fNumSemaphores = 1;
  442. info.fSignalSemaphores = &beSemaphore;
  443. surface->flush(SkSurface::BackendSurfaceAccess::kPresent, info);
  444. // Submit present operation to present queue
  445. const VkPresentInfoKHR presentInfo =
  446. {
  447. VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType
  448. NULL, // pNext
  449. 1, // waitSemaphoreCount
  450. &backbuffer->fRenderSemaphore, // pWaitSemaphores
  451. 1, // swapchainCount
  452. &fSwapchain, // pSwapchains
  453. &backbuffer->fImageIndex, // pImageIndices
  454. NULL // pResults
  455. };
  456. fQueuePresentKHR(fPresentQueue, &presentInfo);
  457. }
  458. } //namespace sk_app