xo-imgui: support dynamic vsync_enabled setting + demo in ex4

This commit is contained in:
Roland Conybeare 2025-11-12 13:33:20 -05:00
commit b4a8ecd7d6
5 changed files with 58 additions and 14 deletions

View file

@ -741,7 +741,7 @@ DrawState::draw_gc_state(const AppState & app_state,
/* TODO: does this reset coord space? */
ImRect alloc_rect;
{
ImGui::BeginChild("top pane", ImVec2(0, 105), ImGuiChildFlags_Border | ImGuiChildFlags_ResizeY);
ImGui::BeginChild("top pane", ImVec2(0, 200), ImGuiChildFlags_Border | ImGuiChildFlags_ResizeY);
alloc_rect = ImRect(canvas_rect.top_left() + ImGui::GetWindowContentRegionMin(),
canvas_rect.top_left() + ImGui::GetWindowContentRegionMax());
@ -817,7 +817,7 @@ DrawState::draw_gc_state(const AppState & app_state,
ImGui::EndChild();
}
ImGui::Text("placeholder text");
//ImGui::Text("placeholder text"); // appears below history_rect
/* BeginChild() again ? */

View file

@ -85,6 +85,8 @@ struct DrawState {
public:
/** when true display imgui demo window **/
bool show_demo_window_ = false;
/** whether vsync feature enabled (throttle to ~60 fps) **/
bool vsync_enabled_ = true;
draw_state_type state_type_ = draw_state_type::alloc;

View file

@ -80,7 +80,7 @@ namespace {
*p_f = 0.0f;
*p_counter = 0;
return [p_app_state, p_draw_state, p_f, p_counter](ImGuiContext * imgui_cx)
return [p_app_state, p_draw_state, p_f, p_counter](VulkanApp * vulkan_app, ImGuiContext * imgui_cx)
{
scope log(XO_DEBUG(false));
@ -108,6 +108,19 @@ namespace {
ImGui::End();
# endif
// 0. main menubar
if (ImGui::BeginMainMenuBar()) {
if (ImGui::BeginMenu("View")) {
bool x = vulkan_app->vsync_enabled_flag();
if (ImGui::MenuItem("vsync", nullptr, &x)) {
vulkan_app->update_vsync_enabled(x);
}
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
}
// 1. create a simple ImGui window
ImGui::Begin("Hello, Vulkan + SDL2!");
ImGui::Text("This is a minimal ImGui + Vulkan + SDL2 example!");

View file

@ -13,7 +13,7 @@
class VulkanApp {
public:
using ImguiDrawFn = std::function<ImDrawData * (ImGuiContext *)>;
using ImguiDrawFn = std::function<ImDrawData * (VulkanApp *, ImGuiContext *)>;
public:
/* create single-window vulkan application;
@ -21,9 +21,17 @@ public:
*/
VulkanApp(ImguiDrawFn fn);
bool vsync_enabled_flag() const { return vsync_enabled_flag_; }
/* update vsync enabled (will recreate xswapchain at next opportunity)
*/
void update_vsync_enabled(bool flag);
/* run application; borrows calling thread for event loop,
* until application exit.
* Invoke load_fonts once imgui context established
* @ref vsync_enabled_flag_. true for VK_PRESENT_MODE_FIFO_KHR;
* false for VK_PRESENT_MODE_IMMEDIATE_KHR
*/
void run(std::function<void (ImGuiContext *)> load_fonts);
@ -47,7 +55,10 @@ private:
*/
void init_sdl_window();
/* setup vulkan state. swapchain, command buffers etc */
/* setup vulkan state. swapchain, command buffers etc
* @ref vsync_enabled_flag_. true for VK_PRESENT_MODE_FIFO_KHR;
* false for VK_PRESENT_MODE_IMMEDIATE_KHR
*/
void init_vulkan();
/* create vulkan instance.
@ -74,6 +85,8 @@ private:
/* populates @ref swapchain_, @ref swapchain_images_,
* @ref swapchain_image_views_, @ref framebuffers_.
* Also $ref render_pass_ iff @p create_render_pass_flag
* @ref vsync_enabled_flag_. true for VK_PRESENT_MODE_FIFO_KHR;
* false for VK_PRESENT_MODE_IMMEDIATE_KHR
*/
void create_xswapchain(bool create_render_pass_flag);
@ -175,6 +188,10 @@ private:
/* abstraction for presentation area (?) */
VkSurfaceKHR surface_;
/* true -> VK_PRESENT_MODE_FIFO_KHR
* false -> VK_PRESENT_MODE_IMMEDIATE_KHR
*/
bool vsync_enabled_flag_ = true;
/* physical device (graphics card) */
VkPhysicalDevice physical_device_;
@ -210,10 +227,14 @@ private:
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.
/* true if xswapchain is out-of-date.
* reset when xswapchain recreated (and therefore in consistent state).
*
* Triggered by:
* - window resize
* - vsync toggled
*/
bool framebuffer_resized_flag_ = false;
bool xswapchain_recreate_flag_ = false;
bool quit_flag_ = false;
/** draw imgui **/

View file

@ -216,7 +216,7 @@ VulkanApp::create_swapchain()
create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
create_info.preTransform = capabilities.currentTransform;
create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
create_info.presentMode = VK_PRESENT_MODE_FIFO_KHR;
create_info.presentMode = (vsync_enabled_flag_ ? VK_PRESENT_MODE_FIFO_KHR : VK_PRESENT_MODE_IMMEDIATE_KHR);
create_info.clipped = VK_TRUE;
if (vkCreateSwapchainKHR(device_, &create_info, nullptr, &(this->swapchain_)) != VK_SUCCESS) {
@ -564,7 +564,7 @@ VulkanApp::draw_frame()
result = vkQueuePresentKHR(graphics_queue_, &presentInfo);
if (framebuffer_resized_flag_)
if (xswapchain_recreate_flag_)
result = VK_ERROR_OUT_OF_DATE_KHR;
switch (result) {
@ -572,7 +572,6 @@ VulkanApp::draw_frame()
break;
case VK_ERROR_OUT_OF_DATE_KHR:
case VK_SUBOPTIMAL_KHR:
framebuffer_resized_flag_ = false;
this->recreate_xswapchain();
break;
default:
@ -582,6 +581,12 @@ VulkanApp::draw_frame()
this->current_frame_ = (current_frame_ + 1) % c_max_frames_in_flight;
}
void
VulkanApp::update_vsync_enabled(bool flag) {
this->vsync_enabled_flag_ = flag;
this->xswapchain_recreate_flag_ = true;
}
void
VulkanApp::record_command_buffer(VkCommandBuffer cmdbuf, uint32_t image_ix)
{
@ -633,7 +638,7 @@ VulkanApp::record_command_buffer(VkCommandBuffer cmdbuf, uint32_t image_ix)
}
#endif
ImDrawData * draw_data = imgui_draw_frame_(imgui_cx_); (void)draw_data;
ImDrawData * draw_data = imgui_draw_frame_(this, imgui_cx_);
ImGui_ImplVulkan_RenderDrawData(draw_data, cmdbuf);
@ -671,11 +676,14 @@ VulkanApp::recreate_xswapchain()
// wait until device idle before cleaning up resources
vkDeviceWaitIdle(device_);
// remember consistent swapchain state restored
this->xswapchain_recreate_flag_ = false;
// cleanup old xswapchain
this->cleanup_xswapchain();
// create new swapchain
this->create_xswapchain(false);
this->create_xswapchain(false /*create_render_pass_flag*/);
}
void