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"
38 "This Flutter Embedder was authored against the stable Flutter "
39 "API at version 1. There has been a serious breakage in the "
40 "API. Please read the ChangeLog and take appropriate action "
41 "before updating this assertion");
74 std::cerr <<
"GLFW Error: (" <<
error <<
") " << description << std::endl;
87 std::chrono::duration_cast<std::chrono::microseconds>(
88 std::chrono::high_resolution_clock::now().time_since_epoch())
104 if (
key == GLFW_MOUSE_BUTTON_1 &&
action == GLFW_PRESS) {
111 if (
key == GLFW_MOUSE_BUTTON_1 &&
action == GLFW_RELEASE) {
115 glfwSetCursorPosCallback(
window,
nullptr);
124 if (
key == GLFW_KEY_ESCAPE &&
action == GLFW_PRESS) {
145 <<
"usage: embedder_example_vulkan <path to project> <path to icudtl.dat>"
151 g_state.resize_pending =
false;
164 uint32_t format_count;
165 d.vkGetPhysicalDeviceSurfaceFormatsKHR(
166 g_state.physical_device,
g_state.surface, &format_count,
nullptr);
167 std::vector<VkSurfaceFormatKHR> formats(format_count);
168 d.vkGetPhysicalDeviceSurfaceFormatsKHR(
169 g_state.physical_device,
g_state.surface, &format_count, formats.data());
170 assert(!formats.empty());
172 g_state.surface_format = formats[0];
173 for (
const auto&
format : formats) {
188 d.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
205 actual_extent.
width =
208 actual_extent.
width));
220 d.vkGetPhysicalDeviceSurfacePresentModesKHR(
222 std::vector<VkPresentModeKHR> modes(mode_count);
223 d.vkGetPhysicalDeviceSurfacePresentModesKHR(
224 g_state.physical_device,
g_state.surface, &mode_count, modes.data());
225 assert(!formats.empty());
229 for (
const auto&
mode : modes) {
244 .imageFormat =
g_state.surface_format.format,
245 .imageColorSpace =
g_state.surface_format.colorSpace,
246 .imageExtent = extent,
247 .imageArrayLayers = 1,
250 .queueFamilyIndexCount = 0,
251 .pQueueFamilyIndices =
nullptr,
254 .presentMode = present_mode,
257 if (
d.vkCreateSwapchainKHR(
g_state.device, &
info,
nullptr,
266 uint32_t image_count;
267 d.vkGetSwapchainImagesKHR(
g_state.device,
g_state.swapchain, &image_count,
269 g_state.swapchain_images.resize(image_count);
270 d.vkGetSwapchainImagesKHR(
g_state.device,
g_state.swapchain, &image_count,
271 g_state.swapchain_images.data());
278 g_state.present_transition_buffers.resize(
g_state.swapchain_images.size());
282 .commandPool =
g_state.swapchain_command_pool,
284 .commandBufferCount =
285 static_cast<uint32_t
>(
g_state.present_transition_buffers.size()),
287 d.vkAllocateCommandBuffers(
g_state.device, &buffers_info,
288 g_state.present_transition_buffers.data());
290 for (
size_t i = 0;
i <
g_state.swapchain_images.size();
i++) {
296 d.vkBeginCommandBuffer(
buffer, &begin_info);
308 .subresourceRange = {
315 d.vkCmdPipelineBarrier(
344 nullptr,
g_state.image_ready_fence,
356 .
image =
reinterpret_cast<uint64_t
>(
358 .format =
g_state.surface_format.format,
367 .waitSemaphoreCount = 0,
368 .pWaitSemaphores =
nullptr,
369 .pWaitDstStageMask = &stage_flags,
370 .commandBufferCount = 1,
373 .signalSemaphoreCount = 1,
374 .pSignalSemaphores = &
g_state.present_transition_semaphore,
376 d.vkQueueSubmit(
g_state.queue, 1, &submit_info,
nullptr);
380 .waitSemaphoreCount = 1,
381 .pWaitSemaphores = &
g_state.present_transition_semaphore,
383 .pSwapchains = &
g_state.swapchain,
384 .pImageIndices = &
g_state.last_image_index,
401 const char* procname) {
402 auto* proc = glfwGetInstanceProcAddress(
403 reinterpret_cast<VkInstance
>(
instance), procname);
404 return reinterpret_cast<void*
>(proc);
413 std::string project_path =
argv[1];
414 std::string icudtl_path =
argv[2];
422 std::cerr <<
"Failed to initialize GLFW." << std::endl;
426 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
428 "Flutter",
nullptr,
nullptr);
430 std::cerr <<
"Failed to create GLFW window." << std::endl;
434 int framebuffer_width, framebuffer_height;
435 glfwGetFramebufferSize(
g_state.window, &framebuffer_width,
436 &framebuffer_height);
447 if (!glfwVulkanSupported()) {
448 std::cerr <<
"GLFW was unable to resolve either a Vulkan loader or a "
449 "compatible physical device!"
451#if defined(__APPLE__)
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"
462 VULKAN_HPP_DEFAULT_DISPATCHER.init(glfwGetInstanceProcAddress);
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*));
477 g_state.enabled_instance_extensions.push_back(
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;
490 .pApplicationName =
"Flutter",
492 .pEngineName =
"No Engine",
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();
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;
516 std::cerr <<
"Failed to create Vulkan instance." << std::endl;
522 VULKAN_HPP_DEFAULT_DISPATCHER.init(vk::Instance(
g_state.instance));
528 if (glfwCreateWindowSurface(
g_state.instance,
g_state.window, NULL,
530 std::cerr <<
"Failed to create window surface." << std::endl;
540 d.vkEnumeratePhysicalDevices(
g_state.instance, &
count,
nullptr);
541 std::vector<VkPhysicalDevice> physical_devices(
count);
543 physical_devices.data());
545 std::cout <<
"Enumerating " <<
count <<
" physical device(s)." << std::endl;
547 uint32_t selected_score = 0;
548 for (
const auto& pdevice : physical_devices) {
551 d.vkGetPhysicalDeviceProperties(pdevice, &properties);
552 d.vkGetPhysicalDeviceFeatures(pdevice, &features);
554 std::cout <<
"Checking device: " << properties.
deviceName << std::endl;
557 std::vector<const char*> supported_extensions;
560 d.vkGetPhysicalDeviceQueueFamilyProperties(pdevice, &qfp_count,
nullptr);
561 std::vector<VkQueueFamilyProperties> qfp(qfp_count);
562 d.vkGetPhysicalDeviceQueueFamilyProperties(pdevice, &qfp_count,
564 std::optional<uint32_t> graphics_queue_family;
565 for (uint32_t
i = 0;
i < qfp.size();
i++) {
570 d.vkGetPhysicalDeviceSurfaceSupportKHR(pdevice,
i,
g_state.surface,
571 &surface_present_supported);
573 if (!graphics_queue_family.has_value() &&
575 surface_present_supported) {
576 graphics_queue_family =
i;
581 if (!graphics_queue_family.has_value()) {
582 std::cout <<
" - Skipping due to no suitable graphics queues."
592 uint32_t extension_count;
593 d.vkEnumerateDeviceExtensionProperties(pdevice,
nullptr, &extension_count,
595 std::vector<VkExtensionProperties> available_extensions(extension_count);
596 d.vkEnumerateDeviceExtensionProperties(pdevice,
nullptr, &extension_count,
597 available_extensions.data());
599 bool supports_swapchain =
false;
600 for (
const auto& available_extension : available_extensions) {
602 available_extension.extensionName) == 0) {
603 supports_swapchain =
true;
609 else if (strcmp(
"VK_KHR_portability_subset",
610 available_extension.extensionName) == 0) {
611 supported_extensions.push_back(
"VK_KHR_portability_subset");
616 available_extension.extensionName) == 0) {
618 supported_extensions.push_back(
624 if (!supports_swapchain) {
625 std::cout <<
" - Skipping due to lack of swapchain support."
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;
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(
645 if (
g_state.physical_device ==
nullptr) {
646 std::cerr <<
"Failed to find a compatible Vulkan physical device."
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;
669 float priority = 1.0f;
675 g_state.enabled_device_extensions.size();
677 g_state.enabled_device_extensions.data();
682 if (
d.vkCreateDevice(
g_state.physical_device, &device_info,
nullptr,
684 std::cerr <<
"Failed to create Vulkan logical device." << std::endl;
699 d.vkCreateFence(
g_state.device, &f_info,
nullptr,
704 d.vkCreateSemaphore(
g_state.device, &s_info,
nullptr,
705 &
g_state.present_transition_semaphore);
709 .queueFamilyIndex =
g_state.queue_family_index,
711 d.vkCreateCommandPool(
g_state.device, &pool_info,
nullptr,
712 &
g_state.swapchain_command_pool);
720 std::cerr <<
"Failed to create swapchain." << std::endl;
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();
752 std::string assets_path = project_path +
"/build/flutter_assets";
755 .assets_path = assets_path.c_str(),
763 std::cerr <<
"Failed to start Flutter Engine." << std::endl;
772 g_state.resize_pending =
false;
783 while (!glfwWindowShouldClose(
g_state.window)) {
792 std::cerr <<
"Flutter Engine shutdown failed." << std::endl;
797 d.vkDestroySemaphore(
g_state.device,
g_state.present_transition_semaphore,
801 d.vkDestroyDevice(
g_state.device,
nullptr);
803 d.vkDestroyInstance(
g_state.instance,
nullptr);
805 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
int main(int argc, char **argv)
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 constexpr FlutterViewId kImplicitViewId
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
const uint8_t uint32_t uint32_t GError ** error
uint32_t uint32_t * format
static float max(float r, float g, float b)
static float min(float r, float g, float b)
sk_sp< const SkImage > image
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
it will be possible to load the file into Perfetto s trace viewer 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 mode
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