Skip to content

Instantly share code, notes, and snippets.

@pollend
Created May 10, 2025 15:55
Show Gist options
  • Save pollend/6b8ac571b90377035fe297a769700a0c to your computer and use it in GitHub Desktop.
Save pollend/6b8ac571b90377035fe297a769700a0c to your computer and use it in GitHub Desktop.
#include "graphics/RIDescriptorSetAllocator.h"
#include "system/stb_ds.h"
#include <cassert>
struct RIDescriptorSetSlot *AllocDescriptorsetSlot( struct RIDescriptorSetAlloc *alloc )
{
if( alloc->blocks == NULL || alloc->blockIndex == RESERVE_BLOCK_SIZE ) {
struct RIDescriptorSetSlot *block = (struct RIDescriptorSetSlot*)calloc( RESERVE_BLOCK_SIZE, sizeof( struct RIDescriptorSetSlot ) );
alloc->blockIndex = 0;
arrpush( alloc->blocks, block );
return block + ( alloc->blockIndex++ );
}
return alloc->blocks[arrlen( alloc->blocks ) - 1] + ( alloc->blockIndex++ );
}
void AttachDescriptorSlot( struct RIDescriptorSetAlloc *alloc, struct RIDescriptorSetSlot *slot )
{
assert( slot );
{
slot->quNext = NULL;
slot->quPrev = alloc->queueEnd;
if( alloc->queueEnd ) {
alloc->queueEnd->quNext = slot;
}
alloc->queueEnd = slot;
if( !alloc->queueBegin ) {
alloc->queueBegin = slot;
}
}
{
const size_t hashIndex = slot->hash % ALLOC_HASH_RESERVE;
slot->hPrev = NULL;
slot->hNext = NULL;
if( alloc->hashSlots[hashIndex] ) {
alloc->hashSlots[hashIndex]->hPrev = slot;
slot->hNext = alloc->hashSlots[hashIndex];
}
alloc->hashSlots[hashIndex] = slot;
}
}
void DetachDescriptorSlot( struct RIDescriptorSetAlloc *alloc, struct RIDescriptorSetSlot *slot )
{
assert( slot );
// remove from queue
{
if( alloc->queueBegin == slot ) {
alloc->queueBegin = slot->quNext;
if( slot->quNext ) {
slot->quNext->quPrev = NULL;
}
} else if( alloc->queueEnd == slot ) {
alloc->queueEnd = slot->quPrev;
if( slot->quPrev ) {
slot->quPrev->quNext = NULL;
}
} else {
if( slot->quPrev ) {
slot->quPrev->quNext = slot->quNext;
}
if( slot->quNext ) {
slot->quNext->quPrev = slot->quPrev;
}
}
}
// free from hashTable
{
const size_t hashIndex = slot->hash % ALLOC_HASH_RESERVE;
if( alloc->hashSlots[hashIndex] == slot ) {
alloc->hashSlots[hashIndex] = slot->hNext;
if( slot->hNext ) {
slot->hPrev = NULL;
}
} else {
if( slot->hPrev ) {
slot->hPrev->hNext = slot->hNext;
}
if( slot->hNext ) {
slot->hNext->hPrev = slot->hPrev;
}
}
}
}
struct RIDescriptorSetResult ResolveDescriptorSet( struct RIDevice_s *device, struct RIDescriptorSetAlloc *alloc, uint32_t frameCount, uint32_t hash )
{
struct RIDescriptorSetResult result = { 0 };
const size_t hashIndex = hash % ALLOC_HASH_RESERVE;
for( struct RIDescriptorSetSlot *c = alloc->hashSlots[hashIndex]; c; c = c->hNext ) {
if( c->hash == hash ) {
if( alloc->queueEnd == c ) {
// already at the end of the queue
} else if (alloc->queueBegin == c) {
alloc->queueBegin = c->quNext;
if( c->quNext ) {
c->quNext->quPrev = NULL;
}
} else {
if( c->quPrev ) {
c->quPrev->quNext = c->quNext;
}
if( c->quNext ) {
c->quNext->quPrev = c->quPrev;
}
}
c->quNext = NULL;
c->quPrev = alloc->queueEnd;
if( alloc->queueEnd ) {
alloc->queueEnd->quNext = c;
}
alloc->queueEnd = c;
c->frameCount = frameCount;
result.set = c;
result.found = true;
assert(result.set);
return result;
}
}
if( alloc->queueBegin && frameCount > alloc->queueBegin->frameCount + alloc->framesInFlight) {
struct RIDescriptorSetSlot *slot = alloc->queueBegin;
DetachDescriptorSlot( alloc, slot );
slot->frameCount = frameCount;
slot->hash = hash;
AttachDescriptorSlot( alloc, slot );
result.set = slot;
result.found = false;
assert(result.set);
return result;
}
if( arrlen( alloc->reservedSlots ) == 0 ) {
alloc->descriptorAllocator(device, alloc);
assert(arrlen(alloc->reservedSlots) > 0); // we didn't reserve any slots ...
}
struct RIDescriptorSetSlot *slot = arrpop( alloc->reservedSlots );
slot->hash = hash;
slot->frameCount = frameCount;
AttachDescriptorSlot( alloc, slot );
result.set = slot;
result.found = false;
assert(result.set);
return result;
}
void FreeDescriptorSetAlloc( struct RIDevice_s *device, struct RIDescriptorSetAlloc *alloc )
{
#if ( DEVICE_IMPL_VULKAN )
for( size_t i = 0; i < arrlen( alloc->blocks ); i++ ) {
// TODO: do i need to free indivudal descriptor sets or can i just free the entire pool
// for(size_t blockIdx = 0; blockIdx < RESERVE_BLOCK_SIZE; blockIdx++) {
// vkFreeDescriptorSets(device->vk.device, alloc->blocks[i]->vk.pool, )
//}
free( alloc->blocks[i] );
}
arrfree( alloc->blocks );
for( size_t i = 0; i < arrlen( alloc->pools ); i++ ) {
vkDestroyDescriptorPool( device->vk.device, alloc->pools[i].vk.handle, NULL );
}
arrfree( alloc->pools );
#endif
}
#ifndef R_DESCRIPTOR_POOL_H
#define R_DESCRIPTOR_POOL_H
#include <cstddef>
#include <stdint.h>
#include "graphics/RITypes.h"
#define RESERVE_BLOCK_SIZE 1024
#define ALLOC_HASH_RESERVE 256
#define DESCRIPTOR_MAX_SIZE 64
#define DESCRIPTOR_RESERVED_SIZE 64
struct RIDescriptorSetSlot {
uint32_t hash;
uint32_t frameCount;
// queue
struct RIDescriptorSetSlot *quNext;
struct RIDescriptorSetSlot *quPrev;
// hash
struct RIDescriptorSetSlot *hNext;
struct RIDescriptorSetSlot *hPrev;
union {
#if ( DEVICE_IMPL_VULKAN )
struct {
VkDescriptorPool pool;
VkDescriptorSet handle;
} vk;
#endif
};
};
struct RIDescriptorPoolAllocSlot {
union {
#if ( DEVICE_IMPL_VULKAN )
struct {
VkDescriptorPool handle;
} vk;
#endif
};
};
struct RIDescriptorSetAlloc;
typedef void ( *RIDescriptorSetAlloc_Create )( struct RIDevice_s *device, struct RIDescriptorSetAlloc *alloc );
struct RIDescriptorSetAlloc {
RIDescriptorSetAlloc_Create descriptorAllocator;
uint8_t framesInFlight; // the number of frames in flight
struct RIDescriptorSetSlot *hashSlots[ALLOC_HASH_RESERVE];
struct RIDescriptorSetSlot *queueBegin;
struct RIDescriptorSetSlot *queueEnd;
struct RIDescriptorSetSlot **reservedSlots; // stb arrays
struct RIDescriptorPoolAllocSlot* pools; // stb arrays
struct RIDescriptorSetSlot **blocks;
size_t blockIndex;
};
struct RIDescriptorSetResult {
bool found;
struct RIDescriptorSetSlot *set; // the associated slot
};
struct RIDescriptorSetResult ResolveDescriptorSet( struct RIDevice_s *device,
struct RIDescriptorSetAlloc *alloc,
uint32_t frameCount,
uint32_t hash );
void FreeDescriptorSetAlloc( struct RIDevice_s *device, struct RIDescriptorSetAlloc *alloc );
// utility
struct RIDescriptorSetSlot *AllocDescriptorsetSlot( struct RIDescriptorSetAlloc *alloc );
void AttachDescriptorSlot( struct RIDescriptorSetAlloc *alloc, struct RIDescriptorSetSlot *slot );
void DetachDescriptorSlot( struct RIDescriptorSetAlloc *alloc, struct RIDescriptorSetSlot *slot );
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment