2026-07-29 10:58:34 -04:00

746 lines
25 KiB
C++

// Dear ImGui: standalone example application for QNX Screen + Vulkan
// Important note to the reader who wishes to integrate imgui_impl_vulkan.cpp/.h in their own engine/app.
// - Common ImGui_ImplVulkan_XXX functions and structures interface with the renderer backend.
// - ImGui_ImplVulkanH_XXX helpers are used by examples and are not intended as an engine abstraction.
#include "imgui.h"
#include "imgui_impl_screen.h"
#include "imgui_impl_vulkan.h"
#include <errno.h>
#include <screen/screen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/keycodes.h>
#include <time.h>
#include <vulkan/vulkan.h>
struct ScreenApp
{
screen_context_t Context;
screen_window_t Window;
screen_event_t Event;
int WindowSize[2];
ScreenApp()
{
memset(this, 0, sizeof(*this));
}
};
static VkAllocationCallbacks* g_Allocator = nullptr;
static VkInstance g_Instance = VK_NULL_HANDLE;
static VkPhysicalDevice g_PhysicalDevice = VK_NULL_HANDLE;
static VkDevice g_Device = VK_NULL_HANDLE;
static uint32_t g_QueueFamily = UINT32_MAX;
static VkQueue g_Queue = VK_NULL_HANDLE;
static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE;
static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
static ImGui_ImplVulkanH_Window g_MainWindowData;
static uint32_t g_MinImageCount = 2;
static bool g_SwapChainRebuild = false;
static void CheckVkResult(VkResult result)
{
if (result == VK_SUCCESS)
{
return;
}
fprintf(stderr, "[vulkan] VkResult = %d\n", result);
if (result < 0)
{
abort();
}
}
static bool IsExtensionAvailable(const ImVector<VkExtensionProperties>& properties, const char* name)
{
for (const VkExtensionProperties& property : properties)
{
if (strcmp(property.extensionName, name) == 0)
{
return true;
}
}
return false;
}
static bool CreateScreenWindow(ScreenApp* app)
{
if (screen_create_context(&app->Context, 0) != 0)
{
fprintf(stderr, "screen_create_context() failed: %s\n", strerror(errno));
return false;
}
if (screen_create_window(&app->Window, app->Context) != 0)
{
fprintf(stderr, "screen_create_window() failed: %s\n", strerror(errno));
return false;
}
if (screen_create_event(&app->Event) != 0)
{
fprintf(stderr, "screen_create_event() failed: %s\n", strerror(errno));
return false;
}
if (screen_get_window_property_iv(app->Window, SCREEN_PROPERTY_SIZE, app->WindowSize) != 0)
{
fprintf(stderr, "screen_get_window_property_iv(SCREEN_PROPERTY_SIZE) failed: %s\n", strerror(errno));
return false;
}
if (app->WindowSize[0] <= 0 || app->WindowSize[1] <= 0)
{
fprintf(stderr, "screen_get_window_property_iv(SCREEN_PROPERTY_SIZE) returned invalid size %dx%d\n",
app->WindowSize[0], app->WindowSize[1]);
return false;
}
const int usage = SCREEN_USAGE_VULKAN | SCREEN_USAGE_NATIVE;
const int transparency = SCREEN_TRANSPARENCY_NONE;
const char* id = "dear-imgui-screen-vulkan";
(void)screen_set_window_property_cv(app->Window, SCREEN_PROPERTY_ID_STRING, (int)strlen(id) + 1, id);
if (screen_set_window_property_iv(app->Window, SCREEN_PROPERTY_USAGE, &usage) != 0 ||
screen_set_window_property_iv(app->Window, SCREEN_PROPERTY_SIZE, app->WindowSize) != 0 ||
screen_set_window_property_iv(app->Window, SCREEN_PROPERTY_TRANSPARENCY, &transparency) != 0)
{
fprintf(stderr, "Failed to configure QNX Screen window: %s\n", strerror(errno));
return false;
}
return true;
}
static bool CreateVulkanInstance()
{
uint32_t extension_count = 0;
VkResult result = vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr);
if (result != VK_SUCCESS)
{
CheckVkResult(result);
return false;
}
ImVector<VkExtensionProperties> available_extensions;
available_extensions.resize(extension_count);
result = vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, available_extensions.Data);
if (result != VK_SUCCESS)
{
CheckVkResult(result);
return false;
}
const char* required_extensions[] =
{
VK_KHR_SURFACE_EXTENSION_NAME,
VK_QNX_SCREEN_SURFACE_EXTENSION_NAME
};
for (const char* extension : required_extensions)
{
if (!IsExtensionAvailable(available_extensions, extension))
{
fprintf(stderr, "Required Vulkan instance extension is unavailable: %s\n", extension);
return false;
}
}
VkApplicationInfo application_info = {};
application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
application_info.pApplicationName = "Dear ImGui QNX Screen Vulkan example";
application_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
application_info.pEngineName = "None";
application_info.engineVersion = VK_MAKE_VERSION(1, 0, 0);
application_info.apiVersion = VK_API_VERSION_1_0;
VkInstanceCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
create_info.pApplicationInfo = &application_info;
create_info.enabledExtensionCount = IM_COUNTOF(required_extensions);
create_info.ppEnabledExtensionNames = required_extensions;
result = vkCreateInstance(&create_info, g_Allocator, &g_Instance);
if (result != VK_SUCCESS)
{
CheckVkResult(result);
return false;
}
return true;
}
static bool CreateVulkanSurface(const ScreenApp* app, VkSurfaceKHR* surface)
{
VkScreenSurfaceCreateInfoQNX create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_SCREEN_SURFACE_CREATE_INFO_QNX;
create_info.context = app->Context;
create_info.window = app->Window;
const VkResult result = vkCreateScreenSurfaceQNX(g_Instance, &create_info, g_Allocator, surface);
if (result != VK_SUCCESS)
{
CheckVkResult(result);
return false;
}
return true;
}
static int PhysicalDeviceScore(VkPhysicalDevice device)
{
VkPhysicalDeviceProperties properties = {};
vkGetPhysicalDeviceProperties(device, &properties);
switch (properties.deviceType)
{
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: return 500;
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: return 400;
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: return 300;
case VK_PHYSICAL_DEVICE_TYPE_CPU: return 100;
default: return 200;
}
}
static bool SelectPhysicalDeviceAndQueue(VkSurfaceKHR surface)
{
uint32_t device_count = 0;
VkResult result = vkEnumeratePhysicalDevices(g_Instance, &device_count, nullptr);
if (result != VK_SUCCESS || device_count == 0)
{
CheckVkResult(result);
fprintf(stderr, "No Vulkan physical device is available.\n");
return false;
}
ImVector<VkPhysicalDevice> devices;
devices.resize(device_count);
result = vkEnumeratePhysicalDevices(g_Instance, &device_count, devices.Data);
if (result != VK_SUCCESS)
{
CheckVkResult(result);
return false;
}
int best_score = -1;
for (VkPhysicalDevice device : devices)
{
uint32_t queue_count = 0;
vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_count, nullptr);
ImVector<VkQueueFamilyProperties> queues;
queues.resize(queue_count);
vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_count, queues.Data);
for (uint32_t queue_index = 0; queue_index < queue_count; queue_index++)
{
VkBool32 present_supported = VK_FALSE;
result = vkGetPhysicalDeviceSurfaceSupportKHR(device, queue_index, surface, &present_supported);
if (result != VK_SUCCESS)
{
continue;
}
if ((queues[queue_index].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0 || present_supported != VK_TRUE)
{
continue;
}
const int score = PhysicalDeviceScore(device);
if (score > best_score)
{
best_score = score;
g_PhysicalDevice = device;
g_QueueFamily = queue_index;
}
}
}
if (g_PhysicalDevice == VK_NULL_HANDLE || g_QueueFamily == UINT32_MAX)
{
fprintf(stderr, "No Vulkan queue family supports both graphics and QNX Screen presentation.\n");
return false;
}
return true;
}
static bool CreateVulkanDevice()
{
uint32_t extension_count = 0;
VkResult result = vkEnumerateDeviceExtensionProperties(g_PhysicalDevice, nullptr, &extension_count, nullptr);
if (result != VK_SUCCESS)
{
CheckVkResult(result);
return false;
}
ImVector<VkExtensionProperties> available_extensions;
available_extensions.resize(extension_count);
result = vkEnumerateDeviceExtensionProperties(g_PhysicalDevice, nullptr, &extension_count, available_extensions.Data);
if (result != VK_SUCCESS)
{
CheckVkResult(result);
return false;
}
if (!IsExtensionAvailable(available_extensions, VK_KHR_SWAPCHAIN_EXTENSION_NAME))
{
fprintf(stderr, "Required Vulkan device extension is unavailable: %s\n", VK_KHR_SWAPCHAIN_EXTENSION_NAME);
return false;
}
const float priority = 1.0f;
VkDeviceQueueCreateInfo queue_info = {};
queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_info.queueFamilyIndex = g_QueueFamily;
queue_info.queueCount = 1;
queue_info.pQueuePriorities = &priority;
const char* device_extensions[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };
VkDeviceCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
create_info.queueCreateInfoCount = 1;
create_info.pQueueCreateInfos = &queue_info;
create_info.enabledExtensionCount = IM_COUNTOF(device_extensions);
create_info.ppEnabledExtensionNames = device_extensions;
result = vkCreateDevice(g_PhysicalDevice, &create_info, g_Allocator, &g_Device);
if (result != VK_SUCCESS)
{
CheckVkResult(result);
return false;
}
vkGetDeviceQueue(g_Device, g_QueueFamily, 0, &g_Queue);
return true;
}
static bool CreateDescriptorPool()
{
VkDescriptorPoolSize pool_sizes[] =
{
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE },
{ VK_DESCRIPTOR_TYPE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE }
};
VkDescriptorPoolCreateInfo pool_info = {};
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
pool_info.poolSizeCount = IM_COUNTOF(pool_sizes);
pool_info.pPoolSizes = pool_sizes;
for (const VkDescriptorPoolSize& pool_size : pool_sizes)
{
pool_info.maxSets += pool_size.descriptorCount;
}
const VkResult result = vkCreateDescriptorPool(g_Device, &pool_info, g_Allocator, &g_DescriptorPool);
if (result != VK_SUCCESS)
{
CheckVkResult(result);
return false;
}
return true;
}
static bool SetupVulkanWindow(ImGui_ImplVulkanH_Window* window_data, VkSurfaceKHR surface, int width, int height)
{
const VkFormat requested_formats[] =
{
VK_FORMAT_B8G8R8A8_UNORM,
VK_FORMAT_R8G8B8A8_UNORM,
};
window_data->Surface = surface;
window_data->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(
g_PhysicalDevice,
surface,
requested_formats,
IM_COUNTOF(requested_formats),
VK_COLORSPACE_SRGB_NONLINEAR_KHR);
if (window_data->SurfaceFormat.format == VK_FORMAT_UNDEFINED)
{
fprintf(stderr, "No suitable Vulkan surface format is available.\n");
return false;
}
const VkPresentModeKHR requested_present_modes[] = { VK_PRESENT_MODE_FIFO_KHR };
window_data->PresentMode = ImGui_ImplVulkanH_SelectPresentMode(
g_PhysicalDevice,
surface,
requested_present_modes,
IM_COUNTOF(requested_present_modes));
ImGui_ImplVulkanH_CreateOrResizeWindow(
g_Instance,
g_PhysicalDevice,
g_Device,
window_data,
g_QueueFamily,
g_Allocator,
width,
height,
g_MinImageCount,
0);
return true;
}
static void FrameRender(ImGui_ImplVulkanH_Window* window_data, ImDrawData* draw_data)
{
VkSemaphore image_acquired = window_data->FrameSemaphores[window_data->SemaphoreIndex].ImageAcquiredSemaphore;
VkSemaphore render_complete = window_data->FrameSemaphores[window_data->SemaphoreIndex].RenderCompleteSemaphore;
VkResult result = vkAcquireNextImageKHR(g_Device, window_data->Swapchain, UINT64_MAX, image_acquired, VK_NULL_HANDLE, &window_data->FrameIndex);
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
{
g_SwapChainRebuild = true;
}
if (result == VK_ERROR_OUT_OF_DATE_KHR)
{
return;
}
if (result != VK_SUBOPTIMAL_KHR)
{
CheckVkResult(result);
}
ImGui_ImplVulkanH_Frame* frame = &window_data->Frames[window_data->FrameIndex];
result = vkWaitForFences(g_Device, 1, &frame->Fence, VK_TRUE, UINT64_MAX);
CheckVkResult(result);
result = vkResetFences(g_Device, 1, &frame->Fence);
CheckVkResult(result);
result = vkResetCommandPool(g_Device, frame->CommandPool, 0);
CheckVkResult(result);
VkCommandBufferBeginInfo begin_info = {};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
result = vkBeginCommandBuffer(frame->CommandBuffer, &begin_info);
CheckVkResult(result);
VkRenderPassBeginInfo render_pass_info = {};
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
render_pass_info.renderPass = window_data->RenderPass;
render_pass_info.framebuffer = frame->Framebuffer;
render_pass_info.renderArea.extent.width = window_data->Width;
render_pass_info.renderArea.extent.height = window_data->Height;
render_pass_info.clearValueCount = 1;
render_pass_info.pClearValues = &window_data->ClearValue;
vkCmdBeginRenderPass(frame->CommandBuffer, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE);
ImGui_ImplVulkan_RenderDrawData(draw_data, frame->CommandBuffer);
vkCmdEndRenderPass(frame->CommandBuffer);
result = vkEndCommandBuffer(frame->CommandBuffer);
CheckVkResult(result);
const VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo submit_info = {};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &image_acquired;
submit_info.pWaitDstStageMask = &wait_stage;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &frame->CommandBuffer;
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &render_complete;
result = vkQueueSubmit(g_Queue, 1, &submit_info, frame->Fence);
CheckVkResult(result);
}
static void FramePresent(ImGui_ImplVulkanH_Window* window_data)
{
if (g_SwapChainRebuild)
{
return;
}
VkSemaphore render_complete = window_data->FrameSemaphores[window_data->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR present_info = {};
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
present_info.waitSemaphoreCount = 1;
present_info.pWaitSemaphores = &render_complete;
present_info.swapchainCount = 1;
present_info.pSwapchains = &window_data->Swapchain;
present_info.pImageIndices = &window_data->FrameIndex;
VkResult result = vkQueuePresentKHR(g_Queue, &present_info);
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
{
g_SwapChainRebuild = true;
}
else
{
CheckVkResult(result);
}
window_data->SemaphoreIndex = (window_data->SemaphoreIndex + 1) % window_data->SemaphoreCount;
}
static bool IsExitEvent(screen_event_t event)
{
int type = SCREEN_EVENT_NONE;
if (screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &type) != 0)
{
return false;
}
if (type == SCREEN_EVENT_KEYBOARD)
{
int flags = 0;
int symbol = 0;
if (screen_get_event_property_iv(event, SCREEN_PROPERTY_FLAGS, &flags) == 0 &&
screen_get_event_property_iv(event, SCREEN_PROPERTY_SYM, &symbol) == 0 &&
(flags & KEY_DOWN) != 0 && symbol == KEYCODE_ESCAPE)
{
return true;
}
}
if (type == SCREEN_EVENT_CLOSE)
{
return true;
}
return false;
}
static bool ProcessScreenEvents(ScreenApp* app)
{
for (;;)
{
if (screen_get_event(app->Context, app->Event, 0) != 0)
{
fprintf(stderr, "screen_get_event() failed: %s\n", strerror(errno));
return false;
}
int type = SCREEN_EVENT_NONE;
if (screen_get_event_property_iv(app->Event, SCREEN_PROPERTY_TYPE, &type) != 0)
{
fprintf(stderr, "screen_get_event_property_iv(SCREEN_PROPERTY_TYPE) failed: %s\n", strerror(errno));
return false;
}
if (type == SCREEN_EVENT_NONE)
{
break;
}
if (IsExitEvent(app->Event))
{
return false;
}
ImGui_ImplScreen_ProcessEvent(app->Event);
}
return true;
}
static void SleepMilliseconds(long milliseconds)
{
struct timespec delay = {};
delay.tv_sec = milliseconds / 1000;
delay.tv_nsec = (milliseconds % 1000) * 1000000L;
nanosleep(&delay, nullptr);
}
static void CleanupVulkanWindow(ImGui_ImplVulkanH_Window* window_data)
{
if (g_Device != VK_NULL_HANDLE && window_data->Surface != VK_NULL_HANDLE)
{
const VkSurfaceKHR surface = window_data->Surface;
ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, window_data, g_Allocator);
vkDestroySurfaceKHR(g_Instance, surface, g_Allocator);
}
}
static void CleanupVulkan()
{
if (g_Device != VK_NULL_HANDLE)
{
if (g_DescriptorPool != VK_NULL_HANDLE)
{
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
}
vkDestroyDevice(g_Device, g_Allocator);
}
if (g_Instance != VK_NULL_HANDLE)
{
vkDestroyInstance(g_Instance, g_Allocator);
}
}
static void DestroyScreenApp(ScreenApp* app)
{
if (app->Event != nullptr)
{
screen_destroy_event(app->Event);
}
if (app->Window != nullptr)
{
screen_destroy_window(app->Window);
}
if (app->Context != nullptr)
{
screen_destroy_context(app->Context);
}
}
int main(int, char**)
{
ScreenApp app;
VkSurfaceKHR surface = VK_NULL_HANDLE;
if (!CreateScreenWindow(&app) ||
!CreateVulkanInstance() ||
!CreateVulkanSurface(&app, &surface) ||
!SelectPhysicalDeviceAndQueue(surface) ||
!CreateVulkanDevice() ||
!CreateDescriptorPool())
{
if (surface != VK_NULL_HANDLE && g_Instance != VK_NULL_HANDLE)
{
vkDestroySurfaceKHR(g_Instance, surface, g_Allocator);
}
CleanupVulkan();
DestroyScreenApp(&app);
return EXIT_FAILURE;
}
int window_size[2] = { app.WindowSize[0], app.WindowSize[1] };
if (!SetupVulkanWindow(&g_MainWindowData, surface, window_size[0], window_size[1]))
{
fprintf(stderr, "Failed to set up the Vulkan swapchain.\n");
vkDestroySurfaceKHR(g_Instance, surface, g_Allocator);
CleanupVulkan();
DestroyScreenApp(&app);
return EXIT_FAILURE;
}
const int visible = 1;
if (screen_set_window_property_iv(app.Window, SCREEN_PROPERTY_VISIBLE, &visible) != 0)
{
fprintf(stderr, "screen_set_window_property_iv(SCREEN_PROPERTY_VISIBLE) failed: %s\n", strerror(errno));
CleanupVulkanWindow(&g_MainWindowData);
CleanupVulkan();
DestroyScreenApp(&app);
return EXIT_FAILURE;
}
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
ImGui::StyleColorsDark();
bool screen_backend_initialized = ImGui_ImplScreen_Init(app.Context, app.Window);
ImGui_ImplVulkan_InitInfo init_info = {};
init_info.ApiVersion = VK_API_VERSION_1_0;
init_info.Instance = g_Instance;
init_info.PhysicalDevice = g_PhysicalDevice;
init_info.Device = g_Device;
init_info.QueueFamily = g_QueueFamily;
init_info.Queue = g_Queue;
init_info.PipelineCache = g_PipelineCache;
init_info.DescriptorPool = g_DescriptorPool;
init_info.MinImageCount = g_MinImageCount;
init_info.ImageCount = g_MainWindowData.ImageCount;
init_info.Allocator = g_Allocator;
init_info.PipelineInfoMain.RenderPass = g_MainWindowData.RenderPass;
init_info.PipelineInfoMain.Subpass = 0;
init_info.PipelineInfoMain.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
init_info.CheckVkResultFn = CheckVkResult;
const bool renderer_backend_initialized = ImGui_ImplVulkan_Init(&init_info);
if (!screen_backend_initialized || !renderer_backend_initialized)
{
fprintf(stderr, "Failed to initialize Dear ImGui backends.\n");
if (renderer_backend_initialized)
{
ImGui_ImplVulkan_Shutdown();
}
if (screen_backend_initialized)
{
ImGui_ImplScreen_Shutdown();
}
ImGui::DestroyContext();
CleanupVulkanWindow(&g_MainWindowData);
CleanupVulkan();
DestroyScreenApp(&app);
return EXIT_FAILURE;
}
bool show_demo_window = true;
bool show_another_window = false;
ImVec4 clear_color = ImVec4(0.10f, 0.12f, 0.15f, 1.00f);
bool running = true;
while (running)
{
running = ProcessScreenEvents(&app);
if (!running)
{
break;
}
if (screen_get_window_property_iv(app.Window, SCREEN_PROPERTY_SIZE, window_size) != 0)
{
fprintf(stderr, "screen_get_window_property_iv(SCREEN_PROPERTY_SIZE) failed: %s\n", strerror(errno));
break;
}
if (window_size[0] <= 0 || window_size[1] <= 0)
{
SleepMilliseconds(10);
continue;
}
if (g_SwapChainRebuild || g_MainWindowData.Width != window_size[0] || g_MainWindowData.Height != window_size[1])
{
ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
ImGui_ImplVulkanH_CreateOrResizeWindow(
g_Instance,
g_PhysicalDevice,
g_Device,
&g_MainWindowData,
g_QueueFamily,
g_Allocator,
window_size[0],
window_size[1],
g_MinImageCount,
0);
g_MainWindowData.FrameIndex = 0;
g_SwapChainRebuild = false;
}
ImGui_ImplVulkan_NewFrame();
ImGui_ImplScreen_NewFrame();
ImGui::NewFrame();
if (show_demo_window)
{
ImGui::ShowDemoWindow(&show_demo_window);
}
static float value = 0.0f;
static int counter = 0;
static char text[128] = "Keyboard input is handled by QNX Screen";
ImGui::Begin("QNX Screen + Vulkan");
ImGui::Checkbox("Demo Window", &show_demo_window);
ImGui::Checkbox("Another Window", &show_another_window);
ImGui::SliderFloat("float", &value, 0.0f, 1.0f);
ImGui::ColorEdit3("clear color", (float*)&clear_color);
ImGui::InputText("text", text, IM_ARRAYSIZE(text));
if (ImGui::Button("Button"))
{
counter++;
}
ImGui::SameLine();
ImGui::Text("counter = %d", counter);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
ImGui::TextUnformatted("Press Esc to exit.");
ImGui::End();
if (show_another_window)
{
ImGui::Begin("Another Window", &show_another_window);
ImGui::TextUnformatted("Hello from QNX Screen!");
if (ImGui::Button("Close Me"))
{
show_another_window = false;
}
ImGui::End();
}
ImGui::Render();
ImDrawData* draw_data = ImGui::GetDrawData();
const bool minimized = draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f;
if (!minimized)
{
g_MainWindowData.ClearValue.color.float32[0] = clear_color.x * clear_color.w;
g_MainWindowData.ClearValue.color.float32[1] = clear_color.y * clear_color.w;
g_MainWindowData.ClearValue.color.float32[2] = clear_color.z * clear_color.w;
g_MainWindowData.ClearValue.color.float32[3] = clear_color.w;
FrameRender(&g_MainWindowData, draw_data);
FramePresent(&g_MainWindowData);
}
}
CheckVkResult(vkDeviceWaitIdle(g_Device));
ImGui_ImplVulkan_Shutdown();
ImGui_ImplScreen_Shutdown();
ImGui::DestroyContext();
CleanupVulkanWindow(&g_MainWindowData);
CleanupVulkan();
DestroyScreenApp(&app);
return EXIT_SUCCESS;
}