Flutter Engine
The Flutter Engine
Public Types | Public Member Functions | List of all members
vulkan::VulkanSwapchain Class Reference

#include <vulkan_swapchain.h>

Public Types

enum class  AcquireStatus { Success , ErrorSurfaceLost , ErrorSurfaceOutOfDate }
 
using AcquireResult = std::pair< AcquireStatus, sk_sp< SkSurface > >
 

Public Member Functions

 VulkanSwapchain (const VulkanProcTable &vk, const VulkanDevice &device, const VulkanSurface &surface, GrDirectContext *skia_context, std::unique_ptr< VulkanSwapchain > old_swapchain, uint32_t queue_family_index)
 
 ~VulkanSwapchain ()
 
bool IsValid () const
 
AcquireResult AcquireSurface ()
 
bool Submit ()
 
SkISize GetSize () const
 
 FML_DISALLOW_COPY_AND_ASSIGN (VulkanSwapchain)
 

Detailed Description

Definition at line 26 of file vulkan_swapchain.h.

Member Typedef Documentation

◆ AcquireResult

Definition at line 50 of file vulkan_swapchain.h.

Member Enumeration Documentation

◆ AcquireStatus

Enumerator
Success 

A valid SkSurface was acquired successfully from the swapchain.

ErrorSurfaceLost 

The underlying surface of the swapchain was permanently lost. This is an unrecoverable error. The entire surface must be recreated along with the swapchain.

ErrorSurfaceOutOfDate 

The swapchain surface is out-of-date with the underlying surface. The swapchain must be recreated.

Definition at line 39 of file vulkan_swapchain.h.

39 {
40 /// A valid SkSurface was acquired successfully from the swapchain.
41 Success,
42 /// The underlying surface of the swapchain was permanently lost. This is an
43 /// unrecoverable error. The entire surface must be recreated along with the
44 /// swapchain.
45 ErrorSurfaceLost,
46 /// The swapchain surface is out-of-date with the underlying surface. The
47 /// swapchain must be recreated.
48 ErrorSurfaceOutOfDate,
49 };

Constructor & Destructor Documentation

◆ VulkanSwapchain()

vulkan::VulkanSwapchain::VulkanSwapchain ( const VulkanProcTable vk,
const VulkanDevice device,
const VulkanSurface surface,
GrDirectContext skia_context,
std::unique_ptr< VulkanSwapchain old_swapchain,
uint32_t  queue_family_index 
)

Definition at line 45 of file vulkan_swapchain.cc.

