summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoromniscient <17525998+omnisci3nce@users.noreply.github.com>2024-10-17 19:18:38 +1100
committeromniscient <17525998+omnisci3nce@users.noreply.github.com>2024-10-17 19:18:38 +1100
commitc557763010a8976680f37609ca10e666ff849cd9 (patch)
treef2fa05b3e45c5fdc3565d654d485b2c46717324e
parent3e1aea0243f54e0b68baa3b19ac19f3d965484e0 (diff)
metal triangle!
-rw-r--r--Makefile17
-rw-r--r--README.md2
-rw-r--r--assets/shaders/triangle.metal38
-rw-r--r--examples/triangle.c46
-rw-r--r--include/celeritas.h77
-rw-r--r--src/backend_mtl.m150
-rw-r--r--src/core.c13
-rw-r--r--src/log.c2
-rw-r--r--src/mem.c89
9 files changed, 387 insertions, 47 deletions
diff --git a/Makefile b/Makefile
index 67b79a4..cc1c3c0 100644
--- a/Makefile
+++ b/Makefile
@@ -18,6 +18,11 @@ EXAMPLES_DIR := examples
SRCS := $(wildcard $(SRC_DIR)/*.c $(SRC_DIR)/**/*.c)
OBJS := $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR)/%.o,$(SRCS))
+# Shader files
+METAL_SHADERS := $(wildcard $(SHADER_DIR)/*.metal)
+METAL_AIR_FILES := $(patsubst $(SHADER_DIR)/%.metal,$(SHADER_OUT_DIR)/%.air,$(METAL_SHADERS))
+METAL_LIB := $(SHADER_OUT_DIR)/default.metallib
+
# Library outputs
STATIC_LIB := $(BUILD_DIR)/libceleritas.a
ifeq ($(UNAME_S),Darwin)
@@ -57,13 +62,21 @@ shared: $(SHARED_LIB)
static: $(STATIC_LIB)
+# Shaders
+$(SHADER_OUT_DIR)/%.air: $(SHADER_DIR)/%.metal
+ @mkdir -p $(SHADER_OUT_DIR)
+ xcrun -sdk macosx metal -c $< -o $@
+
+$(METAL_LIB): $(METAL_AIR_FILES)
+ xcrun -sdk macosx metallib $^ -o $(SHADER_OUT_DIR)/default.metallib
+
.PHONY: all
all: shared static
.PHONY: triangle
-triangle: $(EXAMPLES_DIR)/triangle.c $(SHARED_LIB)
+triangle: $(EXAMPLES_DIR)/triangle.c $(SHARED_LIB) $(SHADER_OUT_DIR)/triangle.air $(METAL_LIB)
@mkdir -p $(BUILD_DIR)
- $(CC) $(CFLAGS) $(EXAMPLES_DIR)/triangle.c -L$(BUILD_DIR) -lceleritas $(LDFLAGS)
+ $(CC) $(CFLAGS) $(EXAMPLES_DIR)/triangle.c -L$(BUILD_DIR) -lceleritas $(LDFLAGS) -o $(BUILD_DIR)/triangle.bin
MTL_DEBUG_LAYER=1 build/triangle.bin
.PHONY: clean
diff --git a/README.md b/README.md
index 1226c6f..60d59a6 100644
--- a/README.md
+++ b/README.md
@@ -37,4 +37,4 @@ Renderer Goals:
- Check symbols in an 'archive' (static library)
- `nm -C build/libcore.a`
- Generate compiler_commands.json
- - `xmake project -k compile_commands`
+ - `bear -- make`
diff --git a/assets/shaders/triangle.metal b/assets/shaders/triangle.metal
index 6055705..6522360 100644
--- a/assets/shaders/triangle.metal
+++ b/assets/shaders/triangle.metal
@@ -1,33 +1,17 @@
#include <metal_stdlib>
-
using namespace metal;
-struct VertexIn {
- float2 position;
- float3 color;
-};
-
-struct VertexOut {
- float4 computedPosition [[position]];
- float3 fragColor;
-};
-
-// Vertex shader
-vertex VertexOut basic_vertex(
- const device VertexIn* vertex_array [[ buffer(0) ]],
- unsigned int vid [[ vertex_id ]]
- ) {
- VertexIn v = vertex_array[vid];
-
- VertexOut outVertex = VertexOut();
- outVertex.computedPosition = float4(v.position.xy, 0.0, 1.0);
- outVertex.fragColor = v.color;
- return outVertex;
+vertex float4
+vertexShader(uint vertexID [[vertex_id]],
+ constant simd::float3* vertexPositions)
+{
+ float4 vertexOutPositions = float4(vertexPositions[vertexID][0],
+ vertexPositions[vertexID][1],
+ vertexPositions[vertexID][2],
+ 1.0f);
+ return vertexOutPositions;
}
-// Fragment shader
-fragment float4 basic_fragment(
- VertexOut interpolated [[stage_in]]
-) {
- return float4(interpolated.fragColor, 1.0);
+fragment float4 fragmentShader(float4 vertexOutPositions [[stage_in]]) {
+ return float4(182.0f/255.0f, 240.0f/255.0f, 228.0f/255.0f, 1.0f);
} \ No newline at end of file
diff --git a/examples/triangle.c b/examples/triangle.c
index ccbcea3..c304562 100644
--- a/examples/triangle.c
+++ b/examples/triangle.c
@@ -2,11 +2,57 @@
#include <celeritas.h>
+static vec4 vertices[] = {
+ {-0.5f, -0.5f, 0.0f, 1.0},
+ { 0.5f, -0.5f, 0.0f, 1.0},
+ { 0.0f, 0.5f, 0.0f, 1.0}
+};
+
+pipeline_handle draw_pipeline;
+buf_handle tri_vert_buffer;
+
+void draw() {
+ render_pass_desc d = {};
+ gpu_encoder* enc = ral_render_encoder(d);
+ ral_encode_bind_pipeline(enc, draw_pipeline);
+ ral_encode_set_vertex_buf(enc, tri_vert_buffer);
+ ral_encode_draw_tris(enc, 0, 3);
+ ral_encoder_finish_and_submit(enc);
+}
+
int main() {
core_bringup("Celeritas Example: Triangle", NULL);
+ // create rendering pipeline
+ gfx_pipeline_desc pipeline_desc = {
+ .label = "Triangle drawing pipeline",
+ .vertex_desc = NULL, // TODO
+ .vertex = {
+ .source = NULL,
+ .is_spirv = false,
+ .entry_point = "vertexShader",
+ .shader_stage = VISIBILITY_VERTEX,
+ },
+ .fragment = {
+ .source = NULL,
+ .is_spirv = false,
+ .entry_point = "fragmentShader",
+ .shader_stage = VISIBILITY_FRAGMENT,
+ },
+ };
+
+ draw_pipeline = ral_gfx_pipeline_create(pipeline_desc);
+
+ // create our buffer to hold vertices
+ printf("size of vertices %ld\n", sizeof(vec4) * 3);
+ tri_vert_buffer = ral_buffer_create(sizeof(vec4) * 3, &vertices);
+
while (!app_should_exit()) {
glfwPollEvents();
+
+ ral_frame_start();
+ ral_frame_draw(&draw);
+ ral_frame_end();
}
return 0;
diff --git a/include/celeritas.h b/include/celeritas.h
index c157918..d4dab98 100644
--- a/include/celeritas.h
+++ b/include/celeritas.h
@@ -6,6 +6,8 @@
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
+#include <assert.h>
+#include <string.h>
// Third party dependency includes
#include <glfw3.h>
@@ -127,7 +129,28 @@ void* void_pool_alloc(void_pool* pool, u32* out_raw_handle);
void void_pool_dealloc(void_pool* pool, u32 raw_handle);
u32 void_pool_insert(void_pool* pool, void* item);
-// TODO: Typed pool
+#define TYPED_POOL(T, Name) \
+ typedef struct Name##_pool { \
+ void_pool inner; \
+ } Name##_pool; \
+ \
+ static Name##_pool Name##_pool_create(void* storage, u64 cap, u64 entry_size) { \
+ void_pool p = void_pool_create(storage, "\"" #Name "\"", cap, entry_size); \
+ return (Name##_pool){ .inner = p }; \
+ } \
+ static inline T* Name##_pool_get(Name##_pool* pool, Name##_handle handle) { \
+ return (T*)void_pool_get(&pool->inner, handle.raw); \
+ } \
+ static inline T* Name##_pool_alloc(Name##_pool* pool, Name##_handle* out_handle) { \
+ return (T*)void_pool_alloc(&pool->inner, &out_handle->raw); \
+ } \
+ static inline void Name##_pool_dealloc(Name##_pool* pool, Name##_handle handle) { \
+ void_pool_dealloc(&pool->inner, handle.raw); \
+ } \
+ static Name##_handle Name##_pool_insert(Name##_pool* pool, T* item) { \
+ u32 raw_handle = void_pool_insert(pool, item); \
+ return (Name##_handle){ .raw = raw_handle }; \
+ }
// --- Strings
@@ -234,15 +257,15 @@ inlined vec3 vec3_div(vec3 u, f32 s);
DEFINE_HANDLE(buf_handle);
DEFINE_HANDLE(tex_handle);
DEFINE_HANDLE(pipeline_handle);
+DEFINE_HANDLE(compute_pipeline_handle);
#define MAX_VERTEX_ATTRIBUTES 16
#define MAX_SHADER_BINDINGS 16
// Backend-specific structs
typedef struct gpu_swapchain gpu_swapchain;
-typedef struct gpu_compute_pipeline gpu_compute_pipeline;
-typedef struct gpu_gfx_pipeline gpu_gfx_pipeline;
-typedef struct gpu_encoder gpu_encoder; // Command encoder
+typedef struct gpu_encoder gpu_encoder; // Render command encoder
+typedef struct gpu_compute_encoder gpu_compute_encoder;
typedef struct gpu_buffer gpu_buffer;
typedef struct gpu_texture gpu_texture;
@@ -325,21 +348,30 @@ typedef struct shader_data_layout {
size_t binding_count;
} shader_data_layout;
-typedef struct shader_desc {
- // TODO
-} shader_desc;
+typedef struct shader_function {
+ const char* source;
+ bool is_spirv;
+ const char* entry_point;
+ shader_vis shader_stage;
+} shader_function;
typedef enum cull_mode { CULL_BACK_FACE, CULL_FRONT_FACE } cull_mode;
typedef struct gfx_pipeline_desc {
const char* label;
vertex_desc vertex_desc;
- shader_desc vs;
- shader_desc fs;
+ shader_function vertex;
+ shader_function fragment;
// ShaderDataLayout data_layouts[MAX_SHADER_DATA_LAYOUTS];
// u32 data_layouts_count;
} gfx_pipeline_desc;
+typedef struct compute_pipeline_desc { /* TODO */ } compute_pipeline_desc;
+
+typedef struct render_pass_desc {
+
+} render_pass_desc;
+
// --- RAL Functions
// Resources
@@ -348,12 +380,39 @@ void ral_buffer_destroy(buf_handle handle);
tex_handle ral_texture_create(texture_desc desc, bool create_view, const void* data);
void ral_texture_destroy(tex_handle handle);
+// Encoders / cmd buffers
+/** @brief grabs a new command encoder from the pool of available ones and begins recording */
+gpu_encoder* ral_render_encoder(render_pass_desc rpass_desc);
+
+gpu_compute_encoder ral_compute_encoder();
+
+void ral_encoder_finish(gpu_encoder* enc);
+void ral_encoder_submit(gpu_encoder* enc);
+void ral_encoder_finish_and_submit(gpu_encoder* enc);
+
+pipeline_handle ral_gfx_pipeline_create(gfx_pipeline_desc desc);
+void ral_gfx_pipeline_destroy(pipeline_handle handle);
+
+compute_pipeline_handle ral_compute_pipeline_create(compute_pipeline_desc);
+void ral_compute_pipeline_destroy(compute_pipeline_handle handle);
+
+// Encoding
+void ral_encode_bind_pipeline(gpu_encoder* enc, pipeline_handle pipeline);
+void ral_encode_set_vertex_buf(gpu_encoder* enc, buf_handle vbuf);
+void ral_encode_set_index_buf(gpu_encoder* enc, buf_handle ibuf);
+void ral_encode_draw_tris(gpu_encoder* enc, size_t start, size_t count);
+
// Backend lifecycle
void ral_backend_init(const char* window_name, struct GLFWwindow* window);
void ral_backend_shutdown();
// Frame lifecycle
+
+typedef void (*scoped_draw_commands)(); // callback that we run our draw commands within.
+// allows us to wrap some api-specific behaviour
+
void ral_frame_start();
+void ral_frame_draw(scoped_draw_commands draw_fn);
void ral_frame_end();
// --- Containers (Forward declared as internals are unnecessary for external header)
diff --git a/src/backend_mtl.m b/src/backend_mtl.m
index b3cd224..6ff5058 100644
--- a/src/backend_mtl.m
+++ b/src/backend_mtl.m
@@ -1,7 +1,6 @@
-#define GPU_METAL 1
+#include <celeritas.h>
#ifdef GPU_METAL
-#include <celeritas.h>
#define MTL_DEBUG_LAYER 1
@@ -16,6 +15,8 @@
#define GLFW_EXPOSE_NATIVE_COCOA
#import <GLFW/glfw3native.h>
+NAMESPACED_LOGGER(metal);
+
// --- RAL types
struct gpu_swapchain {
@@ -23,6 +24,22 @@ struct gpu_swapchain {
CAMetalLayer* swapchain;
};
+struct gpu_encoder {
+ id<MTLCommandBuffer> cmd_buffer;
+ id<MTLRenderCommandEncoder> cmd_encoder;
+};
+
+typedef struct metal_pipeline {
+ id<MTLRenderPipelineState> pso;
+} metal_pipeline;
+
+typedef struct metal_buffer {
+ id<MTLBuffer> id;
+} metal_buffer;
+
+TYPED_POOL(metal_buffer, buf);
+TYPED_POOL(metal_pipeline, pipeline);
+
typedef struct metal_context {
GLFWwindow* window;
NSWindow* metal_window;
@@ -30,20 +47,25 @@ typedef struct metal_context {
id<MTLDevice> device;
id<CAMetalDrawable> surface;
gpu_swapchain default_swapchain;
+ id<MTLLibrary> default_library;
id<MTLCommandQueue> command_queue;
+
+ /* pools */
+ buf_pool bufpool;
+ pipeline_pool psopool; // pso = pipeline state object
} metal_context;
static metal_context ctx;
void ral_backend_init(const char* window_name, struct GLFWwindow* window) {
- printf("loading Metal backend\n");
+ TRACE("loading Metal backend");
- printf("gpu device creation\n");
+ TRACE("gpu device creation");
const id<MTLDevice> gpu = MTLCreateSystemDefaultDevice();
ctx.device = gpu;
- printf("window init\n");
+ TRACE("window init");
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwMakeContextCurrent(window);
NSWindow* nswindow = glfwGetCocoaWindow(window);
@@ -55,14 +77,130 @@ void ral_backend_init(const char* window_name, struct GLFWwindow* window) {
metal_layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
ctx.metal_window.contentView.layer = metal_layer;
ctx.metal_window.contentView.wantsLayer = true;
+ ctx.default_swapchain.swapchain = metal_layer;
- printf("command queue creation\n");
+ TRACE("command queue creation");
const id<MTLCommandQueue> queue = [ctx.device newCommandQueue];
ctx.command_queue = queue;
+
+ TRACE("resource pool init");
+ metal_buffer* buffer_storage = malloc(sizeof(metal_buffer) * 100);
+ ctx.bufpool = buf_pool_create(buffer_storage, 100, sizeof(metal_buffer));
+
+ metal_pipeline* pipeline_storage = malloc(sizeof(metal_pipeline) * 100);
+ ctx.psopool = pipeline_pool_create(pipeline_storage, 100, sizeof(metal_pipeline));
+
+ TRACE("create default metal lib");
+ NSError* nserr = 0x0;
+ id<MTLLibrary> default_library = [ctx.device newLibraryWithFile:@"build/shaders/default.metallib" error:&nserr];
+ if (!default_library) {
+ ERROR("Error loading metal lib\n");
+ exit(1);
+ }
+ ctx.default_library = default_library;
+
+ INFO("Successfully initialised Metal RAL backend");
}
void ral_backend_shutdown() {
// no-op
}
+buf_handle ral_buffer_create(u64 size, const void *data) {
+ buf_handle handle;
+ metal_buffer* buffer = buf_pool_alloc(&ctx.bufpool, &handle);
+ buffer->id = [ctx.device newBufferWithBytes:data length:size options:MTLResourceStorageModeShared];
+
+ return handle;
+}
+
+pipeline_handle ral_gfx_pipeline_create(gfx_pipeline_desc desc) {
+ TRACE("creating graphics pipeline");
+
+ pipeline_handle handle;
+ metal_pipeline* p = pipeline_pool_alloc(&ctx.psopool, &handle);
+
+ @autoreleasepool {
+ // setup vertex and fragment shaders
+ NSString* vertex_entry_point = [NSString stringWithUTF8String:desc.vertex.entry_point];
+ id<MTLFunction> vertex_func = [ctx.default_library newFunctionWithName:vertex_entry_point];
+ assert(vertex_func);
+
+ NSString* fragment_entry_point = [NSString stringWithUTF8String:desc.fragment.entry_point];
+ id<MTLFunction> fragment_func = [ctx.default_library newFunctionWithName:fragment_entry_point];
+ assert(fragment_func);
+
+ NSError* err = 0x0;
+ MTLRenderPipelineDescriptor* pld = [[MTLRenderPipelineDescriptor alloc] init];
+ // in auto release pool so dont need to call release()
+
+ [pld setLabel:@"Pipeline"];
+ [pld setVertexFunction:vertex_func];
+ [pld setFragmentFunction:fragment_func];
+ pld.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
+ pld.colorAttachments[0].blendingEnabled = YES;
+ assert(pld);
+
+ id<MTLRenderPipelineState> pso = [ctx.device newRenderPipelineStateWithDescriptor:pld error:&err];
+ assert(pso);
+ p->pso = pso;
+ }
+
+ return handle;
+}
+
+gpu_encoder* ral_render_encoder(render_pass_desc rpass_desc) {
+ id<MTLCommandBuffer> buffer = [ctx.command_queue commandBuffer];
+
+ // create renderpass descriptor
+ MTLRenderPassDescriptor* rpd = [[MTLRenderPassDescriptor alloc] init];
+ MTLRenderPassColorAttachmentDescriptor* cd = rpd.colorAttachments[0];
+ [cd setTexture:ctx.surface.texture];
+ [cd setLoadAction:MTLLoadActionClear];
+ MTLClearColor clearColor = MTLClearColorMake(41.0f/255.0f, 42.0f/255.0f, 48.0f/255.0f, 1.0);
+ [cd setClearColor:clearColor];
+ [cd setStoreAction:MTLStoreActionStore];
+
+ id<MTLRenderCommandEncoder> encoder = [buffer renderCommandEncoderWithDescriptor:rpd];
+
+ gpu_encoder* enc = malloc(sizeof(gpu_encoder));
+ enc->cmd_buffer = buffer;
+ enc->cmd_encoder = encoder;
+
+ return enc;
+}
+
+void ral_encoder_finish_and_submit(gpu_encoder* enc) {
+ [enc->cmd_encoder endEncoding];
+ [enc->cmd_buffer presentDrawable:ctx.surface];
+ [enc->cmd_buffer commit];
+ [enc->cmd_buffer waitUntilCompleted];
+}
+
+void ral_encode_bind_pipeline(gpu_encoder *enc, pipeline_handle pipeline) {
+ metal_pipeline* p = pipeline_pool_get(&ctx.psopool, pipeline);
+ [enc->cmd_encoder setRenderPipelineState:p->pso];
+}
+
+void ral_encode_set_vertex_buf(gpu_encoder *enc, buf_handle vbuf) {
+ metal_buffer* b = buf_pool_get(&ctx.bufpool, vbuf);
+ [enc->cmd_encoder setVertexBuffer:b->id offset:0 atIndex:0 ];
+}
+
+void ral_encode_draw_tris(gpu_encoder* enc, size_t start, size_t count) {
+ MTLPrimitiveType tri_primitive = MTLPrimitiveTypeTriangle;
+ [enc->cmd_encoder drawPrimitives:tri_primitive vertexStart:start vertexCount:count];
+}
+
+void ral_frame_start() {}
+
+void ral_frame_draw(scoped_draw_commands draw_fn) {
+ @autoreleasepool {
+ ctx.surface = [ctx.default_swapchain.swapchain nextDrawable];
+ draw_fn();
+ }
+}
+
+void ral_frame_end() {}
+
#endif \ No newline at end of file
diff --git a/src/core.c b/src/core.c
index 080e806..210c282 100644
--- a/src/core.c
+++ b/src/core.c
@@ -1,11 +1,18 @@
// The engine "core"
#include <celeritas.h>
+#include <stdlib.h>
NAMESPACED_LOGGER(core);
core g_core = {0};
+#ifdef GPU_METAL
+static const char* gapi = "Metal";
+#else
+static const char* gapi = "Vulkan";
+#endif
+
// forward declares
void key_callback(GLFWwindow* win, int key, int scancode, int action, int mods);
@@ -14,7 +21,11 @@ void core_bringup(const char* window_name, struct GLFWwindow* optional_window) {
INFO("Create GLFW window");
glfwInit();
- GLFWwindow* glfw_window = glfwCreateWindow(800, 600, window_name, NULL, NULL);
+
+ char* full_window_name = malloc(sizeof(char) * 100);
+ int _offset = sprintf(full_window_name, "%s (%s)", window_name, gapi);
+
+ GLFWwindow* glfw_window = glfwCreateWindow(800, 600, full_window_name, NULL, NULL);
g_core.window = glfw_window;
// This may move into a renderer struct
diff --git a/src/log.c b/src/log.c
index 5a6ca5c..1083f29 100644
--- a/src/log.c
+++ b/src/log.c
@@ -7,5 +7,5 @@ static const char* log_level_strings[] = {
void log_output(char* module, loglevel level, const char* message, ...) {
char out_msg[4096];
- printf("[%s] %s Msg: %s\n", module, log_level_strings[level], message);
+ printf("[%s] %s - %s\n", module, log_level_strings[level], message);
}
diff --git a/src/mem.c b/src/mem.c
index e69de29..ba122d7 100644
--- a/src/mem.c
+++ b/src/mem.c
@@ -0,0 +1,89 @@
+#include <celeritas.h>
+
+void_pool void_pool_create(void* storage, const char* debug_label, u64 capacity, u64 entry_size) {
+ size_t memory_requirements = capacity * entry_size;
+ // void* backing_buf = arena_alloc(a, memory_requirements);
+
+ assert(entry_size >= sizeof(void_pool_header)); // TODO: create my own assert with error message
+
+ void_pool pool = { .capacity = capacity,
+ .entry_size = entry_size,
+ .count = 0,
+ .backing_buffer = storage,
+ .free_list_head = NULL,
+ .debug_label = debug_label };
+
+ void_pool_free_all(&pool);
+
+ return pool;
+}
+
+void void_pool_free_all(void_pool* pool) {
+ // set all entries to be free
+ for (u64 i = 0; i < pool->capacity; i++) {
+ void* ptr = &pool->backing_buffer[i * pool->entry_size];
+ void_pool_header* free_node =
+ (void_pool_header*)ptr; // we reuse the actual entry itself to hold the header
+ if (i == (pool->capacity - 1)) {
+ // if the last one we make its next pointer NULL indicating its full
+ free_node->next = NULL;
+ }
+ free_node->next = pool->free_list_head;
+ // now the head points to this entry
+ pool->free_list_head = free_node;
+ }
+}
+
+void* void_pool_get(void_pool* pool, u32 raw_handle) {
+ // An handle is an index into the array essentially
+ void* ptr = pool->backing_buffer + (raw_handle * pool->entry_size);
+ return ptr;
+}
+
+void* void_pool_alloc(void_pool* pool, u32* out_raw_handle) {
+ // get the next free node
+ if (pool->count == pool->capacity) {
+ // WARN("Pool is full!");
+ return NULL;
+ }
+ if (pool->free_list_head == NULL) {
+ // ERROR("%s Pool is full (head = null)", pool->debug_label);
+ return NULL;
+ }
+ void_pool_header* free_node = pool->free_list_head;
+
+ // What index does this become?
+ uintptr_t start = (uintptr_t)pool->backing_buffer;
+ uintptr_t cur = (uintptr_t)free_node;
+ // TRACE("%ld %ld ", start, cur);
+ assert(cur > start);
+ u32 index = (u32)((cur - start) / pool->entry_size);
+ /* printf("Index %d\n", index); */
+ if (out_raw_handle != NULL) {
+ *out_raw_handle = index;
+ }
+
+ pool->free_list_head = free_node->next;
+
+ memset(free_node, 0, pool->entry_size);
+ pool->count++;
+ return (void*)free_node;
+}
+
+void void_pool_dealloc(void_pool* pool, u32 raw_handle) {
+ // push free node back onto the free list
+ void* ptr = void_pool_get(pool, raw_handle);
+ void_pool_header* freed_node = (void_pool_header*)ptr;
+
+ freed_node->next = pool->free_list_head;
+ pool->free_list_head = freed_node;
+
+ pool->count--;
+}
+
+u32 void_pool_insert(void_pool* pool, void* item) {
+ u32 raw_handle;
+ void* item_dest = void_pool_alloc(pool, &raw_handle);
+ memcpy(item_dest, item, pool->entry_size);
+ return raw_handle;
+}