@@ -357,6 +357,12 @@ struct SCGfxContext {
357357 _SCTexData tex_data [SC_GFX_MAX_TEXTURES ];
358358 bool rasterize ; /* if true, software rasterizes quads into framebuffer */
359359
360+ /* Free-list heads for O(1) slot allocation */
361+ u32 buf_free_head ;
362+ u32 tex_free_head ;
363+ u32 shd_free_head ;
364+ u32 pip_free_head ;
365+
360366 /* Submitted draw commands (retained for end_frame) */
361367 SCGfxDrawCmd submit_cmds [SC_GFX_MAX_CMDS ];
362368 u32 submit_ccount ;
@@ -377,15 +383,30 @@ SC_INLINE u8 _sc_f32_to_u8(f32 v) {
377383 return (u8 )(v * 255.0f );
378384}
379385
380- /* ---- ID helpers -------------------------------------------------------- */
381- static u32 _sc_gfx_alloc_slot (_SCSlot * slots , u32 max ) {
382- for (u32 i = 1 ; i < max ; i ++ ) {
383- if (!slots [i ].live ) { slots [i ].live = true; return i ; }
384- }
385- return 0 ;
386+ /* ---- Free-list helpers (O(1) slot alloc/free) ------------------------- */
387+
388+ /* Thread a free-list through the gen field of inactive slots.
389+ gen[slot] = next-free-index, 0 = end-of-list. */
390+ static void _sc_gfx_init_freelist (_SCSlot * slots , u32 max , u32 * head ) {
391+ * head = 1 ;
392+ for (u32 i = 1 ; i < max ; i ++ ) slots [i ].gen = i + 1 ;
393+ slots [max - 1 ].gen = 0 ;
386394}
387- static void _sc_gfx_free_slot (_SCSlot * slots , u32 id ) {
388- if (id > 0 ) { slots [id ].live = false; slots [id ].gen ++ ; }
395+
396+ static u32 _sc_gfx_alloc_slot (_SCSlot * slots , u32 max , u32 * head ) {
397+ (void )max ;
398+ u32 id = * head ;
399+ if (id == 0 ) return 0 ;
400+ * head = slots [id ].gen ;
401+ slots [id ].live = true;
402+ return id ;
403+ }
404+
405+ static void _sc_gfx_free_slot (_SCSlot * slots , u32 id , u32 * head ) {
406+ if (id == 0 ) return ;
407+ slots [id ].live = false;
408+ slots [id ].gen = * head ;
409+ * head = id ;
389410}
390411
391412/* ---- Core API --------------------------------------------------------- */
@@ -400,6 +421,12 @@ SCResult sc_gfx_init(const SCGfxDesc *desc, SCGfxContext **out_ctx) {
400421 ctx -> backend = desc -> backend != SC_BACKEND_AUTO
401422 ? desc -> backend : SC_BACKEND_SOFTWARE ;
402423
424+ /* Initialize free-list slot allocators */
425+ _sc_gfx_init_freelist (ctx -> buf_slots , SC_GFX_MAX_BUFFERS , & ctx -> buf_free_head );
426+ _sc_gfx_init_freelist (ctx -> tex_slots , SC_GFX_MAX_TEXTURES , & ctx -> tex_free_head );
427+ _sc_gfx_init_freelist (ctx -> shd_slots , SC_GFX_MAX_SHADERS , & ctx -> shd_free_head );
428+ _sc_gfx_init_freelist (ctx -> pip_slots , SC_GFX_MAX_PIPELINES , & ctx -> pip_free_head );
429+
403430#ifdef SC_GFX_BACKEND_VULKAN
404431 if (ctx -> backend == SC_BACKEND_VULKAN ) {
405432 SCResult r = sc_vulkan_init (ctx , desc , NULL );
@@ -448,7 +475,7 @@ void sc_gfx_shutdown(SCGfxContext *ctx) {
448475}
449476
450477SCGfxBuffer sc_gfx_make_buffer (SCGfxContext * ctx , const SCGfxBufferDesc * desc ) {
451- u32 id = _sc_gfx_alloc_slot (ctx -> buf_slots , SC_GFX_MAX_BUFFERS );
478+ u32 id = _sc_gfx_alloc_slot (ctx -> buf_slots , SC_GFX_MAX_BUFFERS , & ctx -> buf_free_head );
452479 SCGfxBuffer h = {id };
453480 if (id == 0 ) return h ;
454481#ifdef SC_GFX_BACKEND_VULKAN
@@ -464,7 +491,7 @@ SCGfxBuffer sc_gfx_make_buffer(SCGfxContext *ctx, const SCGfxBufferDesc *desc) {
464491 if (desc -> data && desc -> size > 0 ) {
465492 bd -> data = (u8 * )malloc (desc -> size );
466493 if (!bd -> data ) {
467- _sc_gfx_free_slot (ctx -> buf_slots , id );
494+ _sc_gfx_free_slot (ctx -> buf_slots , id , & ctx -> buf_free_head );
468495 h .id = 0 ;
469496 return h ;
470497 }
@@ -508,7 +535,7 @@ void sc_gfx_destroy_buffer(SCGfxContext *ctx, SCGfxBuffer buf) {
508535 free (ctx -> buf_data [buf .id ].data );
509536 ctx -> buf_data [buf .id ].data = NULL ;
510537 }
511- _sc_gfx_free_slot (ctx -> buf_slots , buf .id );
538+ _sc_gfx_free_slot (ctx -> buf_slots , buf .id , & ctx -> buf_free_head );
512539}
513540
514541SCGfxTexture sc_gfx_make_texture (SCGfxContext * ctx , const SCGfxTextureDesc * desc ) {
@@ -517,7 +544,7 @@ SCGfxTexture sc_gfx_make_texture(SCGfxContext *ctx, const SCGfxTextureDesc *desc
517544 return sc_vulkan_make_texture (ctx , desc );
518545 }
519546#endif
520- u32 id = _sc_gfx_alloc_slot (ctx -> tex_slots , SC_GFX_MAX_TEXTURES );
547+ u32 id = _sc_gfx_alloc_slot (ctx -> tex_slots , SC_GFX_MAX_TEXTURES , & ctx -> tex_free_head );
521548 SCGfxTexture h = {id };
522549 if (id == 0 ) return h ;
523550 if (ctx -> backend == SC_BACKEND_SOFTWARE && desc ) {
@@ -529,7 +556,7 @@ SCGfxTexture sc_gfx_make_texture(SCGfxContext *ctx, const SCGfxTextureDesc *desc
529556 usize sz = (usize )desc -> width * (usize )desc -> height * bpp ;
530557 td -> pixels = (u8 * )malloc (sz );
531558 if (!td -> pixels ) {
532- _sc_gfx_free_slot (ctx -> tex_slots , id );
559+ _sc_gfx_free_slot (ctx -> tex_slots , id , & ctx -> tex_free_head );
533560 h .id = 0 ;
534561 return h ;
535562 }
@@ -567,19 +594,19 @@ void sc_gfx_destroy_texture(SCGfxContext *ctx, SCGfxTexture tex) {
567594#ifdef SC_GFX_BACKEND_VULKAN
568595 if (ctx -> backend == SC_BACKEND_VULKAN ) {
569596 sc_vulkan_destroy_texture (ctx , tex );
570- _sc_gfx_free_slot (ctx -> tex_slots , tex .id );
597+ _sc_gfx_free_slot (ctx -> tex_slots , tex .id , & ctx -> tex_free_head );
571598 return ;
572599 }
573600#endif
574601 if (ctx -> backend == SC_BACKEND_SOFTWARE ) {
575602 free (ctx -> tex_data [tex .id ].pixels );
576603 ctx -> tex_data [tex .id ].pixels = NULL ;
577604 }
578- _sc_gfx_free_slot (ctx -> tex_slots , tex .id );
605+ _sc_gfx_free_slot (ctx -> tex_slots , tex .id , & ctx -> tex_free_head );
579606}
580607
581608SCGfxShader sc_gfx_make_shader (SCGfxContext * ctx , const SCGfxShaderDesc * desc ) {
582- u32 id = _sc_gfx_alloc_slot (ctx -> shd_slots , SC_GFX_MAX_SHADERS );
609+ u32 id = _sc_gfx_alloc_slot (ctx -> shd_slots , SC_GFX_MAX_SHADERS , & ctx -> shd_free_head );
583610 SCGfxShader h = {id };
584611 if (id == 0 ) return h ;
585612#ifdef SC_GFX_BACKEND_VULKAN
@@ -600,11 +627,11 @@ void sc_gfx_destroy_shader(SCGfxContext *ctx, SCGfxShader shd) {
600627 return ;
601628 }
602629#endif
603- _sc_gfx_free_slot (ctx -> shd_slots , shd .id );
630+ _sc_gfx_free_slot (ctx -> shd_slots , shd .id , & ctx -> shd_free_head );
604631}
605632
606633SCGfxPipeline sc_gfx_make_pipeline (SCGfxContext * ctx , const SCGfxPipelineDesc * desc ) {
607- u32 id = _sc_gfx_alloc_slot (ctx -> pip_slots , SC_GFX_MAX_PIPELINES );
634+ u32 id = _sc_gfx_alloc_slot (ctx -> pip_slots , SC_GFX_MAX_PIPELINES , & ctx -> pip_free_head );
608635 SCGfxPipeline h = {id };
609636 if (id == 0 ) return h ;
610637#ifdef SC_GFX_BACKEND_VULKAN
@@ -625,7 +652,7 @@ void sc_gfx_destroy_pipeline(SCGfxContext *ctx, SCGfxPipeline pip) {
625652 return ;
626653 }
627654#endif
628- _sc_gfx_free_slot (ctx -> pip_slots , pip .id );
655+ _sc_gfx_free_slot (ctx -> pip_slots , pip .id , & ctx -> pip_free_head );
629656}
630657
631658void sc_gfx_begin_frame (SCGfxContext * ctx , SCColor c ) {
0 commit comments