xo-imgui: imgui_ex4 working on native ubuntu

requires etc/hostubuntu shim
This commit is contained in:
Roland Conybeare 2025-11-12 10:00:30 -05:00
commit 5fcfadce9a
5 changed files with 555 additions and 586 deletions

View file

@ -1,115 +1,221 @@
/* file VulkanApp.hpp */
#pragma once
#include <SDL.h>
#include <imgui.h>
#include <vulkan/vulkan.h>
//#include <SDL_vulkan.h>
#include <chrono>
#include <vector>
#include <SDL.h>
#include <SDL_vulkan.h>
#include <imgui.h>
#include <backends/imgui_impl_sdl2.h>
#include <backends/imgui_impl_vulkan.h>
#include <iostream>
#include <functional>
#include <vector>
#include <stdexcept>
class VulkanApp {
public:
using ImguiDrawFn = std::function<ImDrawData * (ImGuiContext *)>;
using time_point = std::chrono::steady_clock::time_point;
public:
/* create single-window vulkan application;
* use @p fn to draw each frame
*/
VulkanApp(ImguiDrawFn fn);
#ifdef NOPE
/** set imgui draw function **/
void assign_imgui_draw_frame(ImguiDrawFn fn);
#endif
/* run application; borrows calling thread for event loop,
* until application exit.
* Invoke load_fonts once imgui context established
*/
void run(std::function<void (ImGuiContext *)> load_fonts);
/** frames per second since inception **/
float lifetime_fps() const;
/** equivalent to sequence setup(), main_loop(), cleanup() **/
void run();
/** setup before main loop. idempotent **/
/* application setup (sdl -> vulkan -> imgui)
* Invoke load_fonts once imgui context established.
*/
void setup(std::function<void (ImGuiContext *)> load_fonts);
/* borrow calling thread, run until application end
* Require: app state initialized. see init_sdl_window(), init_vulkan(), init_imgui()
*/
void main_loop();
/** cleanup before shutdown. idempotent **/
/* orderly shutdown
*/
void cleanup();
private:
void init_window();
/* create SDL window for application.
* populates @ref window_
*/
void init_sdl_window();
/* setup vulkan state. swapchain, command buffers etc */
void init_vulkan();
/* create vulkan instance.
* populates @ref instance_
*/
void create_instance();
/* create vulkan surface.
* populates @ref surface_
*/
void create_surface();
/* choose physical device (1:1 with graphics card, presumably)
* populates @ref physical_device_, @ref graphics_queue_family_
*/
void pick_physical_device();
/*
* require: pick_physical_device() has run successfully
* populates @ref device_, @ref graphics_queue_
*/
void create_logical_device();
/* populates @ref swapchain_, @ref swapchain_images_,
* @ref swapchain_image_views_, @ref framebuffers_.
* Also $ref render_pass_ iff @p create_render_pass_flag
*/
void create_xswapchain(bool create_render_pass_flag);
/*
* populates @ref swapchain_, @ref swapchain_images_
*/
void create_swapchain();
/*
* populate @ref swapchain_image_views_
*/
void create_image_views();
/*
* populate @ref render_pass_
*/
void create_render_pass();
/*
* populate @ref framebuffers_
*/
void create_framebuffers();
/*
* populate @ref command_pool_
*/
void create_command_pool();
/*
* populate @ref command_buffers_
*/
void create_command_buffers();
/*
* populate
* @ref image_available_semaphores_,
* @ref render_finished_semaphores_,
* @ref inflight_fences_
*/
void create_sync_objects();
/*
* populate @ref descriptor_pool_
*/
void create_descriptor_pool();
void cleanup_framebuffers();
void cleanup_render_pass();
void cleanup_image_views();
void cleanup_swapchain();
void cleanup_swapchain_deps();
void recreate_swapchain_deps();
/* Setup imgui "framework".
* Invoke @p load_fonts with ImGuiContext
*/
void init_imgui(std::function<void (ImGuiContext *)> load_fonts);
/* Allocate buffer for 'single-time' commands (to be run once?).
* Pair with call to end_single_time_commands()
*/
VkCommandBuffer begin_single_time_commands();
/* complete command buffer begun with begin_single_time_commands();
* also submit, wait for completion + cleanup
*/
void end_single_time_commands(VkCommandBuffer commandBuffer);
void record_command_buffer(VkCommandBuffer commandBuffer,
uint32_t imageIndex);
/** TODO: replace with some generic mechanism **/
/* Accumulate drawing command for next frame.
* Reserves and modifies the @ref current_frame_ element of
* @ref command_buffers_
* @ref image_available_semaphores_
* @ref inflight_fences_
* Advances current_frame_ so that it refers to available resources
*/
void draw_frame();
private:
bool setup_done_ = false;
bool cleanup_done_ = false;
/* record draw instructions into cmdbuf, framebuffers_[image_ix] */
void record_command_buffer(VkCommandBuffer commandBuffer, uint32_t image_ix);
/* Teardown + create swapchain (swapchain + framebuffers + image views).
* Need this after window size changes
*/
void recreate_xswapchain();
/* wait until non-minimized window */
void wait_not_minimized();
/* orderly disposal of swapchin + image_views + framebuffers */
void cleanup_xswapchain();
/* orderly disposal of @ref framebuffers_ */
void cleanup_framebuffers();
/* orderly disposal of @ref swapchain_image_views_ */
void cleanup_image_views();
/* orderly disposal of @ref swapchain_ */
void cleanup_swapchain();
private:
SDL_Window* window_ = nullptr;
ImGuiContext* imgui_cx_ = nullptr;
VkInstance instance;
VkInstance instance_;
/* abstraction for presentation area (?) */
VkSurfaceKHR surface_;
/* physical device (graphics card) */
VkPhysicalDevice physical_device_;
uint32_t graphics_queue_family_ = 0;
/* logical device (graphics card, abstract api (?)) */
VkDevice device_;
VkQueue graphics_queue_;
VkSurfaceKHR surface_;
VkSwapchainKHR swapchain_;
/* drawing state, dependent on window size */
VkFormat swapchain_image_format_;
VkExtent2D swapchain_extent_;
std::vector<VkImage> swapchainImages;
VkSwapchainKHR swapchain_;
std::vector<VkImage> swapchain_images_;
std::vector<VkImageView> swapchain_image_views_;
VkRenderPass render_pass_;
std::vector<VkFramebuffer> framebuffers_;
VkCommandPool command_pool_;
std::vector<VkCommandBuffer> command_buffers_;
/** one per frame (up to MAX_FRAMES_IN_FLIGHT) **/
std::vector<VkSemaphore> image_available_semaphores_;
/** one per frame (up to MAX_FRAMES_IN_FLIGHT) **/
std::vector<VkSemaphore> render_finished_semaphores_;
std::vector<VkFence> in_flight_fences_;
std::vector<VkFence> inflight_fences_;
VkDescriptorPool descriptor_pool_;
/** frame counter, monotonic **/
uint32_t n_frame_ = 0;
/** VulkanApp start time. Captured in 1st render loop, see @ref record_command_buffer **/
time_point start_tm_;
/** time asof most recent render loop **/
time_point now_tm_;
/** time of last console report of fps **/
time_point last_log_fps_tm_;
/** image index of current frame **/
uint32_t current_frame_ = 0;
uint32_t graphics_queue_family_ = 0;
bool quit_ = false;
const size_t c_max_frames_in_flight = 2;
/* true iff @ref setup has been called */
bool setup_flag_ = false;
/* true when window resize behavior detected,
* until swapchain in consistent state.
*/
bool framebuffer_resized_flag_ = false;
bool quit_flag_ = false;
/** draw imgui **/
const ImguiDrawFn imgui_draw_frame_;
};
/* end VulkanApp.hpp */
}; /*VulkanApp*/