work on asset loading queues

This commit is contained in:
Matthew 2025-04-25 18:48:31 +10:00
parent 72e1b91e2a
commit fee5f311f2
11 changed files with 115 additions and 66 deletions

View File

@ -434,9 +434,15 @@ static void HashTableInit(HashTable *table, u32 init_size)
{
table->cap = init_size;
table->count = 0;
table->lists = FLMemAlloc(sizeof(HashList) * init_size);
table->free_lists.first = P_HT_NIL;
table->free_lists.last = P_HT_NIL;
table->lists = FLMemAlloc(sizeof(HashList) * init_size);
for (u32 i = 0; i < init_size; i++)
{
table->lists[i].first = P_HT_NIL;
table->lists[i].last = P_HT_NIL;
}
}
static void HashTableConcatInPlace(HashList *list, HashList *to_concat)
@ -561,7 +567,7 @@ static void HashTableDeleteU64(HashTable *table, u64 key)
node->v.key_u64 = 0;
node->v.value_u64 = 0;
HTQueuePush(ht->free_lists.first, ht->free_lists.last, node);
HTQueuePush(table->free_lists.first, table->free_lists.last, node);
break;
}
}

View File

@ -72,6 +72,7 @@ static void RunCycle(GameContext *ctx, GameInput *inputs, u32 i_count)
GetViewportSize(&ctx->pc.res);
//DescHandle pattermon = CreateAndUploadToTexture(PATTERMON_OBESE);
RenderBuffer *vertex_buffer = MakeArray(ctx->arena, RenderBuffer, 1);
vertex_buffer->type = RENDER_BUFFER_TYPE_VERTEX;

View File

@ -78,7 +78,7 @@ static inline u64 ReadCPUTimer();
#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)
#define DefSigAtomicCompareExchange(T) static inline b32 AtomicCompareExchange##T(T *ptr, T *expected, T desired)
DefScalarSig(AtomicFetchIncr);
DefScalarSig(AtomicFetchSub);

View File

@ -46,9 +46,9 @@ typedef enum RenderBufferType_e
typedef enum TextureBufferType_e
{
IMAGE_BUFFER_TYPE_NONE = 0x0000,
IMAGE_BUFFER_TYPE_IMAGE = 0x0001,
IMAGE_BUFFER_TYPE_SAMPLER = 0x0002,
TEXTURE_BUFFER_TYPE_NONE = 0x0000,
TEXTURE_BUFFER_TYPE_IMAGE = 0x0001,
TEXTURE_BUFFER_TYPE_SAMPLER = 0x0002,
} TextureBufferType;
typedef enum VertexAttrType_e
@ -78,7 +78,7 @@ static b32 CreateBuffer(RenderBuffer *buffer);
static void FreeBuffers(RenderBuffer *buffers, u32 buffer_count);
static b32 UploadToBuffer(RenderBuffer **buffer, rawptr *ptr, u32 count, u32 thr_ix);
static void CreateAndUploadToBuffer(RenderBuffer *buffer, rawptr ptr);
static DescHandle CreateAndUploadToTexture(TextureBuffer *buffer, rawptr ptr);
static DescHandle CreateAndUploadToTexture(TextureAsset asset_id);
static void BindVertexBuffer(RenderBuffer *buffer);
static void BindIndexBuffer(RenderBuffer *buffer);
static AssetHandle RendererLoadTexture(TextureAsset asset_id);

View File

@ -344,6 +344,7 @@ static b32 CreateVkSampler(TextureBuffer *buffer)
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.samples = VK_SAMPLE_COUNT_1_BIT,
.extent = {
.width = buffer->width,
.height = buffer->height,
@ -427,14 +428,17 @@ static void UploadToImage(TextureBuffer *buffer, u8 *data, u32 thread_idx)
u32 width = buffer->width;
u32 height = buffer->height;
u32 channels = buffer->channels;
RenderBuffer staging_buffer;
RenderBuffer staging_buffer = {
.type = RENDER_BUFFER_TYPE_STAGING,
.size = width * height * channels,
};
TransitionImage(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
success = CreateBuffer(&staging_buffer);
success = BeginImmSubmit(device, fence, cmd);
if (success)
success = BeginImmSubmit(device, fence, cmd);
Assert(CreateBuffer(&staging_buffer), "UploadToImage failure: error creating buffer");
if (success)
{
@ -471,6 +475,26 @@ static void UploadToImage(TextureBuffer *buffer, u8 *data, u32 thread_idx)
// ::Vulkan::Descriptors::Functions::Start::
static void DescriptorHandlePush(DescType type, DescHandle handle)
{
DescBindings *bindings = renderer.vk.pipe.bindings + type;
Assert(bindings->free_count < DESC_MAX_BINDINGS-1, "DescriptorHandlePush failure: free_count equal to DESC_MAX_BINDINGS-1");
bindings->free[bindings->free_count] = handle;
bindings->free_count += 1;
}
static DescHandle DescriptorHandlePop(DescType type)
{
DescBindings *bindings = renderer.vk.pipe.bindings + type;
Assert(bindings->free_count > 0, "DescriptorHandlePop failure: free_count is 0");
bindings->free_count -= 1;
return bindings->free[bindings->free_count];
}
static DescAssetInfo *DescriptorTableSearch(DescType type, u64 asset_id)
{
DescAssetInfo *asset_info = NULL;
@ -501,9 +525,7 @@ static void DescriptorTableInsert(DescType type, u64 asset_id, DescHandle handle
static void DescriptorTableDelete(DescType type, u64 asset_id)
{
HashTable *table = &renderer.vk.pipe.bindings[type].lookup_table;
HashTableDeleteU64(table, asset_id);
}
// ::Vulkan::Descriptors::Functions::End::
@ -657,6 +679,7 @@ static b32 CheckDeviceFeatureSupport(VkPhysicalDevice device)
result &= (b32)features.shaderSampledImageArrayDynamicIndexing;
result &= (b32)features.shaderStorageBufferArrayDynamicIndexing;
result &= (b32)features.shaderStorageImageArrayDynamicIndexing;
result &= (b32)features.samplerAnisotropy;
result &= (b32)features_12.descriptorIndexing;
result &= (b32)features_12.bufferDeviceAddress;
@ -1243,12 +1266,11 @@ static b32 CreateDescriptors()
for (u32 i = 0; i < DESC_TYPE_MAX; i++)
{
bindings[i].free = ArenaAlloc(renderer.perm_arena, sizeof(u16) * DESC_MAX_BINDINGS);
bindings[i].used = ArenaAlloc(renderer.perm_arena, sizeof(u16) * DESC_MAX_BINDINGS);
bindings[i].free = ArenaAlloc(renderer.perm_arena, sizeof(u32) * DESC_MAX_BINDINGS);
HashTableInit(&bindings[i].lookup_table, 6);
u16 free_count = 0;
u32 free_count = 0;
for (i32 j = DESC_MAX_BINDINGS-1; j >= 0; j--)
{
bindings[i].free[j] = free_count++;
@ -1422,7 +1444,7 @@ static u32 VkLoaderProcessBuffers(u32 thread_index)
RenderBuffer *buffers[16];
rawptr data[16];
for (u32 i = buffer_count; i >= 0 && count < 16; i++)
for (i32 i = i32(buffer_count - 1); i >= 0 && count < 16; i--)
{
buffers[count] = render_buffers[i];
data[count] = buffer_data[i];
@ -1459,7 +1481,7 @@ static u32 VkLoaderProcessSamplers(u32 thread_index)
TextureBuffer *buffers[16];
rawptr data[16];
for (u32 i = buffer_count; i >= 0 && count < 16; i++)
for (i32 i = i32(buffer_count - 1); i >= 0 && count < 16; i--)
{
buffers[count] = texture_buffers[i];
data[count] = texture_data[i];
@ -1476,7 +1498,12 @@ static u32 VkLoaderProcessSamplers(u32 thread_index)
UploadToImage(buffers[i], data[i], thread_index);
}
JobQueueMarkCompleted(&renderer.vk.imm.texture_queue, count);
JobQueueMarkCompleted(job_queue, count);
for (u32 i = 0; i < count; i++)
{
FLMemFree(buffers[i]);
}
}
return count;
@ -1526,9 +1553,11 @@ void *VkLoaderStart(void *i)
else if (processed_count == 0 && iter_count >= 3)
{
iter_count = 0;
AtomicIncru8(&renderer.vk_conf.sleeping_threads);
pthread_mutex_lock(&mut);
pthread_cond_wait(&cond, &mut);
pthread_mutex_unlock(&mut);
AtomicFetchSubu8(&renderer.vk_conf.sleeping_threads, 1);
}
}
}

View File

@ -240,10 +240,8 @@ typedef struct DescAssetInfo
typedef struct DescBindings
{
u16 *free;
u16 free_count;
u16 *used;
u16 used_count;
u32 *free;
u32 free_count;
HashTable lookup_table;
} DescBindings;
@ -294,8 +292,6 @@ typedef struct ImmediateStructures
VkCommandPool *pools;
VkCommandBuffer *cmds;
VkFence *fences;
JobQueue buffer_queue;
JobQueue texture_queue;
} ImmediateStructures;
typedef struct DeviceQueues
@ -358,6 +354,7 @@ typedef struct PendingUpdates
typedef struct VulkanConfig
{
u8 avail_threads;
u8 volatile sleeping_threads;
#ifdef __linux__
pthread_t *threads;
#elif _WIN32
@ -457,7 +454,10 @@ static void UploadToImage(TextureBuffer *buffer, u8 *data, u32 thread_idx);
// ::Vulkan::Descriptors::Functions::Header::
static void DescriptorHandlePush(DescType type, DescHandle handle);
static DescHandle DescriptorHandlePop(DescType type);
static DescAssetInfo *DescriptorTableSearch(DescType type, u64 asset_id);
static void DescriptorTableDelete(DescType type, u64 asset_id);
// ::Vulkan::CleanUp::Functions::Header::

View File

@ -269,18 +269,40 @@ static void CreateAndUploadToBuffer(RenderBuffer *buffer, rawptr ptr)
VkLoaderWake();
}
static DescHandle CreateAndUploadToTexture(TextureBuffer *buffer, rawptr ptr)
static DescHandle CreateAndUploadToTexture(TextureAsset asset_id)
{
DescHandle handle = 0;
DescAssetInfo *info = DescriptorTableSearch(DESC_TYPE_SAMPLER, asset_id);
if (info == NULL)
{
Asset asset = AssetPackLoadTexture(asset_id);
TextureBuffer *buffer = FLMemAlloc(sizeof(TextureBuffer));
buffer->type = TEXTURE_BUFFER_TYPE_SAMPLER;
buffer->width = asset.texture_meta.w;
buffer->height = asset.texture_meta.h;
buffer->channels = asset.texture_meta.ch;
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;
renderer.upload_queues[DESC_TYPE_SAMPLER].data[job_idx] = asset.bytes;
handle = DescriptorHandlePop(DESC_TYPE_SAMPLER);
TicketMutUnlock(&renderer.upload_queues[DESC_TYPE_SAMPLER].ticket_mut);
VkLoaderWake();
}
else
{
handle = info->handle;
}
return handle;
}
static void FreeBuffers(RenderBuffer *buffers, u32 buffer_count)
{
@ -327,14 +349,22 @@ static AssetHandle RendererLoadTexture(TextureAsset asset_id)
static void WaitForBufferQueue()
{
JobQueueWaitForCompletion(&renderer.vk.imm.buffer_queue);
JobQueueWaitForCompletion(&renderer.vk.imm.texture_queue);
for (u32 i = 0; i < DESC_TYPE_MAX; i++)
{
while (!JobQueueCompleted(&renderer.upload_queues[DESC_TYPE_BUFFER].job_queue))
{
if (renderer.vk_conf.sleeping_threads > 0)
VkLoaderWake();
}
}
}
static void ResetBufferQueue()
{
JobQueueReset(&renderer.vk.imm.texture_queue);
JobQueueReset(&renderer.vk.imm.buffer_queue);
for (u32 i = 0; i < DESC_TYPE_MAX; i++)
{
JobQueueReset(&renderer.upload_queues[i].job_queue);
}
}
// ::Vulkan::Renderer::Buffers::Functions::End::

View File

@ -304,13 +304,13 @@ static inline void EndProfileBlock(ProfileBlock *block)
static inline b32 MutTryLock(Mut *mut)
{
b32 lock = true;
return AtomicCompareExchangeb32(&mut->lock, &lock, false);
b32 lock = false;
return AtomicCompareExchangeb32(&mut->lock, &lock, 1);
}
static inline void MutUnlock(Mut *mut)
{
AtomicStoreb32(&mut->lock, false);
AtomicStoreb32(&mut->lock, 0);
}
static inline void TicketMutLock(TicketMut *mut)
@ -353,12 +353,10 @@ static inline void JobQueueReset(JobQueue *queue)
AtomicFetchSubu32(&queue->remaining, queue->remaining);
}
static inline void JobQueueWaitForCompletion(JobQueue *queue)
static inline b32 JobQueueCompleted(JobQueue *queue)
{
u32 remaining;
do {
remaining = AtomicLoadu32(&queue->remaining);
} while (remaining != 0);
u32 remaining = AtomicLoadu32(&queue->remaining);
return remaining == 0;
}
// ::Util::Async::Functions::End::

View File

@ -57,12 +57,8 @@ typedef struct Arena Arena;
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)
DefSig##def(b32)
#define DefScalarImpl(def) \
Def##def(i8); \
@ -73,12 +69,8 @@ typedef struct Arena Arena;
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)
Def##def(b32)
// ::Util::LinkedList::Macros::
@ -273,4 +265,4 @@ static inline u32 JobQueueAdd(JobQueue *queue, u32 count);
static inline void JobQueueMarkUnqueued(JobQueue *queue, u32 count);
static inline void JobQueueMarkCompleted(JobQueue *queue, u32 count);
static inline void JobQueueReset(JobQueue *queue);
static inline void JobQueueWaitForCompletion(JobQueue *queue);
static inline b32 JobQueueCompleted(JobQueue *queue);

View File

@ -88,14 +88,6 @@ static VkPhysicalDeviceVulkan11Features vk_11_features = {
.pNext = &vk_12_features
};
static const VkPhysicalDeviceFeatures vk_features = {
.shaderUniformBufferArrayDynamicIndexing = VK_TRUE,
.shaderSampledImageArrayDynamicIndexing = VK_TRUE,
.shaderStorageBufferArrayDynamicIndexing = VK_TRUE,
.shaderStorageImageArrayDynamicIndexing = VK_TRUE,
.samplerAnisotropy = VK_TRUE,
};
static const VkPhysicalDeviceFeatures2 vk_features_2 = {
.sType = STYPE(PHYSICAL_DEVICE_FEATURES_2),
.pNext = &vk_11_features,
@ -103,7 +95,8 @@ static const VkPhysicalDeviceFeatures2 vk_features_2 = {
.shaderUniformBufferArrayDynamicIndexing = VK_TRUE,
.shaderSampledImageArrayDynamicIndexing = VK_TRUE,
.shaderStorageBufferArrayDynamicIndexing = VK_TRUE,
.shaderStorageImageArrayDynamicIndexing = VK_TRUE
.shaderStorageImageArrayDynamicIndexing = VK_TRUE,
.samplerAnisotropy = VK_TRUE,
},
};