407 {
408 if (argc != 3) {
410 return 1;
411 }
412
413 std::string project_path =
argv[1];
414 std::string icudtl_path =
argv[2];
415
416
417
418
419
420 {
421 if (!glfwInit()) {
422 std::cerr << "Failed to initialize GLFW." << std::endl;
423 return EXIT_FAILURE;
424 }
425
426 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
428 "Flutter", nullptr, nullptr);
430 std::cerr << "Failed to create GLFW window." << std::endl;
431 return EXIT_FAILURE;
432 }
433
434 int framebuffer_width, framebuffer_height;
435 glfwGetFramebufferSize(
g_state.window, &framebuffer_width,
436 &framebuffer_height);
438
440 }
441
442
443
444
445
446
447 if (!glfwVulkanSupported()) {
448 std::cerr << "GLFW was unable to resolve either a Vulkan loader or a "
449 "compatible physical device!"
450 << std::endl;
451#if defined(__APPLE__)
452 std::cerr
453 << "NOTE: Apple platforms don't ship with a Vulkan loader or any "
454 "Vulkan drivers. Follow this guide to set up a Vulkan loader on "
455 "macOS and use the MoltenVK ICD: "
456 "https://vulkan.lunarg.com/doc/sdk/latest/mac/getting_started.html"
457 << std::endl;
458#endif
459 return EXIT_FAILURE;
460 }
461
462 VULKAN_HPP_DEFAULT_DISPATCHER.init(glfwGetInstanceProcAddress);
463
464
465
466
467
468 {
469 uint32_t extension_count;
470 const char** glfw_extensions =
471 glfwGetRequiredInstanceExtensions(&extension_count);
472 g_state.enabled_instance_extensions.resize(extension_count);
473 memcpy(
g_state.enabled_instance_extensions.data(), glfw_extensions,
474 extension_count * sizeof(char*));
475
477 g_state.enabled_instance_extensions.push_back(
479 }
480
481 std::cout <<
"Enabling " <<
g_state.enabled_instance_extensions.size()
482 << " instance extensions:" << std::endl;
483 for (
const auto& extension :
g_state.enabled_instance_extensions) {
484 std::cout << " - " << extension << std::endl;
485 }
486
489 .pNext = nullptr,
490 .pApplicationName = "Flutter",
492 .pEngineName = "No Engine",
495 };
499 info.pApplicationInfo = &app_info;
500 info.enabledExtensionCount =
g_state.enabled_instance_extensions.size();
501 info.ppEnabledExtensionNames =
g_state.enabled_instance_extensions.data();
503 auto available_layers = vk::enumerateInstanceLayerProperties();
504
505 const char* layer = "VK_LAYER_KHRONOS_validation";
506 for (const auto& l : available_layers.value) {
507 if (strcmp(l.layerName, layer) == 0) {
508 info.enabledLayerCount = 1;
509 info.ppEnabledLayerNames = &layer;
510 break;
511 }
512 }
513 }
514
516 std::cerr << "Failed to create Vulkan instance." << std::endl;
517 return EXIT_FAILURE;
518 }
519 }
520
521
522 VULKAN_HPP_DEFAULT_DISPATCHER.init(vk::Instance(
g_state.instance));
523
524
525
526
527
528 if (glfwCreateWindowSurface(
g_state.instance,
g_state.window, NULL,
530 std::cerr << "Failed to create window surface." << std::endl;
531 return EXIT_FAILURE;
532 }
533
534
535
536
537
538 {
540 d.vkEnumeratePhysicalDevices(
g_state.instance, &
count,
nullptr);
541 std::vector<VkPhysicalDevice> physical_devices(
count);
543 physical_devices.data());
544
545 std::cout <<
"Enumerating " <<
count <<
" physical device(s)." << std::endl;
546
547 uint32_t selected_score = 0;
548 for (const auto& pdevice : physical_devices) {
551 d.vkGetPhysicalDeviceProperties(pdevice, &properties);
552 d.vkGetPhysicalDeviceFeatures(pdevice, &features);
553
554 std::cout <<
"Checking device: " << properties.
deviceName << std::endl;
555
556 uint32_t score = 0;
557 std::vector<const char*> supported_extensions;
558
559 uint32_t qfp_count;
560 d.vkGetPhysicalDeviceQueueFamilyProperties(pdevice, &qfp_count,
nullptr);
561 std::vector<VkQueueFamilyProperties> qfp(qfp_count);
562 d.vkGetPhysicalDeviceQueueFamilyProperties(pdevice, &qfp_count,
563 qfp.data());
564 std::optional<uint32_t> graphics_queue_family;
565 for (uint32_t
i = 0;
i < qfp.size();
i++) {
566
567
568
570 d.vkGetPhysicalDeviceSurfaceSupportKHR(pdevice,
i,
g_state.surface,
571 &surface_present_supported);
572
573 if (!graphics_queue_family.has_value() &&
575 surface_present_supported) {
576 graphics_queue_family =
i;
577 }
578 }
579
580
581 if (!graphics_queue_family.has_value()) {
582 std::cout << " - Skipping due to no suitable graphics queues."
583 << std::endl;
584 continue;
585 }
586
587
589 score += 1 << 30;
590 }
591
592 uint32_t extension_count;
593 d.vkEnumerateDeviceExtensionProperties(pdevice,
nullptr, &extension_count,
594 nullptr);
595 std::vector<VkExtensionProperties> available_extensions(extension_count);
596 d.vkEnumerateDeviceExtensionProperties(pdevice,
nullptr, &extension_count,
597 available_extensions.data());
598
599 bool supports_swapchain = false;
600 for (const auto& available_extension : available_extensions) {
602 available_extension.extensionName) == 0) {
603 supports_swapchain = true;
605 }
606
607
608
609 else if (strcmp("VK_KHR_portability_subset",
610 available_extension.extensionName) == 0) {
611 supported_extensions.push_back("VK_KHR_portability_subset");
612 }
613
614
616 available_extension.extensionName) == 0) {
617 score += 1 << 29;
618 supported_extensions.push_back(
620 }
621 }
622
623
624 if (!supports_swapchain) {
625 std::cout << " - Skipping due to lack of swapchain support."
626 << std::endl;
627 continue;
628 }
629
630
632
633 if (selected_score < score) {
634 std::cout << " - This is the best device so far. Score: 0x" << std::hex
635 << score << std::dec << std::endl;
636
637 selected_score = score;
638 g_state.physical_device = pdevice;
639 g_state.enabled_device_extensions = supported_extensions;
640 g_state.queue_family_index = graphics_queue_family.value_or(
642 }
643 }
644
645 if (
g_state.physical_device ==
nullptr) {
646 std::cerr << "Failed to find a compatible Vulkan physical device."
647 << std::endl;
648 return EXIT_FAILURE;
649 }
650 }
651
652
653
654
655
656 std::cout <<
"Enabling " <<
g_state.enabled_device_extensions.size()
657 << " device extensions:" << std::endl;
658 for (
const char* extension :
g_state.enabled_device_extensions) {
659 std::cout << " - " << extension << std::endl;
660 }
661
662 {
664
669 float priority = 1.0f;
671
675 g_state.enabled_device_extensions.size();
677 g_state.enabled_device_extensions.data();
681
682 if (
d.vkCreateDevice(
g_state.physical_device, &device_info,
nullptr,
684 std::cerr << "Failed to create Vulkan logical device." << std::endl;
685 return EXIT_FAILURE;
686 }
687 }
688
691
692
693
694
695
696
697 {
699 d.vkCreateFence(
g_state.device, &f_info,
nullptr,
701
704 d.vkCreateSemaphore(
g_state.device, &s_info,
nullptr,
705 &
g_state.present_transition_semaphore);
706
709 .queueFamilyIndex =
g_state.queue_family_index,
710 };
711 d.vkCreateCommandPool(
g_state.device, &pool_info,
nullptr,
712 &
g_state.swapchain_command_pool);
713 }
714
715
716
717
718
720 std::cerr << "Failed to create swapchain." << std::endl;
721 return EXIT_FAILURE;
722 }
723
724
725
726
727
728 {
739 g_state.enabled_instance_extensions.size();
741 g_state.enabled_instance_extensions.data();
743 g_state.enabled_device_extensions.size();
745 g_state.enabled_device_extensions.data();
750
751
752 std::string assets_path = project_path + "/build/flutter_assets";
755 .assets_path = assets_path.c_str(),
756 .icu_data_path =
757 icudtl_path.c_str(),
758 };
763 std::cerr << "Failed to start Flutter Engine." << std::endl;
764 return EXIT_FAILURE;
765 }
766
767
768
772 g_state.resize_pending =
false;
773 }
774
775
776
777
778
782
783 while (!glfwWindowShouldClose(
g_state.window)) {
784 glfwWaitEvents();
785 }
786
787
788
789
790
792 std::cerr << "Flutter Engine shutdown failed." << std::endl;
793 }
794
796 nullptr);
797 d.vkDestroySemaphore(
g_state.device,
g_state.present_transition_semaphore,
798 nullptr);
800
801 d.vkDestroyDevice(
g_state.device,
nullptr);
803 d.vkDestroyInstance(
g_state.instance,
nullptr);
804
805 glfwDestroyWindow(
g_state.window);
806 glfwTerminate();
807
808 return 0;
809}
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