400 {
401 if (argc != 3) {
403 return 1;
404 }
405
406 std::string project_path =
argv[1];
407 std::string icudtl_path =
argv[2];
408
409
410
411
412
413 {
414 if (!glfwInit()) {
415 std::cerr << "Failed to initialize GLFW." << std::endl;
416 return EXIT_FAILURE;
417 }
418
419 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
421 "Flutter", nullptr, nullptr);
423 std::cerr << "Failed to create GLFW window." << std::endl;
424 return EXIT_FAILURE;
425 }
426
427 int framebuffer_width, framebuffer_height;
428 glfwGetFramebufferSize(
g_state.window, &framebuffer_width,
429 &framebuffer_height);
431
433 }
434
435
436
437
438
439
440 if (!glfwVulkanSupported()) {
441 std::cerr << "GLFW was unable to resolve either a Vulkan loader or a "
442 "compatible physical device!"
443 << std::endl;
444#if defined(__APPLE__)
445 std::cerr
446 << "NOTE: Apple platforms don't ship with a Vulkan loader or any "
447 "Vulkan drivers. Follow this guide to set up a Vulkan loader on "
448 "macOS and use the MoltenVK ICD: "
449 "https://vulkan.lunarg.com/doc/sdk/latest/mac/getting_started.html"
450 << std::endl;
451#endif
452 return EXIT_FAILURE;
453 }
454
455 VULKAN_HPP_DEFAULT_DISPATCHER.init(glfwGetInstanceProcAddress);
456
457
458
459
460
461 {
462 uint32_t extension_count;
463 const char** glfw_extensions =
464 glfwGetRequiredInstanceExtensions(&extension_count);
465 g_state.enabled_instance_extensions.resize(extension_count);
466 memcpy(
g_state.enabled_instance_extensions.data(), glfw_extensions,
467 extension_count * sizeof(char*));
468
470 g_state.enabled_instance_extensions.push_back(
472 }
473
474 std::cout <<
"Enabling " <<
g_state.enabled_instance_extensions.size()
475 << " instance extensions:" << std::endl;
476 for (
const auto& extension :
g_state.enabled_instance_extensions) {
477 std::cout << " - " << extension << std::endl;
478 }
479
482 .pNext = nullptr,
483 .pApplicationName = "Flutter",
485 .pEngineName = "No Engine",
488 };
492 info.pApplicationInfo = &app_info;
493 info.enabledExtensionCount =
g_state.enabled_instance_extensions.size();
494 info.ppEnabledExtensionNames =
g_state.enabled_instance_extensions.data();
496 auto available_layers = vk::enumerateInstanceLayerProperties();
497
498 const char* layer = "VK_LAYER_KHRONOS_validation";
499 for (const auto& l : available_layers.value) {
500 if (strcmp(l.layerName, layer) == 0) {
501 info.enabledLayerCount = 1;
502 info.ppEnabledLayerNames = &layer;
503 break;
504 }
505 }
506 }
507
509 std::cerr << "Failed to create Vulkan instance." << std::endl;
510 return EXIT_FAILURE;
511 }
512 }
513
514
515 VULKAN_HPP_DEFAULT_DISPATCHER.init(
g_state.instance);
516
517
518
519
520
521 if (glfwCreateWindowSurface(
g_state.instance,
g_state.window, NULL,
523 std::cerr << "Failed to create window surface." << std::endl;
524 return EXIT_FAILURE;
525 }
526
527
528
529
530
531 {
533 d.vkEnumeratePhysicalDevices(
g_state.instance, &
count,
nullptr);
534 std::vector<VkPhysicalDevice> physical_devices(
count);
536 physical_devices.data());
537
538 std::cout <<
"Enumerating " <<
count <<
" physical device(s)." << std::endl;
539
540 uint32_t selected_score = 0;
541 for (const auto& pdevice : physical_devices) {
544 d.vkGetPhysicalDeviceProperties(pdevice, &properties);
545 d.vkGetPhysicalDeviceFeatures(pdevice, &features);
546
547 std::cout <<
"Checking device: " << properties.
deviceName << std::endl;
548
549 uint32_t score = 0;
550 std::vector<const char*> supported_extensions;
551
552 uint32_t qfp_count;
553 d.vkGetPhysicalDeviceQueueFamilyProperties(pdevice, &qfp_count,
nullptr);
554 std::vector<VkQueueFamilyProperties> qfp(qfp_count);
555 d.vkGetPhysicalDeviceQueueFamilyProperties(pdevice, &qfp_count,
556 qfp.data());
557 std::optional<uint32_t> graphics_queue_family;
558 for (uint32_t i = 0; i < qfp.size(); i++) {
559
560
561
563 d.vkGetPhysicalDeviceSurfaceSupportKHR(pdevice, i,
g_state.surface,
564 &surface_present_supported);
565
566 if (!graphics_queue_family.has_value() &&
568 surface_present_supported) {
569 graphics_queue_family = i;
570 }
571 }
572
573
574 if (!graphics_queue_family.has_value()) {
575 std::cout << " - Skipping due to no suitable graphics queues."
576 << std::endl;
577 continue;
578 }
579
580
582 score += 1 << 30;
583 }
584
585 uint32_t extension_count;
586 d.vkEnumerateDeviceExtensionProperties(pdevice,
nullptr, &extension_count,
587 nullptr);
588 std::vector<VkExtensionProperties> available_extensions(extension_count);
589 d.vkEnumerateDeviceExtensionProperties(pdevice,
nullptr, &extension_count,
590 available_extensions.data());
591
592 bool supports_swapchain = false;
593 for (const auto& available_extension : available_extensions) {
595 available_extension.extensionName) == 0) {
596 supports_swapchain = true;
598 }
599
600
601
602 else if (strcmp("VK_KHR_portability_subset",
603 available_extension.extensionName) == 0) {
604 supported_extensions.push_back("VK_KHR_portability_subset");
605 }
606
607
609 available_extension.extensionName) == 0) {
610 score += 1 << 29;
611 supported_extensions.push_back(
613 }
614 }
615
616
617 if (!supports_swapchain) {
618 std::cout << " - Skipping due to lack of swapchain support."
619 << std::endl;
620 continue;
621 }
622
623
625
626 if (selected_score < score) {
627 std::cout << " - This is the best device so far. Score: 0x" << std::hex
628 << score << std::dec << std::endl;
629
630 selected_score = score;
631 g_state.physical_device = pdevice;
632 g_state.enabled_device_extensions = supported_extensions;
633 g_state.queue_family_index = graphics_queue_family.value_or(
634 std::numeric_limits<uint32_t>::max());
635 }
636 }
637
638 if (
g_state.physical_device ==
nullptr) {
639 std::cerr << "Failed to find a compatible Vulkan physical device."
640 << std::endl;
641 return EXIT_FAILURE;
642 }
643 }
644
645
646
647
648
649 std::cout <<
"Enabling " <<
g_state.enabled_device_extensions.size()
650 << " device extensions:" << std::endl;
651 for (
const char* extension :
g_state.enabled_device_extensions) {
652 std::cout << " - " << extension << std::endl;
653 }
654
655 {
657
662 float priority = 1.0f;
664
668 g_state.enabled_device_extensions.size();
670 g_state.enabled_device_extensions.data();
674
675 if (
d.vkCreateDevice(
g_state.physical_device, &device_info,
nullptr,
677 std::cerr << "Failed to create Vulkan logical device." << std::endl;
678 return EXIT_FAILURE;
679 }
680 }
681
684
685
686
687
688
689
690 {
692 d.vkCreateFence(
g_state.device, &f_info,
nullptr,
694
697 d.vkCreateSemaphore(
g_state.device, &s_info,
nullptr,
698 &
g_state.present_transition_semaphore);
699
702 .queueFamilyIndex =
g_state.queue_family_index,
703 };
704 d.vkCreateCommandPool(
g_state.device, &pool_info,
nullptr,
705 &
g_state.swapchain_command_pool);
706 }
707
708
709
710
711
713 std::cerr << "Failed to create swapchain." << std::endl;
714 return EXIT_FAILURE;
715 }
716
717
718
719
720
721 {
732 g_state.enabled_instance_extensions.size();
734 g_state.enabled_instance_extensions.data();
736 g_state.enabled_device_extensions.size();
738 g_state.enabled_device_extensions.data();
743
744
745 std::string assets_path = project_path + "/build/flutter_assets";
748 .assets_path = assets_path.c_str(),
749 .icu_data_path =
750 icudtl_path.c_str(),
751 };
756 std::cerr << "Failed to start Flutter Engine." << std::endl;
757 return EXIT_FAILURE;
758 }
759
760
761
765 g_state.resize_pending =
false;
766 }
767
768
769
770
771
775
776 while (!glfwWindowShouldClose(
g_state.window)) {
777 glfwWaitEvents();
778 }
779
780
781
782
783
785 std::cerr << "Flutter Engine shutdown failed." << std::endl;
786 }
787
789 nullptr);
790 d.vkDestroySemaphore(
g_state.device,
g_state.present_transition_semaphore,
791 nullptr);
793
794 d.vkDestroyDevice(
g_state.device,
nullptr);
796 d.vkDestroyInstance(
g_state.instance,
nullptr);
797
798 glfwDestroyWindow(
g_state.window);
799 glfwTerminate();
800
801 return 0;
802}
FlutterEngineResult FlutterEngineRun(size_t version, const FlutterRendererConfig *config, const FlutterProjectArgs *args, void *user_data, FLUTTER_API_SYMBOL(FlutterEngine) *engine_out)
Initialize and run a Flutter engine instance and return a handle to it. This is a convenience method ...
FlutterEngineResult FlutterEngineShutdown(FLUTTER_API_SYMBOL(FlutterEngine) engine)
Shuts down a Flutter engine instance. The engine handle is no longer valid for any calls in the embed...
#define FLUTTER_ENGINE_VERSION
FlutterVulkanImage FlutterGetNextImageCallback(void *user_data, const FlutterFrameInfo *frame_info)
bool FlutterPresentCallback(void *user_data, const FlutterVulkanImage *image)
void GLFWframebufferSizeCallback(GLFWwindow *window, int width, int height)
static const bool g_enable_validation_layers
static const size_t kInitialWindowHeight
void * FlutterGetInstanceProcAddressCallback(void *user_data, FlutterVulkanInstanceHandle instance, const char *procname)
static const size_t kInitialWindowWidth
void GLFWKeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
void GLFWmouseButtonCallback(GLFWwindow *window, int key, int action, int mods)
void GLFW_ErrorCallback(int error, const char *description)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlutterVulkanRendererConfig vulkan
FlutterVulkanQueueHandle queue
FlutterVulkanDeviceHandle device
FlutterVulkanInstanceProcAddressCallback get_instance_proc_address_callback
size_t struct_size
The size of this struct. Must be sizeof(FlutterVulkanRendererConfig).
size_t enabled_instance_extension_count
uint32_t queue_family_index
The queue family index of the VkQueue supplied in the next field.
FlutterVulkanImageCallback get_next_image_callback
const char ** enabled_instance_extensions
const char ** enabled_device_extensions
size_t enabled_device_extension_count
FlutterVulkanInstanceHandle instance
FlutterVulkanPresentCallback present_image_callback
FlutterVulkanPhysicalDeviceHandle physical_device
VkPhysicalDevice handle.
uint32_t enabledExtensionCount
const VkDeviceQueueCreateInfo * pQueueCreateInfos
const VkPhysicalDeviceFeatures * pEnabledFeatures
const char *const * ppEnabledExtensionNames
uint32_t queueCreateInfoCount
uint32_t queueFamilyIndex
const float * pQueuePriorities
uint32_t maxImageDimension2D
VkPhysicalDeviceType deviceType
char deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE]
VkPhysicalDeviceLimits limits
#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME
#define VK_MAKE_VERSION(major, minor, patch)
#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME
@ VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
#define VK_KHR_SWAPCHAIN_EXTENSION_NAME
@ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO
@ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO
@ VK_STRUCTURE_TYPE_APPLICATION_INFO
@ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO
@ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO
@ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO
@ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO