work on asset loading queues

This commit is contained in:
Matthew 2025-04-25 18:48:13 +10:00
parent 44668e8742
commit 72e1b91e2a
16 changed files with 452 additions and 164 deletions

View File

@ -47,7 +47,7 @@ glsl_stage_geom="-fshader-stage=geom"
glsl_stage_comp="-fshader-stage=comp" glsl_stage_comp="-fshader-stage=comp"
glsl_out="-o./shaders/glsl/" glsl_out="-o./shaders/glsl/"
clang_common="${include_flags} ${render_flag} -DCOMPILER_CLANG -std=c23 -fuse-ld=mold -Xclang -flto-visibility-public-std -Wno-unknown-warning-option -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Wno-for-loop-analysis -DVMA_STATIC_VULKAN_FUNCTIONS=0" clang_common="${include_flags} ${render_flag} -DCOMPILER_CLANG -std=c23 -fuse-ld=mold -Xclang -flto-visibility-public-std -Wno-unknown-warning-option -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Wno-for-loop-analysis -DVMA_STATIC_VULKAN_FUNCTIONS=0 -ferror-limit=200"
clang_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${clang_common}" clang_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${clang_common}"
clang_release="$compiler -O2 ${clang_common}" clang_release="$compiler -O2 ${clang_common}"
clang_test="$compiler -O2 -DBUILD_TEST=1 ${clang_common}" clang_test="$compiler -O2 -DBUILD_TEST=1 ${clang_common}"

View File

@ -69,6 +69,7 @@ static Asset AssetPackLoadTexture(TextureAsset asset_id)
asset.len = asset_info->len; asset.len = asset_info->len;
asset.texture_meta.w = u32(x); asset.texture_meta.w = u32(x);
asset.texture_meta.h = u32(y); asset.texture_meta.h = u32(y);
asset.texture_meta.ch = u32(ch);
Texture_Asset_Lookup[asset_id] = asset; Texture_Asset_Lookup[asset_id] = asset;

View File

@ -65,6 +65,7 @@ typedef struct TextureAssetMeta
{ {
u32 w; u32 w;
u32 h; u32 h;
u32 ch;
} TextureAssetMeta; } TextureAssetMeta;
typedef struct Asset typedef struct Asset

View File

@ -300,7 +300,7 @@ static b32 RBTreeSearchNearest(RBTree *tree, u64 key, RBNode **out_node)
break; break;
u64 diff = node->key - key; u64 diff = node->key - key;
diff = Abs(diff); diff = Absu64(diff);
if (diff == 0) if (diff == 0)
{ {
@ -546,6 +546,27 @@ static KeyValuePair *HashTableSearchRawptr(HashTable *table, rawptr key)
return result; return result;
} }
static void HashTableDeleteU64(HashTable *table, u64 key)
{
u64 hash = HashFromString(String8Struct(&key));
u64 index = hash % table->cap;
HashList *list = table->lists + index;
HashNode *prev = P_HT_NIL;
for (HashNode *node = list->first; node != P_HT_NIL; node = node->next)
{
if (node->v.key_u64 == key)
{
if (prev != P_HT_NIL)
prev->next = node->next;
node->v.key_u64 = 0;
node->v.value_u64 = 0;
HTQueuePush(ht->free_lists.first, ht->free_lists.last, node);
break;
}
}
}
// ::DataStructures::HashTable::Functions::End:: // ::DataStructures::HashTable::Functions::End::

View File

@ -121,4 +121,5 @@ static HashNode *HashTablePushU64U32(HashTable *table, u64 key, u32 value);
static HashNode *HashTablePushU64U64(HashTable *table, u64 key, u64 value); static HashNode *HashTablePushU64U64(HashTable *table, u64 key, u64 value);
static HashNode *HashTablePushU64String8(HashTable *table, u64 key, String8 value); static HashNode *HashTablePushU64String8(HashTable *table, u64 key, String8 value);
static HashNode *HashTablePushU64Rawptr(HashTable *table, u64 key, rawptr value); static HashNode *HashTablePushU64Rawptr(HashTable *table, u64 key, rawptr value);
static void HashTableDeleteU64(HashTable *table, u64 key);

View File

@ -84,7 +84,7 @@ static void RunCycle(GameContext *ctx, GameInput *inputs, u32 i_count)
CreateAndUploadToBuffer(vertex_buffer, ctx->gui.vertices); CreateAndUploadToBuffer(vertex_buffer, ctx->gui.vertices);
CreateAndUploadToBuffer(index_buffer, ctx->gui.indices); CreateAndUploadToBuffer(index_buffer, ctx->gui.indices);
JobQueueWaitForCompletion(&renderer.vk.imm.queue); WaitForBufferQueue();
BeginFrame(); BeginFrame();

View File

@ -73,8 +73,27 @@ static inline u64 ReadCPUTimer();
// ::Platform::Atomics::Header:: // ::Platform::Atomics::Header::
#define DefSigAtomicFetchIncr(T) static inline T AtomicFetchIncr##T(T *ptr)
#define DefSigAtomicFetchSub(T) static inline T AtomicFetchSub##T(T *ptr, T count)
#define DefSigAtomicIncr(T) static inline void AtomicIncr##T(T *ptr)
#define DefSigAtomicStore(T) static inline void AtomicStore##T(T *ptr, T value)
#define DefSigAtomicLoad(T) static inline T AtomicLoad##T(T *ptr)
#define DefSigAtomicCompareExchange(T) static inline T AtomicCompareExchange##T(T *ptr, T *expected, T desired)
DefScalarSig(AtomicFetchIncr);
DefScalarSig(AtomicFetchSub);
DefScalarSig(AtomicIncr);
DefScalarSig(AtomicStore);
DefScalarSig(AtomicLoad);
DefScalarSig(AtomicCompareExchange);
/*
static inline u32 AtomicFetchIncrU32(u32 *ptr); static inline u32 AtomicFetchIncrU32(u32 *ptr);
static inline u32 AtomicFetchSubU32(u32 *ptr, u32 count); static inline u32 AtomicFetchSubU32(u32 *ptr, u32 count);
static inline void AtomicIncrU32(u32 *ptr); static inline void AtomicIncrU32(u32 *ptr);
static inline u32 AtomicFetchU32(u32 *ptr); static inline u32 AtomicFetchU32(u32 *ptr);
static inline void AtomicStoreB32(b32 *ptr, b32 value);
static inline u32 AtomicLoadU32(u32 *ptr); static inline u32 AtomicLoadU32(u32 *ptr);
static inline b32 AtomicCompareExchangeU32(u32 *ptr, u32 *expected, u32 desired);
static inline b32 AtomicCompareExchangeB32(b32 *ptr, b32 *expected, b32 desired);
*/

View File

@ -87,3 +87,40 @@ KeyboardInput ConvertInputEvent(u32 x_key);
b32 CheckSyscallErr(void *ptr); b32 CheckSyscallErr(void *ptr);
// ::Platform::Linux::Atomics::Header::
#define DefAtomicFetchIncr(T) \
static inline T AtomicFetchIncr##T(T *ptr) \
{ \
return __atomic_fetch_add(ptr, (T)1, __ATOMIC_ACQUIRE); \
}
#define DefAtomicIncr(T) \
static inline void AtomicIncr##T(T *ptr) \
{ \
__atomic_fetch_add(ptr, (T)1, __ATOMIC_RELEASE); \
}
#define DefAtomicStore(T) \
static inline void AtomicStore##T(T *ptr, T value) \
{ \
__atomic_store_n(ptr, value, __ATOMIC_RELEASE); \
}
#define DefAtomicLoad(T) \
static inline T AtomicLoad##T(T *ptr) \
{ \
return __atomic_load_n(ptr, __ATOMIC_ACQUIRE); \
}
#define DefAtomicFetchSub(T) \
static inline T AtomicFetchSub##T(T *ptr, T count) \
{ \
return __atomic_fetch_sub(ptr, count, __ATOMIC_ACQUIRE); \
}
#define DefAtomicCompareExchange(T) \
static inline b32 AtomicCompareExchange##T(T *ptr, T *expected, T desired) \
{ \
return __atomic_compare_exchange_n(ptr, expected, desired, true, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED); \
}

View File

@ -334,6 +334,14 @@ static inline u64 ReadCPUTimer()
// ::Platform::Atomics::Functions::Start:: // ::Platform::Atomics::Functions::Start::
DefScalarImpl(AtomicFetchIncr);
DefScalarImpl(AtomicIncr);
DefScalarImpl(AtomicStore);
DefScalarImpl(AtomicLoad);
DefScalarImpl(AtomicFetchSub);
DefScalarImpl(AtomicCompareExchange);
/*
static inline u32 AtomicFetchIncrU32(u32 *ptr) static inline u32 AtomicFetchIncrU32(u32 *ptr)
{ {
return __atomic_fetch_add(ptr, 1, __ATOMIC_ACQUIRE); return __atomic_fetch_add(ptr, 1, __ATOMIC_ACQUIRE);
@ -354,4 +362,15 @@ static inline u32 AtomicFetchSubU32(u32 *ptr, u32 count)
return __atomic_sub_fetch(ptr, count, __ATOMIC_ACQUIRE); return __atomic_sub_fetch(ptr, count, __ATOMIC_ACQUIRE);
} }
static inline b32 AtomicCompareExchangeU32(u32 *ptr, u32 *expected, u32 desired)
{
return __atomic_compare_exchange_n(ptr, expected, desired, true, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
}
static inline b32 AtomicCompareExchangeB32(b32 *ptr, b32 *expected, b32 desired)
{
return __atomic_compare_exchange_n(ptr, expected, desired, true, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
}
*/
// ::Platform::Atomics::Functions::End:: // ::Platform::Atomics::Functions::End::

View File

@ -4,9 +4,17 @@
typedef u32 DescHandle; typedef u32 DescHandle;
// @requirement RenderBuffer type; // @requirement RenderBufferType type
// @requirement u32 size; // @requirement u32 size
// @requirement u32 index
typedef struct RenderBuffer RenderBuffer; typedef struct RenderBuffer RenderBuffer;
// @requirement TextureBufferType type
// @requirement u32 width
// @requirement u32 height
// @requirement u32 index
typedef struct TextureBuffer TextureBuffer;
typedef struct PushConst PushConst; typedef struct PushConst PushConst;
typedef struct ShaderGlobals ShaderGlobals; typedef struct ShaderGlobals ShaderGlobals;
@ -29,13 +37,20 @@ typedef enum PipelineType_e
typedef enum RenderBufferType_e typedef enum RenderBufferType_e
{ {
RENDER_BUFFER_TYPE_NONE = 0x0000, RENDER_BUFFER_TYPE_NONE = 0x0000,
RENDER_BUFFER_TYPE_VERTEX = 0x001, RENDER_BUFFER_TYPE_VERTEX = 0x0001,
RENDER_BUFFER_TYPE_INDEX = 0x002, RENDER_BUFFER_TYPE_INDEX = 0x0002,
RENDER_BUFFER_TYPE_UNIFORM = 0x004, RENDER_BUFFER_TYPE_UNIFORM = 0x0004,
RENDER_BUFFER_TYPE_STAGING = 0x008, RENDER_BUFFER_TYPE_STAGING = 0x0008,
RENDER_BUFFER_TYPE_STORAGE = 0x010, RENDER_BUFFER_TYPE_STORAGE = 0x0010,
} RenderBufferType; } RenderBufferType;
typedef enum TextureBufferType_e
{
IMAGE_BUFFER_TYPE_NONE = 0x0000,
IMAGE_BUFFER_TYPE_IMAGE = 0x0001,
IMAGE_BUFFER_TYPE_SAMPLER = 0x0002,
} TextureBufferType;
typedef enum VertexAttrType_e typedef enum VertexAttrType_e
{ {
VERTEX_ATTRIBUTE_TYPE_VERTEX = 0, VERTEX_ATTRIBUTE_TYPE_VERTEX = 0,
@ -61,8 +76,9 @@ void DestroyRenderer();
static b32 CreateBuffer(RenderBuffer *buffer); static b32 CreateBuffer(RenderBuffer *buffer);
static void FreeBuffers(RenderBuffer *buffers, u32 buffer_count); static void FreeBuffers(RenderBuffer *buffers, u32 buffer_count);
static b32 UploadToBuffer(RenderBuffer **buffer, rawptr *ptr, u32 count, u8 thr_ix); static b32 UploadToBuffer(RenderBuffer **buffer, rawptr *ptr, u32 count, u32 thr_ix);
static void CreateAndUploadToBuffer(RenderBuffer *buffer, rawptr ptr); static void CreateAndUploadToBuffer(RenderBuffer *buffer, rawptr ptr);
static DescHandle CreateAndUploadToTexture(TextureBuffer *buffer, rawptr ptr);
static void BindVertexBuffer(RenderBuffer *buffer); static void BindVertexBuffer(RenderBuffer *buffer);
static void BindIndexBuffer(RenderBuffer *buffer); static void BindIndexBuffer(RenderBuffer *buffer);
static AssetHandle RendererLoadTexture(TextureAsset asset_id); static AssetHandle RendererLoadTexture(TextureAsset asset_id);

View File

@ -319,17 +319,14 @@ static void ResizeSwapchain()
// ::Vulkan::Images::Functions::Start:: // ::Vulkan::Images::Functions::Start::
static b32 CreateVkSampler(Image *image, u32 thread_idx, u8 *buf, u32 width, u32 height) static b32 CreateVkSampler(TextureBuffer *buffer)
{ {
b32 success = true; b32 success = true;
VkDevice device = renderer.vk.device; Image *image = &buffer->image;
VkCommandBuffer cmd = renderer.vk.imm.cmds[thread_idx];
VkFence fence = renderer.vk.imm.fences[thread_idx];
VkQueue queue = renderer.vk.queues.transfer_queue;
RenderBuffer staging_buffer = { RenderBuffer staging_buffer = {
.type = RENDER_BUFFER_TYPE_STAGING, .type = RENDER_BUFFER_TYPE_STAGING,
.size = width * height, .size = buffer->width * buffer->height,
}; };
VmaAllocationCreateInfo alloc_create_info = { VmaAllocationCreateInfo alloc_create_info = {
@ -348,8 +345,8 @@ static b32 CreateVkSampler(Image *image, u32 thread_idx, u8 *buf, u32 width, u32
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE, .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.extent = { .extent = {
.width = width, .width = buffer->width,
.height = height, .height = buffer->height,
.depth = 1, .depth = 1,
}, },
}; };
@ -372,44 +369,7 @@ static b32 CreateVkSampler(Image *image, u32 thread_idx, u8 *buf, u32 width, u32
if (success) if (success)
{ {
image->curr_layout = VK_IMAGE_LAYOUT_UNDEFINED; image->curr_layout = VK_IMAGE_LAYOUT_UNDEFINED;
TransitionImage(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
success = CreateBuffer(&staging_buffer);
}
if (success)
success = BeginImmSubmit(device, fence, cmd);
if (success)
{
rawptr mapped_buf = NULL;
vmaMapMemory(renderer.vk.alloc, staging_buffer.alloc, &mapped_buf);
MemCpy(mapped_buf, buf, width * height);
VkBufferImageCopy buffer_copy = {
.bufferRowLength = width,
.bufferImageHeight = height,
.imageSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.layerCount = 1,
},
.imageExtent = {
.width = width,
.height = height,
.depth = 1,
},
};
vkCmdCopyBufferToImage(cmd, staging_buffer.buffer, image->img, image->curr_layout, 1, &buffer_copy);
vmaUnmapMemory(renderer.vk.alloc, staging_buffer.alloc);
vmaDestroyBuffer(renderer.vk.alloc, staging_buffer.buffer, staging_buffer.alloc);
success = FinishImmSubmit(device, fence, cmd, queue);
}
if (success)
{
VkImageViewCreateInfo view_info = { VkImageViewCreateInfo view_info = {
.sType = STYPE(IMAGE_VIEW_CREATE_INFO), .sType = STYPE(IMAGE_VIEW_CREATE_INFO),
.image = image->img, .image = image->img,
@ -422,7 +382,7 @@ static b32 CreateVkSampler(Image *image, u32 thread_idx, u8 *buf, u32 width, u32
} }
}; };
result = vkCreateImageView(device, &view_info, NULL, &image->view); result = vkCreateImageView(renderer.vk.device, &view_info, NULL, &image->view);
if (result != VK_SUCCESS) if (result != VK_SUCCESS)
success = false; success = false;
} }
@ -447,7 +407,7 @@ static b32 CreateVkSampler(Image *image, u32 thread_idx, u8 *buf, u32 width, u32
.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
}; };
result = vkCreateSampler(device, &sampler_info, NULL, &image->sampler); result = vkCreateSampler(renderer.vk.device, &sampler_info, NULL, &image->sampler);
if (result != VK_SUCCESS) if (result != VK_SUCCESS)
success = false; success = false;
} }
@ -455,6 +415,56 @@ static b32 CreateVkSampler(Image *image, u32 thread_idx, u8 *buf, u32 width, u32
return success; return success;
} }
static void UploadToImage(TextureBuffer *buffer, u8 *data, u32 thread_idx)
{
b32 success = true;
VkDevice device = renderer.vk.device;
VkCommandBuffer cmd = renderer.vk.imm.cmds[thread_idx];
VkFence fence = renderer.vk.imm.fences[thread_idx];
VkQueue queue = renderer.vk.queues.transfer_queue;
Image *image = &buffer->image;
u32 width = buffer->width;
u32 height = buffer->height;
u32 channels = buffer->channels;
RenderBuffer staging_buffer;
TransitionImage(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
success = CreateBuffer(&staging_buffer);
if (success)
success = BeginImmSubmit(device, fence, cmd);
if (success)
{
rawptr mapped_buf = NULL;
vmaMapMemory(renderer.vk.alloc, staging_buffer.alloc, &mapped_buf);
MemCpy(mapped_buf, data, width * height * channels);
VkBufferImageCopy buffer_copy = {
.bufferRowLength = width,
.bufferImageHeight = height,
.imageSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.layerCount = 1,
},
.imageExtent = {
.width = width,
.height = height,
.depth = 1,
},
};
vkCmdCopyBufferToImage(cmd, staging_buffer.buffer, image->img, image->curr_layout, 1, &buffer_copy);
vmaUnmapMemory(renderer.vk.alloc, staging_buffer.alloc);
vmaDestroyBuffer(renderer.vk.alloc, staging_buffer.buffer, staging_buffer.alloc);
success = FinishImmSubmit(device, fence, cmd, queue);
}
}
// ::Vulkan::Images::Functions::End:: // ::Vulkan::Images::Functions::End::
@ -488,6 +498,14 @@ static void DescriptorTableInsert(DescType type, u64 asset_id, DescHandle handle
HashTablePushU64Rawptr(table, asset_id, asset_info); HashTablePushU64Rawptr(table, asset_id, asset_info);
} }
static void DescriptorTableDelete(DescType type, u64 asset_id)
{
HashTable *table = &renderer.vk.pipe.bindings[type].lookup_table;
}
// ::Vulkan::Descriptors::Functions::End:: // ::Vulkan::Descriptors::Functions::End::
@ -971,11 +989,9 @@ static b32 CreateImmediateStructures()
else else
renderer.vk_conf.avail_threads = 0; renderer.vk_conf.avail_threads = 0;
imm->pools = ArenaAlloc(renderer.perm_arena, sizeof(VkCommandPool) * renderer.vk_conf.avail_threads); imm->pools = MakeArray(renderer.perm_arena, VkCommandPool, renderer.vk_conf.avail_threads);
imm->cmds = ArenaAlloc(renderer.perm_arena, sizeof(VkCommandBuffer) * renderer.vk_conf.avail_threads); imm->cmds = MakeArray(renderer.perm_arena, VkCommandBuffer, renderer.vk_conf.avail_threads);
imm->fences = ArenaAlloc(renderer.perm_arena, sizeof(VkFence) * renderer.vk_conf.avail_threads); imm->fences = MakeArray(renderer.perm_arena, VkFence, renderer.vk_conf.avail_threads);
imm->queued_buffers = ArenaAlloc(renderer.perm_arena, sizeof(RenderBuffer) * BUFFER_QUEUE_LEN);
imm->data = ArenaAlloc(renderer.perm_arena, sizeof(void *) * BUFFER_QUEUE_LEN);
for (u32 i = 0; i < renderer.vk_conf.avail_threads && success; i++) for (u32 i = 0; i < renderer.vk_conf.avail_threads && success; i++)
{ {
@ -997,6 +1013,15 @@ static b32 CreateImmediateStructures()
return success; return success;
} }
static void CreateUploadQueues()
{
for (u32 i = 0; i < DESC_TYPE_MAX; i++)
{
renderer.upload_queues[i].queued_ptrs = MakeArray(renderer.perm_arena, rawptr, BUFFER_QUEUE_LEN);
renderer.upload_queues[i].data = MakeArray(renderer.perm_arena, rawptr, BUFFER_QUEUE_LEN);
}
}
static b32 CreateSwapchain() static b32 CreateSwapchain()
{ {
b32 success = true; b32 success = true;
@ -1016,8 +1041,8 @@ static b32 CreateSwapchain()
u32 width = renderer.vk.sc.extent.width; u32 width = renderer.vk.sc.extent.width;
u32 height = renderer.vk.sc.extent.height; u32 height = renderer.vk.sc.extent.height;
extent.width = Clamp((u32)width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width); extent.width = Clampu32((u32)width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
extent.height = Clamp((u32)height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height); extent.height = Clampu32((u32)height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
if (present_mode == INT_MAX || format == INT_MAX || color_space == INT_MAX) if (present_mode == INT_MAX || format == INT_MAX || color_space == INT_MAX)
{ {
@ -1194,7 +1219,7 @@ static b32 CreateDescriptors()
if (result != VK_SUCCESS) if (result != VK_SUCCESS)
success = false; success = false;
for (u32 i = DESC_TYPE_COMBINED_SAMPLER; i < DESC_TYPE_MAX; i++) for (u32 i = DESC_TYPE_SAMPLER; i < DESC_TYPE_MAX; i++)
{ {
bindless_layout_binding.descriptorType = desc_type_map[i]; bindless_layout_binding.descriptorType = desc_type_map[i];
result = vkCreateDescriptorSetLayout(device, &bindless_layout_create_info, NULL, &renderer.vk.pipe.layouts[i]); result = vkCreateDescriptorSetLayout(device, &bindless_layout_create_info, NULL, &renderer.vk.pipe.layouts[i]);
@ -1382,6 +1407,82 @@ static void StartVkLoaderThreads()
// ::Vulkan::Async::Functions::Start:: // ::Vulkan::Async::Functions::Start::
static u32 VkLoaderProcessBuffers(u32 thread_index)
{
JobQueue *job_queue = &renderer.upload_queues[DESC_TYPE_BUFFER].job_queue;
TicketMut *ticket_mut = &renderer.upload_queues[DESC_TYPE_BUFFER].ticket_mut;
RenderBuffer **render_buffers = renderer.upload_queues[DESC_TYPE_BUFFER].queued_buffers;
rawptr *buffer_data = renderer.upload_queues[DESC_TYPE_BUFFER].data;
u32 buffer_count = JobQueueGetCount(job_queue);
u32 count = 0;
if (buffer_count > 0)
{
TicketMutLock(ticket_mut);
RenderBuffer *buffers[16];
rawptr data[16];
for (u32 i = buffer_count; i >= 0 && count < 16; i++)
{
buffers[count] = render_buffers[i];
data[count] = buffer_data[i];
count += 1;
}
JobQueueMarkUnqueued(job_queue, count);
TicketMutUnlock(ticket_mut);
for (u32 i = 0; i < count; i++)
Assert(CreateBuffer(buffers[i]), "VkLoaderProcessBuffers failure: CreateBuffer failed");
Assert(UploadToBuffer(buffers, data, count, thread_index), "VkLoaderProcessBuffers failure: UploadToBuffer failed");
JobQueueMarkCompleted(job_queue, count);
}
return count;
}
static u32 VkLoaderProcessSamplers(u32 thread_index)
{
JobQueue *job_queue = &renderer.upload_queues[DESC_TYPE_SAMPLER].job_queue;
TicketMut *ticket_mut = &renderer.upload_queues[DESC_TYPE_SAMPLER].ticket_mut;
TextureBuffer **texture_buffers = renderer.upload_queues[DESC_TYPE_SAMPLER].queued_textures;
rawptr *texture_data = renderer.upload_queues[DESC_TYPE_SAMPLER].data;
u32 buffer_count = JobQueueGetCount(job_queue);
u32 count = 0;
if (buffer_count > 0)
{
TicketMutLock(ticket_mut);
TextureBuffer *buffers[16];
rawptr data[16];
for (u32 i = buffer_count; i >= 0 && count < 16; i++)
{
buffers[count] = texture_buffers[i];
data[count] = texture_data[i];
count += 1;
}
JobQueueMarkUnqueued(job_queue, count);
TicketMutUnlock(ticket_mut);
for (u32 i = 0; i < count; i++)
{
Assert(CreateVkSampler(buffers[i]), "Unable to create VkSampler");
UploadToImage(buffers[i], data[i], thread_index);
}
JobQueueMarkCompleted(&renderer.vk.imm.texture_queue, count);
}
return count;
}
#ifdef __linux__ #ifdef __linux__
void *VkLoaderStart(void *i) void *VkLoaderStart(void *i)
@ -1391,46 +1492,44 @@ void *VkLoaderStart(void *i)
pthread_mutex_t mut; pthread_mutex_t mut;
pthread_mutex_init(&mut, NULL); pthread_mutex_init(&mut, NULL);
u32 processed_count = 0;
u32 iter_count = 0;
for (;;) for (;;)
{ {
TicketMutLock(&renderer.vk.imm.mut); for (u32 i = 0; i < DESC_TYPE_MAX; i++)
u32 job_count = JobQueueGetCount(&renderer.vk.imm.queue);
if (job_count < 0)
{ {
TicketMutUnlock(&renderer.vk.imm.mut); Mut *mut = &renderer.upload_queues[i].mut;
pthread_exit(NULL); if (MutTryLock(mut))
{
switch (i)
{
case DESC_TYPE_BUFFER:
{
processed_count += VkLoaderProcessBuffers(index);
} break;
case DESC_TYPE_SAMPLER:
{
processed_count += VkLoaderProcessSamplers(index);
} break;
default:
break;
} }
else if (job_count == 0)
MutUnlock(mut);
}
}
iter_count += 1;
if (processed_count < 0)
pthread_exit(NULL);
else if (processed_count == 0 && iter_count >= 3)
{ {
TicketMutUnlock(&renderer.vk.imm.mut); iter_count = 0;
pthread_mutex_lock(&mut); pthread_mutex_lock(&mut);
pthread_cond_wait(&cond, &mut); pthread_cond_wait(&cond, &mut);
pthread_mutex_unlock(&mut); pthread_mutex_unlock(&mut);
} }
else
{
RenderBuffer *buffers[16];
rawptr data[16];
u32 count = 0;
for (u32 i = 0; i < job_count && i < 16; i++)
{
buffers[i] = renderer.vk.imm.queued_buffers[i];
data[i] = renderer.vk.imm.data[i];
count += 1;
}
JobQueueMarkUnqueued(&renderer.vk.imm.queue, count);
TicketMutUnlock(&renderer.vk.imm.mut);
for (u32 i = 0; i < count; i++)
Assert(CreateBuffer(buffers[i]), "VkLoader CreateBuffer failure");
Assert(UploadToBuffer(buffers, data, count, index), "VkLoader UploadToBuffer failure");
JobQueueMarkCompleted(&renderer.vk.imm.queue, count);
}
} }
} }

View File

@ -173,9 +173,10 @@ VK_DECLARE(vkCreateSampler);
typedef enum DescType_e typedef enum DescType_e
{ {
DESC_TYPE_SHARED, DESC_TYPE_SHARED,
DESC_TYPE_COMBINED_SAMPLER, DESC_TYPE_SAMPLER, // DO NOT MOVE FROM POSITION 1 !!
DESC_TYPE_STORAGE_IMAGE, DESC_TYPE_STORAGE_IMAGE,
DESC_TYPE_UNIFORM, DESC_TYPE_UNIFORM,
DESC_TYPE_BUFFER,
DESC_TYPE_MAX, DESC_TYPE_MAX,
} DescType; } DescType;
@ -185,6 +186,26 @@ typedef struct ShaderGlobals
Vec2 res; Vec2 res;
} ShaderGlobals; } ShaderGlobals;
typedef struct Image
{
VkImage img;
VkImageView view;
VkSampler sampler;
VmaAllocation alloc;
VkFormat fmt;
VkImageLayout curr_layout;
} Image;
typedef struct TextureBuffer
{
TextureBufferType type;
Image image;
u32 width;
u32 height;
u32 channels;
u32 index;
} TextureBuffer;
typedef struct RenderBuffer typedef struct RenderBuffer
{ {
RenderBufferType type; RenderBufferType type;
@ -192,7 +213,7 @@ typedef struct RenderBuffer
VmaAllocation alloc; VmaAllocation alloc;
VmaAllocationInfo info; VmaAllocationInfo info;
u32 size; u32 size;
i32 mem_index; // TODO(MA): use this u32 index; // TODO(MA): use this
} RenderBuffer; } RenderBuffer;
typedef struct MeshBuffer typedef struct MeshBuffer
@ -254,15 +275,27 @@ typedef struct FrameStructures
u32 *buffer_counts; u32 *buffer_counts;
} FrameStructures; } FrameStructures;
typedef struct UploadQueue
{
union
{
RenderBuffer **queued_buffers;
TextureBuffer **queued_textures;
rawptr *queued_ptrs;
};
rawptr *data;
TicketMut ticket_mut;
Mut mut;
JobQueue job_queue;
} UploadQueue;
typedef struct ImmediateStructures typedef struct ImmediateStructures
{ {
VkCommandPool *pools; VkCommandPool *pools;
VkCommandBuffer *cmds; VkCommandBuffer *cmds;
VkFence *fences; VkFence *fences;
RenderBuffer **queued_buffers; JobQueue buffer_queue;
rawptr *data; JobQueue texture_queue;
JobQueue queue;
TicketMut mut;
} ImmediateStructures; } ImmediateStructures;
typedef struct DeviceQueues typedef struct DeviceQueues
@ -272,16 +305,6 @@ typedef struct DeviceQueues
b8 single_queue; b8 single_queue;
} DeviceQueues; } DeviceQueues;
typedef struct Image
{
VkImage img;
VkImageView view;
VkSampler sampler;
VmaAllocation alloc;
VkFormat fmt;
VkImageLayout curr_layout;
} Image;
typedef struct SwapchainStructures typedef struct SwapchainStructures
{ {
VkFormat format; VkFormat format;
@ -350,6 +373,7 @@ typedef struct Renderer
PendingUpdates pending; PendingUpdates pending;
Arena *arena; Arena *arena;
Arena *perm_arena; Arena *perm_arena;
UploadQueue upload_queues[DESC_TYPE_MAX];
} Renderer; } Renderer;
// ::Vulkan::Debug::Functions::Header:: // ::Vulkan::Debug::Functions::Header::
@ -384,6 +408,7 @@ static VkFormat GetImageFormat();
static b32 CreateDescriptors(); static b32 CreateDescriptors();
static b32 CreatePipelines(); static b32 CreatePipelines();
static b32 CreateShaderModule(u8 *bytes, u32 len, VkShaderModule *module); static b32 CreateShaderModule(u8 *bytes, u32 len, VkShaderModule *module);
static void CreateUploadQueues();
static void StartVkLoaderThreads(); static void StartVkLoaderThreads();
// ::Vulkan::Util::Functions::Header:: // ::Vulkan::Util::Functions::Header::
@ -409,6 +434,8 @@ static inline void CopyImageToImage(VkCommandBuffer cmd, VkImage src, VkImage ds
#endif #endif
void VkLoaderWake(); void VkLoaderWake();
static u32 VkLoaderProcessBuffers(u32 thread_index);
static u32 VkLoaderProcessSamplers(u32 thread_index);
// ::Vulkan::ImmediateSubmit::Functions::Header:: // ::Vulkan::ImmediateSubmit::Functions::Header::
@ -425,7 +452,8 @@ static void ResizeSwapchain();
// ::Vulkan::Images::Functions::Header:: // ::Vulkan::Images::Functions::Header::
static b32 CreateVkSampler(Image *image, u32 thread_idx, u8 *buf, u32 width, u32 height); static b32 CreateVkSampler(TextureBuffer *buffer);
static void UploadToImage(TextureBuffer *buffer, u8 *data, u32 thread_idx);
// ::Vulkan::Descriptors::Functions::Header:: // ::Vulkan::Descriptors::Functions::Header::

View File

@ -40,6 +40,7 @@ b32 InitRenderer(Arena *arena)
Assert(CreateImmediateStructures(), "Unable to create immediate structures"); Assert(CreateImmediateStructures(), "Unable to create immediate structures");
Assert(CreateDescriptors(), "Unable to initialize descriptors."); Assert(CreateDescriptors(), "Unable to initialize descriptors.");
Assert(CreatePipelines(), "Unable to initialize pipelines."); Assert(CreatePipelines(), "Unable to initialize pipelines.");
CreateUploadQueues();
StartVkLoaderThreads(); StartVkLoaderThreads();
@ -197,7 +198,7 @@ static b32 CreateBuffer(RenderBuffer *buffer)
return success; return success;
} }
static b32 UploadToBuffer(RenderBuffer **buffers, rawptr *ptrs, u32 count, u8 thr_ix) static b32 UploadToBuffer(RenderBuffer **buffers, rawptr *ptrs, u32 count, u32 thr_ix)
{ {
Assert(buffers, "UploadToBuffer: buffer must not be null"); Assert(buffers, "UploadToBuffer: buffer must not be null");
Assert(ptrs, "UploadToBuffer: ptr must not be null"); Assert(ptrs, "UploadToBuffer: ptr must not be null");
@ -257,13 +258,26 @@ static b32 UploadToBuffer(RenderBuffer **buffers, rawptr *ptrs, u32 count, u8 th
static void CreateAndUploadToBuffer(RenderBuffer *buffer, rawptr ptr) static void CreateAndUploadToBuffer(RenderBuffer *buffer, rawptr ptr)
{ {
TicketMutLock(&renderer.vk.imm.mut); TicketMutLock(&renderer.upload_queues[DESC_TYPE_BUFFER].ticket_mut);
u32 job_idx = JobQueueAdd(&renderer.vk.imm.queue, 1); u32 job_idx = JobQueueAdd(&renderer.upload_queues[DESC_TYPE_BUFFER].job_queue, 1);
renderer.vk.imm.queued_buffers[job_idx] = buffer; renderer.upload_queues[DESC_TYPE_BUFFER].queued_buffers[job_idx] = buffer;
renderer.vk.imm.data[job_idx] = ptr; renderer.upload_queues[DESC_TYPE_BUFFER].data[job_idx] = ptr;
TicketMutUnlock(&renderer.vk.imm.mut); TicketMutUnlock(&renderer.upload_queues[DESC_TYPE_BUFFER].ticket_mut);
VkLoaderWake();
}
static DescHandle CreateAndUploadToTexture(TextureBuffer *buffer, rawptr ptr)
{
TicketMutLock(&renderer.upload_queues[DESC_TYPE_SAMPLER].ticket_mut);
u32 job_idx = JobQueueAdd(&renderer.upload_queues[DESC_TYPE_SAMPLER].job_queue, 1);
renderer.upload_queues[DESC_TYPE_SAMPLER].queued_textures[job_idx] = buffer;
renderer.upload_queues[DESC_TYPE_SAMPLER].data[job_idx] = ptr;
TicketMutUnlock(&renderer.upload_queues[DESC_TYPE_SAMPLER].ticket_mut);
VkLoaderWake(); VkLoaderWake();
} }
@ -313,12 +327,14 @@ static AssetHandle RendererLoadTexture(TextureAsset asset_id)
static void WaitForBufferQueue() static void WaitForBufferQueue()
{ {
JobQueueWaitForCompletion(&renderer.vk.imm.queue); JobQueueWaitForCompletion(&renderer.vk.imm.buffer_queue);
JobQueueWaitForCompletion(&renderer.vk.imm.texture_queue);
} }
static void ResetBufferQueue() static void ResetBufferQueue()
{ {
JobQueueReset(&renderer.vk.imm.queue); JobQueueReset(&renderer.vk.imm.texture_queue);
JobQueueReset(&renderer.vk.imm.buffer_queue);
} }
// ::Vulkan::Renderer::Buffers::Functions::End:: // ::Vulkan::Renderer::Buffers::Functions::End::

View File

@ -302,51 +302,62 @@ static inline void EndProfileBlock(ProfileBlock *block)
// ::Util::Async::Functions::Start:: // ::Util::Async::Functions::Start::
static inline b32 MutTryLock(Mut *mut)
{
b32 lock = true;
return AtomicCompareExchangeb32(&mut->lock, &lock, false);
}
static inline void MutUnlock(Mut *mut)
{
AtomicStoreb32(&mut->lock, false);
}
static inline void TicketMutLock(TicketMut *mut) static inline void TicketMutLock(TicketMut *mut)
{ {
u32 ticket = AtomicFetchIncrU32(&mut->ticket); u32 ticket = AtomicFetchIncru32(&mut->ticket);
while (ticket != mut->next_ticket); while (ticket != mut->next_ticket);
} }
static inline void TicketMutUnlock(TicketMut *mut) static inline void TicketMutUnlock(TicketMut *mut)
{ {
AtomicIncrU32(&mut->next_ticket); AtomicIncru32(&mut->next_ticket);
} }
static inline u32 JobQueueAdd(JobQueue *queue, u32 count) static inline u32 JobQueueAdd(JobQueue *queue, u32 count)
{ {
u32 job_idx = AtomicFetchIncrU32(&queue->queued); u32 job_idx = AtomicFetchIncru32(&queue->queued);
AtomicFetchIncrU32(&queue->remaining); AtomicFetchIncru32(&queue->remaining);
return job_idx; return job_idx;
} }
static inline u32 JobQueueGetCount(JobQueue *queue) static inline u32 JobQueueGetCount(JobQueue *queue)
{ {
return AtomicLoadU32(&queue->queued); return AtomicLoadu32(&queue->queued);
} }
static inline void JobQueueMarkUnqueued(JobQueue *queue, u32 count) static inline void JobQueueMarkUnqueued(JobQueue *queue, u32 count)
{ {
AtomicFetchSubU32(&queue->queued, count); AtomicFetchSubu32(&queue->queued, count);
} }
static inline void JobQueueMarkCompleted(JobQueue *queue, u32 count) static inline void JobQueueMarkCompleted(JobQueue *queue, u32 count)
{ {
AtomicFetchSubU32(&queue->remaining, count); AtomicFetchSubu32(&queue->remaining, count);
} }
static inline void JobQueueReset(JobQueue *queue) static inline void JobQueueReset(JobQueue *queue)
{ {
AtomicFetchSubU32(&queue->queued, queue->queued); AtomicFetchSubu32(&queue->queued, queue->queued);
AtomicFetchSubU32(&queue->remaining, queue->remaining); AtomicFetchSubu32(&queue->remaining, queue->remaining);
} }
static inline void JobQueueWaitForCompletion(JobQueue *queue) static inline void JobQueueWaitForCompletion(JobQueue *queue)
{ {
u32 remaining; u32 remaining;
do { do {
remaining = AtomicLoadU32(&queue->remaining); remaining = AtomicLoadu32(&queue->remaining);
} while (remaining != 0); } while (remaining != 0);
} }

View File

@ -48,6 +48,39 @@ typedef struct Arena Arena;
#define cast(T, x) ((T)(x)) #define cast(T, x) ((T)(x))
#define DefScalarSig(def) \
DefSig##def(i8); \
DefSig##def(i16); \
DefSig##def(i32); \
DefSig##def(i64); \
DefSig##def(u8); \
DefSig##def(u16); \
DefSig##def(u32); \
DefSig##def(u64); \
DefSig##def(f32); \
DefSig##def(f64); \
DefSig##def(b8); \
DefSig##def(b32); \
DefSig##def(uintptr); \
DefSig##def(intptr)
#define DefScalarImpl(def) \
Def##def(i8); \
Def##def(i16); \
Def##def(i32); \
Def##def(i64); \
Def##def(u8); \
Def##def(u16); \
Def##def(u32); \
Def##def(u64); \
Def##def(f32); \
Def##def(f64); \
Def##def(b8); \
Def##def(b32); \
Def##def(uintptr); \
Def##def(intptr)
// ::Util::LinkedList::Macros:: // ::Util::LinkedList::Macros::
#define CheckNil(nil, p) ((p) == 0 || (p) == nil) #define CheckNil(nil, p) ((p) == 0 || (p) == nil)
@ -129,49 +162,28 @@ void MemCpy(rawptr dst, rawptr src, usize len);
#define DefMathImpl(def) \ #define DefMathImpl(def) \
DefIntegerImpl(def); \ DefIntegerImpl(def); \
DefFloatImpl(def); DefFloatImpl(def)
#define MathGeneric(fn, params) _Generic(params, \
i8: i8##fn, \
i16: i16##fn, \
i32: i32##fn, \
i64: i64##fn, \
u8: u8##fn, \
u16: u16##fn, \
u32: u32##fn, \
u64: u64##fn, \
f32: f32##fn, \
f64: f64##fn \
)params
#define Min(l, r) MathGeneric(Min, (l, r))
#define Max(l, r) MathGeneric(Max, (l, r))
#define Clamp(v, min, max) MathGeneric(Clamp, (v, min, max))
#define Abs(v) MathGeneric(Abs, (v))
#define DefMin(T) \ #define DefMin(T) \
T T##Min(T l, T r) \ T Min##T(T l, T r) \
{ \ { \
return l < r ? l : r; \ return l < r ? l : r; \
} }
#define DefMax(T) \ #define DefMax(T) \
T T##Max(T l, T r) \ T Max##T(T l, T r) \
{ \ { \
return l > r ? l : r; \ return l > r ? l : r; \
} }
#define DefClamp(T) \ #define DefClamp(T) \
T T##Clamp(T v, T min, T max) \ T Clamp##T(T v, T min, T max) \
{ \ { \
return Min(max, Max(v, min)); \ return Min##T(max, Max##T(v, min)); \
} }
#define DefAbs(T) \ #define DefAbs(T) \
T T##Abs(T v) \ T Abs##T(T v) \
{ \ { \
return v < (T)0 ? -v : v; \ return v < (T)0 ? -v : v; \
} }
@ -242,12 +254,19 @@ typedef struct TicketMut
u32 volatile next_ticket; u32 volatile next_ticket;
} TicketMut; } TicketMut;
typedef struct Mut
{
b32 volatile lock;
} Mut;
typedef struct JobQueue typedef struct JobQueue
{ {
u32 volatile queued; u32 volatile queued;
u32 volatile remaining; u32 volatile remaining;
} JobQueue; } JobQueue;
static inline b32 MutTryLock(Mut *mut);
static inline void MutUnlock(Mut *mut);
static inline void TicketMutLock(TicketMut *mut); static inline void TicketMutLock(TicketMut *mut);
static inline void TicketMutUnlock(TicketMut *mut); static inline void TicketMutUnlock(TicketMut *mut);
static inline u32 JobQueueAdd(JobQueue *queue, u32 count); static inline u32 JobQueueAdd(JobQueue *queue, u32 count);

View File

@ -259,7 +259,7 @@ static VkDescriptorSetLayoutCreateInfo shared_layout_create_info = {
}; };
static VkDescriptorType desc_type_map[DESC_TYPE_MAX] = { static VkDescriptorType desc_type_map[DESC_TYPE_MAX] = {
[DESC_TYPE_COMBINED_SAMPLER] = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, [DESC_TYPE_SAMPLER] = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
[DESC_TYPE_STORAGE_IMAGE] = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, [DESC_TYPE_STORAGE_IMAGE] = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
[DESC_TYPE_UNIFORM] = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, [DESC_TYPE_UNIFORM] = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
}; };