Browse Source

get linear memory allocation working

In hindsight, this was a dumb idea. I basically made a binary file
format with headers pointing to offsets in the memory block. It would be
easier carve up the memory block for arrays of data structures with
pointers to other arrays of (eg. glm::vec3), like a normal arena
allocator. On the plus side, I think I came up with a new anti-pattern.
render_group_fix dumb_memory_idea
cinnaboot 5 years ago
parent
commit
43bdfeed0c
  1. 12
      examples/render_groups/main.cpp
  2. 24
      include/renderer.h
  3. 142
      src/renderer.cpp

12
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;

24
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;

142
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 <cstring>
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);

Loading…
Cancel
Save