9#include "third_party/skia/include/core/SkColorSpace.h"
10#include "third_party/skia/include/core/SkSurface.h"
11#include "third_party/skia/include/gpu/ganesh/GrBackendSurface.h"
12#include "third_party/skia/include/gpu/ganesh/GrDirectContext.h"
13#include "third_party/skia/include/gpu/ganesh/SkSurfaceGanesh.h"
14#include "third_party/skia/include/gpu/ganesh/vk/GrVkBackendSurface.h"
15#include "third_party/skia/include/gpu/ganesh/vk/GrVkTypes.h"
33 return {{VK_FORMAT_R8G8B8A8_SRGB, kRGBA_8888_SkColorType,
34 SkColorSpace::MakeSRGB()},
35 {VK_FORMAT_B8G8R8A8_SRGB, kRGBA_8888_SkColorType,
36 SkColorSpace::MakeSRGB()},
37 {VK_FORMAT_R16G16B16A16_SFLOAT, kRGBA_F16_SkColorType,
38 SkColorSpace::MakeSRGBLinear()},
39 {VK_FORMAT_R8G8B8A8_UNORM, kRGBA_8888_SkColorType,
40 SkColorSpace::MakeSRGB()},
41 {VK_FORMAT_B8G8R8A8_UNORM, kRGBA_8888_SkColorType,
42 SkColorSpace::MakeSRGB()}};
48 GrDirectContext* skia_context,
49 std::unique_ptr<VulkanSwapchain> old_swapchain,
55 current_pipeline_stage_(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT),
56 current_backbuffer_index_(0),
57 current_image_index_(0),
59 if (!device_.IsValid() || !
surface.IsValid() || skia_context ==
nullptr) {
60 FML_DLOG(INFO) <<
"Device or surface is invalid.";
64 if (!device_.GetSurfaceCapabilities(
surface, &capabilities_)) {
65 FML_DLOG(INFO) <<
"Could not find surface capabilities.";
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_;
76 desired_formats[
i] = VK_FORMAT_UNDEFINED;
81 device_.ChooseSurfaceFormat(
surface, desired_formats, &surface_format_);
82 if (format_index < 0) {
83 FML_DLOG(INFO) <<
"Could not choose surface format.";
87 VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR;
88 if (!device_.ChoosePresentMode(
surface, &present_mode)) {
89 FML_DLOG(INFO) <<
"Could not choose present mode.";
95 VkBool32 supported = VK_FALSE;
97 device_.GetPhysicalDeviceHandle(),
100 &supported)) != VK_SUCCESS) {
101 FML_DLOG(INFO) <<
"Could not get physical device surface support.";
105 if (supported != VK_TRUE) {
106 FML_DLOG(INFO) <<
"Surface was not supported by the physical device.";
112 VkSwapchainKHR old_swapchain_handle = VK_NULL_HANDLE;
114 if (old_swapchain !=
nullptr && old_swapchain->IsValid()) {
115 old_swapchain_handle = old_swapchain->swapchain_;
120 VkSurfaceKHR surface_handle =
surface.Handle();
122 VkImageUsageFlags usage_flags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
123 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
124 VK_IMAGE_USAGE_TRANSFER_DST_BIT;
126 const VkSwapchainCreateInfoKHR create_info = {
127 .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
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,
139 .pQueueFamilyIndices =
nullptr,
140 .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
141 .compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
142 .presentMode = present_mode,
144 .oldSwapchain = old_swapchain_handle,
147 VkSwapchainKHR
swapchain = VK_NULL_HANDLE;
152 FML_DLOG(INFO) <<
"Could not create the swapchain.";
158 [[maybe_unused]]
auto result = device_.WaitIdle();
159 vk.DestroySwapchainKHR(device_.GetHandle(),
swapchain,
nullptr);
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.";
178std::vector<VkImage> VulkanSwapchain::GetImages()
const {
181 device_.GetHandle(), swapchain_, &count,
nullptr)) != VK_SUCCESS) {
189 std::vector<VkImage>
images;
194 device_.GetHandle(), swapchain_, &count,
images.data())) !=
203 VkExtent2D extents = capabilities_.currentExtent;
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;
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;
217 return SkISize::Make(extents.width, extents.height);
220sk_sp<SkSurface> VulkanSwapchain::CreateSkiaSurface(
221 GrDirectContext* gr_context,
223 VkImageUsageFlags usage_flags,
226 sk_sp<SkColorSpace> color_space)
const {
227 if (gr_context ==
nullptr) {
236 GrVkImageInfo image_info;
237 image_info.fImage =
image;
238 image_info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
239 image_info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
240 image_info.fFormat = surface_format_.
format;
241 image_info.fImageUsageFlags = usage_flags;
242 image_info.fSampleCount = 1;
243 image_info.fLevelCount = 1;
246 auto backend_render_target =
247 GrBackendRenderTargets::MakeVk(
size.fWidth,
size.fHeight, image_info);
248 SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
250 return SkSurfaces::WrapBackendRenderTarget(
252 backend_render_target,
253 kTopLeft_GrSurfaceOrigin,
255 std::move(color_space),
260bool VulkanSwapchain::CreateSwapchainImages(
261 GrDirectContext* skia_context,
263 const sk_sp<SkColorSpace>& color_space,
264 VkImageUsageFlags usage_flags) {
265 std::vector<VkImage>
images = GetImages();
271 const SkISize surface_size =
GetSize();
275 auto backbuffer = std::make_unique<VulkanBackbuffer>(
276 vk, device_.GetHandle(), device_.GetCommandPool());
278 if (!backbuffer->IsValid()) {
282 backbuffers_.emplace_back(std::move(backbuffer));
285 VulkanHandle<VkImage> image_handle = VulkanHandle<VkImage>{
287 vk.DestroyImage(device_.GetHandle(),
image,
nullptr);
289 auto vulkan_image = std::make_unique<VulkanImage>(std::move(image_handle));
291 if (!vulkan_image->IsValid()) {
295 images_.emplace_back(std::move(vulkan_image));
298 auto surface = CreateSkiaSurface(skia_context,
image, usage_flags,
301 if (surface ==
nullptr) {
305 surfaces_.emplace_back(std::move(surface));
308 FML_DCHECK(backbuffers_.size() == images_.size());
309 FML_DCHECK(images_.size() == surfaces_.size());
314VulkanBackbuffer* VulkanSwapchain::GetNextBackbuffer() {
315 auto available_backbuffers = backbuffers_.size();
317 if (available_backbuffers == 0) {
321 auto next_backbuffer_index =
322 (current_backbuffer_index_ + 1) % backbuffers_.size();
324 auto& backbuffer = backbuffers_[next_backbuffer_index];
326 if (!backbuffer->IsValid()) {
330 current_backbuffer_index_ = next_backbuffer_index;
331 return backbuffer.get();
338 FML_DLOG(INFO) <<
"Swapchain was invalid.";
346 auto backbuffer = GetNextBackbuffer();
348 if (backbuffer ==
nullptr) {
349 FML_DLOG(INFO) <<
"Could not get the next backbuffer.";
357 if (!backbuffer->WaitFences()) {
358 FML_DLOG(INFO) <<
"Failed waiting on fences.";
366 if (!backbuffer->ResetFences()) {
367 FML_DLOG(INFO) <<
"Could not reset fences.";
375 uint32_t next_image_index = 0;
378 vk.AcquireNextImageKHR(device_.GetHandle(),
380 std::numeric_limits<uint64_t>::max(),
381 backbuffer->GetUsageSemaphore(),
385 switch (acquire_result) {
388 case VK_ERROR_OUT_OF_DATE_KHR:
390 case VK_ERROR_SURFACE_LOST_KHR:
393 FML_LOG(INFO) <<
"Unexpected result from AcquireNextImageKHR: "
399 if (next_image_index >= images_.size()) {
400 FML_DLOG(INFO) <<
"Image index returned was out-of-bounds.";
404 auto&
image = images_[next_image_index];
405 if (!
image->IsValid()) {
406 FML_DLOG(INFO) <<
"Image at index was invalid.";
414 if (!backbuffer->GetUsageCommandBuffer().Begin()) {
415 FML_DLOG(INFO) <<
"Could not begin recording to the command buffer.";
423 VkPipelineStageFlagBits destination_pipeline_stage =
424 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
425 VkImageLayout destination_image_layout =
426 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
428 if (!
image->InsertImageMemoryBarrier(
429 backbuffer->GetUsageCommandBuffer(),
430 current_pipeline_stage_,
431 destination_pipeline_stage,
432 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
433 destination_image_layout
435 FML_DLOG(INFO) <<
"Could not insert image memory barrier.";
438 current_pipeline_stage_ = destination_pipeline_stage;
445 if (!backbuffer->GetUsageCommandBuffer().End()) {
446 FML_DLOG(INFO) <<
"Could not end recording to the command buffer.";
454 std::vector<VkSemaphore> wait_semaphores = {backbuffer->GetUsageSemaphore()};
455 std::vector<VkSemaphore> signal_semaphores = {};
456 std::vector<VkCommandBuffer> command_buffers = {
457 backbuffer->GetUsageCommandBuffer().Handle()};
459 if (!device_.QueueSubmit(
460 {destination_pipeline_stage},
464 backbuffer->GetUsageFence()
466 FML_DLOG(INFO) <<
"Could not submit to the device queue.";
474 sk_sp<SkSurface>
surface = surfaces_[next_image_index];
477 FML_DLOG(INFO) <<
"Could not access surface at the image index.";
481 GrBackendRenderTarget backendRT = SkSurfaces::GetBackendRenderTarget(
482 surface.get(), SkSurfaces::BackendHandleAccess::kFlushRead);
483 if (!backendRT.isValid()) {
484 FML_DLOG(INFO) <<
"Could not get backend render target.";
487 GrBackendRenderTargets::SetVkImageLayout(&backendRT,
488 destination_image_layout);
490 current_image_index_ = next_image_index;
497 FML_DLOG(INFO) <<
"Swapchain was invalid.";
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();
509 skgpu::ganesh::FlushAndSubmit(
surface);
515 if (!backbuffer->GetRenderCommandBuffer().Begin()) {
516 FML_DLOG(INFO) <<
"Could not start recording to the command buffer.";
524 VkPipelineStageFlagBits destination_pipeline_stage =
525 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
526 VkImageLayout destination_image_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
528 if (!
image->InsertImageMemoryBarrier(
529 backbuffer->GetRenderCommandBuffer(),
530 current_pipeline_stage_,
531 destination_pipeline_stage,
532 VK_ACCESS_MEMORY_READ_BIT,
533 destination_image_layout
535 FML_DLOG(INFO) <<
"Could not insert memory barrier.";
538 current_pipeline_stage_ = destination_pipeline_stage;
545 if (!backbuffer->GetRenderCommandBuffer().End()) {
546 FML_DLOG(INFO) <<
"Could not end recording to the command buffer.";
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()};
561 if (!device_.QueueSubmit(
564 queue_signal_semaphores,
566 backbuffer->GetRenderFence()
568 FML_DLOG(INFO) <<
"Could not submit to the device queue.";
577 uint32_t present_image_index =
static_cast<uint32_t
>(current_image_index_);
578 const VkPresentInfoKHR present_info = {
579 .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
581 .waitSemaphoreCount =
582 static_cast<uint32_t
>(queue_signal_semaphores.size()),
583 .pWaitSemaphores = queue_signal_semaphores.data(),
586 .pImageIndices = &present_image_index,
591 &present_info)) != VK_SUCCESS) {
592 FML_DLOG(INFO) <<
"Could not submit the present operation.";
AcquireResult AcquireSurface()
std::pair< AcquireStatus, sk_sp< SkSurface > > AcquireResult
@ Success
A valid SkSurface was acquired successfully from the swapchain.
VulkanSwapchain(const VulkanProcTable &vk, const VulkanDevice &device, const VulkanSurface &surface, GrDirectContext *skia_context, std::unique_ptr< VulkanSwapchain > old_swapchain, uint32_t queue_family_index)
FlutterVulkanImage * image
uint32_t queue_family_index
const uint8_t uint32_t uint32_t GError ** error
#define FML_DLOG(severity)
#define FML_LOG(severity)
#define FML_DCHECK(condition)
std::array< MockImage, 3 > images
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
static std::vector< FormatInfo > DesiredFormatInfos()
uint32_t format
The VkFormat of the image (for example: VK_FORMAT_R8G8B8A8_UNORM).
#define VK_CALL_LOG_ERROR(expression)
sk_sp< SkColorSpace > color_space_