summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2025-08-14 11:29:48 -0400
committerJonathan Bradley <jcb@pikum.xyz>2025-08-14 11:46:02 -0400
commitebcae77b137a759c453b89a774ece5a755078a38 (patch)
tree4d2239e94bfbbd7bbe9b33cb33e8ca8262b99ea1 /src
parent0b5f7059cc88d9ee18fa46eb7e6d9fb45ee65da8 (diff)
pke: HACK: avoid modifying in-use vulkan buffers
Replace me with a memory barrier helper fn.
Diffstat (limited to 'src')
-rw-r--r--src/game.cpp1
-rw-r--r--src/static-ui.cpp4
-rw-r--r--src/window.cpp44
-rw-r--r--src/window.hpp4
4 files changed, 51 insertions, 2 deletions
diff --git a/src/game.cpp b/src/game.cpp
index aea1039..27c42ac 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -114,6 +114,7 @@ void Game_Tick(double delta) {
EntityType_Tick_Late(delta);
ECS_Tick_Late(delta);
+ window_tick_late(delta);
}
void Game_Main(PKEWindowProperties windowProps, const char *executablePath) {
diff --git a/src/static-ui.cpp b/src/static-ui.cpp
index 1179028..7e500d9 100644
--- a/src/static-ui.cpp
+++ b/src/static-ui.cpp
@@ -464,10 +464,10 @@ void pke_ui_update_instance_buffer(pk_arr_t<pke_ui_box_instance_buffer_item> &ar
vkResult = vkBindBufferMemory(vkDevice, newBuffer, new_memory, 0);
assert(vkResult == VK_SUCCESS);
if (pke_ui_master.bindings.bd_instance.buffer != VK_NULL_HANDLE) {
- vkDestroyBuffer(vkDevice, pke_ui_master.bindings.bd_instance.buffer, vkAllocator);
+ pkvk_queue_vk_buffer_destroy(pke_ui_master.bindings.bd_instance.buffer);
}
if (pke_ui_master.bindings.deviceMemoryInst != VK_NULL_HANDLE) {
- vkFreeMemory(vkDevice, pke_ui_master.bindings.deviceMemoryInst, vkAllocator);
+ pkvk_queue_vk_memory_free(pke_ui_master.bindings.deviceMemoryInst);
}
pke_ui_master.bindings.bd_instance.buffer = newBuffer;
pke_ui_master.bindings.deviceMemoryInst = new_memory;
diff --git a/src/window.cpp b/src/window.cpp
index fa28e34..0c7f281 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -74,6 +74,13 @@ VkExtent2D Extent;
VkSampler global_sampler;
VkSampleCountFlagBits global_sample_count;
+struct pkvk_queued_actions {
+ struct pkvk_queued_actions_delete {
+ pk_arr_t<VkBuffer> buffers{};
+ pk_arr_t<VkDeviceMemory> memory{};
+ } destroy;
+} pkvk_actn_queue;
+
// pkvk_shared.descr_set_layout.single_sampler
// the pke default, works for:
// 2025-01-28 - present
@@ -705,6 +712,14 @@ void pkvk_texture_upload(pkvk_texture_upload_data *data, pkvk_texture_upload_dat
PKVK_EndBuffer(tmpBufferDetails);
}
+void pkvk_queue_vk_buffer_destroy(VkBuffer buffer) {
+ pk_arr_append_t(&pkvk_actn_queue.destroy.buffers, buffer);
+}
+
+void pkvk_queue_vk_memory_free(VkDeviceMemory memory) {
+ pk_arr_append_t(&pkvk_actn_queue.destroy.memory, memory);
+}
+
unsigned int FindQueueFamilyIndex(VkPhysicalDevice device, char hasPresentSupport = -1, VkQueueFlagBits includeBits = (VkQueueFlagBits)0U, VkQueueFlagBits excludeBits = (VkQueueFlagBits)0U) {
if (hasPresentSupport == -1 && includeBits == 0 && excludeBits == 0) {
@@ -3845,6 +3860,8 @@ void DestroyWindow() {
fprintf(stderr, "VkAllocator has '%u' outstanding allocations!", vulkanAllocs.next);
}
pk_arr_reset(&vulkanAllocs);
+ pk_arr_reset(&pkvk_actn_queue.destroy.buffers);
+ pk_arr_reset(&pkvk_actn_queue.destroy.memory);
// TODO there's un-freed vulkan stuff in the bucket
// comment this out to see it in the debug printout
pk_mem_bucket_destroy(MemBkt_Vulkan);
@@ -3909,6 +3926,33 @@ void CalculateCombinedMemReqs(uint64_t memReqsCount, VkMemoryRequirements *memRe
}
}
+/* 2025-08-07 - JCB DEBT
+ * This function was a result of buffer synchronization issues.
+ * Specifically, the UI module was trying to reallocate its instance buffer.
+ * Vulkan was emitting an error that the buffer was in use by a command buffer.
+ * Processing these actions after the graphics queue is idle solved that specific issue.
+ * This is a stop-gap measure so I can keep working and is not intended to be permanent.
+ * PERF
+ * This will block the main thread until all in-flight renders are no longer using any of the resources needed to render a scene.
+ * Move this to a fire-and-forget background thread that uses a memory barrier and a semaphore specifically for the target resource.
+ */
+void window_tick_late(double delta) {
+ (void)delta;
+ uint32_t i;
+ if (pkvk_actn_queue.destroy.buffers.next > 0
+ || pkvk_actn_queue.destroy.memory.next > 0) {
+ vkQueueWaitIdle(pkvk_shared.queue.graphics);
+ }
+ for (i = 0; i < pkvk_actn_queue.destroy.buffers.next; ++i) {
+ vkDestroyBuffer(vkDevice, pkvk_actn_queue.destroy.buffers[i], vkAllocator);
+ }
+ for (i = 0; i < pkvk_actn_queue.destroy.memory.next; ++i) {
+ vkFreeMemory(vkDevice, pkvk_actn_queue.destroy.memory[i], vkAllocator);
+ }
+ pk_arr_clear(&pkvk_actn_queue.destroy.buffers);
+ pk_arr_clear(&pkvk_actn_queue.destroy.memory);
+}
+
void Render() {
vkWaitForFences(vkDevice, 1, &pkvk_present.fences_in_flight[CURRENT_FRAME], VK_TRUE, UINT64_MAX);
diff --git a/src/window.hpp b/src/window.hpp
index 1df25b7..90793ed 100644
--- a/src/window.hpp
+++ b/src/window.hpp
@@ -96,6 +96,7 @@ extern ImplementedPKVK pkePipelines;
void CreateWindow(PKEWindowProperties wp);
void DestroyWindow();
VkShaderModule UploadShader(AssetHandle handle);
+void window_tick_late(double delta);
void Render();
unsigned int FindMemoryTypeIndex(uint32_t typeFilter, VkMemoryPropertyFlags memPropertyFlags);
@@ -150,4 +151,7 @@ struct pkvk_texture_upload_data_out {
};
void pkvk_texture_upload(pkvk_texture_upload_data *data, pkvk_texture_upload_data_out *out);
+void pkvk_queue_vk_buffer_destroy(VkBuffer buffer);
+void pkvk_queue_vk_memory_free(VkDeviceMemory memory);
+
#endif /* PKE_WINDOW_HPP */