diff --git a/examples/render_groups/main.cpp b/examples/render_groups/main.cpp index 0e78360..24adad9 100644 --- a/examples/render_groups/main.cpp +++ b/examples/render_groups/main.cpp @@ -126,6 +126,7 @@ main() renAddLight(rs, glm::vec3()); renAddLight(rs, glm::vec3()); +#if 0 // FIXME: this introduces a potential buffer overrun. Need to implement // a memory manager for render_groups, eg: // renPushGroup(rs, new_group) @@ -174,6 +175,17 @@ main() entInitMesh(square, sm, GL_LINE_LOOP); renDoRenderLoop(rs, 60, doFrameCallbackPre); +#endif + //rs->assets = memInitBlock(INITIAL_ASSET_BLOCK_SIZE); + rs->assets = memInitBlock(10 * 1024 * 1024); // NOTE: 10MB + assert(rs->assets != nullptr); + + // load assets manually + render_asset* icosphere = memPushAsset(rs->assets, "../data/icosphere.glb"); + assert(icosphere != nullptr); + + render_asset* ship = memPushAsset(rs->assets, "../data/spaceship.glb"); + assert(ship != nullptr); renShutdown(rs); return 0; diff --git a/include/renderer.h b/include/renderer.h index 392ff3d..a5e6d47 100644 --- a/include/renderer.h +++ b/include/renderer.h @@ -47,32 +47,33 @@ struct SDL_Handles struct mesh_asset { // header - size_t size; + uint asset_size; uint num_vertices; uint num_indices; mesh_asset* next; // data + glm::mat4 model_transform; glm::vec3* vertices; uint* indices; glm::vec3* texture_coords; - glm::mat4* model_transform; }; #define MAX_PATH_SIZE 256 struct render_asset { // header - size_t size; + uint total_size; uint num_meshes; uint name_len; render_asset* next; // data char* filepath; - mesh_asset* meshes; + mesh_asset* head_mesh; // FIXME: also need to flatten diffuse_texture->pixels and track size of // util_image structure, ie) another heaader + pixels + //uint tex_size; util_image* diffuse_texture; // FIXME: node_animation has a pointer to a render_object. need to decouple // that somehow @@ -81,12 +82,16 @@ struct render_asset // NOTE: This is a linearly allocated block to contain all used mesh assets // Assets are loaded once, and then copied to video memory as needed. +// NOTE: sub-data structures are implemented as a write only single linked list, +// with no insertion or moving of items +// https://en.wikipedia.org/wiki/Region-based_memory_management +// http://cslibrary.stanford.edu/103/LinkedListBasics.pdf struct asset_memory_block { - uint asset_count; size_t max_size; - render_asset* first; - render_asset* next_free; + render_asset* head; + render_asset* tail; + uint asset_count; }; #define INITIAL_ASSET_BLOCK_SIZE 256 * 1024 * 1024 // 256MB @@ -94,7 +99,7 @@ asset_memory_block* memInitBlock(size_t initial_size = INITIAL_ASSET_BLOCK_SIZE); render_asset* -memAddAsset(const char* filepath); +memPushAsset(asset_memory_block* block, const char* filepath); void memFreeBlock(asset_memory_block* block); @@ -115,6 +120,9 @@ struct render_state render_group** render_groups; uint render_group_count; + // WIP + asset_memory_block* assets; + // TODO: hide shaders behind a better abstraction than 'shader_wrapper' default_shader_program* default_shader; simple_shader_program* simple_shader; diff --git a/src/renderer.cpp b/src/renderer.cpp index 8430bcc..13b3a9d 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -37,6 +37,146 @@ void setDefaults(render_state* rs, glm::vec2 viewport_dims); // interface +// WIP +size_t +getBlockFreeSpace(asset_memory_block* block) +{ + return (uint8_t*) block + + block->max_size + - (uint8_t*) block->tail + + block->tail->total_size; +} + +uint +getAssetSize(const mesh_group& mg, uint name_len) +{ + uint total = sizeof(render_asset); + total += name_len; + + for (uint i = 0; i < mg.num_meshes; i++) { + mesh_info* mi = mg.meshes[i]; + total += sizeof(mesh_asset); + // NOTE: vertices, normals, and tex coords + total += 3 * mi->num_vertices * sizeof(glm::vec3); + total += mi->num_indices * sizeof(uint); + } + + return total; +} + +void* +getAddressOffset(void* address, uint offset) +{ + return (void*) ((uint8_t*) address + offset); +} + +// TODO: replace mesh_info structure +mesh_asset* +initMeshAsset(mesh_asset* mesh, mesh_info* mi) +{ + mesh->num_vertices = mi->num_vertices; + mesh->num_indices = mi->num_indices; + mesh->asset_size = sizeof(mesh_asset); + mesh->vertices = (glm::vec3*) ((uint8_t*) mesh + mesh->asset_size); + // NOTE: vertices, normals, and tex coords + mesh->asset_size += 3 * mesh->num_vertices * sizeof(glm::vec3); + mesh->asset_size += mesh->num_indices * sizeof(uint); + mesh->asset_size += sizeof(glm::mat4); + // FIXME: this should be set in the outer loop + //mesh->next = (mesh_asset*) ((uint8_t*) mesh + mesh->asset_size); + // FIXME: copy vertices, normals, tex coords, and xform + + return mesh; +} + +render_asset* +getNextFreeRenderAsset(asset_memory_block* block) +{ + return (render_asset*) + getAddressOffset(block->tail, block->tail->total_size); +} + +#include +render_asset* +initRenderAsset( + render_asset* ra, + uint total_size, + uint num_meshes, + const char* filepath) +{ + ra->total_size = total_size; + ra->num_meshes = num_meshes; + ra->name_len = (uint) std::strlen(filepath) + 1; + ra->next = nullptr; + ra->filepath = (char*) ra + sizeof(render_asset); + std::memcpy(ra->filepath, filepath, ra->name_len); + ra->head_mesh = (mesh_asset*) ((uint8_t*) ra->filepath + ra->name_len); + // TODO: texture + //ra->diffuse_texture = (util_image*) ra->filepath; + + return ra; +} + +asset_memory_block* +memInitBlock(size_t initial_size) +{ + // NOTE: need to alloc as uint8_t and recast here so we can get the correct + // size in bytes + asset_memory_block* block = (asset_memory_block*) UTIL_ALLOC( + sizeof(asset_memory_block) + initial_size, uint8_t); + block->max_size = initial_size - sizeof(asset_memory_block); + block->head = block->tail = + (render_asset*) ((uint8_t*) block + sizeof(asset_memory_block)); + return block; +} + +void +memFreeBlock(asset_memory_block* block) +{ + utilSafeFree(block); +} + +render_asset* +memPushAsset(asset_memory_block* block, const char* filepath) +{ + // TODO: rewrite mesh.cpp to load assimp structure into render_asset + // directly + mesh_group mg; + meLoadFromFile(mg, filepath); + uint name_len = (uint) std::strlen(filepath) + 1; + assert(name_len <= MAX_PATH_SIZE); + uint asize = getAssetSize(mg, name_len); + + if (getBlockFreeSpace(block) < asize) { + LOG(Error) << "not enough free space in block\n"; + return nullptr; + } + + render_asset* ra = getNextFreeRenderAsset(block); + initRenderAsset(ra, asize, mg.num_meshes, filepath); + block->max_size -= asize; + block->asset_count++; + + // NOTE: special case when adding the first asset + if (block->head == block->tail) + block->head->next = ra; + else + block->tail->next = ra; + + block->tail = ra; + mesh_asset* next = ra->head_mesh; + + for (uint i = 0; i < mg.num_meshes; i++) { + mesh_asset* mesh = initMeshAsset(next, mg.meshes[i]); + next = (mesh_asset*) getAddressOffset(mesh, mesh->asset_size); + // NOTE: leave the last link as nullptr + (i < mg.num_meshes - 1) ? mesh->next = next : mesh->next = nullptr; + } + + return ra; +} +// end WIP + render_state* renInit(const char* title, glm::vec2 viewport_dims, Uint32 SDL_init_flags) { @@ -77,6 +217,8 @@ renShutdown(render_state* rs) lightsOut(rs->lights); utilSafeFree(rs->render_groups); + memFreeBlock(rs->assets); + rs->assets = nullptr; meShutdownAssimp(); SDL_GL_DeleteContext(rs->handles->glContext); SDL_DestroyWindow(rs->handles->window);