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