51 : vk(p_vk),
52 device_(device),
53 capabilities_(),
54 surface_format_(),
55 current_pipeline_stage_(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT),
56 current_backbuffer_index_(0),
57 current_image_index_(0),
58 valid_(false) {
59 if (!device_.IsValid() || !surface.IsValid() || skia_context == nullptr) {
60 FML_DLOG(INFO) << "Device or surface is invalid.";
61 return;
62 }
63
64 if (!device_.GetSurfaceCapabilities(surface, &capabilities_)) {
65 FML_DLOG(INFO) << "Could not find surface capabilities.";
66 return;
67 }
68
69 const auto format_infos = DesiredFormatInfos();
70 std::vector<VkFormat> desired_formats(format_infos.size());
71 for (size_t i = 0; i < format_infos.size(); ++i) {
72 if (skia_context->colorTypeSupportedAsSurface(
73 format_infos[i].color_type_)) {
74 desired_formats[i] = format_infos[i].format_;
75 } else {
76 desired_formats[i] = VK_FORMAT_UNDEFINED;
77 }
78 }
79
80 int format_index =
81 device_.ChooseSurfaceFormat(surface, desired_formats, &surface_format_);
82 if (format_index < 0) {
83 FML_DLOG(INFO) << "Could not choose surface format.";
84 return;
85 }
86
88 if (!device_.ChoosePresentMode(surface, &present_mode)) {
89 FML_DLOG(INFO) << "Could not choose present mode.";
90 return;
91 }
92
93 // Check if the surface can present.
94
95 VkBool32 supported = VK_FALSE;
96 if (VK_CALL_LOG_ERROR(vk.GetPhysicalDeviceSurfaceSupportKHR(
97 device_.GetPhysicalDeviceHandle(), // physical device
98 queue_family_index, // queue family
99 surface.Handle(), // surface to test
100 &supported)) != VK_SUCCESS) {
101 FML_DLOG(INFO) << "Could not get physical device surface support.";
102 return;
103 }
104
105 if (supported != VK_TRUE) {
106 FML_DLOG(INFO) << "Surface was not supported by the physical device.";
107 return;
108 }
109
110 // Construct the Swapchain
111
112 VkSwapchainKHR old_swapchain_handle = VK_NULL_HANDLE;
113
114 if (old_swapchain != nullptr && old_swapchain->IsValid()) {
115 old_swapchain_handle = old_swapchain->swapchain_;
116 // The unique pointer to the swapchain will go out of scope here
117 // and its handle collected after the appropriate device wait.
118 }
119
120 VkSurfaceKHR surface_handle = surface.Handle();
121
125
126 const VkSwapchainCreateInfoKHR create_info = {
128 .pNext = nullptr,
129 .flags = 0,
130 .surface = surface_handle,
131 .minImageCount = capabilities_.minImageCount,
132 .imageFormat = surface_format_.format,
133 .imageColorSpace = surface_format_.colorSpace,
134 .imageExtent = capabilities_.currentExtent,
135 .imageArrayLayers = 1,
136 .imageUsage = usage_flags,
137 .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
138 .queueFamilyIndexCount = 0, // Because of the exclusive sharing mode.
139 .pQueueFamilyIndices = nullptr,
141 .compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
142 .presentMode = present_mode,
143 .clipped = VK_FALSE,
144 .oldSwapchain = old_swapchain_handle,
145 };
146
147 VkSwapchainKHR swapchain = VK_NULL_HANDLE;
148
149 if (VK_CALL_LOG_ERROR(vk.CreateSwapchainKHR(device_.GetHandle(), &create_info,
150 nullptr, &swapchain)) !=
151 VK_SUCCESS) {
152 FML_DLOG(INFO) << "Could not create the swapchain.";
153 return;
154 }
155
156 swapchain_ = VulkanHandle<VkSwapchainKHR>{
157 swapchain, [this](VkSwapchainKHR swapchain) {
158 FML_ALLOW_UNUSED_LOCAL(device_.WaitIdle());
159 vk.DestroySwapchainKHR(device_.GetHandle(), swapchain, nullptr);
160 }};
161
162 if (!CreateSwapchainImages(
163 skia_context, format_infos[format_index].color_type_,
164 format_infos[format_index].color_space_, usage_flags)) {
165 FML_DLOG(INFO) << "Could not create swapchain images.";
166 return;
167 }
168
169 valid_ = true;
170}
SK_API bool colorTypeSupportedAsSurface(SkColorType colorType) const
VkSwapchainKHR swapchain
Definition: main.cc:64
VkDevice device
Definition: main.cc:53
uint32_t queue_family_index
Definition: main.cc:54
VkSurfaceKHR surface
Definition: main.cc:49
#define FML_ALLOW_UNUSED_LOCAL(x)
#define FML_DLOG(severity)
Definition: logging.h:102
vk
Definition: malisc.py:42
static std::vector< FormatInfo > DesiredFormatInfos()
VkStructureType sType
Definition: vulkan_core.h:7727
@ VK_SHARING_MODE_EXCLUSIVE
Definition: vulkan_core.h:1813
#define VK_TRUE
Definition: vulkan_core.h:131
VkFlags VkImageUsageFlags
Definition: vulkan_core.h:2382
@ VK_IMAGE_USAGE_TRANSFER_DST_BIT
Definition: vulkan_core.h:2353
@ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
Definition: vulkan_core.h:2356
@ VK_IMAGE_USAGE_TRANSFER_SRC_BIT
Definition: vulkan_core.h:2352
@ VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
Definition: vulkan_core.h:7643
#define VK_FALSE
Definition: vulkan_core.h:125
@ VK_SUCCESS
Definition: vulkan_core.h:141
@ VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
Definition: vulkan_core.h:7627
VkPresentModeKHR
Definition: vulkan_core.h:7594
@ VK_PRESENT_MODE_FIFO_KHR
Definition: vulkan_core.h:7597
#define VK_NULL_HANDLE
Definition: vulkan_core.h:46
@ VK_FORMAT_UNDEFINED
Definition: vulkan_core.h:1459
uint32_t VkBool32
Definition: vulkan_core.h:94
@ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
Definition: vulkan_core.h:2435
@ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR
Definition: vulkan_core.h:418
#define VK_CALL_LOG_ERROR(expression)
SkColorType color_type_
sk_sp< SkColorSpace > color_space_

