13#define VULKAN_HPP_NO_EXCEPTIONS 1
14#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
15#include "vulkan/vulkan.hpp"
16VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
19auto&
d = vk::defaultDispatchLoaderDynamic;
22#include "GLFW/glfw3.h"
37 "This Flutter Embedder was authored against the stable Flutter "
38 "API at version 1. There has been a serious breakage in the "
39 "API. Please read the ChangeLog and take appropriate action "
40 "before updating this assertion");
73 std::cerr <<
"GLFW Error: (" <<
error <<
") " << description << std::endl;
86 std::chrono::duration_cast<std::chrono::microseconds>(
87 std::chrono::high_resolution_clock::now().time_since_epoch())
100 if (
key == GLFW_MOUSE_BUTTON_1 &&
action == GLFW_PRESS) {
107 if (
key == GLFW_MOUSE_BUTTON_1 &&
action == GLFW_RELEASE) {
111 glfwSetCursorPosCallback(
window,
nullptr);
120 if (
key == GLFW_KEY_ESCAPE &&
action == GLFW_PRESS) {
138 <<
"usage: embedder_example_vulkan <path to project> <path to icudtl.dat>"
144 g_state.resize_pending =
false;
157 uint32_t format_count;
158 d.vkGetPhysicalDeviceSurfaceFormatsKHR(
159 g_state.physical_device,
g_state.surface, &format_count,
nullptr);
160 std::vector<VkSurfaceFormatKHR> formats(format_count);
161 d.vkGetPhysicalDeviceSurfaceFormatsKHR(
162 g_state.physical_device,
g_state.surface, &format_count, formats.data());
163 assert(!formats.empty());
165 g_state.surface_format = formats[0];
166 for (
const auto&
format : formats) {
181 d.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
198 actual_extent.
width =
201 actual_extent.
width));
213 d.vkGetPhysicalDeviceSurfacePresentModesKHR(
215 std::vector<VkPresentModeKHR> modes(mode_count);
216 d.vkGetPhysicalDeviceSurfacePresentModesKHR(
217 g_state.physical_device,
g_state.surface, &mode_count, modes.data());
218 assert(!formats.empty());
222 for (
const auto& mode : modes) {
237 .imageFormat =
g_state.surface_format.format,
238 .imageColorSpace =
g_state.surface_format.colorSpace,
239 .imageExtent = extent,
240 .imageArrayLayers = 1,
243 .queueFamilyIndexCount = 0,
244 .pQueueFamilyIndices =
nullptr,
247 .presentMode = present_mode,
250 if (
d.vkCreateSwapchainKHR(
g_state.device, &
info,
nullptr,
259 uint32_t image_count;
260 d.vkGetSwapchainImagesKHR(
g_state.device,
g_state.swapchain, &image_count,
262 g_state.swapchain_images.resize(image_count);
263 d.vkGetSwapchainImagesKHR(
g_state.device,
g_state.swapchain, &image_count,
264 g_state.swapchain_images.data());
271 g_state.present_transition_buffers.resize(
g_state.swapchain_images.size());
275 .commandPool =
g_state.swapchain_command_pool,
277 .commandBufferCount =
278 static_cast<uint32_t
>(
g_state.present_transition_buffers.size()),
280 d.vkAllocateCommandBuffers(
g_state.device, &buffers_info,
281 g_state.present_transition_buffers.data());
283 for (
size_t i = 0; i <
g_state.swapchain_images.size(); i++) {
289 d.vkBeginCommandBuffer(
buffer, &begin_info);
301 .subresourceRange = {
308 d.vkCmdPipelineBarrier(
337 nullptr,
g_state.image_ready_fence,
349 .
image =
reinterpret_cast<uint64_t
>(
351 .format =
g_state.surface_format.format,
360 .waitSemaphoreCount = 0,
361 .pWaitSemaphores =
nullptr,
362 .pWaitDstStageMask = &stage_flags,
363 .commandBufferCount = 1,
366 .signalSemaphoreCount = 1,
367 .pSignalSemaphores = &
g_state.present_transition_semaphore,
369 d.vkQueueSubmit(
g_state.queue, 1, &submit_info,
nullptr);
373 .waitSemaphoreCount = 1,
374 .pWaitSemaphores = &
g_state.present_transition_semaphore,
376 .pSwapchains = &
g_state.swapchain,
377 .pImageIndices = &
g_state.last_image_index,
394 const char* procname) {
395 auto* proc = glfwGetInstanceProcAddress(
396 reinterpret_cast<VkInstance
>(
instance), procname);
397 return reinterpret_cast<void*
>(proc);
400int main(
int argc,
char** argv) {
406 std::string project_path =
argv[1];
407 std::string icudtl_path =
argv[2];
415 std::cerr <<
"Failed to initialize GLFW." << std::endl;
419 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
421 "Flutter",
nullptr,
nullptr);
423 std::cerr <<
"Failed to create GLFW window." << std::endl;
427 int framebuffer_width, framebuffer_height;
428 glfwGetFramebufferSize(
g_state.window, &framebuffer_width,
429 &framebuffer_height);
440 if (!glfwVulkanSupported()) {
441 std::cerr <<
"GLFW was unable to resolve either a Vulkan loader or a "
442 "compatible physical device!"
444#if defined(__APPLE__)
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"
455 VULKAN_HPP_DEFAULT_DISPATCHER.init(glfwGetInstanceProcAddress);
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*));
470 g_state.enabled_instance_extensions.push_back(
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;
483 .pApplicationName =
"Flutter",
485 .pEngineName =
"No Engine",
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();
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;
509 std::cerr <<
"Failed to create Vulkan instance." << std::endl;
515 VULKAN_HPP_DEFAULT_DISPATCHER.init(
g_state.instance);
521 if (glfwCreateWindowSurface(
g_state.instance,
g_state.window, NULL,
523 std::cerr <<
"Failed to create window surface." << std::endl;
533 d.vkEnumeratePhysicalDevices(
g_state.instance, &
count,
nullptr);
534 std::vector<VkPhysicalDevice> physical_devices(
count);
536 physical_devices.data());
538 std::cout <<
"Enumerating " <<
count <<
" physical device(s)." << std::endl;
540 uint32_t selected_score = 0;
541 for (
const auto& pdevice : physical_devices) {
544 d.vkGetPhysicalDeviceProperties(pdevice, &properties);
545 d.vkGetPhysicalDeviceFeatures(pdevice, &features);
547 std::cout <<
"Checking device: " << properties.
deviceName << std::endl;
550 std::vector<const char*> supported_extensions;
553 d.vkGetPhysicalDeviceQueueFamilyProperties(pdevice, &qfp_count,
nullptr);
554 std::vector<VkQueueFamilyProperties> qfp(qfp_count);
555 d.vkGetPhysicalDeviceQueueFamilyProperties(pdevice, &qfp_count,
557 std::optional<uint32_t> graphics_queue_family;
558 for (uint32_t i = 0; i < qfp.size(); i++) {
563 d.vkGetPhysicalDeviceSurfaceSupportKHR(pdevice, i,
g_state.surface,
564 &surface_present_supported);
566 if (!graphics_queue_family.has_value() &&
568 surface_present_supported) {
569 graphics_queue_family = i;
574 if (!graphics_queue_family.has_value()) {
575 std::cout <<
" - Skipping due to no suitable graphics queues."
585 uint32_t extension_count;
586 d.vkEnumerateDeviceExtensionProperties(pdevice,
nullptr, &extension_count,
588 std::vector<VkExtensionProperties> available_extensions(extension_count);
589 d.vkEnumerateDeviceExtensionProperties(pdevice,
nullptr, &extension_count,
590 available_extensions.data());
592 bool supports_swapchain =
false;
593 for (
const auto& available_extension : available_extensions) {
595 available_extension.extensionName) == 0) {
596 supports_swapchain =
true;
602 else if (strcmp(
"VK_KHR_portability_subset",
603 available_extension.extensionName) == 0) {
604 supported_extensions.push_back(
"VK_KHR_portability_subset");
609 available_extension.extensionName) == 0) {
611 supported_extensions.push_back(
617 if (!supports_swapchain) {
618 std::cout <<
" - Skipping due to lack of swapchain support."
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;
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());
638 if (
g_state.physical_device ==
nullptr) {
639 std::cerr <<
"Failed to find a compatible Vulkan physical device."
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;
662 float priority = 1.0f;
668 g_state.enabled_device_extensions.size();
670 g_state.enabled_device_extensions.data();
675 if (
d.vkCreateDevice(
g_state.physical_device, &device_info,
nullptr,
677 std::cerr <<
"Failed to create Vulkan logical device." << std::endl;
692 d.vkCreateFence(
g_state.device, &f_info,
nullptr,
697 d.vkCreateSemaphore(
g_state.device, &s_info,
nullptr,
698 &
g_state.present_transition_semaphore);
702 .queueFamilyIndex =
g_state.queue_family_index,
704 d.vkCreateCommandPool(
g_state.device, &pool_info,
nullptr,
705 &
g_state.swapchain_command_pool);
713 std::cerr <<
"Failed to create swapchain." << std::endl;
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();
745 std::string assets_path = project_path +
"/build/flutter_assets";
748 .assets_path = assets_path.c_str(),
756 std::cerr <<
"Failed to start Flutter Engine." << std::endl;
765 g_state.resize_pending =
false;
776 while (!glfwWindowShouldClose(
g_state.window)) {
785 std::cerr <<
"Flutter Engine shutdown failed." << std::endl;
790 d.vkDestroySemaphore(
g_state.device,
g_state.present_transition_semaphore,
794 d.vkDestroyDevice(
g_state.device,
nullptr);
796 d.vkDestroyInstance(
g_state.instance,
nullptr);
798 glfwDestroyWindow(
g_state.window);
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
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 FlutterEngineSendWindowMetricsEvent(FLUTTER_API_SYMBOL(FlutterEngine) engine, const FlutterWindowMetricsEvent *flutter_metrics)
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...
FlutterEngineResult FlutterEngineSendPointerEvent(FLUTTER_API_SYMBOL(FlutterEngine) engine, const FlutterPointerEvent *pointers, size_t events_count)
FlutterPointerPhase
The phase of the pointer event.
void * FlutterVulkanInstanceHandle
Alias for VkInstance.
#define FLUTTER_ENGINE_VERSION
bool InitializeSwapchain()
std::vector< VkCommandBuffer > present_transition_buffers
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
uint32_t last_image_index
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)
VkPhysicalDevice physical_device
std::vector< const char * > enabled_device_extensions
static const bool g_enable_validation_layers
static double g_pixelRatio
VkCommandPool swapchain_command_pool
static const VkPresentModeKHR kPreferredPresentMode
void GLFWcursorPositionCallbackAtPhase(GLFWwindow *window, FlutterPointerPhase phase, double x, double y)
std::vector< const char * > enabled_instance_extensions
VkSurfaceFormatKHR surface_format
static const size_t kInitialWindowHeight
VkSemaphore present_transition_semaphore
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)
VkFence image_ready_fence
struct @13 g_state
Global struct for holding the Window+Vulkan state.
void GLFWcursorPositionCallback(GLFWwindow *window, double x, double y)
uint32_t queue_family_index
void GLFWmouseButtonCallback(GLFWwindow *window, int key, int action, int mods)
std::vector< VkImage > swapchain_images
void GLFW_ErrorCallback(int error, const char *description)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
static const uint8_t buffer[]
const uint8_t uint32_t uint32_t GError ** error
uint32_t uint32_t * format
size_t struct_size
The size of this struct. Must be sizeof(FlutterPointerEvent).
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.
size_t struct_size
The size of this struct. Must be sizeof(FlutterWindowMetricsEvent).
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
VkSurfaceTransformFlagBitsKHR currentTransform
VkExtent2D maxImageExtent
VkExtent2D minImageExtent
VkFlags VkPipelineStageFlags
@ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
@ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
@ VK_COMMAND_BUFFER_LEVEL_PRIMARY
@ VK_SHARING_MODE_EXCLUSIVE
@ VK_IMAGE_ASPECT_COLOR_BIT
@ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
@ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR
#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME
@ VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT
#define VK_MAKE_VERSION(major, minor, patch)
#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME
@ VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
@ VK_ERROR_OUT_OF_DATE_KHR
@ VK_ACCESS_MEMORY_READ_BIT
@ VK_PRESENT_MODE_FIFO_KHR
@ VK_FORMAT_B8G8R8A8_UNORM
@ VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
#define VK_KHR_SWAPCHAIN_EXTENSION_NAME
@ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
@ VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT
#define VK_QUEUE_FAMILY_IGNORED
@ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO
@ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO
@ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO
@ VK_STRUCTURE_TYPE_APPLICATION_INFO
@ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO
@ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO
@ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR
@ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO
@ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO
@ VK_STRUCTURE_TYPE_SUBMIT_INFO
@ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO
@ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR
@ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER