[graphics] use a single handle arena for all graphics subsystem handles

This commit is contained in:
Martin Fouilleul 2023-02-28 20:33:55 +01:00
parent 5a19c03ad6
commit 6bf989564d
3 changed files with 120 additions and 212 deletions

View File

@ -183,7 +183,7 @@ mg_surface mg_egl_surface_create_for_window(mp_window window)
eglSwapInterval(surface->eglDisplay, 1);
res = mg_surface_alloc_handle((mg_surface_data*)surface);
res = mg_surface_handle_alloc((mg_surface_data*)surface);
}
return(res);
}

View File

@ -154,43 +154,31 @@ typedef struct mg_font_data
typedef struct mg_canvas_data mg_canvas_data;
typedef struct mg_image_data mg_image_data;
typedef struct mg_resource_slot
typedef enum mg_handle_kind
{
MG_HANDLE_NONE = 0,
MG_HANDLE_SURFACE,
MG_HANDLE_CANVAS,
MG_HANDLE_FONT,
MG_HANDLE_IMAGE,
} mg_handle_kind;
typedef struct mg_handle_slot
{
list_elt freeListElt;
u32 generation;
union
{
mg_surface_data* surface;
mg_image_data* image;
mg_canvas_data* canvas;
mg_font_data* font;
//...
};
mg_handle_kind kind;
} mg_resource_slot;
void* data;
enum
{
MG_MAX_RESOURCE_SLOTS = 128,
//...
};
typedef struct mg_resource_pool
{
mg_resource_slot slots[MG_MAX_RESOURCE_SLOTS];
list_info freeList;
u32 nextIndex;
} mg_resource_pool;
} mg_handle_slot;
typedef struct mg_data
{
bool init;
mg_resource_pool surfaces;
mg_resource_pool canvases;
mg_resource_pool fonts;
//...
mem_arena handleArena;
list_info handleFreeList;
} mg_data;
@ -218,8 +206,6 @@ typedef struct mg_canvas_data
u32 primitiveCount;
mg_primitive primitives[MG_MAX_PRIMITIVE_COUNT];
mg_resource_pool imagePool;
/*
vec2 atlasPos;
u32 atlasLineHeight;
@ -248,7 +234,9 @@ void mg_init()
{
if(!__mgData.init)
{
mem_arena_init(&__mgData.handleArena);
__mgData.init = true;
//...
}
}
@ -257,199 +245,120 @@ void mg_init()
// handle pools procedures
//------------------------------------------------------------------------
mg_resource_slot* mg_resource_slot_alloc(mg_resource_pool* pool)
u64 mg_handle_alloc(mg_handle_kind kind, void* data)
{
if(!__mgData.init)
{
//TODO: see if we require an init at all, and if we want to make it explicit to the user
mg_init();
}
mem_arena* arena = &__mgData.handleArena;
mg_resource_slot* slot = ListPopEntry(&pool->freeList, mg_resource_slot, freeListElt);
if(!slot && pool->nextIndex < MG_MAX_RESOURCE_SLOTS)
mg_handle_slot* slot = ListPopEntry(&__mgData.handleFreeList, mg_handle_slot, freeListElt);
if(!slot)
{
slot = &pool->slots[pool->nextIndex];
slot = mem_arena_alloc_type(arena, mg_handle_slot);
DEBUG_ASSERT(slot);
slot->generation = 1;
pool->nextIndex++;
}
return(slot);
}
slot->kind = kind;
slot->data = data;
void mg_resource_slot_recycle(mg_resource_pool* pool, mg_resource_slot* slot)
{
DEBUG_ASSERT(slot >= pool->slots && slot < pool->slots + MG_MAX_RESOURCE_SLOTS);
#ifdef DEBUG
if(slot->generation == UINT32_MAX)
{
LOG_ERROR("surface slot generation wrap around\n");
}
#endif
slot->generation++;
ListPush(&pool->freeList, &slot->freeListElt);
}
mg_resource_slot* mg_resource_slot_from_handle(mg_resource_pool* pool, u64 h)
{
u32 index = h>>32;
u32 generation = h & 0xffffffff;
if(index >= MG_MAX_RESOURCE_SLOTS)
{
return(0);
}
mg_resource_slot* slot = &pool->slots[index];
if(slot->generation != generation)
{
return(0);
}
else
{
return(slot);
}
}
u64 mg_resource_handle_from_slot(mg_resource_pool* pool, mg_resource_slot* slot)
{
DEBUG_ASSERT( (slot - pool->slots) >= 0
&& (slot - pool->slots) < MG_MAX_RESOURCE_SLOTS);
u64 h = ((u64)(slot - pool->slots))<<32
u64 h = ((u64)(slot - (mg_handle_slot*)arena->ptr))<<32
|((u64)(slot->generation));
return(h);
}
void mg_resource_handle_recycle(mg_resource_pool* pool, u64 h)
void mg_handle_recycle(u64 h)
{
mg_resource_slot* slot = mg_resource_slot_from_handle(pool, h);
if(slot)
DEBUG_ASSERT(__mgData.init);
u32 index = h>>32;
u32 generation = h & 0xffffffff;
mem_arena* arena = &__mgData.handleArena;
if(index*sizeof(mg_handle_slot) < arena->offset)
{
mg_resource_slot_recycle(pool, slot);
mg_handle_slot* slot = (mg_handle_slot*)arena->ptr + index;
if(slot->generation == generation)
{
DEBUG_ASSERT(slot->generation != UINT32_MAX, "surface slot generation wrap around\n");
slot->generation++;
ListPush(&__mgData.handleFreeList, &slot->freeListElt);
}
}
}
//------------------------------------------------------------------------
// surface handles
//------------------------------------------------------------------------
mg_surface mg_surface_nil() { return((mg_surface){.h = 0}); }
bool mg_surface_is_nil(mg_surface surface) { return(surface.h == 0); }
mg_surface mg_surface_alloc_handle(mg_surface_data* surface)
void* mg_data_from_handle(mg_handle_kind kind, u64 h)
{
mg_resource_slot* slot = mg_resource_slot_alloc(&__mgData.surfaces);
if(!slot)
DEBUG_ASSERT(__mgData.init);
void* data = 0;
u32 index = h>>32;
u32 generation = h & 0xffffffff;
mem_arena* arena = &__mgData.handleArena;
if(index*sizeof(mg_handle_slot) < arena->offset)
{
LOG_ERROR("no more surface slots\n");
return(mg_surface_nil());
mg_handle_slot* slot = (mg_handle_slot*)arena->ptr + index;
if( slot->generation == generation
&& slot->kind == kind)
{
data = slot->data;
}
slot->surface = surface;
u64 h = mg_resource_handle_from_slot(&__mgData.surfaces, slot);
mg_surface handle = {h};
return(handle);
}
mg_surface_data* mg_surface_data_from_handle(mg_surface surface)
{
mg_resource_slot* slot = mg_resource_slot_from_handle(&__mgData.surfaces, surface.h);
mg_surface_data* data = 0;
if(slot)
{
data = slot->surface;
}
return(data);
}
//------------------------------------------------------------------------
// canvas handles
//------------------------------------------------------------------------
mg_canvas mg_canvas_nil() { return((mg_canvas){.h = 0}); }
bool mg_canvas_is_nil(mg_canvas canvas) { return(canvas.h == 0); }
mg_canvas mg_canvas_alloc_handle(mg_canvas_data* canvas)
//---------------------------------------------------------------
// typed handles functions
//---------------------------------------------------------------
mg_surface mg_surface_handle_alloc(mg_surface_data* surface)
{
mg_resource_slot* slot = mg_resource_slot_alloc(&__mgData.canvases);
if(!slot)
{
LOG_ERROR("no more canvas slots\n");
return(mg_canvas_nil());
}
slot->canvas = canvas;
u64 h = mg_resource_handle_from_slot(&__mgData.canvases, slot);
mg_canvas handle = {h};
mg_surface handle = {.h = mg_handle_alloc(MG_HANDLE_SURFACE, (void*)surface) };
return(handle);
}
mg_canvas_data* mg_canvas_data_from_handle(mg_canvas canvas)
mg_surface_data* mg_surface_data_from_handle(mg_surface handle)
{
mg_canvas_data* data = 0;
mg_resource_slot* slot = mg_resource_slot_from_handle(&__mgData.canvases, canvas.h);
if(slot)
{
data = slot->canvas;
}
mg_surface_data* data = mg_data_from_handle(MG_HANDLE_SURFACE, handle.h);
return(data);
}
//------------------------------------------------------------------------
// image handles
//------------------------------------------------------------------------
mg_image mg_image_nil() { return((mg_image){.h = 0}); }
bool mg_image_is_nil(mg_image image) { return(image.h == 0); }
mg_image mg_image_alloc_handle(mg_canvas_data* canvas, mg_image_data* image)
mg_canvas mg_canvas_handle_alloc(mg_canvas_data* canvas)
{
mg_resource_slot* slot = mg_resource_slot_alloc(&canvas->imagePool);
if(!slot)
{
LOG_ERROR("no more canvas slots\n");
return(mg_image_nil());
}
slot->image = image;
u64 h = mg_resource_handle_from_slot(&canvas->imagePool, slot);
mg_image handle = {h};
mg_canvas handle = {.h = mg_handle_alloc(MG_HANDLE_CANVAS, (void*)canvas) };
return(handle);
}
mg_image_data* mg_image_data_from_handle(mg_canvas_data* canvas, mg_image handle)
mg_canvas_data* mg_canvas_data_from_handle(mg_canvas handle)
{
mg_image_data* data = 0;
mg_resource_slot* slot = mg_resource_slot_from_handle(&canvas->imagePool, handle.h);
if(slot)
{
data = slot->image;
}
mg_canvas_data* data = mg_data_from_handle(MG_HANDLE_CANVAS, handle.h);
return(data);
}
//------------------------------------------------------------------------
// font handles
//------------------------------------------------------------------------
mg_font mg_font_nil() { return((mg_font){.h = 0}); }
bool mg_font_is_nil(mg_font font) { return(font.h == 0); }
mg_font mg_font_alloc_handle(mg_font_data* font)
mg_font mg_font_handle_alloc(mg_font_data* font)
{
mg_resource_slot* slot = mg_resource_slot_alloc(&__mgData.fonts);
if(!slot)
{
LOG_ERROR("no more font slots\n");
return(mg_font_nil());
}
slot->font = font;
u64 h = mg_resource_handle_from_slot(&__mgData.fonts, slot);
mg_font handle = {h};
mg_font handle = {.h = mg_handle_alloc(MG_HANDLE_FONT, (void*)font) };
return(handle);
}
mg_font_data* mg_font_data_from_handle(mg_font font)
mg_font_data* mg_font_data_from_handle(mg_font handle)
{
mg_font_data* data = 0;
mg_resource_slot* slot = mg_resource_slot_from_handle(&__mgData.fonts, font.h);
if(slot)
{
data = slot->font;
}
mg_font_data* data = mg_data_from_handle(MG_HANDLE_FONT, handle.h);
return(data);
}
mg_image mg_image_handle_alloc(mg_image_data* image)
{
mg_image handle = {.h = mg_handle_alloc(MG_HANDLE_IMAGE, (void*)image) };
return(handle);
}
mg_image_data* mg_image_data_from_handle(mg_image handle)
{
mg_image_data* data = mg_data_from_handle(MG_HANDLE_IMAGE, handle.h);
return(data);
}
@ -520,6 +429,9 @@ bool mg_is_canvas_backend_available(mg_backend_id backend)
return(result);
}
mg_surface mg_surface_nil() { return((mg_surface){.h = 0}); }
bool mg_surface_is_nil(mg_surface surface) { return(surface.h == 0); }
mg_surface mg_surface_create_for_window(mp_window window, mg_backend_id backend)
{
mg_surface surface = mg_surface_nil();
@ -553,11 +465,11 @@ mg_surface mg_surface_create_for_window(mp_window window, mg_backend_id backend)
void mg_surface_destroy(mg_surface handle)
{
DEBUG_ASSERT(__mgData.init);
mg_resource_slot* slot = mg_resource_slot_from_handle(&__mgData.surfaces, handle.h);
if(slot)
mg_surface_data* surface = mg_surface_data_from_handle(handle);
if(surface)
{
slot->surface->destroy(slot->surface);
mg_resource_slot_recycle(&__mgData.surfaces, slot);
surface->destroy(surface);
mg_handle_recycle(handle.h);
}
}
@ -2249,16 +2161,13 @@ void mg_render_ellipse_stroke(mg_canvas_data* canvas, mp_rect rect, mg_attribute
//NOTE(martin): fonts
//------------------------------------------------------------------------------------------
mg_font mg_font_nil() { return((mg_font){.h = 0}); }
bool mg_font_is_nil(mg_font font) { return(font.h == 0); }
mg_font mg_font_create_from_memory(u32 size, byte* buffer, u32 rangeCount, unicode_range* ranges)
{
mg_font_data* fontData = malloc_type(mg_font_data);
mg_font font = mg_font_alloc_handle(fontData);
if(mg_font_is_nil(font))
{
free(fontData);
return(font);
}
mg_font font = mg_font_handle_alloc(fontData);
stbtt_fontinfo stbttFontInfo;
stbtt_InitFont(&stbttFontInfo, buffer, 0);
@ -2423,23 +2332,14 @@ mg_font mg_font_create_from_memory(u32 size, byte* buffer, u32 rangeCount, unico
void mg_font_destroy(mg_font fontHandle)
{
mg_font_data* fontData = mg_font_data_from_handle(fontHandle);
if(!fontData)
if(fontData)
{
return;
}
#ifdef DEBUG
if(fontData->generation == UINT32_MAX)
{
LOG_ERROR("font info generation wrap around\n");
}
#endif
fontData->generation++;
free(fontData->glyphMap);
free(fontData->glyphs);
free(fontData->outlines);
free(fontData);
mg_resource_handle_recycle(&__mgData.fonts, fontHandle.h);
mg_handle_recycle(fontHandle.h);
}
}
str32 mg_font_get_glyph_indices_from_font_data(mg_font_data* fontData, str32 codePoints, str32 backing)
@ -2695,6 +2595,10 @@ mp_rect mg_text_bounding_box(mg_font font, f32 fontSize, str8 text)
//NOTE(martin): graphics canvas API
//------------------------------------------------------------------------------------------
mg_canvas mg_canvas_nil() { return((mg_canvas){.h = 0}); }
bool mg_canvas_is_nil(mg_canvas canvas) { return(canvas.h == 0); }
#if MG_COMPILE_BACKEND_METAL
mg_canvas_backend* mg_mtl_canvas_create(mg_surface surface);
#endif
@ -2748,7 +2652,7 @@ mg_canvas mg_canvas_create(mg_surface surface)
0, 1, 0}};
canvas = mg_canvas_alloc_handle(canvasData);
canvas = mg_canvas_handle_alloc(canvasData);
mg_canvas_set_current(canvas);
//TODO: move that in mg_canvas_set_current() if needed?
@ -2774,7 +2678,7 @@ void mg_canvas_destroy(mg_canvas handle)
canvas->backend->destroy(canvas->backend);
}
free(canvas);
mg_resource_handle_recycle(&__mgData.canvases, handle.h);
mg_handle_recycle(handle.h);
}
}
@ -2900,7 +2804,7 @@ void mg_flush_commands(int primitiveCount, mg_primitive* primitives, mg_path_elt
if(i && primitive->attributes.image.h != canvas->image.h)
{
mg_image_data* imageData = mg_image_data_from_handle(canvas, canvas->image);
mg_image_data* imageData = mg_image_data_from_handle(canvas->image);
mg_draw_batch(canvas, imageData);
canvas->image = primitive->attributes.image;
}
@ -2991,7 +2895,7 @@ void mg_flush_commands(int primitiveCount, mg_primitive* primitives, mg_path_elt
}
exit_command_loop: ;
mg_image_data* imageData = mg_image_data_from_handle(canvas, canvas->image);
mg_image_data* imageData = mg_image_data_from_handle(canvas->image);
mg_draw_batch(canvas, imageData);
canvas->backend->end(canvas->backend);
@ -3632,6 +3536,10 @@ void mg_arc(f32 x, f32 y, f32 r, f32 arcAngle, f32 startAngle)
//NOTE(martin): images
//------------------------------------------------------------------------------------------
mg_image mg_image_nil() { return((mg_image){.h = 0}); }
bool mg_image_is_nil(mg_image image) { return(image.h == 0); }
mg_image mg_image_create(u32 width, u32 height)
{
mg_image image = mg_image_nil();
@ -3641,7 +3549,7 @@ mg_image mg_image_create(u32 width, u32 height)
mg_image_data* imageData = canvas->backend->imageCreate(canvas->backend, (vec2){width, height});
if(imageData)
{
image = mg_image_alloc_handle(canvas, imageData);
image = mg_image_handle_alloc(imageData);
}
}
return(image);
@ -3695,11 +3603,11 @@ void mg_image_destroy(mg_image image)
mg_canvas_data* canvas = __mgCurrentCanvas;
if(canvas)
{
mg_image_data* imageData = mg_image_data_from_handle(canvas, image);
mg_image_data* imageData = mg_image_data_from_handle(image);
if(imageData)
{
canvas->backend->imageDestroy(canvas->backend, imageData);
mg_resource_handle_recycle(&canvas->imagePool, image.h);
mg_handle_recycle(image.h);
}
}
}
@ -3709,7 +3617,7 @@ void mg_image_upload_region_rgba8(mg_image image, mp_rect region, u8* pixels)
mg_canvas_data* canvas = __mgCurrentCanvas;
if(canvas)
{
mg_image_data* imageData = mg_image_data_from_handle(canvas, image);
mg_image_data* imageData = mg_image_data_from_handle(image);
if(imageData)
{
canvas->backend->imageUploadRegion(canvas->backend, imageData, region, pixels);
@ -3723,7 +3631,7 @@ vec2 mg_image_size(mg_image image)
mg_canvas_data* canvas = __mgCurrentCanvas;
if(canvas)
{
mg_image_data* imageData = mg_image_data_from_handle(canvas, image);
mg_image_data* imageData = mg_image_data_from_handle(image);
if(imageData)
{
res = imageData->size;

View File

@ -236,7 +236,7 @@ mg_surface mg_mtl_surface_create_for_window(mp_window window)
surface->commandBuffer = nil;
}
mg_surface handle = mg_surface_alloc_handle((mg_surface_data*)surface);
mg_surface handle = mg_surface_handle_alloc((mg_surface_data*)surface);
return(handle);
}
}