◆ ~VulkanSwapchain()

vulkan::VulkanSwapchain::~VulkanSwapchain ( )
default

Member Function Documentation

◆ AcquireSurface()

VulkanSwapchain::AcquireResult vulkan::VulkanSwapchain::AcquireSurface ( )

Acquire an SkSurface from the swapchain for the caller to render into for later submission via |Submit|. There must not be consecutive calls to |AcquireFrame| without and interleaving |Submit|.

Definition at line 334 of file vulkan_swapchain.cc.

334 {
336
337 if (!IsValid()) {
338 FML_DLOG(INFO) << "Swapchain was invalid.";
339 return error;
340 }
341
342 // ---------------------------------------------------------------------------
343 // Step 0:
344 // Acquire the next available backbuffer.
345 // ---------------------------------------------------------------------------
346 auto backbuffer = GetNextBackbuffer();
347
348 if (backbuffer == nullptr) {
349 FML_DLOG(INFO) << "Could not get the next backbuffer.";
350 return error;
351 }
352
353 // ---------------------------------------------------------------------------
354 // Step 1:
355 // Wait for use readiness.
356 // ---------------------------------------------------------------------------
357 if (!backbuffer->WaitFences()) {
358 FML_DLOG(INFO) << "Failed waiting on fences.";
359 return error;
360 }
361
362 // ---------------------------------------------------------------------------
363 // Step 2:
364 // Put fences in an unsignaled state.
365 // ---------------------------------------------------------------------------
366 if (!backbuffer->ResetFences()) {
367 FML_DLOG(INFO) << "Could not reset fences.";
368 return error;
369 }
370
371 // ---------------------------------------------------------------------------
372 // Step 3:
373 // Acquire the next image index.
374 // ---------------------------------------------------------------------------
375 uint32_t next_image_index = 0;
376
377 VkResult acquire_result = VK_CALL_LOG_ERROR(
378 vk.AcquireNextImageKHR(device_.GetHandle(), //
379 swapchain_, //
381 backbuffer->GetUsageSemaphore(), //
383 &next_image_index));
384
385 switch (acquire_result) {
386 case VK_SUCCESS:
387 break;
389 return {AcquireStatus::ErrorSurfaceOutOfDate, nullptr};
391 return {AcquireStatus::ErrorSurfaceLost, nullptr};
392 default:
393 FML_LOG(INFO) << "Unexpected result from AcquireNextImageKHR: "
394 << acquire_result;
395 return {AcquireStatus::ErrorSurfaceLost, nullptr};
396 }
397
398 // Simple sanity checking of image index.
399 if (next_image_index >= images_.size()) {
400 FML_DLOG(INFO) << "Image index returned was out-of-bounds.";
401 return error;
402 }
403
404 auto& image = images_[next_image_index];
405 if (!image->IsValid()) {
406 FML_DLOG(INFO) << "Image at index was invalid.";
407 return error;
408 }
409
410 // ---------------------------------------------------------------------------
411 // Step 4:
412 // Start recording to the command buffer.
413 // ---------------------------------------------------------------------------
414 if (!backbuffer->GetUsageCommandBuffer().Begin()) {
415 FML_DLOG(INFO) << "Could not begin recording to the command buffer.";
416 return error;
417 }
418
419 // ---------------------------------------------------------------------------
420 // Step 5:
421 // Set image layout to color attachment mode.
422 // ---------------------------------------------------------------------------
423 VkPipelineStageFlagBits destination_pipeline_stage =
425 VkImageLayout destination_image_layout =
427
428 if (!image->InsertImageMemoryBarrier(
429 backbuffer->GetUsageCommandBuffer(), // command buffer
430 current_pipeline_stage_, // src_pipeline_bits
431 destination_pipeline_stage, // dest_pipeline_bits
432 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // dest_access_flags
433 destination_image_layout // dest_layout
434 )) {
435 FML_DLOG(INFO) << "Could not insert image memory barrier.";
436 return error;
437 } else {
438 current_pipeline_stage_ = destination_pipeline_stage;
439 }
440
441 // ---------------------------------------------------------------------------
442 // Step 6:
443 // End recording to the command buffer.
444 // ---------------------------------------------------------------------------
445 if (!backbuffer->GetUsageCommandBuffer().End()) {
446 FML_DLOG(INFO) << "Could not end recording to the command buffer.";
447 return error;
448 }
449
450 // ---------------------------------------------------------------------------
451 // Step 7:
452 // Submit the command buffer to the device queue.
453 // ---------------------------------------------------------------------------
454 std::vector<VkSemaphore> wait_semaphores = {backbuffer->GetUsageSemaphore()};
455 std::vector<VkSemaphore> signal_semaphores = {};
456 std::vector<VkCommandBuffer> command_buffers = {
457 backbuffer->GetUsageCommandBuffer().Handle()};
458
459 if (!device_.QueueSubmit(
460 {destination_pipeline_stage}, // wait_dest_pipeline_stages
461 wait_semaphores, // wait_semaphores
462 signal_semaphores, // signal_semaphores
463 command_buffers, // command_buffers
464 backbuffer->GetUsageFence() // fence
465 )) {
466 FML_DLOG(INFO) << "Could not submit to the device queue.";
467 return error;
468 }
469
470 // ---------------------------------------------------------------------------
471 // Step 8:
472 // Tell Skia about the updated image layout.
473 // ---------------------------------------------------------------------------
474 sk_sp<SkSurface> surface = surfaces_[next_image_index];
475
476 if (surface == nullptr) {
477 FML_DLOG(INFO) << "Could not access surface at the image index.";
478 return error;
479 }
480
483 if (!backendRT.isValid()) {
484 FML_DLOG(INFO) << "Could not get backend render target.";
485 return error;
486 }
488 destination_image_layout);
489
490 current_image_index_ = next_image_index;
491
493}
@ kFlushRead
back-end object is readable
std::pair< AcquireStatus, sk_sp< SkSurface > > AcquireResult
@ Success
A valid SkSurface was acquired successfully from the swapchain.
const uint8_t uint32_t uint32_t GError ** error
#define FML_LOG(severity)
Definition: logging.h:82
static float max(float r, float g, float b)
Definition: hsl.cpp:49
SK_API void SetVkImageLayout(GrBackendRenderTarget *, VkImageLayout)
sk_sp< const SkImage > image
Definition: SkRecords.h:269
SK_API GrBackendRenderTarget GetBackendRenderTarget(SkSurface *, BackendHandleAccess)
VkImageLayout
Definition: vulkan_core.h:1330
@ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
Definition: vulkan_core.h:1333
VkResult
Definition: vulkan_core.h:140
@ VK_ERROR_OUT_OF_DATE_KHR
Definition: vulkan_core.h:168
@ VK_ERROR_SURFACE_LOST_KHR
Definition: vulkan_core.h:165
@ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
Definition: vulkan_core.h:2208
VkPipelineStageFlagBits
Definition: vulkan_core.h:2434
@ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
Definition: vulkan_core.h:2445

