summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
4 files changed, 246 insertions, 8 deletions
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;
+}