Unlimited font face allocation

This commit is contained in:
Allen Webster 2017-11-19 18:00:26 -05:00
parent ca8d9e2729
commit cee8ce18cb
5 changed files with 230 additions and 111 deletions

View File

@ -220,7 +220,7 @@ allocate_markers_state(General_Memory *general, Editing_File *file, u32 new_arra
u32 real_max = (memory_size - sizeof_marker_array)/sizeof(Marker); u32 real_max = (memory_size - sizeof_marker_array)/sizeof(Marker);
Marker_Array *array = (Marker_Array*)general_memory_allocate(general, memory_size); Marker_Array *array = (Marker_Array*)general_memory_allocate(general, memory_size);
dll_back_insert(&file->markers.sentinel, array); dll_insert_back(&file->markers.sentinel, array);
array->buffer_id = file->id; array->buffer_id = file->id;
array->count = 0; array->count = 0;
array->sim_max = new_array_max; array->sim_max = new_array_max;

View File

@ -112,8 +112,8 @@ typedef Sys_Font_Load_New_Font_Sig(Font_Load_New_Font_Function, stub);
#define Sys_Font_Get_Count_Sig(n) i32 (n)(void) #define Sys_Font_Get_Count_Sig(n) i32 (n)(void)
typedef Sys_Font_Get_Count_Sig(Font_Get_Count_Function); typedef Sys_Font_Get_Count_Sig(Font_Get_Count_Function);
#define Sys_Font_Get_Name_By_ID_Sig(n, out, cap) i32 (n)(Font_ID font_id, char *out, u32 cap) #define Sys_Font_Get_Name_By_ID_Sig(n, font_id, out, cap) i32 (n)(Font_ID font_id, char *out, u32 cap)
typedef Sys_Font_Get_Name_By_ID_Sig(Font_Get_Name_By_ID_Function, out, cap); typedef Sys_Font_Get_Name_By_ID_Sig(Font_Get_Name_By_ID_Function, font_id, out, cap);
#define Sys_Font_Get_Pointers_By_ID_Sig(n,font_id) Font_Pointers (n)(Font_ID font_id) #define Sys_Font_Get_Pointers_By_ID_Sig(n,font_id) Font_Pointers (n)(Font_ID font_id)
typedef Sys_Font_Get_Pointers_By_ID_Sig(Font_Get_Pointers_By_ID_Function, font_id); typedef Sys_Font_Get_Pointers_By_ID_Sig(Font_Get_Pointers_By_ID_Function, font_id);

View File

@ -350,6 +350,23 @@ font_load(System_Functions *system, Font_Settings *settings, Font_Metrics *metri
//////////////////////////////// ////////////////////////////////
internal
Sys_Font_Allocate_Sig(system_font_allocate, size){
umem *size_ptr = 0;
void *result = system_memory_allocate(size + sizeof(*size_ptr));
size_ptr = (umem*)result;
*size_ptr = size + 4;
return(size_ptr + 1);
}
internal
Sys_Font_Free_Sig(system_font_free, ptr){
if (ptr != 0){
umem *size_ptr = ((umem*)ptr) - 1;
system_memory_free(size_ptr, *size_ptr);
}
}
internal internal
Sys_Font_Get_Loadable_Count_Sig(system_font_get_loadable_count){ Sys_Font_Get_Loadable_Count_Sig(system_font_get_loadable_count){
return(fontvars.loadable_count); return(fontvars.loadable_count);
@ -367,23 +384,119 @@ Sys_Font_Get_Loadable_Sig(system_font_get_loadable, i, out){
internal internal
Sys_Font_Load_New_Font_Sig(system_font_load_new_font, stub){ Sys_Font_Load_New_Font_Sig(system_font_load_new_font, stub){
Font_ID new_id = 0; i32 slot_max = fontvars.max_slot_count;
Font_Slot_Page *page_with_slot = 0;
i32 font_count_max = ArrayCount(fontvars.slots); Assert(fontvars.used_slot_count <= slot_max);
if (fontvars.count < font_count_max){ if (fontvars.used_slot_count == slot_max){
i32 index = fontvars.count; i32 memsize = l_round_up_i32(SLOT_PAGE_SIZE, KB(4));
Font_Slot *slot = &fontvars.slots[index]; i32 page_count = memsize/SLOT_PAGE_SIZE;
Font_Settings *settings = &slot->settings; void *ptr = system_font_allocate(memsize);
Font_Metrics *metrics = &slot->metrics; memset(ptr, 0, memsize);
Font_Page_Storage *pages = &slot->pages;
Assert(!slot->is_active); page_with_slot = (Font_Slot_Page*)ptr;
for (i32 i = 0; i < page_count; ++i){
i32 page_slot_count = SLOT_PER_PAGE;
Font_Slot_Page *page = (Font_Slot_Page*)ptr;
page->is_active = (u64*)(page + 1);
page->settings = (Font_Settings*)(page->is_active + (page_slot_count + 63)/64);
page->metrics = (Font_Metrics*)(page->settings + page_slot_count);
page->pages = (Font_Page_Storage*)(page->metrics + page_slot_count);
ptr = page->pages + page_slot_count;
page->used_count = 0;
page->fill_count = 0;
page->max = page_slot_count;
dll_insert_back(&fontvars.slot_pages_sentinel, page);
if (page->prev == &fontvars.slot_pages_sentinel){
page->first_id = 1;
}
else{
page->first_id = page->prev->first_id + page->prev->max;
}
// NOTE(allen): Some of the last 64 bits of the is_active array may not line up with actual slots.
// Set such bits to 1 to simulate the "slot" being filled for allocation purposes.
// TODO(allen): This could be O(log n) instead of O(n) if I end up making bit manipulation helpers someday.
u64 last_mask_fill = 0;
if (page_slot_count%64 != 0){
last_mask_fill = (1LLU << 63);
for (i32 spread_step = (page_slot_count%64) - 1;
spread_step > 0;
--spread_step){
last_mask_fill |= (last_mask_fill >> 1);
}
}
i32 is_active_max = (page_with_slot->max + 63)/64;
page->is_active[is_active_max - 1] = last_mask_fill;
}
fontvars.max_slot_count += page_count*SLOT_PER_PAGE;
}
else{
for (Font_Slot_Page *page = fontvars.slot_pages_sentinel.next;
page != &fontvars.slot_pages_sentinel;
page = page->next){
if (page->used_count < page->max){
page_with_slot = page;
break;
}
}
}
if (page_with_slot == 0){
LOG("Could not get a font slot while loading a font\n");
return(0);
}
Assert(page_with_slot->used_count < page_with_slot->max);
// Get a fillable index
i32 index = -1;
if (page_with_slot->fill_count < page_with_slot->max){
index = page_with_slot->fill_count;
}
else{
i32 is_active_max = (page_with_slot->max + 63)/64;
u64 *is_active_ptr = page_with_slot->is_active;
for (i32 i = 0; i < is_active_max; ++i){
u64 is_active_v = is_active_ptr[i];
if (is_active_v != (~0)){
i32 j_stop = 64;
if (i + 1 == is_active_max){
j_stop = SLOT_PER_PAGE%64;
}
for (i32 j = 0; j < j_stop; ++j){
if ((is_active_v & (1LLU << j)) == 0){
index = i*64 + j;
break;
}
}
break;
}
}
}
// Get the slot pointers.
Assert(index != -1);
u64 *is_active_flags = &page_with_slot->is_active[index/64];
u64 is_active_mask = (1LLU << (index % 64));
Font_Settings *settings = &page_with_slot->settings[index];
Font_Metrics *metrics = &page_with_slot->metrics[index];
Font_Page_Storage *pages = &page_with_slot->pages[index];
Font_ID new_id = page_with_slot->first_id + index;
Assert(((*is_active_flags) & is_active_mask) == 0);
char *filename = stub->name; char *filename = stub->name;
i32 filename_len = 0; i32 filename_len = 0;
for (;filename[filename_len];++filename_len); for (;filename[filename_len];++filename_len);
// Initialize Font Parameters // Initialize Font Parameters
Assert(filename_len <= sizeof(settings->stub.name) - 1); Assert(filename_len <= sizeof(settings->stub.name) - 1);
memset(settings, 0, sizeof(*settings)); memset(settings, 0, sizeof(*settings));
@ -395,48 +508,78 @@ Sys_Font_Load_New_Font_Sig(system_font_load_new_font, stub){
memset(pages, 0, sizeof(*pages)); memset(pages, 0, sizeof(*pages));
b32 success = font_load(&sysfunc, settings, metrics, pages); b32 success = font_load(&sysfunc, settings, metrics, pages);
if (success){ if (success){
slot->is_active = true; *is_active_flags |= is_active_mask;
new_id = (Font_ID)(index + 1); ++fontvars.used_slot_count;
++fontvars.count; ++page_with_slot->used_count;
if (index >= page_with_slot->fill_count){
page_with_slot->fill_count = index + 1;
} }
} }
else{
new_id = 0;
}
return(new_id); return(new_id);
} }
internal internal
Sys_Font_Get_Count_Sig(system_font_get_count){ Sys_Font_Get_Count_Sig(system_font_get_count){
return(fontvars.count); return(fontvars.used_slot_count);
}
internal Font_Slot_Page_And_Index
system_font_get_active_location(Font_ID font_id){
Font_Slot_Page_And_Index result = {0};
for (Font_Slot_Page *page = fontvars.slot_pages_sentinel.next;
page != &fontvars.slot_pages_sentinel;
page = page->next){
if (page->first_id <= font_id && font_id < page->first_id + SLOT_PER_PAGE){
i32 index = (i32)(font_id - page->first_id);
u64 is_active_v = page->is_active[index/64];
if ((is_active_v & (1LLU << (index%64))) != 0){
result.page = page;
result.index = index;
}
break;
}
}
return(result);
} }
internal internal
Sys_Font_Get_Name_By_ID_Sig(system_font_get_name_by_id, str_out, capacity){ Sys_Font_Get_Name_By_ID_Sig(system_font_get_name_by_id, font_id, str_out, capacity){
i32 length = 0; i32 length = 0;
if (0 < font_id && font_id <= (u32)fontvars.count){ if (font_id == 0){
u32 index = font_id - 1; return(length);
Font_Slot *slot = &fontvars.slots[index]; }
if (slot->is_active){
Font_Metrics *metrics = &slot->metrics; Font_Slot_Page_And_Index page_and_index = system_font_get_active_location(font_id);
if (page_and_index.page != 0){
Font_Metrics *metrics = &page_and_index.page->metrics[page_and_index.index];
length = metrics->name_len; length = metrics->name_len;
copy_partial_cs(str_out, capacity, make_string(metrics->name, length)); copy_partial_cs(str_out, capacity, make_string(metrics->name, length));
} }
}
return(length); return(length);
} }
internal internal
Sys_Font_Get_Pointers_By_ID_Sig(system_font_get_pointers_by_id, font_id){ Sys_Font_Get_Pointers_By_ID_Sig(system_font_get_pointers_by_id, font_id){
Font_Pointers font = {0}; Font_Pointers font = {0};
if (0 < font_id && font_id <= (u32)fontvars.count){ if (font_id == 0){
u32 index = font_id - 1; return(font);
Font_Slot *slot = &fontvars.slots[index]; }
if (slot->is_active){
Font_Slot_Page_And_Index page_and_index = system_font_get_active_location(font_id);
if (page_and_index.page != 0){
font.valid = true; font.valid = true;
font.settings = &slot->settings; font.settings = &page_and_index.page->settings[page_and_index.index];
font.metrics = &slot->metrics; font.metrics = &page_and_index.page->metrics[page_and_index.index];
font.pages = &slot->pages; font.pages = &page_and_index.page->pages[page_and_index.index];
}
} }
return(font); return(font);
} }
@ -446,23 +589,6 @@ Sys_Font_Load_Page_Sig(system_font_load_page, settings, metrics, page, page_numb
font_load_page_layout(settings, metrics, page, page_number); font_load_page_layout(settings, metrics, page, page_number);
} }
internal
Sys_Font_Allocate_Sig(system_font_allocate, size){
umem *size_ptr = 0;
void *result = system_memory_allocate(size + sizeof(*size_ptr));
size_ptr = (umem*)result;
*size_ptr = size + 4;
return(size_ptr + 1);
}
internal
Sys_Font_Free_Sig(system_font_free, ptr){
if (ptr != 0){
umem *size_ptr = ((umem*)ptr) - 1;
system_memory_free(size_ptr, *size_ptr);
}
}
//////////////////////////////// ////////////////////////////////
internal Font_Setup_List internal Font_Setup_List
@ -524,6 +650,9 @@ system_font_init(Font_Functions *font_links, u32 pt_size, b32 use_hinting, Font_
font_links->allocate = system_font_allocate; font_links->allocate = system_font_allocate;
font_links->free = system_font_free; font_links->free = system_font_free;
// Initialize fontvars
memset(&fontvars, 0, sizeof(fontvars));
dll_init_sentinel(&fontvars.slot_pages_sentinel);
fontvars.pt_size = pt_size; fontvars.pt_size = pt_size;
fontvars.use_hinting = use_hinting; fontvars.use_hinting = use_hinting;
@ -568,44 +697,9 @@ system_font_init(Font_Functions *font_links, u32 pt_size, b32 use_hinting, Font_
} }
} }
// Filling initial fonts // Force load one font.
i32 font_count_max = 1; Font_Setup *first_setup = list.first;
for (Font_Setup *ptr = list.first; system_font_load_new_font(&first_setup->stub);
ptr != 0;
ptr = ptr->next){
Font_Loadable_Stub *stub = &ptr->stub;
Font_ID new_id = 0;
if (fontvars.count < font_count_max){
i32 index = fontvars.count;
Font_Slot *slot = &fontvars.slots[index];
Font_Settings *settings = &slot->settings;
Font_Metrics *metrics = &slot->metrics;
Font_Page_Storage *pages = &slot->pages;
Assert(!slot->is_active);
char *filename = stub->name;
i32 filename_len = 0;
for (;filename[filename_len];++filename_len);
// Initialize Font Parameters
Assert(filename_len <= sizeof(settings->stub.name) - 1);
memset(settings, 0, sizeof(*settings));
memcpy(&settings->stub, stub, sizeof(*stub));
settings->pt_size = fontvars.pt_size;
settings->use_hinting = fontvars.use_hinting;
memset(metrics, 0, sizeof(*metrics));
memset(pages, 0, sizeof(*pages));
b32 success = font_load(&sysfunc, settings, metrics, pages);
if (success){
slot->is_active = true;
new_id = (Font_ID)(index + 1);
++fontvars.count;
}
}
}
} }
// BOTTOM // BOTTOM

View File

@ -12,7 +12,6 @@
#if !defined(FCODER_FONT_PROVIDER_FREETYPE_H) #if !defined(FCODER_FONT_PROVIDER_FREETYPE_H)
#define FCODER_FONT_PROVIDER_FREETYPE_H #define FCODER_FONT_PROVIDER_FREETYPE_H
// NOTE(allen): Implemented by the freetype font provider.
struct Font_Slot{ struct Font_Slot{
b32 is_active; b32 is_active;
Font_Settings settings; Font_Settings settings;
@ -20,9 +19,35 @@ struct Font_Slot{
Font_Page_Storage pages; Font_Page_Storage pages;
}; };
struct Font_Slot_Page{
Font_Slot_Page *next;
Font_Slot_Page *prev;
u64 *is_active;
Font_Settings *settings;
Font_Metrics *metrics;
Font_Page_Storage *pages;
i32 used_count;
i32 fill_count;
i32 max;
Font_ID first_id;
};
struct Font_Slot_Page_And_Index{
Font_Slot_Page *page;
i32 index;
};
// NOTE(allen): SLOT_PER_PAGE must be >= 1
global int32_t SLOT_PER_PAGE = 32;
global int32_t SLOT_SIZE = sizeof(Font_Settings) + sizeof(Font_Metrics) + sizeof(Font_Page_Storage);
global int32_t SLOT_PAGE_SIZE = sizeof(Font_Slot_Page) + ((SLOT_PER_PAGE + 63)/64)*8 + SLOT_PER_PAGE*SLOT_SIZE;
struct Font_Vars{ struct Font_Vars{
Font_Slot slots[32]; Font_Slot_Page slot_pages_sentinel;
i32 count; i32 used_slot_count;
i32 max_slot_count;
Font_Loadable_Description loadables[4096]; Font_Loadable_Description loadables[4096];
i32 loadable_count; i32 loadable_count;

View File

@ -14,9 +14,9 @@
// is the same as the type of the next/prev pointers. // is the same as the type of the next/prev pointers.
#define dll_init_sentinel(s) (s)->next=(s),(s)->prev=(s) #define dll_init_sentinel(s) (s)->next=(s),(s)->prev=(s)
#define dll_insert(p,v) (v)->next=(p)->next,(v)->prev=(p),(p)->next=(v),(v)->next->prev=(v) #define dll_insert(p,n) (n)->next=(p)->next,(n)->prev=(p),(p)->next=(n),(n)->next->prev=(n)
#define dll_back_insert(p,v) (v)->prev=(p)->prev,(v)->next=(p),(p)->prev=(v),(v)->prev->next=(v) #define dll_insert_back(p,n) (n)->prev=(p)->prev,(n)->next=(p),(p)->prev=(n),(n)->prev->next=(n)
#define dll_remove(v) (v)->next->prev=(v)->prev,(v)->prev->next=(v)->next #define dll_remove(n) (n)->next->prev=(n)->prev,(n)->prev->next=(n)->next
// HACK(allen): I don't like this anymore, get rid of it. // HACK(allen): I don't like this anymore, get rid of it.
// for(dll_items(iterator, sentinel_ptr)){...} // for(dll_items(iterator, sentinel_ptr)){...}