◆ FML_DISALLOW_COPY_AND_ASSIGN()

vulkan::VulkanSwapchain::FML_DISALLOW_COPY_AND_ASSIGN ( VulkanSwapchain  )

◆ GetSize()

SkISize vulkan::VulkanSwapchain::GetSize ( ) const

Definition at line 202 of file vulkan_swapchain.cc.

202 {
203 VkExtent2D extents = capabilities_.currentExtent;
204
205 if (extents.width < capabilities_.minImageExtent.width) {
206 extents.width = capabilities_.minImageExtent.width;
207 } else if (extents.width > capabilities_.maxImageExtent.width) {
208 extents.width = capabilities_.maxImageExtent.width;
209 }
210
211 if (extents.height < capabilities_.minImageExtent.height) {
212 extents.height = capabilities_.minImageExtent.height;
213 } else if (extents.height > capabilities_.maxImageExtent.height) {
214 extents.height = capabilities_.maxImageExtent.height;
215 }
216
217 return SkISize::Make(extents.width, extents.height);
218}
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20
uint32_t width
Definition: vulkan_core.h:2858
uint32_t height
Definition: vulkan_core.h:2859

◆ IsValid()

bool vulkan::VulkanSwapchain::IsValid ( ) const

Definition at line 174 of file vulkan_swapchain.cc.

174 {
175 return valid_;
176}

◆ Submit()

bool vulkan::VulkanSwapchain::Submit ( )

Submit a previously acquired. There must not be consecutive calls to |Submit| without and interleaving |AcquireFrame|.

Definition at line 495 of file vulkan_swapchain.cc.

