167 g_state.resize_pending =
false;
172 VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT);
180 uint32_t format_count;
181 d.vkGetPhysicalDeviceSurfaceFormatsKHR(
182 g_state.physical_device,
g_state.surface, &format_count,
nullptr);
183 std::vector<VkSurfaceFormatKHR> formats(format_count);
184 d.vkGetPhysicalDeviceSurfaceFormatsKHR(
185 g_state.physical_device,
g_state.surface, &format_count, formats.data());
186 assert(!formats.empty());
188 g_state.surface_format = formats[0];
189 for (
const auto&
format : formats) {
190 if (
format.format == VK_FORMAT_B8G8R8A8_UNORM &&
191 format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
203 VkSurfaceCapabilitiesKHR surface_capabilities;
204 d.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
207 if (surface_capabilities.currentExtent.width !=
UINT32_MAX) {
209 extent = surface_capabilities.currentExtent;
217 VkExtent2D actual_extent = {
218 .width =
static_cast<uint32_t
>(
width),
221 actual_extent.width =
222 std::max(surface_capabilities.minImageExtent.width,
223 std::min(surface_capabilities.maxImageExtent.width,
224 actual_extent.width));
225 actual_extent.height =
226 std::max(surface_capabilities.minImageExtent.height,
227 std::min(surface_capabilities.maxImageExtent.height,
228 actual_extent.height));
236 d.vkGetPhysicalDeviceSurfacePresentModesKHR(
238 std::vector<VkPresentModeKHR> modes(mode_count);
239 d.vkGetPhysicalDeviceSurfacePresentModesKHR(
240 g_state.physical_device,
g_state.surface, &mode_count, modes.data());
241 assert(!formats.empty());
244 VkPresentModeKHR present_mode = modes[0];
245 for (
const auto& mode : modes) {
256 VkSwapchainCreateInfoKHR info = {
257 .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
259 .minImageCount = surface_capabilities.minImageCount + 1,
260 .imageFormat =
g_state.surface_format.format,
261 .imageColorSpace =
g_state.surface_format.colorSpace,
262 .imageExtent = extent,
263 .imageArrayLayers = 1,
264 .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
265 .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
266 .queueFamilyIndexCount = 0,
267 .pQueueFamilyIndices =
nullptr,
268 .preTransform = surface_capabilities.currentTransform,
269 .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
270 .presentMode = present_mode,
273 if (
d.vkCreateSwapchainKHR(
g_state.device, &info,
nullptr,
274 &
g_state.swapchain) != VK_SUCCESS) {
282 uint32_t image_count;
283 d.vkGetSwapchainImagesKHR(
g_state.device,
g_state.swapchain, &image_count,
285 g_state.swapchain_images.resize(image_count);
286 d.vkGetSwapchainImagesKHR(
g_state.device,
g_state.swapchain, &image_count,
287 g_state.swapchain_images.data());
294 g_state.present_transition_buffers.resize(
g_state.swapchain_images.size());
296 VkCommandBufferAllocateInfo buffers_info = {
297 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
298 .commandPool =
g_state.swapchain_command_pool,
299 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
300 .commandBufferCount =
301 static_cast<uint32_t
>(
g_state.present_transition_buffers.size()),
303 d.vkAllocateCommandBuffers(
g_state.device, &buffers_info,
304 g_state.present_transition_buffers.data());
306 for (
size_t i = 0;
i <
g_state.swapchain_images.size();
i++) {
308 auto buffer =
g_state.present_transition_buffers[
i];
310 VkCommandBufferBeginInfo begin_info = {
311 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
312 d.vkBeginCommandBuffer(buffer, &begin_info);
315 VkImageMemoryBarrier barrier = {
316 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
318 .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
319 .oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
320 .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
321 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
322 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
324 .subresourceRange = {
325 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
331 d.vkCmdPipelineBarrier(
333 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
334 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
344 d.vkEndCommandBuffer(buffer);
479 std::string project_path =
argv[1];
480 std::string icudtl_path =
argv[2];
488 std::cerr <<
"Failed to initialize GLFW." << std::endl;
492 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
494 "Flutter",
nullptr,
nullptr);
496 std::cerr <<
"Failed to create GLFW window." << std::endl;
500 int framebuffer_width, framebuffer_height;
501 glfwGetFramebufferSize(
g_state.window, &framebuffer_width,
502 &framebuffer_height);
513 if (!glfwVulkanSupported()) {
514 std::cerr <<
"GLFW was unable to resolve either a Vulkan loader or a "
515 "compatible physical device!"
517#if defined(__APPLE__)
519 <<
"NOTE: Apple platforms don't ship with a Vulkan loader or any "
520 "Vulkan drivers. Follow this guide to set up a Vulkan loader on "
521 "macOS and use the MoltenVK ICD: "
522 "https://vulkan.lunarg.com/doc/sdk/latest/mac/getting_started.html"
528 VULKAN_HPP_DEFAULT_DISPATCHER.init(glfwGetInstanceProcAddress);
535 uint32_t extension_count;
536 const char** glfw_extensions =
537 glfwGetRequiredInstanceExtensions(&extension_count);
538 g_state.enabled_instance_extensions.resize(extension_count);
539 memcpy(
g_state.enabled_instance_extensions.data(), glfw_extensions,
540 extension_count *
sizeof(
char*));
542 if (
g_debug.enable_validation_layers) {
543 auto props = vk::enumerateInstanceExtensionProperties();
544 for (
const auto& prop : props.value) {
545 if (strcmp(prop.extensionName,
546 VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME) == 0) {
547 g_state.enabled_instance_extensions.push_back(
548 VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME);
550 if (strcmp(prop.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) ==
552 g_debug.utils_supported =
true;
554 if (strcmp(prop.extensionName, VK_EXT_DEBUG_REPORT_EXTENSION_NAME) ==
556 g_debug.report_supported =
true;
560 g_state.enabled_instance_extensions.push_back(
561 VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
562 g_debug.report_supported =
false;
563 }
else if (
g_debug.report_supported) {
564 g_state.enabled_instance_extensions.push_back(
565 VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
568 auto available_layers = vk::enumerateInstanceLayerProperties();
569 for (
const auto& l : available_layers.value) {
570 if (strcmp(l.layerName,
"VK_LAYER_KHRONOS_validation") == 0) {
571 g_state.enabled_layer_names.push_back(
"VK_LAYER_KHRONOS_validation");
576 std::cout <<
"Enabling " <<
g_state.enabled_instance_extensions.size()
577 <<
" instance extensions:" << std::endl;
578 for (
const auto& extension :
g_state.enabled_instance_extensions) {
579 std::cout <<
" - " << extension << std::endl;
581 std::cout <<
"Enabling " <<
g_state.enabled_layer_names.size()
582 <<
" layers:" << std::endl;
583 for (
const auto& layer :
g_state.enabled_layer_names) {
584 std::cout <<
" - " << layer << std::endl;
587 VkApplicationInfo app_info = {
588 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
590 .pApplicationName =
"Flutter",
591 .applicationVersion = VK_MAKE_VERSION(1, 0, 0),
592 .pEngineName =
"No Engine",
593 .engineVersion = VK_MAKE_VERSION(1, 0, 0),
594 .apiVersion = VK_MAKE_VERSION(1, 1, 0),
596 VkInstanceCreateInfo info = {};
597 info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
599 info.pApplicationInfo = &app_info;
600 info.enabledExtensionCount =
g_state.enabled_instance_extensions.size();
601 info.ppEnabledExtensionNames =
g_state.enabled_instance_extensions.data();
602 info.enabledLayerCount =
g_state.enabled_layer_names.size();
603 info.ppEnabledLayerNames =
g_state.enabled_layer_names.data();
605 if (
d.vkCreateInstance(&info,
nullptr, &
g_state.instance) != VK_SUCCESS) {
606 std::cerr <<
"Failed to create Vulkan instance." << std::endl;
612 VULKAN_HPP_DEFAULT_DISPATCHER.init(vk::Instance(
g_state.instance));
618 if (glfwCreateWindowSurface(
g_state.instance,
g_state.window, NULL,
619 &
g_state.surface) != VK_SUCCESS) {
620 std::cerr <<
"Failed to create window surface." << std::endl;
630 d.vkEnumeratePhysicalDevices(
g_state.instance, &count,
nullptr);
631 std::vector<VkPhysicalDevice> physical_devices(count);
632 d.vkEnumeratePhysicalDevices(
g_state.instance, &count,
633 physical_devices.data());
635 std::cout <<
"Enumerating " << count <<
" physical device(s)." << std::endl;
637 uint32_t selected_score = 0;
638 for (
const auto& pdevice : physical_devices) {
639 VkPhysicalDeviceProperties properties;
640 VkPhysicalDeviceFeatures features;
641 d.vkGetPhysicalDeviceProperties(pdevice, &properties);
642 d.vkGetPhysicalDeviceFeatures(pdevice, &features);
644 std::cout <<
"Checking device: " << properties.deviceName << std::endl;
647 std::vector<const char*> supported_extensions;
650 d.vkGetPhysicalDeviceQueueFamilyProperties(pdevice, &qfp_count,
nullptr);
651 std::vector<VkQueueFamilyProperties> qfp(qfp_count);
652 d.vkGetPhysicalDeviceQueueFamilyProperties(pdevice, &qfp_count,
654 std::optional<uint32_t> graphics_queue_family;
655 for (uint32_t
i = 0;
i < qfp.size();
i++) {
659 VkBool32 surface_present_supported;
660 d.vkGetPhysicalDeviceSurfaceSupportKHR(pdevice,
i,
g_state.surface,
661 &surface_present_supported);
663 if (!graphics_queue_family.has_value() &&
664 qfp[
i].queueFlags & VK_QUEUE_GRAPHICS_BIT &&
665 surface_present_supported) {
666 graphics_queue_family =
i;
671 if (!graphics_queue_family.has_value()) {
672 std::cout <<
" - Skipping due to no suitable graphics queues."
678 if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
682 uint32_t extension_count;
683 d.vkEnumerateDeviceExtensionProperties(pdevice,
nullptr, &extension_count,
685 std::vector<VkExtensionProperties> available_extensions(extension_count);
686 d.vkEnumerateDeviceExtensionProperties(pdevice,
nullptr, &extension_count,
687 available_extensions.data());
689 bool supports_swapchain =
false;
690 for (
const auto& available_extension : available_extensions) {
691 if (strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME,
692 available_extension.extensionName) == 0) {
693 supports_swapchain =
true;
694 supported_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
699 else if (strcmp(
"VK_KHR_portability_subset",
700 available_extension.extensionName) == 0) {
701 supported_extensions.push_back(
"VK_KHR_portability_subset");
705 else if (strcmp(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
706 available_extension.extensionName) == 0) {
708 supported_extensions.push_back(
709 VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
714 if (!supports_swapchain) {
715 std::cout <<
" - Skipping due to lack of swapchain support."
721 score += properties.limits.maxImageDimension2D;
723 if (selected_score < score) {
724 std::cout <<
" - This is the best device so far. Score: 0x" << std::hex
725 << score << std::dec << std::endl;
727 selected_score = score;
728 g_state.physical_device = pdevice;
729 g_state.enabled_device_extensions = supported_extensions;
730 g_state.queue_family_index = graphics_queue_family.value_or(
731 std::numeric_limits<uint32_t>::max());
735 if (
g_state.physical_device ==
nullptr) {
736 std::cerr <<
"Failed to find a compatible Vulkan physical device."
746 std::cout <<
"Enabling " <<
g_state.enabled_device_extensions.size()
747 <<
" device extensions:" << std::endl;
748 for (
const char* extension :
g_state.enabled_device_extensions) {
749 std::cout <<
" - " << extension << std::endl;
753 VkPhysicalDeviceFeatures device_features = {};
755 VkDeviceQueueCreateInfo graphics_queue = {};
756 graphics_queue.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
757 graphics_queue.queueFamilyIndex =
g_state.queue_family_index;
758 graphics_queue.queueCount = 1;
759 float priority = 1.0f;
760 graphics_queue.pQueuePriorities = &priority;
762 VkDeviceCreateInfo device_info = {};
763 device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
764 device_info.enabledExtensionCount =
765 g_state.enabled_device_extensions.size();
766 device_info.ppEnabledExtensionNames =
767 g_state.enabled_device_extensions.data();
768 device_info.pEnabledFeatures = &device_features;
769 device_info.queueCreateInfoCount = 1;
770 device_info.pQueueCreateInfos = &graphics_queue;
772 if (
d.vkCreateDevice(
g_state.physical_device, &device_info,
nullptr,
773 &
g_state.device) != VK_SUCCESS) {
774 std::cerr <<
"Failed to create Vulkan logical device." << std::endl;
788 VkFenceCreateInfo f_info = {.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};
789 d.vkCreateFence(
g_state.device, &f_info,
nullptr,
792 VkSemaphoreCreateInfo s_info = {
793 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
794 d.vkCreateSemaphore(
g_state.device, &s_info,
nullptr,
795 &
g_state.present_transition_semaphore);
797 VkCommandPoolCreateInfo pool_info = {
798 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
799 .queueFamilyIndex =
g_state.queue_family_index,
801 d.vkCreateCommandPool(
g_state.device, &pool_info,
nullptr,
802 &
g_state.swapchain_command_pool);
810 std::cerr <<
"Failed to create swapchain." << std::endl;
829 g_state.enabled_instance_extensions.size();
831 g_state.enabled_instance_extensions.data();
833 g_state.enabled_device_extensions.size();
835 g_state.enabled_device_extensions.data();
842 std::string assets_path = project_path +
"/build/flutter_assets";
845 .assets_path = assets_path.c_str(),
853 std::cerr <<
"Failed to start Flutter Engine." << std::endl;
862 g_state.resize_pending =
false;
873 while (!glfwWindowShouldClose(
g_state.window)) {
882 std::cerr <<
"Flutter Engine shutdown failed." << std::endl;
887 d.vkDestroySemaphore(
g_state.device,
g_state.present_transition_semaphore,
895 d.vkDestroyDevice(
g_state.device,
nullptr);
898 if (
g_debug.enable_validation_layers) {
900 d.vkDestroyDebugReportCallbackEXT(
g_state.instance,
901 g_debug.report_callback,
nullptr);
903 if (
g_debug.utils_messenger_callback) {
904 d.vkDestroyDebugUtilsMessengerEXT(
909 d.vkDestroyInstance(
g_state.instance,
nullptr);
911 glfwDestroyWindow(
g_state.window);
VkBool32 DebugReportCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT, uint64_t, size_t, int32_t, const char *pLayerPrefix, const char *pMessage, void *)