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, ...)
0 commit comments