495 {
496 if (!IsValid()) {
497 FML_DLOG(INFO) << "Swapchain was invalid.";
498 return false;
499 }
500
501 sk_sp<SkSurface> surface = surfaces_[current_image_index_];
502 const std::unique_ptr<VulkanImage>& image = images_[current_image_index_];
503 auto backbuffer = backbuffers_[current_backbuffer_index_].get();
504
505 // ---------------------------------------------------------------------------
506 // Step 0:
507 // Make sure Skia has flushed all work for the surface to the gpu.
508 // ---------------------------------------------------------------------------
510
511 // ---------------------------------------------------------------------------
512 // Step 1:
513 // Start recording to the command buffer.
514 // ---------------------------------------------------------------------------
515 if (!backbuffer->GetRenderCommandBuffer().Begin()) {
516 FML_DLOG(INFO) << "Could not start recording to the command buffer.";
517 return false;
518 }
519
520 // ---------------------------------------------------------------------------
521 // Step 2:
522 // Set image layout to present mode.
523 // ---------------------------------------------------------------------------
524 VkPipelineStageFlagBits destination_pipeline_stage =
526 VkImageLayout destination_image_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
527
528 if (!image->InsertImageMemoryBarrier(
529 backbuffer->GetRenderCommandBuffer(), // command buffer
530 current_pipeline_stage_, // src_pipeline_bits
531 destination_pipeline_stage, // dest_pipeline_bits
532 VK_ACCESS_MEMORY_READ_BIT, // dest_access_flags
533 destination_image_layout // dest_layout
534 )) {
535 FML_DLOG(INFO) << "Could not insert memory barrier.";
536 return false;
537 } else {
538 current_pipeline_stage_ = destination_pipeline_stage;
539 }
540
541 // ---------------------------------------------------------------------------
542 // Step 3:
543 // End recording to the command buffer.
544 // ---------------------------------------------------------------------------
545 if (!backbuffer->GetRenderCommandBuffer().End()) {
546 FML_DLOG(INFO) << "Could not end recording to the command buffer.";
547 return false;
548 }
549
550 // ---------------------------------------------------------------------------
551 // Step 4:
552 // Submit the command buffer to the device queue. Tell it to signal the render
553 // semaphore.
554 // ---------------------------------------------------------------------------
555 std::vector<VkSemaphore> wait_semaphores = {};
556 std::vector<VkSemaphore> queue_signal_semaphores = {
557 backbuffer->GetRenderSemaphore()};
558 std::vector<VkCommandBuffer> command_buffers = {
559 backbuffer->GetRenderCommandBuffer().Handle()};
560
561 if (!device_.QueueSubmit(
562 {/* Empty. No wait semaphores. */}, // wait_dest_pipeline_stages
563 wait_semaphores, // wait_semaphores
564 queue_signal_semaphores, // signal_semaphores
565 command_buffers, // command_buffers
566 backbuffer->GetRenderFence() // fence
567 )) {
568 FML_DLOG(INFO) << "Could not submit to the device queue.";
569 return false;
570 }
571
572 // ---------------------------------------------------------------------------
573 // Step 5:
574 // Submit the present operation and wait on the render semaphore.
575 // ---------------------------------------------------------------------------
576 VkSwapchainKHR swapchain = swapchain_;
577 uint32_t present_image_index = static_cast<uint32_t>(current_image_index_);
578 const VkPresentInfoKHR present_info = {
580 .pNext = nullptr,
581 .waitSemaphoreCount =
582 static_cast<uint32_t>(queue_signal_semaphores.size()),
583 .pWaitSemaphores = queue_signal_semaphores.data(),
584 .swapchainCount = 1,
585 .pSwapchains = &swapchain,
586 .pImageIndices = &present_image_index,
587 .pResults = nullptr,
588 };
589
590 if (VK_CALL_LOG_ERROR(vk.QueuePresentKHR(device_.GetQueueHandle(),
591 &present_info)) != VK_SUCCESS) {
592 FML_DLOG(INFO) << "Could not submit the present operation.";
593 return false;
594 }
595
596 return true;
597}
T * get() const
Definition: SkRefCnt.h:303
SK_API void FlushAndSubmit(sk_sp< SkSurface >)
VkStructureType sType
Definition: vulkan_core.h:7748
@ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
Definition: vulkan_core.h:1348
@ VK_ACCESS_MEMORY_READ_BIT
Definition: vulkan_core.h:2215
@ VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT
Definition: vulkan_core.h:2448
@ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR
Definition: vulkan_core.h:419

The documentation for this class was generated from the following files: