diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2025-09-16 16:58:02 -0400 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2025-09-16 17:00:08 -0400 |
| commit | 73c5e170260638cc566cba2689ea570caee39251 (patch) | |
| tree | 256b36398d33650054a885e572437909f88485cb | |
| parent | e52ef2e49ae660833370befc34ba79d412cb4604 (diff) | |
pke: major object lifetime overhaul.
Added pke-test-load-unload to ensure objects are
managed as expected.
| -rw-r--r-- | Makefile | 1 | ||||
| -rw-r--r-- | config.mk | 2 | ||||
| -rw-r--r-- | src/camera.cpp | 32 | ||||
| -rw-r--r-- | src/camera.hpp | 1 | ||||
| -rw-r--r-- | src/ecs.cpp | 23 | ||||
| -rw-r--r-- | src/font.cpp | 159 | ||||
| -rw-r--r-- | src/font.hpp | 20 | ||||
| -rw-r--r-- | src/game.cpp | 15 | ||||
| -rw-r--r-- | src/level.cpp | 29 | ||||
| -rw-r--r-- | src/level.hpp | 1 | ||||
| -rw-r--r-- | src/physics.cpp | 24 | ||||
| -rw-r--r-- | src/project.cpp | 9 | ||||
| -rw-r--r-- | src/scene.cpp | 24 | ||||
| -rw-r--r-- | src/scene.hpp | 2 | ||||
| -rw-r--r-- | src/serialization.cpp | 10 | ||||
| -rw-r--r-- | src/static-ui.cpp | 106 | ||||
| -rw-r--r-- | src/thread-pool.cpp | 10 | ||||
| -rw-r--r-- | src/window.cpp | 10 | ||||
| -rw-r--r-- | tests/pke-test-asset-manager.cpp | 7 | ||||
| -rw-r--r-- | tests/pke-test-dummy.cpp | 9 | ||||
| -rw-r--r-- | tests/pke-test-load-unload.cpp | 303 | ||||
| -rw-r--r-- | tests/pke-test-load-unload.h | 16 | ||||
| -rw-r--r-- | tests/pke-test-serialization.cpp | 51 | ||||
| -rw-r--r-- | tests/pke-test-static-ui.cpp | 9 | ||||
| -rw-r--r-- | tests/pke-test.cpp | 10 |
25 files changed, 671 insertions, 212 deletions
@@ -250,6 +250,7 @@ $(DIR_OBJ)/libpke-test.$(LIB_EXT): $(DIR_OBJ)/pke-test-dummy.$(OBJ_EXT) $(DIR_OBJ)/libpke-test.$(LIB_EXT): $(DIR_OBJ)/pke-test-audio.$(OBJ_EXT) $(DIR_OBJ)/libpke-test.$(LIB_EXT): $(DIR_OBJ)/pke-test-static-ui.$(OBJ_EXT) $(DIR_OBJ)/libpke-test.$(LIB_EXT): $(DIR_OBJ)/pke-test-serialization.$(OBJ_EXT) +$(DIR_OBJ)/libpke-test.$(LIB_EXT): $(DIR_OBJ)/pke-test-load-unload.$(OBJ_EXT) $(DIR_OBJ)/libpke-test.$(LIB_EXT): $(DIR_OBJ)/pke-test-asset-manager.$(OBJ_EXT) ar rcs $@ $(filter %.$(OBJ_EXT),$^) @@ -33,6 +33,7 @@ LIBS = -lm `$(PKG_CONFIG) --libs $(USED_LIBS)` -lpthread # -fsanitize=address \ # -rdynamic is for pkfuncinstr # -finstrument-functions is for pkfuncinstr +# -DPKE_AUDIO_IMPL_PIPEWIRE \ SHARED_FLAGS = -D_DEFAULT_SOURCE \ -D_POSIX_C_SOURCE=200809L \ @@ -42,7 +43,6 @@ SHARED_FLAGS = -D_DEFAULT_SOURCE \ -pthread \ -rdynamic \ -finstrument-functions \ - -DPKE_AUDIO_IMPL_PIPEWIRE \ CFLAGS += -Wall -Wextra $(SHARED_FLAGS) CXXFLAGS += -Wall -Wextra $(SHARED_FLAGS) diff --git a/src/camera.cpp b/src/camera.cpp index ca2c11f..07e4253 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -158,20 +158,6 @@ void PkeCamera_SetPrimary(CameraHandle cameraHandle) { } } -void PkeCamera_Destroy(CameraHandle cameraHandle) { - assert(cameraHandle != CameraHandle_MAX); - auto *camPtr = &cam_mstr.bktc_cameras[cameraHandle]; - auto &cam = *camPtr; - - if (cam.phys.constraint != nullptr && cam.phys.constraint != CAFE_BABE(btTypedConstraint)) { - // reminder: this is not currently handled by ECS - BtDynamicsWorld->removeConstraint(cam.phys.constraint); - pk_delete<btTypedConstraint>(cam.phys.constraint, MemBkt_Bullet); - } - - ECS_MarkForRemoval(camPtr); -} - pk_bkt_arr &PkeCamera_GetPkBktArr() { return cam_mstr.bktc_cameras; } @@ -217,16 +203,30 @@ void PkeCamera_Tick(double delta) { bool b; b = pk_bkt_arr_iter_begin(&cam_mstr.bktc_cameras, &iter_cam); while (b == true) { + inst = ECS_GetInstance(iter_cam->phys.instHandle); if (iter_cam->isMarkedForRemoval == true) { - pk_bkt_arr_free_handle(&cam_mstr.bktc_cameras, iter_cam->camHandle); if (ActiveCamera == iter_cam.data) { ActiveCamera = &NullCamera; } + if (iter_cam->phys.constraint != nullptr && iter_cam->phys.constraint != CAFE_BABE(btTypedConstraint)) { + // reminder: this is not currently handled by ECS + BtDynamicsWorld->removeConstraint(iter_cam->phys.constraint); + pk_delete<btTypedConstraint>(iter_cam->phys.constraint, MemBkt_Bullet); + } + if (inst != nullptr) { + if (inst->bt.rigidBody != nullptr) { + BtDynamicsWorld->removeRigidBody(inst->bt.rigidBody); + pk_delete<btRigidBody>(inst->bt.rigidBody, MemBkt_Bullet); + } + if (inst->bt.motionState != nullptr) { + pk_delete<btDefaultMotionState>(inst->bt.motionState, MemBkt_Bullet); + } + } + pk_bkt_arr_free_handle(&cam_mstr.bktc_cameras, iter_cam->camHandle); new (iter_cam.data) PkeCamera{}; b = pk_bkt_arr_iter_increment(&cam_mstr.bktc_cameras, &iter_cam); continue; } - inst = ECS_GetInstance(iter_cam->phys.instHandle); assert(inst != nullptr); if (inst->isNeedingUpdated == true) { iter_cam->stale = iter_cam->stale | PKE_CAMERA_STALE_POSROT; diff --git a/src/camera.hpp b/src/camera.hpp index 9486c84..1226c11 100644 --- a/src/camera.hpp +++ b/src/camera.hpp @@ -51,7 +51,6 @@ void PkeCamera_TargetInstance(CameraHandle cameraHandle, CompInstance *inst); void PkeCamera_UntargetInstance(CameraHandle cameraHandle); pk_bkt_arr &PkeCamera_GetPkBktArr(); void PkeCamera_SetPrimary(CameraHandle handle); -void PkeCamera_Destroy(CameraHandle handle); void PkeCamera_Teardown(); void PkeCamera_Tick(double delta); diff --git a/src/ecs.cpp b/src/ecs.cpp index dd521ce..b4391dc 100644 --- a/src/ecs.cpp +++ b/src/ecs.cpp @@ -15,6 +15,7 @@ typedef pk_bkt_arr_t<Entity_Base *> type_bkt_arr_entities ; struct ECS { struct pk_membucket *bkt = nullptr; + pk_ev_mgr_id_T ev_mgr_id; struct ECSBucketContainers { pk_bkt_arr_t<Entity_Base> generics{}; type_bkt_arr_entities entityPtrs{}; @@ -28,6 +29,15 @@ struct ECS { * Entities that have been marked for removal by calling ECS_MarkForRemoval * * Used to build the other "removal" lists. + * + * Each ECS module is REQUIRED to manage the lifetimes of its objects. + * Each module MUST wait for an entity to be flagged "IsMarkedForRemoval". + * Even though the module itself is sometimes the source of reporting the + * entity to be cleaned up, it must wait to free resources until marked. + * Do note that this means that it can take several ticks for all resources + * of a level to get freed. + * Ex: box with text; text isn't marked for removal until after box. + * (This happens when deserializing, the FontRender doesn't know about its parent") */ pk_arr_t<Entity_Base *> entitiesMarkedForRemoval{}; /* @@ -68,7 +78,7 @@ void ECS_Init() { pk_arr_reserve(&entitiesMarkedForRemoval, 16); pk_arr_reserve(&entitiesYetToBeRemoved, 16); pk_arr_reserve(&EntitiesWithExcessInstances, 16); - pk_ev_create_mgr(); + ecs.ev_mgr_id = pk_ev_create_mgr(); } Entity_Base *ECS_CreateGenericEntity() { @@ -105,8 +115,8 @@ Entity_Base *ECS_GetEntityByUUID(pk_uuid uuid) { auto entity_ptr_find_cb = [](void *user_data, const void *arr_user_data, const void *arr_obj_data) { (void)user_data; const pk_uuid &uuid = *reinterpret_cast<const pk_uuid*>(arr_user_data);; - const Entity_Base &ent = **reinterpret_cast<const Entity_Base*const*>(arr_obj_data); - return (ent.uuid == uuid); + const Entity_Base *ent = *reinterpret_cast<const Entity_Base*const*>(arr_obj_data); + return (ent->uuid == uuid); }; EntityHandle handle { pk_bkt_arr_find_first_handle(&ecs.bc.entityPtrs, entity_ptr_find_cb, NULL, &uuid) }; if (handle == EntityHandle_MAX) return nullptr; @@ -203,8 +213,7 @@ void ECS_Tick_Early(double delta) { while (b == true) { Entity_Base *ent = ecs.bc.entityPtrs[iter_comp_ev->entity_handle]; if (ent->isMarkedForRemoval) { - pk_ev_destroy_mgr(iter_comp_ev->ev_mgr_id); - pk_bkt_arr_free_handle(&ecs.bc.ev_mgrs, iter_comp_ev->entity_handle); + pk_bkt_arr_free_handle(&ecs.bc.ev_mgrs, iter_comp_ev->pke_event_handle); new (&(*iter_comp_ev)) pke_component_event{}; } b = pk_bkt_arr_iter_increment(&ecs.bc.ev_mgrs, &iter_comp_ev); @@ -565,9 +574,8 @@ CompInstance *ECS_GetInstance(InstanceHandle instanceHandle ) { if (instanceHandle == InstanceHandle_MAX) return nullptr; assert(pk_bkt_arr_handle_validate(&ecs.bc.instances, instanceHandle) == PK_BKT_ARR_HANDLE_VALIDATION_VALID); - auto *inst = &ecs.bc.instances[instanceHandle]; - return inst; + return &ecs.bc.instances[instanceHandle]; } void ECS_GetInstances(Entity_Base *entity, pk_arr_t<CompInstance *> &arr) { @@ -657,6 +665,7 @@ pk_bkt_arr *ECS_GetEvs() { } void ECS_Teardown() { + pk_ev_destroy_mgr(ecs.ev_mgr_id); pk_arr_reset(&EntitiesWithExcessInstances); pk_arr_reset(&entitiesYetToBeRemoved); pk_arr_reset(&entitiesMarkedForRemoval); diff --git a/src/font.cpp b/src/font.cpp index b24ea8f..58d5f50 100644 --- a/src/font.cpp +++ b/src/font.cpp @@ -34,9 +34,9 @@ TypeSafeInt_B(FONT_GLYPH_CHAR_FLAG); TypeSafeInt_B(FONT_RENDER_SURFACE_AREA_TYPE_FLAG); struct FontTypeData { - FontType *arr_ft; + FontType *arr_ft = nullptr; + uint64_t unused_fts = 0xFFFFFFFFFFFFFFFF; FontTypeIndex n_ft{0}; - FontTypeIndex h_ft{0}; } ftd; struct FontInstanceBufferItem { @@ -51,6 +51,8 @@ struct FontInstanceBufferItem { float padding[3]; }; +void FontType_Unload(FontTypeIndex idx); + uint32_t utf8_to_unicode(const char* str, uint32_t &out) { uint32_t i = 0; out = 0; @@ -243,10 +245,9 @@ void FontType_Inner_CalcTransforms(const FontType *ft, FontRender *fr, FontInsta void FontType_Init() { FontTypeIndex fti; - ftd.h_ft = FontTypeIndex{0}; - ftd.n_ft = FontTypeIndex{5}; - ftd.arr_ft = pk_new_arr<FontType>(5); - for (FontTypeIndex_T i = 0; i < 5; ++i) { + ftd.n_ft = FontTypeIndex{8}; + ftd.arr_ft = pk_new_arr<FontType>(8); + for (FontTypeIndex_T i = 0; i < 8; ++i) { FontType *ft = &ftd.arr_ft[i]; ft->glyphs = nullptr; ft->renders = nullptr; @@ -276,9 +277,10 @@ void FontType_Init() { } void FontType_Teardown() { - FontTypeIndex i; - for (i = FontTypeIndex{0}; i < ftd.h_ft; ++i) { - FontType_Unload(i); + int i; + for (i = (int)(FontTypeIndex_T)ftd.n_ft-1; i >= 0; --i) { + if ((ftd.unused_fts & (1llu << i)) != 0) continue; + FontType_Unload(FontTypeIndex{(FontTypeIndex_T)i}); } if (ftd.arr_ft != nullptr) pk_delete_arr<FontType>(ftd.arr_ft, (FontTypeIndex_T)ftd.n_ft); } @@ -294,19 +296,43 @@ void FontType_Tick(double delta) { size_t index; FontType *ft; FontRender *fr; - for (FontTypeIndex_T i = 0; i < (FontTypeIndex_T)ftd.h_ft; ++i) { + for (FontTypeIndex_T i = 0; i < (FontTypeIndex_T)ftd.n_ft; ++i) { + + if ((ftd.unused_fts & (1llu << i)) != 0) continue; + index = 0; ft = &ftd.arr_ft[i]; - if (pkeSettings.rt.was_framebuffer_resized == false && ft->gr.should_update_instance_buffer == false) { + + for (FontRenderIndex_T k = 0; k < (FontRenderIndex_T)ft->n_render; ++k) { + if ((ft->unused_frs & (1llu << k)) != 0) continue; + fr = &ft->renders[k]; + if (fr->isMarkedForRemoval == true) { + if (fr->text.reserved > 0) { + // 2025-04-16 - JCB + // not passing a specific bucket because pk_cstr doesn't store it. + // FontType_AddStringRender requires a `pk_cstr &&`, so we are the proper owner. + // It's up to us to free it. + pk_delete_arr<char>(fr->text.val, fr->text.reserved); + } + ft->unused_frs |= (1llu << k); + new (fr) FontRender{}; + ft->gr.should_update_instance_buffer = true; + continue; + } + index += fr->n_glyphs; + } + + if (ft->isMarkedForRemoval == true) { + FontType_Unload(FontTypeIndex{i}); continue; } - // TODO specific bucket - for (FontRenderIndex_T k = 0; k < (FontRenderIndex_T)ft->h_render; ++k) { - index += ft->renders[k].n_glyphs; + if (pkeSettings.rt.was_framebuffer_resized == false && ft->gr.should_update_instance_buffer == false) { + continue; } if (index == 0) { + ft->bindings.instance_counter = index; continue; } ft->gr.should_update_instance_buffer = false; @@ -314,7 +340,8 @@ void FontType_Tick(double delta) { fibis = pk_new_arr<FontInstanceBufferItem>(index); ft->bindings.instance_counter = index; index = 0; - for (FontRenderIndex_T k = 0; k < (FontRenderIndex_T)ft->h_render; ++k) { + for (FontRenderIndex_T k = 0; k < (FontRenderIndex_T)ft->n_render; ++k) { + if ((ft->unused_frs & (1llu << k)) != 0) continue; fr = &ft->renders[k]; FontType_Inner_CalcTransforms(ft, fr, &fibis[index]); index += fr->n_glyphs; @@ -525,13 +552,14 @@ void FontType_Deserialize(std::istream &stream) { } FontType* FontType_Get(FontTypeIndex idx) { - assert(idx < ftd.h_ft); + assert((ftd.unused_fts & (1llu << FontTypeIndex_T(idx))) == 0); return &ftd.arr_ft[static_cast<FontTypeIndex_T>(idx)]; } FontType* FontType_GetByTitle(const pk_cstr title) { assert(title.val != nullptr); - for (FontTypeIndex_T i = 0; i < static_cast<FontTypeIndex_T>(ftd.h_ft); ++i) { + for (FontTypeIndex_T i = 0; i < (FontTypeIndex_T)ftd.n_ft; ++i) { + if ((ftd.unused_fts & (1llu << i)) != 0) continue; if (ftd.arr_ft[i].title.val == title.val) return &ftd.arr_ft[i]; if (strcmp(ftd.arr_ft[i].title.val, title.val) == 0) @@ -540,28 +568,40 @@ FontType* FontType_GetByTitle(const pk_cstr title) { return nullptr; } -FontType* FontType_GetFonts(FontTypeIndex &count) { - count = ftd.h_ft; +FontType* FontType_GetFonts(uint64_t &idx_unused) { + idx_unused = ftd.unused_fts; return ftd.arr_ft; } FontTypeIndex FontType_RegisterFont(pk_cstr title, AssetHandle fontTextureHandle, AssetHandle glyphsHandle, FontTypeMSDFSettings *msdf_settings, FontTypeSpacing *spacing) { VkResult vkResult; - pk_arr arr_vert_mem_reqs; - memset(&arr_vert_mem_reqs, 0, sizeof(pk_arr)); - arr_vert_mem_reqs.alignment = alignof(VkMemoryRequirements); - arr_vert_mem_reqs.stride = sizeof(VkMemoryRequirements); constexpr VkDeviceSize startingGlyphCount = 4; + const Asset *fontTexture = nullptr; + const Asset *glyphs = nullptr; + FontTypeIndex idx{0}; + FontTypeIndex_T idx_t; + FontType *ft; + uint16_t u; + assert(fontTextureHandle != AssetHandle_MAX); assert(glyphsHandle != AssetHandle_MAX); assert(msdf_settings != nullptr); assert(spacing != nullptr); - const Asset *fontTexture = AM_Get(fontTextureHandle); - FontTypeIndex idx = ftd.h_ft; - ftd.h_ft += FontTypeIndex{1}; - if (ftd.h_ft >= ftd.n_ft) { - ftd.n_ft += FontTypeIndex{5}; + for (u = 0; u < (FontTypeIndex_T)ftd.n_ft; ++u) { + if ((ftd.unused_fts & (1llu << u)) != 0) { + idx_t = u; + idx = FontTypeIndex{idx_t}; + ftd.unused_fts &= ~(1llu << idx_t); + break; + } + } + + if (idx >= ftd.n_ft) { + if (idx_t >= PKE_FONT_MAX_FONT_TYPES) { + throw "[font.cpp] out of font type slots"; + } + ftd.n_ft = FontTypeIndex{8}; FontType *arr = pk_new_arr<FontType>((FontTypeIndex_T)ftd.n_ft); if (idx > FontTypeIndex{0}) { memcpy(arr, ftd.arr_ft, sizeof(FontType) * (FontTypeIndex_T)idx); @@ -570,18 +610,20 @@ FontTypeIndex FontType_RegisterFont(pk_cstr title, AssetHandle fontTextureHandle ftd.arr_ft = arr; } - FontTypeIndex_T idx_t = (FontTypeIndex_T)idx; - FontType *ft = &ftd.arr_ft[idx_t]; + fontTexture = AM_Get(fontTextureHandle); + + idx_t = (FontTypeIndex_T)idx; + ft = &ftd.arr_ft[idx_t]; ft->title = title; ft->fontTextureAssetHandle = fontTextureHandle; ft->glyphDetailsAssetHandle = glyphsHandle; ft->renders = pk_new_arr<FontRender>(startingGlyphCount); - ft->h_render = FontRenderIndex{0}; ft->n_render = FontRenderIndex{startingGlyphCount}; + ft->unused_frs = 0xFFFFFFFFFFFFFFFF; ft->msdf_settings = *msdf_settings; ft->spacing = *spacing; - const Asset *glyphs = AM_Get(glyphsHandle); + glyphs = AM_Get(glyphsHandle); ft->n_glyphs = glyphs->size / sizeof(FontGlyphChar); ft->glyphs = (FontGlyphChar*)glyphs->ptr; @@ -708,11 +750,14 @@ FontTypeIndex FontType_RegisterFont(pk_cstr title, AssetHandle fontTextureHandle } void FontType_Unload(FontTypeIndex idx) { + assert((ftd.unused_fts & (1llu << (FontTypeIndex_T)idx)) == 0); + FontType *ft = &ftd.arr_ft[(FontTypeIndex_T)idx]; // TODO specific bucket if (ft->renders != nullptr) { - for (FontRenderIndex_T i = 0; i < (FontRenderIndex_T)ft->h_render; ++i) { + for (FontRenderIndex_T i = 0; i < (FontRenderIndex_T)ft->n_render; ++i) { + if ((ft->unused_frs & (1llu << i)) != 0) continue; if (ft->renders[i].glyph_indices != nullptr) { pk_delete_arr<uint32_t>(ft->renders[i].glyph_indices, ft->renders[i].n_glyphs); } @@ -793,7 +838,8 @@ void FontType_Unload(FontTypeIndex idx) { ft->title.val = nullptr; ft->title.length = 0; } - ECS_MarkForRemoval(ft); + ftd.unused_fts |= (1llu << (FontTypeIndex_T)idx); + new (ft) FontType{}; } void FontType_cstr_to_unicode(const FontType &ft, pk_arr_t<uint32_t> &arr, const pk_cstr &str) { @@ -843,12 +889,22 @@ FontRenderHandle FontType_AddStringRender(FontTypeIndex idx_ft, const pk_cstr && FontType *ft = &ftd.arr_ft[(FontTypeIndex_T)idx_ft]; FontRender *fr; uint32_t i, count; - FontRenderIndex idx_fr = ft->h_render; - ft->h_render += FontRenderIndex{1}; + FontRenderIndex idx_fr = FontRenderIndex{0}; - if (ft->h_render >= ft->n_render) { + for (i = 0; i < (FontRenderIndex_T)ft->n_render; ++i) { + if ((ft->unused_frs & (1llu << i)) != 0) { + ft->unused_frs &= ~(1llu << i); + idx_fr = FontRenderIndex{0}; + break; + } + } + + if (idx_fr >= ft->n_render) { + if (idx_fr >= FontRenderIndex{PKE_FONT_MAX_FONT_RENDERS}) { + throw "[font.cpp] out of FontRender slots"; + } FontRenderIndex_T old_count{static_cast<FontRenderIndex_T>(ft->n_render)}; - ft->n_render += FontRenderIndex{5}; + ft->n_render += FontRenderIndex{8}; FontRender *arr = pk_new_arr<FontRender>((FontRenderIndex_T)ft->n_render); memcpy(arr, ft->renders, sizeof(FontRender) * old_count); pk_delete_arr<FontRender>(ft->renders, old_count); @@ -890,11 +946,11 @@ FontRenderHandle FontType_AddStringRender(FontTypeIndex idx_ft, const pk_cstr && } FontRender *FontType_GetFontRender(FontRenderHandle frh) { - if (frh.index_ft >= ftd.h_ft) { + if ((ftd.unused_fts & (1llu << (FontTypeIndex_T)frh.index_ft)) != 0) { return nullptr; } FontType *ft = &ftd.arr_ft[static_cast<FontTypeIndex_T>(frh.index_ft)]; - if (frh.index_fr >= ft->h_render) { + if ((ft->unused_frs & (1llu << (FontRenderIndex_T)frh.index_fr)) != 0) { return nullptr; } return &ft->renders[static_cast<FontRenderIndex_T>(frh.index_fr)]; @@ -902,18 +958,18 @@ FontRender *FontType_GetFontRender(FontRenderHandle frh) { void FontType_UpdateStringRender(FontRenderHandle frh, FontRenderSettings *settings) { assert(settings != nullptr); - assert((FontTypeIndex_T)ftd.h_ft > (FontTypeIndex_T)frh.index_ft); + assert((ftd.unused_fts & (1llu << (FontTypeIndex_T)frh.index_ft)) == 0); FontType *ft = &ftd.arr_ft[(FontTypeIndex_T)frh.index_ft]; - assert((FontRenderIndex_T)ft->h_render > (FontRenderIndex_T)frh.index_fr); + assert((ft->unused_frs & (1llu << (FontTypeIndex_T)frh.index_fr)) == 0); ft->gr.should_update_instance_buffer = true; ft->renders[(FontRenderIndex_T)frh.index_fr].settings = *settings; } void FontType_UpdateStringRenderText(FontRenderHandle frh, pk_cstr &&cstr) { uint32_t i, count; - assert(frh.index_ft < ftd.h_ft); + assert((ftd.unused_fts & (1llu << (FontTypeIndex_T)frh.index_ft)) == 0); FontType &ft = ftd.arr_ft[static_cast<FontTypeIndex_T>(frh.index_ft)]; - assert(frh.index_fr < ft.h_render); + assert((ft.unused_frs & (1llu << (FontTypeIndex_T)frh.index_fr)) == 0); FontRender &fr = ft.renders[static_cast<FontRenderIndex_T>(frh.index_fr)]; pk_cstr old_str = fr.text; if (window == NULL) { @@ -941,25 +997,10 @@ void FontType_UpdateStringRenderText(FontRenderHandle frh, pk_cstr &&cstr) { void FontType_RemoveStringRender(FontRenderHandle handle) { FontRender *fr; - uint32_t buffer_start_index; FontType *ft = &ftd.arr_ft[(FontTypeIndex_T)handle.index_ft]; // hack, but works ft->gr.should_update_instance_buffer = true; fr = &ft->renders[(FontRenderIndex_T)handle.index_fr]; - ft->bindings.instance_counter -= fr->n_glyphs; - buffer_start_index = fr->buffer_start_index; - fr->n_glyphs = 0; - for (FontRenderIndex_T i = (FontRenderIndex_T)handle.index_fr + 1; FontRenderIndex{i} < ft->h_render; ++i) { - fr = &ft->renders[i]; - fr->buffer_start_index = buffer_start_index; - buffer_start_index += fr->n_glyphs; - } - if (fr->text.reserved > 0) { - // 2025-04-16 - JCB - // not passing a specific bucket because pk_cstr doesn't store it. - // font.cpp assumes the user has already cloned the string if necessary - only assigns the value. - pk_delete_arr<char>(fr->text.val, fr->text.reserved); - } ECS_MarkForRemoval(fr); } diff --git a/src/font.hpp b/src/font.hpp index 912327e..75035b8 100644 --- a/src/font.hpp +++ b/src/font.hpp @@ -7,6 +7,9 @@ #include "vendor-glm-include.hpp" +#define PKE_FONT_MAX_FONT_TYPES 64 +#define PKE_FONT_MAX_FONT_RENDERS 64 + TypeSafeInt_H(FontTypeIndex, uint16_t, 0xFFFF); TypeSafeInt_H(FontRenderIndex, uint16_t, 0xFFFF); @@ -65,12 +68,12 @@ struct FontRenderSettings { FONT_RENDER_SURFACE_AREA_TYPE_FLAG surface_area_type_flags; // TODO }; struct FontRender : public Entity_Base { - uint32_t *glyph_indices; - FontRenderHandle fr_handle; - uint32_t n_glyphs; - uint32_t buffer_start_index; - FontRenderSettings settings; - pk_cstr text; + uint32_t *glyph_indices = nullptr; + FontRenderHandle fr_handle = FontRenderHandle_MAX; + uint32_t n_glyphs = 0; + uint32_t buffer_start_index = 0; + FontRenderSettings settings{}; + pk_cstr text{}; }; struct FontTypeMSDFSettings { float minimum_scale; @@ -94,7 +97,7 @@ struct FontType : public Entity_Base { glm::vec2 atlas_size; uint32_t n_glyphs; FontRenderIndex n_render = FontRenderIndex{0}; - FontRenderIndex h_render = FontRenderIndex{0}; + uint64_t unused_frs; FontTypeIndex index_ft = FontTypeIndex{0}; struct FontTypeMSDFSettings msdf_settings; struct FontTypeSpacing spacing; @@ -127,9 +130,8 @@ void FontType_Serialize(std::ostream &stream, FontType *ft); void FontType_Deserialize(std::istream &stream); FontType* FontType_Get(FontTypeIndex idx); FontType* FontType_GetByTitle(const pk_cstr title); -FontType* FontType_GetFonts(FontTypeIndex &count); +FontType* FontType_GetFonts(uint64_t &idx_unused); FontTypeIndex FontType_RegisterFont(pk_cstr title, AssetHandle fontTextureHandle, AssetHandle glyphsHandle, FontTypeMSDFSettings *msdf_settings, FontTypeSpacing *spacing); -void FontType_Unload(FontTypeIndex idx); FontRenderHandle FontType_AddStringRender(FontTypeIndex idx_ft, const pk_cstr &&str, FontRenderSettings *settings, Entity_Base *parent = nullptr, pk_uuid uuid = pk_uuid_zed); FontRender *FontType_GetFontRender(FontRenderHandle frh); void FontType_UpdateStringRender(FontRenderHandle frh, FontRenderSettings *settings); diff --git a/src/game.cpp b/src/game.cpp index 448bf3d..ef3f2fb 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -104,11 +104,13 @@ void Game_Tick(double delta) { */ ECS_Tick_Early(delta); - EntityType_Tick(delta); - ECS_Tick(delta); pke_input_tick(delta); + + EntityType_Tick(delta); + pke_level_tick(delta); pke_ui_tick(delta); - FontType_Tick(delta); + pke_scene_tick(delta); + PkeCamera_Tick(delta); for (long i = 0; i < LoadedPkePlugins.next; ++i) { if (LoadedPkePlugins[i].OnTick != nullptr) { @@ -120,7 +122,8 @@ void Game_Tick(double delta) { reinterpret_cast<void(*)(double delta)>(pkeSettings.rt.activeLevel->pke_cb_tick.func)(delta); } - PkeCamera_Tick(delta); + FontType_Tick(delta); + ECS_Tick(delta); pke_audio_tick(delta); @@ -146,9 +149,9 @@ void Game_Main(PKEWindowProperties windowProps, const char *executablePath) { CreateWindow(windowProps); EntityType_Init(); pke_input_init(); + FontType_Init(); pke_ui_init(); pke_ui_init_bindings(); - FontType_Init(); PkeProject_Load(pkeSettings.args.projectPath); if (pkeSettings.args.pluginPath != nullptr) { PkePlugin_Load(pkeSettings.args.pluginPath); @@ -288,8 +291,8 @@ GAME_SHUTDOWN: } PkePlugin_Teardown(); EntityType_Teardown(); - FontType_Teardown(); pke_ui_teardown(); + FontType_Teardown(); pke_input_teardown(); pke_scene_master_teardown(); pke_level_teardown(); diff --git a/src/level.cpp b/src/level.cpp index 120ef57..27e7722 100644 --- a/src/level.cpp +++ b/src/level.cpp @@ -4,6 +4,7 @@ #include "ecs.hpp" #include "pk.h" #include "scene.hpp" +#include "static-ui.hpp" struct level_mstr { pk_membucket *bkt; @@ -98,6 +99,25 @@ struct pk_bkt_arr *pke_level_get_levels() { return &level_mstr.bc; } +void pke_level_tick(double delta) { + (void)delta; + pk_iter_t<pke_level> iter; + bool b; + + b = pk_bkt_arr_iter_begin(&level_mstr.bc, &iter); + while (b == true) { + if (iter->isMarkedForRemoval) { + pk_arr_reset(&iter->scene_instances); + pk_arr_reset(&iter->cameras); + pk_arr_reset(&iter->root_ui_boxes); + pk_arr_reset(&iter->input_handles); + pk_bkt_arr_free_handle(&level_mstr.bc, iter->levelHandle); + new (&*iter) pke_level{}; + } + b = pk_bkt_arr_iter_increment(&level_mstr.bc, &iter); + } +} + void pke_level_teardown(pke_level *level) { uint32_t u; assert(level != nullptr); @@ -106,10 +126,10 @@ void pke_level_teardown(pke_level *level) { } ECS_MarkForRemoval(level); for (u = 0; u < level->scene_instances.next; ++u) { - pke_scene_remove(level->scene_instances[u].scene_handle); + ECS_MarkForRemoval(pke_scene_get_by_handle(level->scene_instances[u].scene_handle)); } for (u = 0; u < level->cameras.next; ++u) { - PkeCamera_Destroy(level->cameras[u]->camHandle); + ECS_MarkForRemoval(level->cameras[u]); } for (u = 0; u < level->input_handles.next; ++u) { pke_input_deactivate_set(level->input_handles[u]); @@ -124,11 +144,6 @@ void pke_level_teardown(pke_level *level) { if (level->bkt != nullptr) { pk_mem_bucket_destroy(level->bkt); } - pk_arr_reset(&level->scene_instances); - pk_arr_reset(&level->cameras); - pk_arr_reset(&level->root_ui_boxes); - pk_arr_reset(&level->input_handles); - pk_bkt_arr_free_handle(&level_mstr.bc, level->levelHandle); } void pke_level_register_camera(pke_level *level, PkeCamera *camera) { diff --git a/src/level.hpp b/src/level.hpp index e9cb0c5..b85a608 100644 --- a/src/level.hpp +++ b/src/level.hpp @@ -10,6 +10,7 @@ pke_level *pke_level_create(const char *levelName, pk_uuid level_uuid, pk_uuid e pke_level *pke_level_get(LevelHandle handle); pke_level *pke_level_get_by_name(const char *levelName); struct pk_bkt_arr *pke_level_get_levels(); +void pke_level_tick(double delta); void pke_level_teardown(pke_level *level); diff --git a/src/physics.cpp b/src/physics.cpp index 34cfbed..fe0385c 100644 --- a/src/physics.cpp +++ b/src/physics.cpp @@ -22,10 +22,11 @@ struct AllocedData { }; pk_arr_t<AllocedData> bulletAllocs{}; +btHashedOverlappingPairCache *overlappingPairCache = nullptr; btDefaultCollisionConfiguration *btConfiguration = nullptr; btCollisionDispatcher *btDispatcher = nullptr; -btBroadphaseInterface *btBroadphase = nullptr; -btConstraintSolver *btSolver = nullptr; +btDbvtBroadphase *btBroadphase = nullptr; +btSequentialImpulseConstraintSolver *btSolver = nullptr; struct EntityCollision { CompInstance *a, *b; @@ -111,7 +112,7 @@ void Physics_Init() { btBroadphase = pk_new<btDbvtBroadphase>(MemBkt_Bullet); #if 1 - btHashedOverlappingPairCache *overlappingPairCache = pk_new<btHashedOverlappingPairCache>(MemBkt_Bullet); + overlappingPairCache = pk_new<btHashedOverlappingPairCache>(MemBkt_Bullet); overlappingPairCache->setOverlapFilterCallback(&collisionHandlerStruct); new (btBroadphase) btDbvtBroadphase(overlappingPairCache); #else @@ -136,7 +137,22 @@ int32_t Physics_Tick(double delta) { void Physics_Teardown() { pk_arr_reset(&collisionsThisTick); - pk_delete<btDiscreteDynamicsWorld>(BtDynamicsWorld, MemBkt_Bullet); + if (BtDynamicsWorld != nullptr) + pk_delete<btDiscreteDynamicsWorld>(BtDynamicsWorld, MemBkt_Bullet); + if (overlappingPairCache != nullptr) + pk_delete<btHashedOverlappingPairCache>(overlappingPairCache, MemBkt_Bullet); + if (btConfiguration != nullptr) + pk_delete<btDefaultCollisionConfiguration>(btConfiguration, MemBkt_Bullet); + if (btSolver != nullptr) + pk_delete<btSequentialImpulseConstraintSolver>(btSolver, MemBkt_Bullet); + if (btDispatcher != nullptr) + pk_delete<btCollisionDispatcher>(btDispatcher, MemBkt_Bullet); + if (btBroadphase != nullptr) + pk_delete<btDbvtBroadphase>(btBroadphase, MemBkt_Bullet); + btConfiguration = nullptr; + btSolver = nullptr; + btBroadphase = nullptr; + btDispatcher = nullptr; BtDynamicsWorld = nullptr; // TODO should we manually delete each bullet alloc? // or just drop? diff --git a/src/project.cpp b/src/project.cpp index 62525ef..e1c3333 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -452,10 +452,11 @@ void PkeProject_Save(const char *filePath) { b = pk_bkt_arr_iter_increment(bkt_arr_ent_types, &iter_ent_type); } - FontTypeIndex font_count; - FontType *fonts = FontType_GetFonts(font_count); - for (FontTypeIndex b = FontTypeIndex{0}; b < font_count; ++b) { - FontType *ft = &fonts[(FontTypeIndex_T)b]; + uint64_t idx_unused; + FontType *fonts = FontType_GetFonts(idx_unused); + for (uint64_t u = 0; u < PKE_FONT_MAX_FONT_TYPES; ++u) { + if ((idx_unused & (1llu << u)) != 0) continue; + FontType *ft = &fonts[(FontTypeIndex_T)u]; if (ft->title.val == nullptr) continue; if (PK_HAS_FLAG(ft->entity_flags, ENTITY_FLAG_DO_NOT_SERIALIZE)) continue; stream << PKE_PROJ_FILE_OBJ_FONT << std::endl; diff --git a/src/scene.cpp b/src/scene.cpp index ecc0fc8..4d5cc76 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -86,15 +86,19 @@ pk_bkt_arr *pke_scene_get_scenes() { return &scene_mstr.bc; } -void pke_scene_remove(SceneHandle handle) { - pke_scene *scn = &scene_mstr.bc[handle]; - assert(scn != nullptr && "[pke_scene_remove] Failed to find scene by requested SceneHandle"); - ECS_MarkForRemoval(scn); - if (scn->file_path.reserved > 0) { - pk_delete_arr<char>(scn->file_path.val, scn->file_path.reserved); +void pke_scene_tick(double delta) { + (void)delta; + pk_iter_t<pke_scene> iter; + bool b; + b = pk_bkt_arr_iter_begin(&scene_mstr.bc, &iter); + while (b == true) { + if (iter->isMarkedForRemoval == true) { + if (iter->file_path.reserved > 0) { + pk_delete_arr<char>(iter->file_path.val, iter->file_path.reserved); + } + pk_bkt_arr_free_handle(&scene_mstr.bc, iter->scene_handle); + new (&*iter) pke_scene{}; + } + b = pk_bkt_arr_iter_increment(&scene_mstr.bc, &iter); } - scn->file_path = {}; - scn->name[0] = '\0'; - scn->scene_handle = SceneHandle_MAX; - pk_bkt_arr_free_handle(&scene_mstr.bc, handle); } diff --git a/src/scene.hpp b/src/scene.hpp index 70b5f06..e61b8ba 100644 --- a/src/scene.hpp +++ b/src/scene.hpp @@ -11,6 +11,6 @@ struct pke_scene *pke_scene_create(const char *scene_name); struct pke_scene *pke_scene_get_by_handle(SceneHandle scene_handle); struct pke_scene *pke_scene_get_by_name(const char *scene_name); pk_bkt_arr *pke_scene_get_scenes(); -void pke_scene_remove(SceneHandle handle); +void pke_scene_tick(double delta); #endif /* PKE_SCENE_HPP */ diff --git a/src/serialization.cpp b/src/serialization.cpp index 63123fe..dbf9646 100644 --- a/src/serialization.cpp +++ b/src/serialization.cpp @@ -80,11 +80,13 @@ void pke_serialize_scene(srlztn_serialize_helper *h) { pke_serialize_input_set(h, &sets[i]); } - FontTypeIndex font_type_count; - FontType *fonts = FontType_GetFonts(font_type_count); - for (FontTypeIndex_T b = 0; b < (FontTypeIndex_T)font_type_count; ++b) { + uint64_t idx_unused; + FontType *fonts = FontType_GetFonts(idx_unused); + for (FontTypeIndex_T b = 0; b < PKE_FONT_MAX_FONT_TYPES; ++b) { + if ((idx_unused & (1llu << b)) != 0) continue; FontType *ft = &fonts[b]; - for (FontRenderIndex_T i = 0; i < (FontRenderIndex_T)ft->h_render; ++i) { + for (FontRenderIndex_T i = 0; i < (FontRenderIndex_T)ft->n_render; ++i) { + if ((ft->unused_frs & (1llu << i)) != 0) continue; pke_serialize_font_render(h, &ft->renders[i]); } } diff --git a/src/static-ui.cpp b/src/static-ui.cpp index b4bdc5c..c8200b0 100644 --- a/src/static-ui.cpp +++ b/src/static-ui.cpp @@ -52,9 +52,10 @@ struct pke_ui_master { const pke_input_event *mouse_middle = nullptr; pke_ui_box *deepest_pressed = nullptr; } state; + pk_arr_t<pke_ui_box*> boxes_to_delete{}; } pke_ui_master; -void pke_ui_teardown_box_recursive(pke_ui_box *box); +void pke_ui_teardown_box_recursive(pke_ui_box *box, uint8_t depth); // typedef void(*pke_box_search)(pke_ui_box &box); typedef std::function<void(pke_ui_box &box)> pke_box_iterate ; @@ -554,6 +555,12 @@ void pke_ui_tick(double delta) { (void)delta; pke_ui_box_count_T i, ii; uint32_t u; + + for (u = 0; u < pke_ui_master.boxes_to_delete.next; ++u) { + pk_delete<pke_ui_box>(pke_ui_master.boxes_to_delete[u], pke_ui_master.bkt); + } + pk_arr_clear(&pke_ui_master.boxes_to_delete); + if (pke_ui_master.h_root_boxes == 0) return; pke_ui_master.state.mouse_left = pke_input_query_by_action_name(ui_ux_mouse_left); @@ -576,19 +583,17 @@ void pke_ui_tick(double delta) { // Leaving this as-is for the time being because you can control the // visibility of child boxes with flags and don't need to completely remove them. if (box->isMarkedForRemoval == true) { - pke_ui_teardown_box_recursive(box); + pke_ui_teardown_box_recursive(box, 0); for (ii = 0; i + ii + 1 < pke_ui_master.r_root_boxes; ++ii) { pke_ui_master.root_boxes[i + ii] = pke_ui_master.root_boxes[i + ii + 1]; } pke_ui_master.h_root_boxes -= 1; i -= 1; pke_ui_master.should_update_buffer = true; - goto skip_calc; + continue; } pke_ui_calc_px(arr, tmp_txtr_arr, nullptr, box); pke_ui_recalc_sizes_recursive(arr, tmp_txtr_arr, box); -skip_calc: - continue; } for (i = 0; i < tmp_txtr_arr.next; ++i) { @@ -629,50 +634,80 @@ skip_calc: } } -void pke_ui_teardown_box_recursive(pke_ui_box *box) { +void pke_ui_teardown_box_recursive(pke_ui_box *box, uint8_t depth) { + FontRender *fr; + pke_ui_graphics_bindings_texture *bindings = nullptr; for (pke_ui_box_count_T i = 0; i < box->internal.h_children; ++i) { - pke_ui_teardown_box_recursive(box->internal.children[i]); + pke_ui_teardown_box_recursive(box->internal.children[i], depth + 1); } if (box->internal.children != nullptr) { pk_delete_arr<pke_ui_box *>(box->internal.children, box->internal.r_children, pke_ui_master.bkt); } if (box->type_data != nullptr) { - if (box->type == PKE_UI_BOX_TYPE_BUTTON_IMAGE && box->type_data->button_image.gr_binds_bkt_arr_handle != pk_bkt_arr_handle_MAX) { - - pke_ui_graphics_bindings_texture *bindings = &pke_ui_master.bindings_texture[box->type_data->button_image.gr_binds_bkt_arr_handle]; - - // reminder that we are not passing the flag on the pool to manually manage descriptor sets, so all we need to do is destroy the pool - if (bindings->descriptor_pool != VK_NULL_HANDLE) { - pkvk_queue_vk_descriptor_pool_destroy(bindings->descriptor_pool); - } - if (bindings->descriptor_sets != nullptr) { - pk_delete_arr(bindings->descriptor_sets, prevSwapchainLength, MemBkt_Vulkan); - } - - if (bindings->image_view!= VK_NULL_HANDLE) { - pkvk_queue_vk_image_view_destroy(bindings->image_view); - } - if (bindings->image!= VK_NULL_HANDLE) { - pkvk_queue_vk_image_destroy(bindings->image); - } - if (bindings->image_memory != VK_NULL_HANDLE) { - pkvk_queue_vk_memory_free(bindings->image_memory); - } - - bindings->descriptor_sets = nullptr; - bindings->descriptor_pool = VK_NULL_HANDLE; - pk_bkt_arr_free_handle(&pke_ui_master.bindings_texture, box->type_data->button_image.gr_binds_bkt_arr_handle); - bindings = nullptr; + switch (box->type) { + case PKE_UI_BOX_TYPE_TEXT: + // 2025-09-16 JCB + // If correctly parented, this is unnecessary, but serialization does + // not construct text boxes in this way. + // Handle to avoid memory leaks. + fr = FontType_GetFontRender(box->type_data->text.font_render_handle); + if (fr != nullptr && fr->parentHandle != box->handle) { + FontType_RemoveStringRender(box->type_data->text.font_render_handle); + } + break; + case PKE_UI_BOX_TYPE_BUTTON_TEXT: + fr = FontType_GetFontRender(box->type_data->button_text.font_render_handle); + if (fr != nullptr && fr->parentHandle != box->handle) { + FontType_RemoveStringRender(box->type_data->button_text.font_render_handle); + } + break; + case PKE_UI_BOX_TYPE_BUTTON_IMAGE: + if (box->type_data->button_image.gr_binds_bkt_arr_handle != pk_bkt_arr_handle_MAX) { + bindings = &pke_ui_master.bindings_texture[box->type_data->button_image.gr_binds_bkt_arr_handle]; + // reminder that we are not passing the flag on the pool to manually manage descriptor sets, so all we need to do is destroy the pool + if (bindings->descriptor_pool != VK_NULL_HANDLE) { + pkvk_queue_vk_descriptor_pool_destroy(bindings->descriptor_pool); + } + if (bindings->descriptor_sets != nullptr) { + pk_delete_arr(bindings->descriptor_sets, prevSwapchainLength, MemBkt_Vulkan); + } + if (bindings->image_view!= VK_NULL_HANDLE) { + pkvk_queue_vk_image_view_destroy(bindings->image_view); + } + if (bindings->image!= VK_NULL_HANDLE) { + pkvk_queue_vk_image_destroy(bindings->image); + } + if (bindings->image_memory != VK_NULL_HANDLE) { + pkvk_queue_vk_memory_free(bindings->image_memory); + } + bindings->descriptor_sets = nullptr; + bindings->descriptor_pool = VK_NULL_HANDLE; + pk_bkt_arr_free_handle(&pke_ui_master.bindings_texture, box->type_data->button_image.gr_binds_bkt_arr_handle); + bindings = nullptr; + } + break; + case PKE_UI_BOX_TYPE_INPUT_TEXT: + // TODO + break; + case PKE_UI_BOX_TYPE_INPUT_MULTILINE_TEXT: + // TODO + break; + default: + fprintf(stderr, "[%s][pke_ui_teardown_box_recursive] unknown box type: %hhu", __FILE__, static_cast<PKE_UI_BOX_TYPE_T>(box->type)); } pk_delete<pke_ui_box_type_data>(box->type_data, pke_ui_master.bkt); + box->type_data = nullptr; + } + pk_arr_append_t<pke_ui_box*>(&pke_ui_master.boxes_to_delete, box); + if (depth != 0) { + ECS_MarkForRemoval(box); } - pk_delete<pke_ui_box>(box, pke_ui_master.bkt); pke_ui_master.should_update_buffer = true; } void pke_ui_teardown() { for (pke_ui_box_count_T i = 0; i < pke_ui_master.h_root_boxes; ++i) { - pke_ui_teardown_box_recursive(pke_ui_master.root_boxes[i]); + pke_ui_teardown_box_recursive(pke_ui_master.root_boxes[i], 0); } pk_delete_arr<pke_ui_box *>(pke_ui_master.root_boxes, pke_ui_master.r_root_boxes, pke_ui_master.bkt); pke_ui_master.bindings_texture.~texture_binding_bkt_arr(); @@ -720,6 +755,7 @@ void pke_ui_teardown() { vkFreeMemory(vkDevice, pke_ui_master.bindings.deviceMemoryVert, vkAllocator); pke_ui_master.bindings.deviceMemoryVert = VK_NULL_HANDLE; + pk_arr_reset(&pke_ui_master.boxes_to_delete); pke_input_unregister_set(pke_ui_master.input_action_set_handle); } diff --git a/src/thread-pool.cpp b/src/thread-pool.cpp index f9ff155..d040fa4 100644 --- a/src/thread-pool.cpp +++ b/src/thread-pool.cpp @@ -74,6 +74,9 @@ void inline PkeThreads_Reset_Inner(ThreadPool &tp) { tp.mutex.lock(); tp.maxJobQueueCount = 0; tp.completedCount = 0; + for (uint32_t i = 0; i < tp.threads.next; ++i) { + pk_delete<std::thread>(tp.threads[i]); + } pk_arr_clear(&tp.jobQueue); pk_arr_clear(&tp.threads); tp.mutex.unlock(); @@ -208,6 +211,13 @@ void PkeThreads_Teardown(ThreadPoolHandle handle) { PkeThreads_Shutdown_Inner(*tp); PkeThreads_JoinAll_Inner(*tp); PkeThreads_Reset_Inner(*tp); + + for (uint32_t i = 0; i < tp->threads.next; ++i) { + if (tp->threads[i] != nullptr) { + pk_delete<std::thread>(tp->threads[i]); + } + } + pk_arr_reset(&tp->jobQueue); pk_arr_reset(&tp->threads); tp->jobQueue.bkt = CAFE_BABE(struct pk_membucket); diff --git a/src/window.cpp b/src/window.cpp index 6655488..d3a7234 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -3728,11 +3728,11 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { vkCmdSetScissor(commandBuffer, 0, 1, &scissor); // 2d - font glyphs - FontTypeIndex count; - FontType *fts = FontType_GetFonts(count); - for (FontTypeIndex i = FontTypeIndex{0}; i < count; ++i) - { - FontType *ft = &fts[(FontTypeIndex_T)i]; + uint64_t idx_unused; + FontType *fts = FontType_GetFonts(idx_unused); + for (uint32_t u = 0; u < 64; ++u) { + if ((idx_unused & (1llu << u)) != 0) continue; + FontType *ft = &fts[(FontTypeIndex_T)u]; if (ft->bindings.instance_counter == 0) continue; vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipelines.named.font_glyph); diff --git a/tests/pke-test-asset-manager.cpp b/tests/pke-test-asset-manager.cpp index 180d134..55a368f 100644 --- a/tests/pke-test-asset-manager.cpp +++ b/tests/pke-test-asset-manager.cpp @@ -6,7 +6,11 @@ #include "font.hpp" #include "thread-pool.hpp" +static pk_membucket *bkt; + void pke_test_asset_manager_spinup() { + bkt = pk_mem_bucket_create("pke_test_asset_manager", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE); + pk_mem_bucket_set_client_mem_bucket(bkt); pk_ev_init(nullptr); PkeThreads_Init(); AM_Init(); @@ -20,6 +24,9 @@ void pke_test_asset_manager_teardown() { AM_Teardown(); PkeThreads_Teardown(); pk_ev_teardown(); + pk_mem_bucket_destroy(bkt); + pk_mem_bucket_set_client_mem_bucket(nullptr); + bkt = nullptr; }; int pke_test_asset_manager_001() { diff --git a/tests/pke-test-dummy.cpp b/tests/pke-test-dummy.cpp index e8c34ba..914f3cf 100644 --- a/tests/pke-test-dummy.cpp +++ b/tests/pke-test-dummy.cpp @@ -11,8 +11,12 @@ #include "static-ui.hpp" #include "thread-pool.hpp" +static pk_membucket *bkt; + int pke_test_dummy_001() { - pk_ev_init(nullptr); + bkt = pk_mem_bucket_create("pke_test_dummy", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE); + pk_mem_bucket_set_client_mem_bucket(bkt); + pk_ev_init(bkt); Physics_Init(); PkeThreads_Init(); AM_Init(); @@ -40,6 +44,9 @@ int pke_test_dummy_001() { PkeThreads_Teardown(); Physics_Teardown(); pk_ev_teardown(); + pk_mem_bucket_destroy(bkt); + pk_mem_bucket_set_client_mem_bucket(nullptr); + bkt = nullptr; return 0; } diff --git a/tests/pke-test-load-unload.cpp b/tests/pke-test-load-unload.cpp new file mode 100644 index 0000000..f714538 --- /dev/null +++ b/tests/pke-test-load-unload.cpp @@ -0,0 +1,303 @@ + +#include "pke-test-load-unload.h" + +#include "asset-manager.hpp" +#include "audio.hpp" +#include "camera.hpp" +#include "ecs.hpp" +#include "entities.hpp" +#include "game-settings.hpp" +#include "game.hpp" +#include "level.hpp" +#include "physics.hpp" +#include "pk.h" +#include "player-input.hpp" +#include "scene.hpp" +#include "static-ui.hpp" +#include "thread-pool.hpp" + +#include "pk.h" + +extern pk_arr_t<Entity_Base*> entitiesMarkedForRemoval; +extern pk_arr_t<EntityHandle> entitiesYetToBeRemoved; + +static pk_membucket *bkt; +static pke_level *level_01; + +void print_entities_marked_for_removal() { + bool b; + pk_iter_t<Entity_Base*> iter{}; + fprintf(stdout, "marked for removal BEGIN\n"); + b = pk_arr_iter_begin(&entitiesMarkedForRemoval, &iter); + while (b == true) { + fprintf(stdout, "0x%.2X 0x%.2X\n", (*iter)->handle.b, (*iter)->handle.i); + b = pk_arr_iter_increment(&entitiesMarkedForRemoval, &iter); + } + fprintf(stdout, "marked for removal END\n\n"); +} + +void print_entities_yet_to_be_removed() { + bool b; + pk_iter_t<EntityHandle> iter{}; + fprintf(stdout, "yet to be removed BEGIN\n"); + b = pk_arr_iter_begin(&entitiesYetToBeRemoved, &iter); + while (b == true) { + fprintf(stdout, "0x%.2X 0x%.2X\n", iter->b, iter->i); + b = pk_arr_iter_increment(&entitiesYetToBeRemoved, &iter); + } + fprintf(stdout, "yet to be removed END\n\n"); +} + +int pke_test_load_unload_do_thing_001(int iteration) { + uint64_t err_index = iteration << 16; + + // fprintf(stdout, "begin\n"); + + pkeSettings.rt.activeLevel = pke_level_create("load_unload_faux", pk_uuid_zed, pk_uuid_zed); + assert(pkeSettings.rt.activeLevel->isMarkedForRemoval == false); + + PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.nextLevel == NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index); + PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index); + PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 0, err_index); + // print_entities_marked_for_removal(); + // print_entities_yet_to_be_removed(); + // fprintf(stdout, "tick 1\n"); + Game_Tick(double(1.0 / 120.0)); + // print_entities_marked_for_removal(); + // print_entities_yet_to_be_removed(); + PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.nextLevel == NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index); + PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index); + PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 0, err_index); + + level_01 = pke_level_create("load_unload_01", pk_uuid_zed, pk_uuid_zed); + assert(level_01->isMarkedForRemoval == false); + pkeSettings.rt.nextLevel = level_01; + + /* JCB + * Double tick so that the level can get flushed out. + * We need to do this so the first few asserts get a clean starting point. + * This *IS* expected behavior + */ + PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.nextLevel != NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index); + PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index); + PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 0, err_index); + // print_entities_marked_for_removal(); + // print_entities_yet_to_be_removed(); + // fprintf(stdout, "tick 2\n"); + Game_Tick(double(1.0 / 120.0)); + // print_entities_marked_for_removal(); + // print_entities_yet_to_be_removed(); + PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.nextLevel == NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index); + PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index); + PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 1, err_index); + // fprintf(stdout, "tick 3\n"); + Game_Tick(double(1.0 / 120.0)); + // print_entities_marked_for_removal(); + // print_entities_yet_to_be_removed(); + PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.nextLevel == NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index); + PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index); + PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 0, err_index); + + return 0; +} + +int pke_test_load_unload_do_thing_002(int iteration) { + uint64_t err_index = iteration << 16; + + // fprintf(stdout, "begin\n"); + + pkeSettings.rt.activeLevel = pke_level_create("load_unload_faux", pk_uuid_zed, pk_uuid_zed); + assert(pkeSettings.rt.activeLevel->isMarkedForRemoval == false); + + // 1 + PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.nextLevel == NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index); + PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index); + PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 0, err_index); + // print_entities_marked_for_removal(); + // print_entities_yet_to_be_removed(); + // fprintf(stdout, "tick 1\n"); + Game_Tick(double(1.0 / 120.0)); + // print_entities_marked_for_removal(); + // print_entities_yet_to_be_removed(); + PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.nextLevel == NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index); + PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index); + PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 0, err_index); + + level_01 = pke_level_create("load_unload_01", pk_uuid_zed, pk_uuid_zed); + assert(level_01->isMarkedForRemoval == false); + pkeSettings.rt.nextLevel = level_01; + pke_ui_box *bx = pke_ui_box_new_root(PKE_UI_BOX_TYPE_TEXT); + FontRenderSettings frs_01{}; + bx->type_data->text.font_render_handle = FontType_AddStringRender(FontTypeIndex{0}, std::move(cstring_to_pk_cstr("one")), &frs_01, bx); + bx->flags |= PKE_UI_BOX_FLAG_POSITION_TYPE_STATIC; + pke_level_register_root_ui_box(level_01, bx); + + // 11 + PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.nextLevel != NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index); + PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index); + PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 0, err_index); + // print_entities_marked_for_removal(); + // print_entities_yet_to_be_removed(); + // fprintf(stdout, "tick 2\n"); + Game_Tick(double(1.0 / 120.0)); + // print_entities_marked_for_removal(); + // print_entities_yet_to_be_removed(); + PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.nextLevel == NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index); + PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index); + PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 1, err_index); + // fprintf(stdout, "tick 3\n"); + Game_Tick(double(1.0 / 120.0)); + // print_entities_marked_for_removal(); + // print_entities_yet_to_be_removed(); + PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.nextLevel == NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index); + PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index); + PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 0, err_index); + + pkeSettings.rt.nextLevel = pke_level_create("load_unload_faux", pk_uuid_zed, pk_uuid_zed); + + // 26 + // print_entities_marked_for_removal(); + // print_entities_yet_to_be_removed(); + // fprintf(stdout, "tick 4\n"); + Game_Tick(double(1.0 / 120.0)); + // print_entities_marked_for_removal(); + // print_entities_yet_to_be_removed(); + PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.nextLevel == NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index); + PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index); + PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 3, err_index); + // fprintf(stdout, "tick 5\n"); + Game_Tick(double(1.0 / 120.0)); + // print_entities_marked_for_removal(); + // print_entities_yet_to_be_removed(); + PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.nextLevel == NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index); + PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index); + PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 0, err_index); + // fprintf(stdout, "tick 6\n"); + Game_Tick(double(1.0 / 120.0)); + // print_entities_marked_for_removal(); + // print_entities_yet_to_be_removed(); + PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.nextLevel == NULL, err_index); + PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index); + PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index); + PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 0, err_index); + + return 0; +} + +void pke_test_load_unload_init() { + bkt = pk_mem_bucket_create("pke_test_load_unload", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE); + pk_mem_bucket_set_client_mem_bucket(bkt); + pkeSettings.mem_bkt.game = bkt; + pkeSettings.mem_bkt.game_transient = pk_mem_bucket_create("pke_test_load_unload_transient", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_TRANSIENT); + pk_ev_init(bkt); + Physics_Init(); + PkeThreads_Init(); + AM_Init(); + ECS_Init(); + pke_audio_init(); + pke_input_init(); + pke_ui_init(); + PkeCamera_Init(); + FontType_Init(); + pke_scene_master_init(); + pke_level_init(); + EntityType_Init(); +} + +void pke_test_load_unload_teardown() { + EntityType_Teardown(); + pke_level_teardown(); + pke_scene_master_teardown(); + FontType_Teardown(); + PkeCamera_Teardown(); + pke_ui_teardown(); + pke_input_teardown(); + pke_audio_teardown(); + ECS_Teardown(); + AM_Teardown(); + PkeThreads_Teardown(); + Physics_Teardown(); + pk_ev_teardown(); + pk_mem_bucket_destroy(pkeSettings.mem_bkt.game_transient); + pk_mem_bucket_destroy(bkt); + pk_mem_bucket_set_client_mem_bucket(nullptr); + bkt = nullptr; + pkeSettings.mem_bkt.game = nullptr; + pkeSettings.mem_bkt.game_transient = nullptr; + pkeSettings.rt.activeLevel = nullptr; + pkeSettings.rt.nextLevel = nullptr; + pkeSettings.rt.previousLevel = nullptr; +} + +int pke_test_load_unload_001() { + int i, k; + for (i = 0; i < 255; ++i) { + if (k = pke_test_load_unload_do_thing_001(i), k != 0){ + return k; + } + } + return 0; +} + +int pke_test_load_unload_002() { + int i, k; + for (i = 0; i < 255; ++i) { + if (k = pke_test_load_unload_do_thing_002(i), k != 0){ + return k; + } + } + return 0; +} + +struct pke_test_group * +pke_test_load_unload_get_group() +{ + static const uint64_t test_count = 2; + static struct pke_test tests[test_count] = { + { + .title = "test 001", + .func = pke_test_load_unload_001, + .expected_result = 0, + }, + { + .title = "test 002", + .func = pke_test_load_unload_002, + .expected_result = 0, + }, + }; + static struct pke_test_group group{}; + group.title = "load-unload"; + group.group_setup = nullptr; + group.group_teardown = nullptr; + group.test_setup = pke_test_load_unload_init; + group.test_teardown = pke_test_load_unload_teardown; + group.n_tests = test_count; + group.tests = &tests[0]; + return &group; +} + diff --git a/tests/pke-test-load-unload.h b/tests/pke-test-load-unload.h new file mode 100644 index 0000000..be28f0f --- /dev/null +++ b/tests/pke-test-load-unload.h @@ -0,0 +1,16 @@ +#ifndef PKE_PKE_TEST_LOAD_UNLOAD_H +#define PKE_PKE_TEST_LOAD_UNLOAD_H + +#include "pke-test-types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct pke_test_group *pke_test_load_unload_get_group(); + +#ifdef __cplusplus +} +#endif + +#endif /* PKE_PKE_TEST_LOAD_UNLOAD_H */ diff --git a/tests/pke-test-serialization.cpp b/tests/pke-test-serialization.cpp index 374d77e..de483f7 100644 --- a/tests/pke-test-serialization.cpp +++ b/tests/pke-test-serialization.cpp @@ -18,7 +18,7 @@ #include <cstring> #include <sstream> -pk_membucket *bkt = nullptr; +static pk_membucket *bkt = nullptr; const char *test_level_name = "srlztn_test_level"; pke_level *test_level = nullptr; FontType *ft; @@ -48,6 +48,8 @@ const pk_uuid uuid_n[] = { void pke_test_serialization_spinup() { // pk_funcinstr_init(); + bkt = pk_mem_bucket_create("pke_test_serialization", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE); + pk_mem_bucket_set_client_mem_bucket(bkt); pkeSettings.isSimulationPaused = true; pk_ev_init(nullptr); PkeThreads_Init(); @@ -58,8 +60,8 @@ void pke_test_serialization_spinup() { PkeCamera_Init(); pke_scene_master_init(); pke_input_init(); - pke_ui_init(); FontType_Init(); + pke_ui_init(); test_level = pke_level_create(test_level_name, pk_uuid_zed, pk_uuid_zed); // pk_funcinstr_teardown(); }; @@ -68,8 +70,8 @@ void pke_test_serialization_teardown() { // pk_funcinstr_init(); pke_level_teardown(test_level); test_level = nullptr; - FontType_Teardown(); pke_ui_teardown(); + FontType_Teardown(); pke_input_teardown(); pke_scene_master_teardown(); PkeCamera_Teardown(); @@ -79,6 +81,8 @@ void pke_test_serialization_teardown() { AM_Teardown(); PkeThreads_Teardown(); pk_ev_teardown(); + pk_mem_bucket_destroy(bkt); + pk_mem_bucket_set_client_mem_bucket(nullptr); bkt = nullptr; // pk_funcinstr_teardown(); }; @@ -142,7 +146,6 @@ int pke_test_serialization_001() { srlztn_serialize_helper *h; std::stringstream ss; try { - bkt = pk_mem_bucket_create("pke_test_serialization", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE); h = pke_serialize_init(bkt); glm::vec3 pos = glm::vec3(0,1,2); @@ -171,10 +174,8 @@ int pke_test_serialization_001() { pke_serialize_teardown(h); } catch (const std::exception &ex) { - pk_mem_bucket_destroy(bkt); throw; } - pk_mem_bucket_destroy(bkt); pk_funcinstr_teardown(); return 0; } @@ -184,7 +185,6 @@ int pke_test_deserialization_101() { srlztn_deserialize_helper *h; std::stringstream ss(test_001_str); try { - bkt = pk_mem_bucket_create("pke_test_serialization", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE); h = pke_deserialize_init(test_level, bkt); pke_deserialize_scene_from_stream(ss, h); @@ -214,10 +214,8 @@ int pke_test_deserialization_101() { pke_deserialize_teardown(h); } catch (const std::exception &ex) { - pk_mem_bucket_destroy(bkt); throw; } - pk_mem_bucket_destroy(bkt); return 0; } @@ -255,7 +253,6 @@ int pke_test_serialization_002() { pke_kve *kve = nullptr; std::stringstream ss; try { - bkt = pk_mem_bucket_create("pke_test_serialization", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE); h = pke_serialize_init(bkt); // reminder that 'targeting' moves and rotates the camera, so we shouldn't see these values in the output @@ -313,10 +310,8 @@ int pke_test_serialization_002() { pke_serialize_teardown(h); } catch (const std::exception &ex) { - pk_mem_bucket_destroy(bkt); throw; } - pk_mem_bucket_destroy(bkt); return 0; } @@ -327,7 +322,6 @@ int pke_test_deserialization_102() { srlztn_deserialize_helper *h; std::stringstream ss(test_002_str); try { - bkt = pk_mem_bucket_create("pke_test_serialization", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE); h = pke_deserialize_init(test_level, bkt); pke_deserialize_scene_from_stream(ss, h); @@ -385,10 +379,8 @@ int pke_test_deserialization_102() { pke_deserialize_teardown(h); } catch (const std::exception &ex) { - pk_mem_bucket_destroy(bkt); throw; } - pk_mem_bucket_destroy(bkt); return 0; } @@ -433,10 +425,9 @@ int pke_test_serialization_003() { pke_kve *kve = nullptr; std::stringstream ss; try { - bkt = pk_mem_bucket_create("pke_test_serialization", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE); h = pke_serialize_init(bkt); - FontTypeIndex fti; + uint64_t idx_unused; FontRenderSettings frs; frs.char_scale = 1.0; frs.char_spacing_scale = 1.0; @@ -444,7 +435,7 @@ int pke_test_serialization_003() { frs.surface_area_size = glm::ivec2(250, 250); frs.surface_area_pos = glm::ivec2(0, 0); frs.surface_area_type_flags = FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_FLUID; - FontRenderHandle fr_handle = FontType_AddStringRender(FontType_GetFonts(fti)[0].index_ft, std::move(cstring_to_pk_cstr("asdf")), &frs, nullptr, uuid_n[1]); + FontRenderHandle fr_handle = FontType_AddStringRender(FontType_GetFonts(idx_unused)[0].index_ft, std::move(cstring_to_pk_cstr("asdf")), &frs, nullptr, uuid_n[1]); pke_ui_box *ui_box = pke_ui_box_new_root(PKE_UI_BOX_TYPE_TEXT, uuid_n[2]); ui_box->flags |= PKE_UI_BOX_FLAG_POSITION_TYPE_DYNAMIC; @@ -491,10 +482,8 @@ int pke_test_serialization_003() { pke_serialize_teardown(h); } catch (const std::exception &ex) { - pk_mem_bucket_destroy(bkt); throw; } - pk_mem_bucket_destroy(bkt); return 0; } @@ -505,7 +494,6 @@ int pke_test_deserialization_103() { srlztn_deserialize_helper *h; std::stringstream ss(test_003_str); try { - bkt = pk_mem_bucket_create("pke_test_serialization", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE); h = pke_deserialize_init(test_level, bkt); pke_deserialize_scene_from_stream(ss, h); @@ -539,16 +527,15 @@ int pke_test_deserialization_103() { pke_deserialize_scene(h); - FontTypeIndex fti = FontTypeIndex{0}; - FontType *fonts = FontType_GetFonts(fti); + uint64_t idx_unused; + FontType *fonts = FontType_GetFonts(idx_unused); // 66 - PKE_TEST_ASSERT(fti > FontTypeIndex{0}, err_index); PKE_TEST_ASSERT(fonts != nullptr, err_index); - PKE_TEST_ASSERT(fonts->h_render > FontRenderIndex{0}, err_index); + PKE_TEST_ASSERT(idx_unused != 0xFFFFFFFFFFFFFFFF, err_index); PKE_TEST_ASSERT(fonts->n_render > FontRenderIndex{0}, err_index); FontRender *fr = &fonts[0].renders[0]; - // 70 + // 69 PKE_TEST_ASSERT(fr->settings.char_scale == 1.f, err_index); PKE_TEST_ASSERT(fr->settings.line_height_scale == 1.f, err_index); PKE_TEST_ASSERT(fr->settings.char_spacing_scale == 1.f, err_index); @@ -560,7 +547,7 @@ int pke_test_deserialization_103() { PKE_TEST_ASSERT(fr->settings.color_foreground == glm::vec4(0.4, 0.9, 0.5, 0.8), err_index); PKE_TEST_ASSERT(fr->settings.color_background == glm::vec4(0.0, 0.0, 0.0, 0.0), err_index); - // 78 + // 77 PKE_TEST_ASSERT(fr->uuid == uuid_n[1], err_index); PKE_TEST_ASSERT(fr->text.val != nullptr, err_index); PKE_TEST_ASSERT(fr->text.val[0] == 'a', err_index); @@ -569,7 +556,7 @@ int pke_test_deserialization_103() { PKE_TEST_ASSERT(fr->text.val[3] == 'f', err_index); PKE_TEST_ASSERT(fr->text.val[4] == '\0', err_index); - // 85 + // 84 pke_ui_box_count_T count; pke_ui_box **boxes = pke_ui_get_root_boxes(&count); pke_ui_box *box = boxes[0]; @@ -582,10 +569,8 @@ int pke_test_deserialization_103() { pke_deserialize_teardown(h); } catch (const std::exception &ex) { - pk_mem_bucket_destroy(bkt); throw; } - pk_mem_bucket_destroy(bkt); return 0; } @@ -622,7 +607,6 @@ int pke_test_serialization_004() { pke_kve *kve = nullptr; std::stringstream ss; try { - bkt = pk_mem_bucket_create("pke_test_serialization", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE); h = pke_serialize_init(bkt); pke_ui_box *ui_box_p = pke_ui_box_new_root(PKE_UI_BOX_TYPE_STANDARD, uuid_n[2]); @@ -670,10 +654,8 @@ int pke_test_serialization_004() { pke_serialize_teardown(h); } catch (const std::exception &ex) { - pk_mem_bucket_destroy(bkt); throw; } - pk_mem_bucket_destroy(bkt); return 0; } @@ -684,7 +666,6 @@ int pke_test_deserialization_104() { pke_kve *kve = nullptr; std::stringstream ss(test_004_str); try { - bkt = pk_mem_bucket_create("pke_test_serialization", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE); h = pke_deserialize_init(test_level, bkt); pke_deserialize_scene_from_stream(ss, h); @@ -750,10 +731,8 @@ int pke_test_deserialization_104() { pke_deserialize_teardown(h); } catch (const std::exception &ex) { - pk_mem_bucket_destroy(bkt); throw; } - pk_mem_bucket_destroy(bkt); return 0; } diff --git a/tests/pke-test-static-ui.cpp b/tests/pke-test-static-ui.cpp index ca696fc..c102aba 100644 --- a/tests/pke-test-static-ui.cpp +++ b/tests/pke-test-static-ui.cpp @@ -8,6 +8,7 @@ #include "window.hpp" #include "vendor-glm-include.hpp" #include <limits> + struct pke_ui_box_instance_buffer_item { glm::mat4 pos_scale; glm::vec2 px_scale; @@ -18,10 +19,15 @@ struct pke_ui_flex_params { float px_per_unit; float unit_total; }; + #define PKE_TEST_EXPOSE #include "static-ui.hpp" +static pk_membucket *bkt; + void pke_test_static_ui_setup() { + bkt = pk_mem_bucket_create("pke_test_static_ui", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE); + pk_mem_bucket_set_client_mem_bucket(bkt); Extent.width = 1920; Extent.height = 1080; pk_ev_init(nullptr); @@ -35,6 +41,9 @@ void pke_test_static_ui_teardown() { ECS_Teardown(); pk_ev_teardown(); pke_input_teardown(); + pk_mem_bucket_destroy(bkt); + pk_mem_bucket_set_client_mem_bucket(nullptr); + bkt = nullptr; } // test static diff --git a/tests/pke-test.cpp b/tests/pke-test.cpp index 97694b2..4c6f560 100644 --- a/tests/pke-test.cpp +++ b/tests/pke-test.cpp @@ -1,12 +1,13 @@ #include "./pke-test-types.h" -#include "./pke-test-stubs.h" -#include "./pke-test-audio.h" #include "./pke-test-asset-manager.h" +#include "./pke-test-audio.h" #include "./pke-test-dummy.h" +#include "./pke-test-load-unload.h" #include "./pke-test-serialization.h" #include "./pke-test-static-ui.h" +#include "./pke-test-stubs.h" #include "pk.h" #include "unistd.h" @@ -42,6 +43,7 @@ int main(int argc, char *argv[]) pke_test_static_ui_get_group, pke_test_serialization_get_group, pke_test_asset_manager_get_group, + pke_test_load_unload_get_group, // pke_test_audio_get_group, NULL, }; @@ -55,9 +57,6 @@ int main(int argc, char *argv[]) fprintf(stdout, "[pke-test]:[%s] Begin.\n", group->title); if (group->group_setup != NULL) (group->group_setup)(); for (k = 0; k < group->n_tests; ++k) { - struct pk_membucket *bkt = pk_mem_bucket_create("pke-test-bucket", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE); - pk_mem_bucket_set_client_mem_bucket(bkt); - fprintf(stdout, "[pke-test]:[%s]:[%s] Begin.\n", group->title, group->tests[k].title); pke_test_stub_init_vulkan(); if (group->test_setup != NULL) (group->test_setup)(); lj.expected_exit = 0; @@ -76,7 +75,6 @@ int main(int argc, char *argv[]) } if (group->test_teardown != NULL) (group->test_teardown)(); pke_test_stub_teardown_vulkan(); - pk_mem_bucket_destroy(bkt); } if (group->group_teardown != NULL) (group->group_teardown)(); fprintf(stdout, "[pke-test]:[%s] End. ( %s%03d%s / %03d ) Tests Completed.\n", group->title, pass_count == group->n_tests ? CLR_GREEN : CLR_RED, pass_count, CLR_WHITE, group->n_tests); |
