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);
407int main(
int argc,
char** argv) {
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(
641 std::numeric_limits<uint32_t>::max());
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
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
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).
size_t struct_size
The size of this struct. Must be sizeof(FlutterProjectArgs).
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