Skip to content

Commit f4d6bcf

Browse files
committed
Fix UI overlay, create buffers in multiples of chunk size to avoid frequent rebuilds
1 parent 8f6ac89 commit f4d6bcf

4 files changed

Lines changed: 25 additions & 49 deletions

File tree

base/VulkanBuffer.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Encapsulates a Vulkan buffer
55
*
6-
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
6+
* Copyright (C) 2016-2025 by Sascha Willems - www.saschawillems.de
77
*
88
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
99
*/
@@ -126,10 +126,12 @@ namespace vks
126126
if (buffer)
127127
{
128128
vkDestroyBuffer(device, buffer, nullptr);
129+
buffer = VK_NULL_HANDLE;
129130
}
130131
if (memory)
131132
{
132133
vkFreeMemory(device, memory, nullptr);
134+
memory = VK_NULL_HANDLE;
133135
}
134136
}
135137
};

base/VulkanUIOverlay.cpp

Lines changed: 22 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -232,11 +232,8 @@ namespace vks
232232
VK_CHECK_RESULT(vkCreatePipelineLayout(device->logicalDevice, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
233233

234234
// Setup graphics pipeline for UI rendering
235-
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState =
236-
vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE);
237-
238-
VkPipelineRasterizationStateCreateInfo rasterizationState =
239-
vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE, VK_FRONT_FACE_COUNTER_CLOCKWISE);
235+
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE);
236+
VkPipelineRasterizationStateCreateInfo rasterizationState = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE, VK_FRONT_FACE_COUNTER_CLOCKWISE);
240237

241238
// Enable blending
242239
VkPipelineColorBlendAttachmentState blendAttachmentState{};
@@ -249,27 +246,13 @@ namespace vks
249246
blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
250247
blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;
251248

252-
VkPipelineColorBlendStateCreateInfo colorBlendState =
253-
vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState);
254-
255-
VkPipelineDepthStencilStateCreateInfo depthStencilState =
256-
vks::initializers::pipelineDepthStencilStateCreateInfo(VK_FALSE, VK_FALSE, VK_COMPARE_OP_ALWAYS);
257-
258-
VkPipelineViewportStateCreateInfo viewportState =
259-
vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0);
260-
261-
VkPipelineMultisampleStateCreateInfo multisampleState =
262-
vks::initializers::pipelineMultisampleStateCreateInfo(rasterizationSamples);
263-
264-
std::vector<VkDynamicState> dynamicStateEnables = {
265-
VK_DYNAMIC_STATE_VIEWPORT,
266-
VK_DYNAMIC_STATE_SCISSOR
267-
};
268-
VkPipelineDynamicStateCreateInfo dynamicState =
269-
vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables);
270-
249+
VkPipelineColorBlendStateCreateInfo colorBlendState = vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState);
250+
VkPipelineDepthStencilStateCreateInfo depthStencilState = vks::initializers::pipelineDepthStencilStateCreateInfo(VK_FALSE, VK_FALSE, VK_COMPARE_OP_ALWAYS);
251+
VkPipelineViewportStateCreateInfo viewportState = vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0);
252+
VkPipelineMultisampleStateCreateInfo multisampleState = vks::initializers::pipelineMultisampleStateCreateInfo(rasterizationSamples);
253+
std::vector<VkDynamicState> dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
254+
VkPipelineDynamicStateCreateInfo dynamicState = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables);
271255
VkGraphicsPipelineCreateInfo pipelineCreateInfo = vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass);
272-
273256
pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState;
274257
pipelineCreateInfo.pRasterizationState = &rasterizationState;
275258
pipelineCreateInfo.pColorBlendState = &colorBlendState;
@@ -316,7 +299,7 @@ namespace vks
316299

317300
/** Update vertex and index buffer containing the imGui elements when required */
318301
void UIOverlay::update(uint32_t currentBuffer)
319-
{
302+
{
320303
ImDrawData* imDrawData = ImGui::GetDrawData();
321304

322305
if (!imDrawData) {
@@ -326,23 +309,28 @@ namespace vks
326309
// Note: Alignment is done inside buffer creation
327310
VkDeviceSize vertexBufferSize = imDrawData->TotalVtxCount * sizeof(ImDrawVert);
328311
VkDeviceSize indexBufferSize = imDrawData->TotalIdxCount * sizeof(ImDrawIdx);
329-
312+
330313
// Update buffers only if vertex or index count has been changed compared to current buffer size
331314
if ((vertexBufferSize == 0) || (indexBufferSize == 0)) {
332315
return;
333316
}
334317

335-
// Vertex buffer
336-
if ((buffers[currentBuffer].vertexBuffer.buffer == VK_NULL_HANDLE) || (buffers[currentBuffer].vertexCount != imDrawData->TotalVtxCount)) {
318+
// Create buffers with multiple of a chunk size to minimize the need to recreate them
319+
const VkDeviceSize chunkSize = 16384;
320+
vertexBufferSize = ((vertexBufferSize + chunkSize - 1) / chunkSize) * chunkSize;
321+
indexBufferSize = ((indexBufferSize + chunkSize - 1) / chunkSize) * chunkSize;
322+
323+
// Recreate vertex buffer only if necessary
324+
if ((buffers[currentBuffer].vertexBuffer.buffer == VK_NULL_HANDLE) || (buffers[currentBuffer].vertexBuffer.size < vertexBufferSize)) {
337325
buffers[currentBuffer].vertexBuffer.unmap();
338326
buffers[currentBuffer].vertexBuffer.destroy();
339327
VK_CHECK_RESULT(device->createBuffer(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &buffers[currentBuffer].vertexBuffer, vertexBufferSize));
340328
buffers[currentBuffer].vertexCount = imDrawData->TotalVtxCount;
341329
buffers[currentBuffer].vertexBuffer.map();
342330
}
343331

344-
// Index buffer
345-
if ((buffers[currentBuffer].indexBuffer.buffer == VK_NULL_HANDLE) || (buffers[currentBuffer].indexCount < imDrawData->TotalIdxCount)) {
332+
// Recreate index buffer only if necessary
333+
if ((buffers[currentBuffer].indexBuffer.buffer == VK_NULL_HANDLE) || (buffers[currentBuffer].indexBuffer.size < indexBufferSize)) {
346334
buffers[currentBuffer].indexBuffer.unmap();
347335
buffers[currentBuffer].indexBuffer.destroy();
348336
VK_CHECK_RESULT(device->createBuffer(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &buffers[currentBuffer].indexBuffer, indexBufferSize));
@@ -382,7 +370,7 @@ namespace vks
382370
}
383371

384372
ImGuiIO& io = ImGui::GetIO();
385-
373+
386374
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
387375
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL);
388376

@@ -396,11 +384,9 @@ namespace vks
396384
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &buffers[currentBuffer].vertexBuffer.buffer, offsets);
397385
vkCmdBindIndexBuffer(commandBuffer, buffers[currentBuffer].indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT16);
398386

399-
for (int32_t i = 0; i < imDrawData->CmdListsCount; i++)
400-
{
387+
for (int32_t i = 0; i < imDrawData->CmdListsCount; i++) {
401388
const ImDrawList* cmd_list = imDrawData->CmdLists[i];
402-
for (int32_t j = 0; j < cmd_list->CmdBuffer.Size; j++)
403-
{
389+
for (int32_t j = 0; j < cmd_list->CmdBuffer.Size; j++) {
404390
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[j];
405391
VkRect2D scissorRect;
406392
scissorRect.offset.x = std::max((int32_t)(pcmd->ClipRect.x), 0);

base/VulkanUIOverlay.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@ namespace vks
4848
vks::Buffer indexBuffer;
4949
int32_t vertexCount{ 0 };
5050
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 };
5351
};
5452
std::vector<Buffers> buffers;
5553
uint32_t maxConcurrentFrames{ 0 };

base/vulkanexamplebase.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -685,15 +685,6 @@ void VulkanExampleBase::updateOverlay()
685685
if (!settings.overlay)
686686
return;
687687

688-
// The overlay does not need to be updated with each frame, so we limit the update rate
689-
// Not only does this save performance but it also makes display of fast changig values like fps more stable
690-
ui.buffers[currentBuffer].updateTimer -= frameTimer;
691-
if (ui.buffers[currentBuffer].updateTimer >= 0.0f) {
692-
return;
693-
}
694-
// Update at max. rate of 30 fps
695-
ui.buffers[currentBuffer].updateTimer = 1.0f / 30.0f;
696-
697688
ImGuiIO& io = ImGui::GetIO();
698689

699690
io.DisplaySize = ImVec2((float)width, (float)height);
@@ -755,7 +746,6 @@ void VulkanExampleBase::prepareFrame(bool waitForFence)
755746
VK_CHECK_RESULT(vkWaitForFences(device, 1, &waitFences[currentBuffer], VK_TRUE, UINT64_MAX));
756747
VK_CHECK_RESULT(vkResetFences(device, 1, &waitFences[currentBuffer]));
757748
}
758-
// Update UI if necessary
759749
updateOverlay();
760750
// Acquire the next image from the swap chain
761751
VkResult result = swapChain.acquireNextImage(presentCompleteSemaphores[currentBuffer], currentImageIndex);

0 commit comments

Comments
 (0)