Skip to content

Commit ac160ad

Browse files
committed
Adopt UI Overlay to new sync
Prob. needs adjustments for other platforms than Windows
1 parent 40563ce commit ac160ad

3 files changed

Lines changed: 73 additions & 88 deletions

File tree

base/VulkanUIOverlay.cpp

Lines changed: 51 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
/*
33
* UI overlay class using ImGui
44
*
5-
* Copyright (C) 2017-2024 by Sascha Willems - www.saschawillems.de
5+
* Copyright (C) 2017-2025 by Sascha Willems - www.saschawillems.de
66
*
77
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
88
*/
@@ -83,7 +83,7 @@ namespace vks
8383
io.Fonts->GetTexDataAsRGBA32(&fontData, &texWidth, &texHeight);
8484
VkDeviceSize uploadSize = texWidth*texHeight * 4 * sizeof(char);
8585

86-
//SRS - Set ImGui style scale factor to handle retina and other HiDPI displays (same as font scaling above)
86+
// Set ImGui style scale factor to handle retina and other HiDPI displays (same as font scaling above)
8787
ImGuiStyle& style = ImGui::GetStyle();
8888
style.ScaleAllSizes(scale);
8989

@@ -214,6 +214,10 @@ namespace vks
214214
vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, &fontDescriptor)
215215
};
216216
vkUpdateDescriptorSets(device->logicalDevice, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr);
217+
218+
// Buffers per max. frames-in-flight
219+
assert(maxConcurrentFrames > 0);
220+
buffers.resize(maxConcurrentFrames);
217221
}
218222

219223
/** Prepare a separate pipeline for the UI overlay rendering decoupled from the main application */
@@ -278,7 +282,7 @@ namespace vks
278282
pipelineCreateInfo.subpass = subpass;
279283

280284
#if defined(VK_KHR_dynamic_rendering)
281-
// SRS - if we are using dynamic rendering (i.e. renderPass null), must define color, depth and stencil attachments at pipeline create time
285+
// Of we are using dynamic rendering (i.e. renderPass null), we must define color, depth and stencil attachments at pipeline create time
282286
VkPipelineRenderingCreateInfo pipelineRenderingCreateInfo = {};
283287
if (renderPass == VK_NULL_HANDLE) {
284288
pipelineRenderingCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO;
@@ -311,46 +315,45 @@ namespace vks
311315
}
312316

313317
/** Update vertex and index buffer containing the imGui elements when required */
314-
bool UIOverlay::update()
318+
void UIOverlay::update(uint32_t currentBuffer)
315319
{
316320
ImDrawData* imDrawData = ImGui::GetDrawData();
317-
bool updateCmdBuffers = false;
318321

319-
if (!imDrawData) { return false; };
322+
if (!imDrawData) {
323+
return;
324+
}
320325

321326
// Note: Alignment is done inside buffer creation
322327
VkDeviceSize vertexBufferSize = imDrawData->TotalVtxCount * sizeof(ImDrawVert);
323328
VkDeviceSize indexBufferSize = imDrawData->TotalIdxCount * sizeof(ImDrawIdx);
324329

325330
// Update buffers only if vertex or index count has been changed compared to current buffer size
326331
if ((vertexBufferSize == 0) || (indexBufferSize == 0)) {
327-
return false;
332+
return;
328333
}
329334

330335
// Vertex buffer
331-
if ((vertexBuffer.buffer == VK_NULL_HANDLE) || (vertexCount != imDrawData->TotalVtxCount)) {
332-
vertexBuffer.unmap();
333-
vertexBuffer.destroy();
334-
VK_CHECK_RESULT(device->createBuffer(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &vertexBuffer, vertexBufferSize));
335-
vertexCount = imDrawData->TotalVtxCount;
336-
vertexBuffer.unmap();
337-
vertexBuffer.map();
338-
updateCmdBuffers = true;
336+
if ((buffers[currentBuffer].vertexBuffer.buffer == VK_NULL_HANDLE) || (buffers[currentBuffer].vertexCount != imDrawData->TotalVtxCount)) {
337+
buffers[currentBuffer].vertexBuffer.unmap();
338+
buffers[currentBuffer].vertexBuffer.destroy();
339+
VK_CHECK_RESULT(device->createBuffer(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &buffers[currentBuffer].vertexBuffer, vertexBufferSize));
340+
buffers[currentBuffer].vertexCount = imDrawData->TotalVtxCount;
341+
//buffers[currentBuffer].vertexBuffer.unmap();
342+
buffers[currentBuffer].vertexBuffer.map();
339343
}
340344

341345
// Index buffer
342-
if ((indexBuffer.buffer == VK_NULL_HANDLE) || (indexCount < imDrawData->TotalIdxCount)) {
343-
indexBuffer.unmap();
344-
indexBuffer.destroy();
345-
VK_CHECK_RESULT(device->createBuffer(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &indexBuffer, indexBufferSize));
346-
indexCount = imDrawData->TotalIdxCount;
347-
indexBuffer.map();
348-
updateCmdBuffers = true;
346+
if ((buffers[currentBuffer].indexBuffer.buffer == VK_NULL_HANDLE) || (buffers[currentBuffer].indexCount < imDrawData->TotalIdxCount)) {
347+
buffers[currentBuffer].indexBuffer.unmap();
348+
buffers[currentBuffer].indexBuffer.destroy();
349+
VK_CHECK_RESULT(device->createBuffer(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &buffers[currentBuffer].indexBuffer, indexBufferSize));
350+
buffers[currentBuffer].indexCount = imDrawData->TotalIdxCount;
351+
buffers[currentBuffer].indexBuffer.map();
349352
}
350353

351354
// Upload data
352-
ImDrawVert* vtxDst = (ImDrawVert*)vertexBuffer.mapped;
353-
ImDrawIdx* idxDst = (ImDrawIdx*)indexBuffer.mapped;
355+
ImDrawVert* vtxDst = (ImDrawVert*)buffers[currentBuffer].vertexBuffer.mapped;
356+
ImDrawIdx* idxDst = (ImDrawIdx*)buffers[currentBuffer].indexBuffer.mapped;
354357

355358
for (int n = 0; n < imDrawData->CmdListsCount; n++) {
356359
const ImDrawList* cmd_list = imDrawData->CmdLists[n];
@@ -361,13 +364,11 @@ namespace vks
361364
}
362365

363366
// Flush to make writes visible to GPU
364-
vertexBuffer.flush();
365-
indexBuffer.flush();
366-
367-
return updateCmdBuffers;
367+
buffers[currentBuffer].vertexBuffer.flush();
368+
buffers[currentBuffer].indexBuffer.flush();
368369
}
369370

370-
void UIOverlay::draw(const VkCommandBuffer commandBuffer)
371+
void UIOverlay::draw(const VkCommandBuffer commandBuffer, uint32_t currentBuffer)
371372
{
372373
ImDrawData* imDrawData = ImGui::GetDrawData();
373374
int32_t vertexOffset = 0;
@@ -377,6 +378,10 @@ namespace vks
377378
return;
378379
}
379380

381+
if (buffers[currentBuffer].vertexBuffer.buffer == VK_NULL_HANDLE || buffers[currentBuffer].indexBuffer.buffer == VK_NULL_HANDLE) {
382+
return;
383+
}
384+
380385
ImGuiIO& io = ImGui::GetIO();
381386

382387
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
@@ -386,9 +391,11 @@ namespace vks
386391
pushConstBlock.translate = glm::vec2(-1.0f);
387392
vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(PushConstBlock), &pushConstBlock);
388393

394+
assert(buffers[currentBuffer].vertexBuffer.buffer != VK_NULL_HANDLE && buffers[currentBuffer].indexBuffer.buffer != VK_NULL_HANDLE);
395+
389396
VkDeviceSize offsets[1] = { 0 };
390-
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertexBuffer.buffer, offsets);
391-
vkCmdBindIndexBuffer(commandBuffer, indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT16);
397+
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &buffers[currentBuffer].vertexBuffer.buffer, offsets);
398+
vkCmdBindIndexBuffer(commandBuffer, buffers[currentBuffer].indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT16);
392399

393400
for (int32_t i = 0; i < imDrawData->CmdListsCount; i++)
394401
{
@@ -408,7 +415,7 @@ namespace vks
408415
#if (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT)) && TARGET_OS_SIMULATOR
409416
// Apple Device Simulator does not support vkCmdDrawIndexed() with vertexOffset > 0, so rebind vertex buffer instead
410417
offsets[0] += cmd_list->VtxBuffer.Size * sizeof(ImDrawVert);
411-
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertexBuffer.buffer, offsets);
418+
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &buffers[currentBuffer].vertexBuffer.buffer, offsets);
412419
#else
413420
vertexOffset += cmd_list->VtxBuffer.Size;
414421
#endif
@@ -423,8 +430,10 @@ namespace vks
423430

424431
void UIOverlay::freeResources()
425432
{
426-
vertexBuffer.destroy();
427-
indexBuffer.destroy();
433+
for (auto& buffer : buffers) {
434+
buffers[currentBuffer].vertexBuffer.destroy();
435+
buffers[currentBuffer].indexBuffer.destroy();
436+
}
428437
vkDestroyImageView(device->logicalDevice, fontView, nullptr);
429438
vkDestroyImage(device->logicalDevice, fontImage, nullptr);
430439
vkFreeMemory(device->logicalDevice, fontMemory, nullptr);
@@ -442,46 +451,35 @@ namespace vks
442451

443452
bool UIOverlay::checkBox(const char *caption, bool *value)
444453
{
445-
bool res = ImGui::Checkbox(caption, value);
446-
if (res) { updated = true; };
447-
return res;
454+
return ImGui::Checkbox(caption, value);
448455
}
449456

450457
bool UIOverlay::checkBox(const char *caption, int32_t *value)
451458
{
452459
bool val = (*value == 1);
453460
bool res = ImGui::Checkbox(caption, &val);
454461
*value = val;
455-
if (res) { updated = true; };
456462
return res;
457463
}
458464

459465
bool UIOverlay::radioButton(const char* caption, bool value)
460466
{
461-
bool res = ImGui::RadioButton(caption, value);
462-
if (res) { updated = true; };
463-
return res;
467+
return ImGui::RadioButton(caption, value);
464468
}
465469

466470
bool UIOverlay::inputFloat(const char *caption, float *value, float step, uint32_t precision)
467471
{
468-
bool res = ImGui::InputFloat(caption, value, step, step * 10.0f, precision);
469-
if (res) { updated = true; };
470-
return res;
472+
return ImGui::InputFloat(caption, value, step, step * 10.0f, precision);
471473
}
472474

473475
bool UIOverlay::sliderFloat(const char* caption, float* value, float min, float max)
474476
{
475-
bool res = ImGui::SliderFloat(caption, value, min, max);
476-
if (res) { updated = true; };
477-
return res;
477+
return ImGui::SliderFloat(caption, value, min, max);
478478
}
479479

480480
bool UIOverlay::sliderInt(const char* caption, int32_t* value, int32_t min, int32_t max)
481481
{
482-
bool res = ImGui::SliderInt(caption, value, min, max);
483-
if (res) { updated = true; };
484-
return res;
482+
return ImGui::SliderInt(caption, value, min, max);
485483
}
486484

487485
bool UIOverlay::comboBox(const char *caption, int32_t *itemindex, std::vector<std::string> items)
@@ -495,22 +493,16 @@ namespace vks
495493
charitems.push_back(items[i].c_str());
496494
}
497495
uint32_t itemCount = static_cast<uint32_t>(charitems.size());
498-
bool res = ImGui::Combo(caption, itemindex, &charitems[0], itemCount, itemCount);
499-
if (res) { updated = true; };
500-
return res;
496+
return ImGui::Combo(caption, itemindex, &charitems[0], itemCount, itemCount);
501497
}
502498

503499
bool UIOverlay::button(const char *caption)
504500
{
505-
bool res = ImGui::Button(caption);
506-
if (res) { updated = true; };
507-
return res;
501+
return ImGui::Button(caption);
508502
}
509503

510504
bool UIOverlay::colorPicker(const char* caption, float* color) {
511-
bool res = ImGui::ColorEdit4(caption, color, ImGuiColorEditFlags_NoInputs);
512-
if (res) { updated = true; };
513-
return res;
505+
return ImGui::ColorEdit4(caption, color, ImGuiColorEditFlags_NoInputs);
514506
}
515507

516508
void UIOverlay::text(const char *formatstr, ...)

base/VulkanUIOverlay.h

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* UI overlay class using ImGui
33
*
4-
* Copyright (C) 2017-2024 by Sascha Willems - www.saschawillems.de
4+
* Copyright (C) 2017-2025 by Sascha Willems - www.saschawillems.de
55
*
66
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
77
*/
@@ -43,10 +43,17 @@ namespace vks
4343
VkSampleCountFlagBits rasterizationSamples{ VK_SAMPLE_COUNT_1_BIT };
4444
uint32_t subpass{ 0 };
4545

46-
vks::Buffer vertexBuffer;
47-
vks::Buffer indexBuffer;
48-
int32_t vertexCount{ 0 };
49-
int32_t indexCount{ 0 };
46+
struct Buffers {
47+
vks::Buffer vertexBuffer;
48+
vks::Buffer indexBuffer;
49+
int32_t vertexCount{ 0 };
50+
int32_t indexCount{ 0 };
51+
// UI update rate is capped for performance reasons, so we need to know when to update
52+
float updateTimer{ 0.0f };
53+
};
54+
std::vector<Buffers> buffers;
55+
uint32_t maxConcurrentFrames{ 0 };
56+
uint32_t currentBuffer{ 0 };
5057

5158
std::vector<VkPipelineShaderStageCreateInfo> shaders;
5259

@@ -67,18 +74,16 @@ namespace vks
6774
} pushConstBlock;
6875

6976
bool visible{ true };
70-
bool updated{ false };
7177
float scale{ 1.0f };
72-
float updateTimer{ 0.0f };
7378

7479
UIOverlay();
7580
~UIOverlay();
7681

7782
void preparePipeline(const VkPipelineCache pipelineCache, const VkRenderPass renderPass, const VkFormat colorFormat, const VkFormat depthFormat);
7883
void prepareResources();
7984

80-
bool update();
81-
void draw(const VkCommandBuffer commandBuffer);
85+
void update(uint32_t currentBuffer);
86+
void draw(const VkCommandBuffer commandBuffer, uint32_t currentBuffer);
8287
void resize(uint32_t width, uint32_t height);
8388

8489
void freeResources();

0 commit comments

Comments
 (0)