• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "flutter/vulkan/vulkan_swapchain.h"
6 
7 #include "flutter/vulkan/vulkan_backbuffer.h"
8 #include "flutter/vulkan/vulkan_device.h"
9 #ifdef RS_ENABLE_VK
10 #include "flutter/vulkan/vulkan_hilog.h"
11 #endif
12 #include "flutter/vulkan/vulkan_image.h"
13 #include "flutter/vulkan/vulkan_proc_table.h"
14 #include "flutter/vulkan/vulkan_surface.h"
15 #include "third_party/skia/include/gpu/GrBackendSurface.h"
16 #include "third_party/skia/include/gpu/GrContext.h"
17 #include "third_party/skia/include/gpu/vk/GrVkTypes.h"
18 
19 namespace vulkan {
20 
21 namespace {
22 struct FormatInfo {
23   VkFormat format_;
24   SkColorType color_type_;
25   sk_sp<SkColorSpace> color_space_;
26 };
27 }  // namespace
28 
29 #ifdef RS_ENABLE_VK
DesiredFormatInfos()30 static std::vector<FormatInfo> DesiredFormatInfos() {
31   return {{VK_FORMAT_R8G8B8A8_SRGB, kRGBA_8888_SkColorType,
32            SkColorSpace::MakeSRGBLinear()},
33           {VK_FORMAT_B8G8R8A8_SRGB, kBGRA_8888_SkColorType,
34            SkColorSpace::MakeSRGBLinear()},
35           {VK_FORMAT_R16G16B16A16_SFLOAT, kRGBA_F16_SkColorType,
36            SkColorSpace::MakeSRGBLinear()},
37           {VK_FORMAT_R8G8B8A8_UNORM, kRGBA_8888_SkColorType,
38            SkColorSpace::MakeSRGB()},
39           {VK_FORMAT_B8G8R8A8_UNORM, kRGBA_8888_SkColorType,
40            SkColorSpace::MakeSRGB()}};
41 }
42 
43 std::mutex VulkanSwapchain::map_mutex_;
44 std::unordered_map<std::thread::id, VulkanSwapchain*> VulkanSwapchain::to_be_present_;
45 
46 #else
DesiredFormatInfos()47 static std::vector<FormatInfo> DesiredFormatInfos() {
48   return {{VK_FORMAT_R8G8B8A8_SRGB, kRGBA_8888_SkColorType,
49            SkColorSpace::MakeSRGB()},
50           {VK_FORMAT_B8G8R8A8_SRGB, kRGBA_8888_SkColorType,
51            SkColorSpace::MakeSRGB()},
52           {VK_FORMAT_R16G16B16A16_SFLOAT, kRGBA_F16_SkColorType,
53            SkColorSpace::MakeSRGBLinear()},
54           {VK_FORMAT_R8G8B8A8_UNORM, kRGBA_8888_SkColorType,
55            SkColorSpace::MakeSRGB()},
56           {VK_FORMAT_B8G8R8A8_UNORM, kRGBA_8888_SkColorType,
57            SkColorSpace::MakeSRGB()}};
58 }
59 #endif
60 
VulkanSwapchain(const VulkanProcTable & p_vk,const VulkanDevice & device,const VulkanSurface & surface,GrContext * skia_context,std::unique_ptr<VulkanSwapchain> old_swapchain,uint32_t queue_family_index)61 VulkanSwapchain::VulkanSwapchain(const VulkanProcTable& p_vk,
62                                  const VulkanDevice& device,
63                                  const VulkanSurface& surface,
64                                  GrContext* skia_context,
65                                  std::unique_ptr<VulkanSwapchain> old_swapchain,
66                                  uint32_t queue_family_index)
67     : vk(p_vk),
68       device_(device),
69       capabilities_(),
70       surface_format_(),
71       current_pipeline_stage_(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT),
72       current_backbuffer_index_(0),
73       current_image_index_(0),
74       valid_(false) {
75   if (!device_.IsValid() || !surface.IsValid() || skia_context == nullptr) {
76 #ifdef RS_ENABLE_VK
77     LOGE("Device or surface is invalid.");
78 #else
79     FML_DLOG(INFO) << "Device or surface is invalid.";
80 #endif
81     return;
82   }
83 
84   if (!device_.GetSurfaceCapabilities(surface, &capabilities_)) {
85 #ifdef RS_ENABLE_VK
86     LOGE("Could not find surface capabilities.");
87 #else
88     FML_DLOG(INFO) << "Could not find surface capabilities.";
89 #endif
90     return;
91   }
92 
93   const auto format_infos = DesiredFormatInfos();
94   std::vector<VkFormat> desired_formats(format_infos.size());
95   for (size_t i = 0; i < format_infos.size(); ++i) {
96     if (skia_context->colorTypeSupportedAsSurface(
97             format_infos[i].color_type_)) {
98       desired_formats[i] = format_infos[i].format_;
99     } else {
100       desired_formats[i] = VK_FORMAT_UNDEFINED;
101     }
102   }
103 
104   int format_index =
105       device_.ChooseSurfaceFormat(surface, desired_formats, &surface_format_);
106   if (format_index < 0) {
107 #ifdef RS_ENABLE_VK
108     LOGE("Could not choose surface format.");
109 #else
110     FML_DLOG(INFO) << "Could not choose surface format.";
111 #endif
112     return;
113   }
114 
115   VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR;
116   if (!device_.ChoosePresentMode(surface, &present_mode)) {
117 #ifdef RS_ENABLE_VK
118     LOGE("Could not choose present mode.");
119 #else
120     FML_DLOG(INFO) << "Could not choose present mode.";
121 #endif
122     return;
123   }
124 
125   // Check if the surface can present.
126 
127   VkBool32 supported = VK_FALSE;
128   if (VK_CALL_LOG_ERROR(vk.GetPhysicalDeviceSurfaceSupportKHR(
129           device_.GetPhysicalDeviceHandle(),  // physical device
130           queue_family_index,                 // queue family
131           surface.Handle(),                   // surface to test
132           &supported)) != VK_SUCCESS) {
133 #ifdef RS_ENABLE_VK
134     LOGE("Could not get physical device surface support.");
135 #else
136     FML_DLOG(INFO) << "Could not get physical device surface support.";
137 #endif
138     return;
139   }
140 
141   if (supported != VK_TRUE) {
142 #ifdef RS_ENABLE_VK
143     LOGE("Surface was not supported by the physical device.");
144 #else
145     FML_DLOG(INFO) << "Surface was not supported by the physical device.";
146 #endif
147     return;
148   }
149 
150   // Construct the Swapchain
151 
152   VkSwapchainKHR old_swapchain_handle = VK_NULL_HANDLE;
153 
154   if (old_swapchain != nullptr && old_swapchain->IsValid()) {
155     old_swapchain_handle = old_swapchain->swapchain_;
156     // The unique pointer to the swapchain will go out of scope here
157     // and its handle collected after the appropriate device wait.
158   }
159 
160   VkSurfaceKHR surface_handle = surface.Handle();
161 
162   const VkSwapchainCreateInfoKHR create_info = {
163       .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
164       .pNext = nullptr,
165       .flags = 0,
166       .surface = surface_handle,
167       .minImageCount = capabilities_.minImageCount,
168       .imageFormat = surface_format_.format,
169       .imageColorSpace = surface_format_.colorSpace,
170       .imageExtent = capabilities_.currentExtent,
171       .imageArrayLayers = 1,
172       .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
173       .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
174       .queueFamilyIndexCount = 0,  // Because of the exclusive sharing mode.
175       .pQueueFamilyIndices = nullptr,
176       .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
177       .compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
178       .presentMode = present_mode,
179       .clipped = VK_FALSE,
180       .oldSwapchain = old_swapchain_handle,
181   };
182 
183   VkSwapchainKHR swapchain = VK_NULL_HANDLE;
184 
185   if (VK_CALL_LOG_ERROR(vk.CreateSwapchainKHR(device_.GetHandle(), &create_info,
186                                               nullptr, &swapchain)) !=
187       VK_SUCCESS) {
188 #ifdef RS_ENABLE_VK
189     LOGE("Could not create the swapchain.");
190 #else
191     FML_DLOG(INFO) << "Could not create the swapchain.";
192 #endif
193     return;
194   }
195 
196 #ifdef RS_ENABLE_VK
197   swapchain_ = {swapchain, [this](VkSwapchainKHR swapchain) {
198                   device_.WaitIdle();
199                   vk.DestroySwapchainKHR(device_.GetHandle(), swapchain, nullptr);
200                 }};
201 #else
202   swapchain_ = {swapchain, [this](VkSwapchainKHR swapchain) {
203                   FML_ALLOW_UNUSED_LOCAL(device_.WaitIdle());
204                   vk.DestroySwapchainKHR(device_.GetHandle(), swapchain,
205                                          nullptr);
206                 }};
207 #endif
208 
209   if (!CreateSwapchainImages(skia_context,
210                              format_infos[format_index].color_type_,
211                              format_infos[format_index].color_space_)) {
212 #ifdef RS_ENABLE_VK
213     LOGE("Could not create swapchain images.");
214 #else
215     FML_DLOG(INFO) << "Could not create swapchain images.";
216 #endif
217     return;
218   }
219 
220   valid_ = true;
221 }
222 
223 VulkanSwapchain::~VulkanSwapchain() = default;
224 
IsValid() const225 bool VulkanSwapchain::IsValid() const {
226   return valid_;
227 }
228 
GetImages() const229 std::vector<VkImage> VulkanSwapchain::GetImages() const {
230   uint32_t count = 0;
231   if (VK_CALL_LOG_ERROR(vk.GetSwapchainImagesKHR(
232           device_.GetHandle(), swapchain_, &count, nullptr)) != VK_SUCCESS) {
233     return {};
234   }
235 
236   if (count == 0) {
237     return {};
238   }
239 
240   std::vector<VkImage> images;
241 
242   images.resize(count);
243 
244   if (VK_CALL_LOG_ERROR(vk.GetSwapchainImagesKHR(
245           device_.GetHandle(), swapchain_, &count, images.data())) !=
246       VK_SUCCESS) {
247     return {};
248   }
249 
250   return images;
251 }
252 
GetSize() const253 SkISize VulkanSwapchain::GetSize() const {
254   VkExtent2D extents = capabilities_.currentExtent;
255 
256   if (extents.width < capabilities_.minImageExtent.width) {
257     extents.width = capabilities_.minImageExtent.width;
258   } else if (extents.width > capabilities_.maxImageExtent.width) {
259     extents.width = capabilities_.maxImageExtent.width;
260   }
261 
262   if (extents.height < capabilities_.minImageExtent.height) {
263     extents.height = capabilities_.minImageExtent.height;
264   } else if (extents.height > capabilities_.maxImageExtent.height) {
265     extents.height = capabilities_.maxImageExtent.height;
266   }
267 
268   return SkISize::Make(extents.width, extents.height);
269 }
270 
CreateSkiaSurface(GrContext * gr_context,VkImage image,const SkISize & size,SkColorType color_type,sk_sp<SkColorSpace> color_space) const271 sk_sp<SkSurface> VulkanSwapchain::CreateSkiaSurface(
272     GrContext* gr_context,
273     VkImage image,
274     const SkISize& size,
275     SkColorType color_type,
276     sk_sp<SkColorSpace> color_space) const {
277   if (gr_context == nullptr) {
278     return nullptr;
279   }
280 
281   if (color_type == kUnknown_SkColorType) {
282     // Unexpected Vulkan format.
283     return nullptr;
284   }
285 
286   const GrVkImageInfo image_info = {
287       image,                      // image
288       GrVkAlloc(),                // alloc
289       VK_IMAGE_TILING_OPTIMAL,    // tiling
290       VK_IMAGE_LAYOUT_UNDEFINED,  // layout
291       surface_format_.format,     // format
292       1,                          // level count
293   };
294 
295   // TODO(chinmaygarde): Setup the stencil buffer and the sampleCnt.
296   GrBackendRenderTarget backend_render_target(size.fWidth, size.fHeight, 0,
297                                               image_info);
298   SkSurfaceProps props(SkSurfaceProps::InitType::kLegacyFontHost_InitType);
299 
300   return SkSurface::MakeFromBackendRenderTarget(
301       gr_context,                // context
302       backend_render_target,     // backend render target
303       kTopLeft_GrSurfaceOrigin,  // origin
304       color_type,                // color type
305       std::move(color_space),    // color space
306       &props                     // surface properties
307   );
308 }
309 
CreateSwapchainImages(GrContext * skia_context,SkColorType color_type,sk_sp<SkColorSpace> color_space)310 bool VulkanSwapchain::CreateSwapchainImages(GrContext* skia_context,
311                                             SkColorType color_type,
312                                             sk_sp<SkColorSpace> color_space) {
313   std::vector<VkImage> images = GetImages();
314 
315   if (images.size() == 0) {
316     return false;
317   }
318 
319   const SkISize surface_size = GetSize();
320 
321   for (const VkImage& image : images) {
322     // Populate the backbuffer.
323     auto backbuffer = std::make_unique<VulkanBackbuffer>(
324         vk, device_.GetHandle(), device_.GetCommandPool());
325 
326     if (!backbuffer->IsValid()) {
327       return false;
328     }
329 
330     backbuffers_.emplace_back(std::move(backbuffer));
331 
332     // Populate the image.
333     auto vulkan_image = std::make_unique<VulkanImage>(image);
334 
335     if (!vulkan_image->IsValid()) {
336       return false;
337     }
338 
339     images_.emplace_back(std::move(vulkan_image));
340 
341     // Populate the surface.
342     auto surface = CreateSkiaSurface(skia_context, image, surface_size,
343                                      color_type, color_space);
344 
345     if (surface == nullptr) {
346       return false;
347     }
348 
349     surfaces_.emplace_back(std::move(surface));
350   }
351 
352 #ifdef RS_ENABLE_VK
353   if (backbuffers_.size() != images_.size()) {
354     LOGE("backbuffers_.size() != images_.size()");
355   }
356   if (images_.size() != surfaces_.size()) {
357     LOGE("images_.size() != surfaces_.size()");
358   }
359 #else
360   FML_DCHECK(backbuffers_.size() == images_.size());
361   FML_DCHECK(images_.size() == surfaces_.size());
362 #endif
363 
364   return true;
365 }
366 
GetNextBackbuffer()367 VulkanBackbuffer* VulkanSwapchain::GetNextBackbuffer() {
368   auto available_backbuffers = backbuffers_.size();
369 
370   if (available_backbuffers == 0) {
371     return nullptr;
372   }
373 
374   auto next_backbuffer_index =
375       (current_backbuffer_index_ + 1) % backbuffers_.size();
376 
377   auto& backbuffer = backbuffers_[next_backbuffer_index];
378 
379   if (!backbuffer->IsValid()) {
380     return nullptr;
381   }
382 
383   current_backbuffer_index_ = next_backbuffer_index;
384   return backbuffer.get();
385 }
386 
AcquireSurface()387 VulkanSwapchain::AcquireResult VulkanSwapchain::AcquireSurface() {
388   AcquireResult error = {AcquireStatus::ErrorSurfaceLost, nullptr};
389 
390   if (!IsValid()) {
391 #ifdef RS_ENABLE_VK
392     LOGE("Swapchain was invalid.");
393 #else
394     FML_DLOG(INFO) << "Swapchain was invalid.";
395 #endif
396     return error;
397   }
398 
399   // ---------------------------------------------------------------------------
400   // Step 0:
401   // Acquire the next available backbuffer.
402   // ---------------------------------------------------------------------------
403   auto backbuffer = GetNextBackbuffer();
404 
405   if (backbuffer == nullptr) {
406 #ifdef RS_ENABLE_VK
407     LOGE("Could not get the next backbuffer.");
408 #else
409     FML_DLOG(INFO) << "Could not get the next backbuffer.";
410 #endif
411     return error;
412   }
413 
414 #ifdef RS_ENABLE_VK
415   // -----------------------------------------------------------------------------
416   // when back buffer is used in multi threading mode it need to wait shared fence
417   // instead of its private fence
418   // -----------------------------------------------------------------------------
419 
420   if (!backbuffer->IsMultiThreading()) {
421 #endif
422     // ---------------------------------------------------------------------------
423     // Step 1:
424     // Wait for use readiness.
425     // ---------------------------------------------------------------------------
426     if (!backbuffer->WaitFences()) {
427 #ifdef RS_ENABLE_VK
428       LOGE("Failed waiting on fences.");
429 #else
430       FML_DLOG(INFO) << "Failed waiting on fences.";
431 #endif
432       return error;
433     }
434 
435   // ---------------------------------------------------------------------------
436   // Step 2:
437   // Put semaphores in unsignaled state.
438   // ---------------------------------------------------------------------------
439     if (!backbuffer->ResetFences()) {
440 #ifdef RS_ENABLE_VK
441       LOGE("Could not reset fences.");
442 #else
443       FML_DLOG(INFO) << "Could not reset fences.";
444 #endif
445       return error;
446     }
447 #ifdef RS_ENABLE_VK
448   } // !backbuffer->IsMultiThreading()
449 #endif
450 
451   // ---------------------------------------------------------------------------
452   // Step 3:
453   // Acquire the next image index.
454   // ---------------------------------------------------------------------------
455   uint32_t next_image_index = 0;
456 
457   VkResult acquire_result = VK_CALL_LOG_ERROR(
458       vk.AcquireNextImageKHR(device_.GetHandle(),                   //
459                              swapchain_,                            //
460                              std::numeric_limits<uint64_t>::max(),  //
461                              backbuffer->GetUsageSemaphore(),       //
462                              VK_NULL_HANDLE,                        //
463                              &next_image_index));
464 
465   switch (acquire_result) {
466     case VK_SUCCESS:
467       break;
468     case VK_ERROR_OUT_OF_DATE_KHR:
469       return {AcquireStatus::ErrorSurfaceOutOfDate, nullptr};
470     case VK_ERROR_SURFACE_LOST_KHR:
471       return {AcquireStatus::ErrorSurfaceLost, nullptr};
472     default:
473 #ifdef RS_ENABLE_VK
474       LOGE("Unexpected result from AcquireNextImageKHR: %d", acquire_result);
475 #else
476       FML_LOG(INFO) << "Unexpected result from AcquireNextImageKHR: "
477                     << acquire_result;
478 #endif
479       return {AcquireStatus::ErrorSurfaceLost, nullptr};
480   }
481 
482   // Simple sanity checking of image index.
483   if (next_image_index >= images_.size()) {
484 #ifdef RS_ENABLE_VK
485     LOGE("Image index returned was out-of-bounds.");
486 #else
487     FML_DLOG(INFO) << "Image index returned was out-of-bounds.";
488 #endif
489     return error;
490   }
491 
492   auto& image = images_[next_image_index];
493   if (!image->IsValid()) {
494 #ifdef RS_ENABLE_VK
495     LOGE("Image at index was invalid.");
496 #else
497     FML_DLOG(INFO) << "Image at index was invalid.";
498 #endif
499     return error;
500   }
501 
502   // ---------------------------------------------------------------------------
503   // Step 4:
504   // Start recording to the command buffer.
505   // ---------------------------------------------------------------------------
506   if (!backbuffer->GetUsageCommandBuffer().Begin()) {
507 #ifdef RS_ENABLE_VK
508     LOGE("Could not begin recording to the command buffer.");
509 #else
510     FML_DLOG(INFO) << "Could not begin recording to the command buffer.";
511 #endif
512     return error;
513   }
514 
515   // ---------------------------------------------------------------------------
516   // Step 5:
517   // Set image layout to color attachment mode.
518   // ---------------------------------------------------------------------------
519   VkPipelineStageFlagBits destination_pipeline_stage =
520       VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
521   VkImageLayout destination_image_layout =
522       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
523 
524   if (!image->InsertImageMemoryBarrier(
525           backbuffer->GetUsageCommandBuffer(),   // command buffer
526           current_pipeline_stage_,               // src_pipeline_bits
527           destination_pipeline_stage,            // dest_pipeline_bits
528           VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,  // dest_access_flags
529           destination_image_layout               // dest_layout
530           )) {
531 #ifdef RS_ENABLE_VK
532     LOGE("Could not insert image memory barrier.");
533 #else
534     FML_DLOG(INFO) << "Could not insert image memory barrier.";
535 #endif
536     return error;
537   } else {
538     current_pipeline_stage_ = destination_pipeline_stage;
539   }
540 
541   // ---------------------------------------------------------------------------
542   // Step 6:
543   // End recording to the command buffer.
544   // ---------------------------------------------------------------------------
545   if (!backbuffer->GetUsageCommandBuffer().End()) {
546 #ifdef RS_ENABLE_VK
547     LOGE("Could not end recording to the command buffer.");
548 #else
549     FML_DLOG(INFO) << "Could not end recording to the command buffer.";
550 #endif
551     return error;
552   }
553 
554   // ---------------------------------------------------------------------------
555   // Step 7:
556   // Submit the command buffer to the device queue.
557   // ---------------------------------------------------------------------------
558   std::vector<VkSemaphore> wait_semaphores = {backbuffer->GetUsageSemaphore()};
559   std::vector<VkSemaphore> signal_semaphores = {};
560   std::vector<VkCommandBuffer> command_buffers = {
561       backbuffer->GetUsageCommandBuffer().Handle()};
562 
563   if (!device_.QueueSubmit(
564           {destination_pipeline_stage},  // wait_dest_pipeline_stages
565           wait_semaphores,               // wait_semaphores
566           signal_semaphores,             // signal_semaphores
567           command_buffers,               // command_buffers
568           backbuffer->GetUsageFence()    // fence
569           )) {
570 #ifdef RS_ENABLE_VK
571     LOGE("Could not submit to the device queue.");
572 #else
573     FML_DLOG(INFO) << "Could not submit to the device queue.";
574 #endif
575     return error;
576   }
577 
578 #ifdef RS_ENABLE_VK
579   // reset to not under multi-threading by default
580   // the reality will be judged later in flush stage
581   backbuffer->UnsetMultiThreading();
582 #endif
583   // ---------------------------------------------------------------------------
584   // Step 8:
585   // Tell Skia about the updated image layout.
586   // ---------------------------------------------------------------------------
587   sk_sp<SkSurface> surface = surfaces_[next_image_index];
588 
589   if (surface == nullptr) {
590 #ifdef RS_ENABLE_VK
591     LOGE("Could not access surface at the image index.");
592 #else
593     FML_DLOG(INFO) << "Could not access surface at the image index.";
594 #endif
595     return error;
596   }
597 
598   GrBackendRenderTarget backendRT = surface->getBackendRenderTarget(
599       SkSurface::kFlushRead_BackendHandleAccess);
600   if (!backendRT.isValid()) {
601 #ifdef RS_ENABLE_VK
602     LOGE("Could not get backend render target.");
603 #else
604     FML_DLOG(INFO) << "Could not get backend render target.";
605 #endif
606     return error;
607   }
608   backendRT.setVkImageLayout(destination_image_layout);
609 
610   current_image_index_ = next_image_index;
611 
612   return {AcquireStatus::Success, surface};
613 }
614 
615 #ifdef RS_ENABLE_VK
FlushCommands()616 bool VulkanSwapchain::FlushCommands() {
617   if (!IsValid()) {
618     LOGE("Swapchain was invalid.");
619     return false;
620   }
621 
622   sk_sp<SkSurface> surface = surfaces_[current_image_index_];
623   const std::unique_ptr<VulkanImage>& image = images_[current_image_index_];
624   auto backbuffer = backbuffers_[current_backbuffer_index_].get();
625 
626   // ---------------------------------------------------------------------------
627   // Step 0:
628   // Make sure Skia has flushed all work for the surface to the gpu.
629   // ---------------------------------------------------------------------------
630   surface->flush();
631 
632   // ---------------------------------------------------------------------------
633   // Step 1:
634   // Start recording to the command buffer.
635   // ---------------------------------------------------------------------------
636   if (!backbuffer->GetRenderCommandBuffer().Begin()) {
637     LOGE("Could not start recording to the command buffer.");
638     return false;
639   }
640 
641   // ---------------------------------------------------------------------------
642   // Step 2:
643   // Set image layout to present mode.
644   // ---------------------------------------------------------------------------
645   VkPipelineStageFlagBits destination_pipeline_stage =
646       VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
647   VkImageLayout destination_image_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
648 
649   if (!image->InsertImageMemoryBarrier(
650           backbuffer->GetRenderCommandBuffer(),  // command buffer
651           current_pipeline_stage_,               // src_pipeline_bits
652           destination_pipeline_stage,            // dest_pipeline_bits
653           VK_ACCESS_MEMORY_READ_BIT,             // dest_access_flags
654           destination_image_layout               // dest_layout
655           )) {
656     LOGE("Could not insert memory barrier.");
657     return false;
658   } else {
659     current_pipeline_stage_ = destination_pipeline_stage;
660   }
661 
662   // ---------------------------------------------------------------------------
663   // Step 3:
664   // End recording to the command buffer
665   // ---------------------------------------------------------------------------
666   if (!backbuffer->GetRenderCommandBuffer().End()) {
667     LOGE("Could not end recording to the command buffer.");
668     return false;
669   }
670   return true;
671 }
672 
AddToPresent()673 void VulkanSwapchain::AddToPresent() {
674   std::lock_guard<std::mutex> lock(map_mutex_);
675   to_be_present_[std::this_thread::get_id()] = this;
676 }
677 
PresentAll(VulkanHandle<VkFence> & shared_fence)678 void VulkanSwapchain::PresentAll(VulkanHandle<VkFence>& shared_fence) {
679   if (to_be_present_.empty()) {
680     LOGE("nothing to be presented");
681     return;
682   }
683 
684   std::lock_guard<std::mutex> lock(map_mutex_);
685   // ---------------------------------------------------------------------------
686   // Submit all the command buffer to the device queue. Tell it to signal the render
687   // semaphore.
688   // ---------------------------------------------------------------------------
689   std::vector<VkSemaphore> wait_semaphores = {};
690   std::vector<VkSemaphore> queue_signal_semaphores;
691   std::vector<VkCommandBuffer> command_buffers;
692   std::vector<VkSwapchainKHR> swapchains;
693   std::vector<uint32_t> present_image_indices;
694   queue_signal_semaphores.reserve(to_be_present_.size());
695   command_buffers.reserve(to_be_present_.size());
696   swapchains.reserve(to_be_present_.size());
697   present_image_indices.reserve(to_be_present_.size());
698   VulkanSwapchain* tmpSwapChain = nullptr;
699   for (const auto& entry : to_be_present_) {
700     auto swapchain = entry.second;
701     if (!tmpSwapChain) tmpSwapChain = swapchain;
702     auto backbuffer = swapchain->backbuffers_[swapchain->current_backbuffer_index_].get();
703     backbuffer->SetMultiThreading();
704     queue_signal_semaphores.push_back(backbuffer->GetRenderSemaphore());
705     command_buffers.push_back(backbuffer->GetRenderCommandBuffer().Handle());
706     swapchains.push_back(swapchain->swapchain_);
707     present_image_indices.push_back(static_cast<uint32_t>(swapchain->current_image_index_));
708   }
709 
710   const VulkanProcTable& vk = tmpSwapChain->vk;
711   const VulkanDevice& device = tmpSwapChain->device_;
712 
713   if (!device.QueueSubmit(
714       {/*Empty, No wait Semaphores. */},
715       wait_semaphores,
716       queue_signal_semaphores,
717       command_buffers,
718       shared_fence
719       )) {
720     LOGE("Could not submit to the device queue");
721     return;
722   }
723 
724   // ----------------------------------------
725   //  present multiple swapchain all at once
726   // ----------------------------------------
727   const VkPresentInfoKHR present_info = {
728     .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
729     .pNext = nullptr,
730     .waitSemaphoreCount =
731       static_cast<uint32_t> (queue_signal_semaphores.size()),
732     .pWaitSemaphores = queue_signal_semaphores.data(),
733     .swapchainCount = static_cast<uint32_t>(swapchains.size()),
734     .pSwapchains = swapchains.data(),
735     .pImageIndices = present_image_indices.data(),
736     .pResults = nullptr,
737   };
738 
739   if (VK_CALL_LOG_ERROR(vk.QueuePresentKHR(device.GetQueueHandle(),
740     &present_info)) != VK_SUCCESS) {
741     LOGE("Could not submit the present operation");
742     return;
743   }
744 
745   to_be_present_.clear();
746 }
747 #endif
748 
Submit()749 bool VulkanSwapchain::Submit() {
750   if (!IsValid()) {
751 #ifdef RS_ENABLE_VK
752     LOGE("Swapchain was invalid.");
753 #else
754     FML_DLOG(INFO) << "Swapchain was invalid.";
755 #endif
756     return false;
757   }
758 
759   sk_sp<SkSurface> surface = surfaces_[current_image_index_];
760   const std::unique_ptr<VulkanImage>& image = images_[current_image_index_];
761   auto backbuffer = backbuffers_[current_backbuffer_index_].get();
762 
763   // ---------------------------------------------------------------------------
764   // Step 0:
765   // Make sure Skia has flushed all work for the surface to the gpu.
766   // ---------------------------------------------------------------------------
767   surface->flush();
768 
769   // ---------------------------------------------------------------------------
770   // Step 1:
771   // Start recording to the command buffer.
772   // ---------------------------------------------------------------------------
773   if (!backbuffer->GetRenderCommandBuffer().Begin()) {
774 #ifdef RS_ENABLE_VK
775     LOGE("Could not start recording to the command buffer.");
776 #else
777     FML_DLOG(INFO) << "Could not start recording to the command buffer.";
778 #endif
779     return false;
780   }
781 
782   // ---------------------------------------------------------------------------
783   // Step 2:
784   // Set image layout to present mode.
785   // ---------------------------------------------------------------------------
786   VkPipelineStageFlagBits destination_pipeline_stage =
787       VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
788   VkImageLayout destination_image_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
789 
790   if (!image->InsertImageMemoryBarrier(
791           backbuffer->GetRenderCommandBuffer(),  // command buffer
792           current_pipeline_stage_,               // src_pipeline_bits
793           destination_pipeline_stage,            // dest_pipeline_bits
794           VK_ACCESS_MEMORY_READ_BIT,             // dest_access_flags
795           destination_image_layout               // dest_layout
796           )) {
797 #ifdef RS_ENABLE_VK
798     LOGE("Could not insert memory barrier.");
799 #else
800     FML_DLOG(INFO) << "Could not insert memory barrier.";
801 #endif
802     return false;
803   } else {
804     current_pipeline_stage_ = destination_pipeline_stage;
805   }
806 
807   // ---------------------------------------------------------------------------
808   // Step 3:
809   // End recording to the command buffer.
810   // ---------------------------------------------------------------------------
811   if (!backbuffer->GetRenderCommandBuffer().End()) {
812 #ifdef RS_ENABLE_VK
813     LOGE("Could not end recording to the command buffer.");
814 #else
815     FML_DLOG(INFO) << "Could not end recording to the command buffer.";
816 #endif
817     return false;
818   }
819 
820   // ---------------------------------------------------------------------------
821   // Step 4:
822   // Submit the command buffer to the device queue. Tell it to signal the render
823   // semaphore.
824   // ---------------------------------------------------------------------------
825   std::vector<VkSemaphore> wait_semaphores = {};
826   std::vector<VkSemaphore> queue_signal_semaphores = {
827       backbuffer->GetRenderSemaphore()};
828   std::vector<VkCommandBuffer> command_buffers = {
829       backbuffer->GetRenderCommandBuffer().Handle()};
830 
831   if (!device_.QueueSubmit(
832           {/* Empty. No wait semaphores. */},  // wait_dest_pipeline_stages
833           wait_semaphores,                     // wait_semaphores
834           queue_signal_semaphores,             // signal_semaphores
835           command_buffers,                     // command_buffers
836           backbuffer->GetRenderFence()         // fence
837           )) {
838 #ifdef RS_ENABLE_VK
839     LOGE("Could not submit to the device queue.");
840 #else
841     FML_DLOG(INFO) << "Could not submit to the device queue.";
842 #endif
843     return false;
844   }
845 
846 #ifdef RS_ENABLE_VK
847   backbuffer->UnsetMultiThreading();
848 #endif
849   // ---------------------------------------------------------------------------
850   // Step 5:
851   // Submit the present operation and wait on the render semaphore.
852   // ---------------------------------------------------------------------------
853   VkSwapchainKHR swapchain = swapchain_;
854   uint32_t present_image_index = static_cast<uint32_t>(current_image_index_);
855   const VkPresentInfoKHR present_info = {
856       .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
857       .pNext = nullptr,
858       .waitSemaphoreCount =
859           static_cast<uint32_t>(queue_signal_semaphores.size()),
860       .pWaitSemaphores = queue_signal_semaphores.data(),
861       .swapchainCount = 1,
862       .pSwapchains = &swapchain,
863       .pImageIndices = &present_image_index,
864       .pResults = nullptr,
865   };
866 
867   if (VK_CALL_LOG_ERROR(vk.QueuePresentKHR(device_.GetQueueHandle(),
868                                            &present_info)) != VK_SUCCESS) {
869 #ifdef RS_ENABLE_VK
870     LOGE("Could not submit the present operation.");
871 #else
872     FML_DLOG(INFO) << "Could not submit the present operation.";
873 #endif
874     return false;
875   }
876 
877   return true;
878 }
879 
880 }  // namespace vulkan
881