From 81bdfd478c7b59f64d648a2af1059656780dd797 Mon Sep 17 00:00:00 2001 From: sam Date: Sun, 10 Nov 2024 10:04:32 +1300 Subject: [PATCH] add basic texture stuff --- compile_commands.json | 42 ++++++- shader.frag | 10 -- shader.frag.spv | Bin 380 -> 0 bytes shader.spv | Bin 1332 -> 0 bytes shader.vert | 12 -- shader.vert.spv | Bin 1048 -> 0 bytes shaders/basic.frag | 13 +++ shaders/basic.vert | 21 ++++ src/brimstone/graphics/command_buffer.c | 9 +- src/brimstone/graphics/device.c | 12 +- src/brimstone/graphics/pipeline.c | 23 +++- src/brimstone/graphics/pipeline.h | 2 + src/brimstone/graphics/shaders.c | 23 +++- src/brimstone/graphics/shaders.h | 5 +- src/brimstone/graphics/transfer_buffer.c | 33 ++++++ src/brimstone/graphics/transfer_buffer.h | 12 ++ src/brimstone/graphics/upload.c | 91 +++++++++------ src/brimstone/graphics/upload.h | 11 +- src/brimstone/graphics/vertex.h | 3 + src/brimstone/init/systems.c | 6 +- src/brimstone/io/copy_pass.c | 4 +- src/brimstone/io/file.c | 28 +++-- src/brimstone/io/file.h | 7 +- src/brimstone/main.c | 134 ++++++++++++++++------- src/brimstone/misc/log.h | 41 +++++++ src/brimstone/misc/malloc.c | 21 ++++ src/brimstone/misc/malloc.h | 13 +++ src/pch.h | 16 +-- xmake.lua | 21 +++- 29 files changed, 454 insertions(+), 159 deletions(-) delete mode 100644 shader.frag delete mode 100644 shader.frag.spv delete mode 100644 shader.spv delete mode 100644 shader.vert delete mode 100644 shader.vert.spv create mode 100644 shaders/basic.frag create mode 100644 shaders/basic.vert create mode 100644 src/brimstone/graphics/transfer_buffer.c create mode 100644 src/brimstone/graphics/transfer_buffer.h create mode 100644 src/brimstone/misc/log.h create mode 100644 src/brimstone/misc/malloc.c create mode 100644 src/brimstone/misc/malloc.h diff --git a/compile_commands.json b/compile_commands.json index f944c8f..75428b9 100644 --- a/compile_commands.json +++ b/compile_commands.json @@ -1,21 +1,51 @@ [ { "directory": "/home/sam/Documents/Projects/brimstone", - "arguments": ["/usr/bin/gcc", "-c", "-g", "-O0", "-Isrc", "-o", "build/.objs/brimstone/linux/arm64/debug/src/brimstone/io/file.c.o", "src/brimstone/io/file.c"], + "arguments": ["/usr/bin/gcc", "-c", "-g", "-O0", "-Isrc", "-DDEBUG", "-I", "/home/sam/.xmake/packages/s/stc/v4.2/bfec6d3335d54b48969cc50946a9b5ac/include", "-I", "/home/sam/.xmake/packages/c/cglm/v0.9.4/02efbe15d36b48b6bf756a5d63445178/include", "-o", "build/.objs/brimstone/linux/arm64/debug/src/brimstone/io/file.c.o", "src/brimstone/io/file.c"], "file": "src/brimstone/io/file.c" }, { "directory": "/home/sam/Documents/Projects/brimstone", - "arguments": ["/usr/bin/gcc", "-c", "-g", "-O0", "-Isrc", "-o", "build/.objs/brimstone/linux/arm64/debug/src/brimstone/shaders/shaders.c.o", "src/brimstone/shaders/shaders.c"], - "file": "src/brimstone/shaders/shaders.c" + "arguments": ["/usr/bin/gcc", "-c", "-g", "-O0", "-Isrc", "-DDEBUG", "-I", "/home/sam/.xmake/packages/s/stc/v4.2/bfec6d3335d54b48969cc50946a9b5ac/include", "-I", "/home/sam/.xmake/packages/c/cglm/v0.9.4/02efbe15d36b48b6bf756a5d63445178/include", "-o", "build/.objs/brimstone/linux/arm64/debug/src/brimstone/io/copy_pass.c.o", "src/brimstone/io/copy_pass.c"], + "file": "src/brimstone/io/copy_pass.c" }, { "directory": "/home/sam/Documents/Projects/brimstone", - "arguments": ["/usr/bin/gcc", "-c", "-g", "-O0", "-Isrc", "-o", "build/.objs/brimstone/linux/arm64/debug/src/brimstone/device/device.c.o", "src/brimstone/device/device.c"], - "file": "src/brimstone/device/device.c" + "arguments": ["/usr/bin/gcc", "-c", "-g", "-O0", "-Isrc", "-DDEBUG", "-I", "/home/sam/.xmake/packages/s/stc/v4.2/bfec6d3335d54b48969cc50946a9b5ac/include", "-I", "/home/sam/.xmake/packages/c/cglm/v0.9.4/02efbe15d36b48b6bf756a5d63445178/include", "-o", "build/.objs/brimstone/linux/arm64/debug/src/brimstone/graphics/transfer_buffer.c.o", "src/brimstone/graphics/transfer_buffer.c"], + "file": "src/brimstone/graphics/transfer_buffer.c" }, { "directory": "/home/sam/Documents/Projects/brimstone", - "arguments": ["/usr/bin/gcc", "-c", "-g", "-O0", "-Isrc", "-o", "build/.objs/brimstone/linux/arm64/debug/src/brimstone/main.c.o", "src/brimstone/main.c"], + "arguments": ["/usr/bin/gcc", "-c", "-g", "-O0", "-Isrc", "-DDEBUG", "-I", "/home/sam/.xmake/packages/s/stc/v4.2/bfec6d3335d54b48969cc50946a9b5ac/include", "-I", "/home/sam/.xmake/packages/c/cglm/v0.9.4/02efbe15d36b48b6bf756a5d63445178/include", "-o", "build/.objs/brimstone/linux/arm64/debug/src/brimstone/graphics/upload.c.o", "src/brimstone/graphics/upload.c"], + "file": "src/brimstone/graphics/upload.c" +}, +{ + "directory": "/home/sam/Documents/Projects/brimstone", + "arguments": ["/usr/bin/gcc", "-c", "-g", "-O0", "-Isrc", "-DDEBUG", "-I", "/home/sam/.xmake/packages/s/stc/v4.2/bfec6d3335d54b48969cc50946a9b5ac/include", "-I", "/home/sam/.xmake/packages/c/cglm/v0.9.4/02efbe15d36b48b6bf756a5d63445178/include", "-o", "build/.objs/brimstone/linux/arm64/debug/src/brimstone/graphics/command_buffer.c.o", "src/brimstone/graphics/command_buffer.c"], + "file": "src/brimstone/graphics/command_buffer.c" +}, +{ + "directory": "/home/sam/Documents/Projects/brimstone", + "arguments": ["/usr/bin/gcc", "-c", "-g", "-O0", "-Isrc", "-DDEBUG", "-I", "/home/sam/.xmake/packages/s/stc/v4.2/bfec6d3335d54b48969cc50946a9b5ac/include", "-I", "/home/sam/.xmake/packages/c/cglm/v0.9.4/02efbe15d36b48b6bf756a5d63445178/include", "-o", "build/.objs/brimstone/linux/arm64/debug/src/brimstone/graphics/shaders.c.o", "src/brimstone/graphics/shaders.c"], + "file": "src/brimstone/graphics/shaders.c" +}, +{ + "directory": "/home/sam/Documents/Projects/brimstone", + "arguments": ["/usr/bin/gcc", "-c", "-g", "-O0", "-Isrc", "-DDEBUG", "-I", "/home/sam/.xmake/packages/s/stc/v4.2/bfec6d3335d54b48969cc50946a9b5ac/include", "-I", "/home/sam/.xmake/packages/c/cglm/v0.9.4/02efbe15d36b48b6bf756a5d63445178/include", "-o", "build/.objs/brimstone/linux/arm64/debug/src/brimstone/graphics/device.c.o", "src/brimstone/graphics/device.c"], + "file": "src/brimstone/graphics/device.c" +}, +{ + "directory": "/home/sam/Documents/Projects/brimstone", + "arguments": ["/usr/bin/gcc", "-c", "-g", "-O0", "-Isrc", "-DDEBUG", "-I", "/home/sam/.xmake/packages/s/stc/v4.2/bfec6d3335d54b48969cc50946a9b5ac/include", "-I", "/home/sam/.xmake/packages/c/cglm/v0.9.4/02efbe15d36b48b6bf756a5d63445178/include", "-o", "build/.objs/brimstone/linux/arm64/debug/src/brimstone/graphics/pipeline.c.o", "src/brimstone/graphics/pipeline.c"], + "file": "src/brimstone/graphics/pipeline.c" +}, +{ + "directory": "/home/sam/Documents/Projects/brimstone", + "arguments": ["/usr/bin/gcc", "-c", "-g", "-O0", "-Isrc", "-DDEBUG", "-I", "/home/sam/.xmake/packages/s/stc/v4.2/bfec6d3335d54b48969cc50946a9b5ac/include", "-I", "/home/sam/.xmake/packages/c/cglm/v0.9.4/02efbe15d36b48b6bf756a5d63445178/include", "-o", "build/.objs/brimstone/linux/arm64/debug/src/brimstone/init/systems.c.o", "src/brimstone/init/systems.c"], + "file": "src/brimstone/init/systems.c" +}, +{ + "directory": "/home/sam/Documents/Projects/brimstone", + "arguments": ["/usr/bin/gcc", "-c", "-g", "-O0", "-Isrc", "-DDEBUG", "-I", "/home/sam/.xmake/packages/s/stc/v4.2/bfec6d3335d54b48969cc50946a9b5ac/include", "-I", "/home/sam/.xmake/packages/c/cglm/v0.9.4/02efbe15d36b48b6bf756a5d63445178/include", "-o", "build/.objs/brimstone/linux/arm64/debug/src/brimstone/main.c.o", "src/brimstone/main.c"], "file": "src/brimstone/main.c" }] diff --git a/shader.frag b/shader.frag deleted file mode 100644 index 084e7df..0000000 --- a/shader.frag +++ /dev/null @@ -1,10 +0,0 @@ -#version 460 - -layout(location = 0) in vec4 vertColor; - -layout(location = 0) out vec4 fragColor; - -void main() { - fragColor = vertColor; -} - diff --git a/shader.frag.spv b/shader.frag.spv deleted file mode 100644 index 17f5fecd5b3fad32880d5bd0af4f6184a7558666..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 380 zcmYk1xeCHy5QJA_4sS)!P89oKp(2Pj7HQJ?1OX2O4~XJZ`am{<^Th*ynC$NC?9Rr? z4}7znl`XKUyH&+eWO56sTYJMWqE&e_v$ZJ!R|R0yFL`g~oz(5jHd(5d`j|7gEInI88aKY3(* zDYSJ}tqW&?xP^Tg=B2pRZlEp8TEr9L4z>(KzKnJg|3<=moUn7gXA%8A(kT+XS_-r=4QTD z<<8uxxEthhG;49+bz=7Yiag(eSmZ_g2AKP->BZHNV)k~Q9OvJ{JDYPkzq$Wi%=%5d zcT?|Q2-{8WOi#Hf-+}MS<-7Ppb_@TK8}Uy3e}C!r42yi3#4CTGKgb)Q z&$HPRbHZfiednDsGiRHPorw_Mh3POEzJ|e>4-J?AH(vSH>BZ?@zr5btKlr9%HZ&`t znz=Al#bf;6w)2ia<^%Q_Tf>_C8u(`lk}$^aO`E`|zt4K*Nw?_sh}Br%u8D*>mccj0 z_C?p$TVoZFfE zR}{ls!Vd1^aX$BI(^1?4yThh{BX)kVGyI{#`90GEH{{IAjq03D&N*VOv7B$$BIAAP z?By)6_adzPHX3V;mx;#lDYk;14_;yKO2LzOwem+bb{{$Q@A1}))yH||)r;NN9d^NL zXR#2Tj+elTM5&NtUi=ADzYbo)TO+qg(!h0 zeSXr_cQzM$t`j?BylaD4&J#JmwcKdWt(qI{nZjAG-n>13v5Vh(8}sdaALkIK*ekbw G$NmGxxjyOu diff --git a/shaders/basic.frag b/shaders/basic.frag new file mode 100644 index 0000000..06f11b4 --- /dev/null +++ b/shaders/basic.frag @@ -0,0 +1,13 @@ +#version 460 + +layout(location = 0) in vec4 vertColor; +layout(location = 1) in vec2 vertTexCoords; + +layout(location = 0) out vec4 fragColor; + +layout(set = 2, binding = 0) uniform sampler2D Sampler; + +void main() { + fragColor = texture(Sampler, vertTexCoords) * vertColor; +} + diff --git a/shaders/basic.vert b/shaders/basic.vert new file mode 100644 index 0000000..e5698ce --- /dev/null +++ b/shaders/basic.vert @@ -0,0 +1,21 @@ +#version 460 + +layout(location = 0) in vec3 aPos; +layout(location = 1) in vec3 aColor; +layout(location = 2) in vec2 aTexCoords; + +layout(location = 0) out vec4 vertColor; +layout(location = 1) out vec2 vertTexCoords; + +layout(set = 1, binding = 0) uniform UBO { + mat4 viewproj; + mat4 model; +}; + +void main() { + vertTexCoords = aTexCoords; + vertColor = vec4(aColor, 1.0f); + + mat4 mvp = viewproj * model; + gl_Position = mvp * vec4(aPos, 1.0f); +} diff --git a/src/brimstone/graphics/command_buffer.c b/src/brimstone/graphics/command_buffer.c index a240b7e..ed68476 100644 --- a/src/brimstone/graphics/command_buffer.c +++ b/src/brimstone/graphics/command_buffer.c @@ -1,13 +1,10 @@ -#include #include SDL_GPUCommandBuffer* CommandBufferAcquire(SDL_GPUDevice* device) { SDL_assert(device != NULL); SDL_GPUCommandBuffer* command_buffer = SDL_AcquireGPUCommandBuffer(device); - if(command_buffer == NULL) { - SDL_Log("Failed to acquire command buffer: %s", SDL_GetError()); - } + LogAssertSDL(command_buffer != NULL, "Failed to acquire GPU command buffer"); return command_buffer; } @@ -16,9 +13,7 @@ bool CommandBufferSubmit(SDL_GPUCommandBuffer* command_buffer) { SDL_assert(command_buffer != NULL); bool success = SDL_SubmitGPUCommandBuffer(command_buffer); - if(!success) { - SDL_Log("Failed to submit command buffer: %s", SDL_GetError()); - } + LogAssertSDL(success, "Failed to submit command buffer"); return success; } diff --git a/src/brimstone/graphics/device.c b/src/brimstone/graphics/device.c index 33304b1..224c293 100644 --- a/src/brimstone/graphics/device.c +++ b/src/brimstone/graphics/device.c @@ -1,14 +1,12 @@ -#include -#include #include SDL_GPUDevice* DeviceCreate() { + // TODO: once SDL3 and adjacent tools have stable releases shadercross and such will be easier to add + // and other backends and shader formats can be used SDL_GPUDevice* device = SDL_CreateGPUDevice(SDL_GPU_SHADERFORMAT_SPIRV, true, NULL); - if(device == NULL) { - SDL_Log("Failed to create device: %s", SDL_GetError()); - } else { - SDL_Log("Created GPU device using %s", SDL_GetGPUDeviceDriver(device)); - } + LogAssertSDL(device != NULL, "Failed to create device"); + + SDL_Log("Created GPU device using %s", SDL_GetGPUDeviceDriver(device)); return device; } diff --git a/src/brimstone/graphics/pipeline.c b/src/brimstone/graphics/pipeline.c index 87bfb57..9b5e839 100644 --- a/src/brimstone/graphics/pipeline.c +++ b/src/brimstone/graphics/pipeline.c @@ -27,7 +27,7 @@ SDL_GPUGraphicsPipeline* GraphicsPipelineCreate(SDL_GPUDevice* device, SDL_Windo .pitch = sizeof(Vertex), }, }, - .num_vertex_attributes = 2, + .num_vertex_attributes = 3, .vertex_attributes = (SDL_GPUVertexAttribute[]){ { .buffer_slot = 0, @@ -40,6 +40,12 @@ SDL_GPUGraphicsPipeline* GraphicsPipelineCreate(SDL_GPUDevice* device, SDL_Windo .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3, .location = 1, .offset = offsetof(Vertex, color), + }, + { + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2, + .location = 2, + .offset = offsetof(Vertex, texcoords), } } }, @@ -47,9 +53,18 @@ SDL_GPUGraphicsPipeline* GraphicsPipelineCreate(SDL_GPUDevice* device, SDL_Windo .vertex_shader = vertex_shader, .fragment_shader = fragment_shader, }); - if(pipeline == NULL) { - SDL_Log("Failed to create pipeline: %s", SDL_GetError()); - } + LogAssertSDL(pipeline != NULL, "Failed to create pipeline"); return pipeline; } + +void GraphicsPipelineBind(SDL_GPURenderPass* render_pass, SDL_GPUGraphicsPipeline* pipeline) { + SDL_BindGPUGraphicsPipeline(render_pass, pipeline); +} + +void GraphicsPipelineFree(SDL_GPUDevice* device, SDL_GPUGraphicsPipeline* pipeline) { + SDL_assert(device != NULL); + SDL_assert(pipeline != NULL); + + SDL_ReleaseGPUGraphicsPipeline(device, pipeline); +} diff --git a/src/brimstone/graphics/pipeline.h b/src/brimstone/graphics/pipeline.h index c2cca64..f9b4f6c 100644 --- a/src/brimstone/graphics/pipeline.h +++ b/src/brimstone/graphics/pipeline.h @@ -5,5 +5,7 @@ SDL_GPUGraphicsPipeline* GraphicsPipelineCreate(SDL_GPUDevice* device, SDL_Window* window, SDL_GPUShader* vertex_shader, SDL_GPUShader* fragment_shader); +void GraphicsPipelineBind(SDL_GPURenderPass* render_pass, SDL_GPUGraphicsPipeline* pipeline); +void GraphicsPipelineFree(SDL_GPUDevice* device, SDL_GPUGraphicsPipeline* pipeline); #endif diff --git a/src/brimstone/graphics/shaders.c b/src/brimstone/graphics/shaders.c index 6f7130c..c84a102 100644 --- a/src/brimstone/graphics/shaders.c +++ b/src/brimstone/graphics/shaders.c @@ -1,9 +1,12 @@ #include -SDL_GPUShader* ShaderLoad(SDL_GPUDevice* device, const char* filename, SDL_GPUShaderStage stage) { +SDL_GPUShader* ShaderLoad(SDL_GPUDevice* device, const char* filename, SDL_GPUShaderStage stage, + uint32_t num_uniform_buffers, uint32_t num_samplers) { SDL_assert(device != NULL); - FileData file = FileRead(filename); + FileData file = FileReadBinary(filename); + LogAssertErrnof(file.data != NULL, "Failed to read shader file: %s", filename); + SDL_GPUShader* shader = SDL_CreateGPUShader(device, &(SDL_GPUShaderCreateInfo){ .code = file.data, @@ -11,10 +14,20 @@ SDL_GPUShader* ShaderLoad(SDL_GPUDevice* device, const char* filename, SDL_GPUSh .stage = stage, .format = SDL_GPU_SHADERFORMAT_SPIRV, .entrypoint = "main", + .num_uniform_buffers = num_uniform_buffers, + .num_samplers = num_samplers, }); - if(shader == NULL) { - SDL_Log("Failed to create shader: %s", SDL_GetError()); - } + + FileFree(file); + + LogAssertSDL(shader != NULL, "Failed to create shader"); return shader; } + +void ShaderFree(SDL_GPUDevice* device, SDL_GPUShader* shader) { + SDL_assert(device != NULL); + SDL_assert(shader != NULL); + + SDL_ReleaseGPUShader(device, shader); +} diff --git a/src/brimstone/graphics/shaders.h b/src/brimstone/graphics/shaders.h index 1f24c9d..747c901 100644 --- a/src/brimstone/graphics/shaders.h +++ b/src/brimstone/graphics/shaders.h @@ -3,6 +3,9 @@ #include -SDL_GPUShader* ShaderLoad(SDL_GPUDevice* device, const char* filename, SDL_GPUShaderStage stage); +// SDL_GPUShader* ShaderLoad(SDL_GPUDevice* device, const char* filename, SDL_GPUShaderStage stage); +SDL_GPUShader* ShaderLoad(SDL_GPUDevice* device, const char* filename, SDL_GPUShaderStage stage, + uint32_t num_uniform_buffers, uint32_t num_samplers); +void ShaderFree(SDL_GPUDevice* device, SDL_GPUShader* shader); #endif diff --git a/src/brimstone/graphics/transfer_buffer.c b/src/brimstone/graphics/transfer_buffer.c new file mode 100644 index 0000000..49ad05b --- /dev/null +++ b/src/brimstone/graphics/transfer_buffer.c @@ -0,0 +1,33 @@ +#include + +SDL_GPUTransferBuffer* TransferBufferCreate( + SDL_GPUDevice* device, SDL_GPUTransferBufferUsage usage, size_t size) { + SDL_assert(device != NULL); + + SDL_GPUTransferBuffer* transfer_buffer = SDL_CreateGPUTransferBuffer(device, + &(SDL_GPUTransferBufferCreateInfo){ + .usage = usage, + .size = size, + }); + LogAssertSDL(transfer_buffer != NULL, "Failed to create GPU transfer buffer"); + + return transfer_buffer; +} + +void* TransferBufferMap(SDL_GPUDevice* device, SDL_GPUTransferBuffer* transfer_buffer) { + void* mapped_buffer = SDL_MapGPUTransferBuffer(device, transfer_buffer, false); + LogAssertSDL(mapped_buffer != NULL, "Failed to map GPU transfer buffer"); + + return mapped_buffer; +} + +void TransferBufferUnmap(SDL_GPUDevice* device, SDL_GPUTransferBuffer* transfer_buffer) { + SDL_UnmapGPUTransferBuffer(device, transfer_buffer); +} + +void TransferBufferFree(SDL_GPUDevice* device, SDL_GPUTransferBuffer* transfer_buffer) { + SDL_assert(device != NULL); + SDL_assert(transfer_buffer != NULL); + + SDL_ReleaseGPUTransferBuffer(device, transfer_buffer); +} diff --git a/src/brimstone/graphics/transfer_buffer.h b/src/brimstone/graphics/transfer_buffer.h new file mode 100644 index 0000000..07f7738 --- /dev/null +++ b/src/brimstone/graphics/transfer_buffer.h @@ -0,0 +1,12 @@ +#ifndef TRANSFER_BUFFER_H +#define TRANSFER_BUFFER_H + +#include + +SDL_GPUTransferBuffer* TransferBufferCreate( + SDL_GPUDevice* device, SDL_GPUTransferBufferUsage usage, size_t size); +void* TransferBufferMap(SDL_GPUDevice* device, SDL_GPUTransferBuffer* transfer_buffer); +void TransferBufferUnmap(SDL_GPUDevice* device, SDL_GPUTransferBuffer* transfer_buffer); +void TransferBufferFree(SDL_GPUDevice* device, SDL_GPUTransferBuffer* transfer_buffer); + +#endif diff --git a/src/brimstone/graphics/upload.c b/src/brimstone/graphics/upload.c index 143a5cd..8d12dc8 100644 --- a/src/brimstone/graphics/upload.c +++ b/src/brimstone/graphics/upload.c @@ -1,41 +1,36 @@ -#include "brimstone/graphics/command_buffer.h" -#include #include -bool UploadToBuffer(SDL_GPUDevice* device, const void* data, size_t byte_size, SDL_GPUBuffer* buffer) { +UploadState UploadBegin(SDL_GPUDevice* device, const void* data, size_t byte_size) { + UploadState state = { 0 }; + + state.transfer_buffer = TransferBufferCreate(device, SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD, byte_size); + void* mapped_buffer = TransferBufferMap(device, state.transfer_buffer); + memcpy(mapped_buffer, data, byte_size); + TransferBufferUnmap(device, state.transfer_buffer); + + state.command_buffer = CommandBufferAcquire(device); + state.copy_pass = CopyPassBegin(state.command_buffer); + + return state; +} + +void UploadEnd(SDL_GPUDevice* device, const UploadState* state) { + CopyPassEnd(state->copy_pass); + CommandBufferSubmit(state->command_buffer); + TransferBufferFree(device, state->transfer_buffer); +} + +void UploadToBuffer(SDL_GPUDevice* device, const void* data, size_t byte_size, SDL_GPUBuffer* buffer) { SDL_assert(device != NULL); SDL_assert(data != NULL); + SDL_assert(byte_size > 0); SDL_assert(buffer != NULL); - SDL_GPUTransferBuffer* transfer_buffer = SDL_CreateGPUTransferBuffer(device, - &(SDL_GPUTransferBufferCreateInfo){ - .usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD, - .size = byte_size, - }); - if(transfer_buffer == NULL) { - SDL_Log("Failed to create transfer buffer: %s", SDL_GetError()); - return false; - } + UploadState upload_state = UploadBegin(device, data, byte_size); - void* mapped_buffer = SDL_MapGPUTransferBuffer(device, transfer_buffer, false); - if(mapped_buffer == NULL) { - SDL_Log("Failed to map GPU transfer buffer: %s", SDL_GetError()); - return false; - } - - memcpy(mapped_buffer, data, byte_size); - - SDL_UnmapGPUTransferBuffer(device, transfer_buffer); - - SDL_GPUCommandBuffer* copy_command_buffer = CommandBufferAcquire(device); - SDL_assert(copy_command_buffer != NULL); - - SDL_GPUCopyPass* copy_pass = CopyPassBegin(copy_command_buffer); - SDL_assert(copy_pass != NULL); - - SDL_UploadToGPUBuffer(copy_pass, + SDL_UploadToGPUBuffer(upload_state.copy_pass, &(SDL_GPUTransferBufferLocation){ - .transfer_buffer = transfer_buffer, + .transfer_buffer = upload_state.transfer_buffer, .offset = 0, }, &(SDL_GPUBufferRegion){ @@ -45,9 +40,35 @@ bool UploadToBuffer(SDL_GPUDevice* device, const void* data, size_t byte_size, S }, false); - CopyPassEnd(copy_pass); - bool submit_success = CommandBufferSubmit(copy_command_buffer); - SDL_ReleaseGPUTransferBuffer(device, transfer_buffer); - - return submit_success; + UploadEnd(device, &upload_state); +} + +void UploadToTexture(SDL_GPUDevice* device, SDL_Surface* surface, SDL_GPUTexture* texture) { + UploadToTextureRaw(device, surface->pixels, surface->w, surface->h, texture); +} + +void UploadToTextureRaw( + SDL_GPUDevice* device, const void* pixels, int width, int height, SDL_GPUTexture* texture) { + SDL_assert(device != NULL); + SDL_assert(pixels != NULL); + SDL_assert(width > 0); + SDL_assert(height > 0); + SDL_assert(texture != NULL); + + UploadState upload_state = UploadBegin(device, pixels, width * height * 4); + + SDL_UploadToGPUTexture(upload_state.copy_pass, + &(SDL_GPUTextureTransferInfo){ + .transfer_buffer = upload_state.transfer_buffer, + .offset = 0, + }, + &(SDL_GPUTextureRegion){ + .texture = texture, + .w = width, + .h = height, + .d = 1, + }, + false); + + UploadEnd(device, &upload_state); } diff --git a/src/brimstone/graphics/upload.h b/src/brimstone/graphics/upload.h index 6e00f22..b296f35 100644 --- a/src/brimstone/graphics/upload.h +++ b/src/brimstone/graphics/upload.h @@ -3,6 +3,15 @@ #include -bool UploadToBuffer(SDL_GPUDevice* device, const void* data, size_t byte_size, SDL_GPUBuffer* buffer); +typedef struct { + SDL_GPUTransferBuffer* transfer_buffer; + SDL_GPUCopyPass* copy_pass; + SDL_GPUCommandBuffer* command_buffer; +} UploadState; + +void UploadToBuffer(SDL_GPUDevice* device, const void* data, size_t byte_size, SDL_GPUBuffer* buffer); +void UploadToTexture(SDL_GPUDevice* device, SDL_Surface* surface, SDL_GPUTexture* texture); +void UploadToTextureRaw( + SDL_GPUDevice* device, const void* pixels, int width, int height, SDL_GPUTexture* texture); #endif diff --git a/src/brimstone/graphics/vertex.h b/src/brimstone/graphics/vertex.h index d685077..284d4f8 100644 --- a/src/brimstone/graphics/vertex.h +++ b/src/brimstone/graphics/vertex.h @@ -8,6 +8,9 @@ typedef struct { struct { float r, g, b; } color; + struct { + float x, y; + } texcoords; } Vertex; #endif diff --git a/src/brimstone/init/systems.c b/src/brimstone/init/systems.c index 2fe182f..07b84b4 100644 --- a/src/brimstone/init/systems.c +++ b/src/brimstone/init/systems.c @@ -1,8 +1,6 @@ #include void InitSystems() { - if(!SDL_Init(SDL_INIT_VIDEO)) { - SDL_Log("Failed to initialize SDL: %s", SDL_GetError()); - exit(EXIT_FAILURE); - } + bool success = SDL_Init(SDL_INIT_VIDEO); + LogAssertSDL(success, "Failed to initialize SDL"); } diff --git a/src/brimstone/io/copy_pass.c b/src/brimstone/io/copy_pass.c index c1f2f15..d8830f8 100644 --- a/src/brimstone/io/copy_pass.c +++ b/src/brimstone/io/copy_pass.c @@ -4,9 +4,7 @@ SDL_GPUCopyPass* CopyPassBegin(SDL_GPUCommandBuffer* copy_command_buffer) { SDL_assert(copy_command_buffer != NULL); SDL_GPUCopyPass* copy_pass = SDL_BeginGPUCopyPass(copy_command_buffer); - if(copy_pass == NULL) { - SDL_Log("Failed to begin copy pass: %s", SDL_GetError()); - } + LogAssertSDL(copy_pass != NULL, "Failed to begin copy pass"); return copy_pass; } diff --git a/src/brimstone/io/file.c b/src/brimstone/io/file.c index 16ded48..cdfad6a 100644 --- a/src/brimstone/io/file.c +++ b/src/brimstone/io/file.c @@ -1,32 +1,42 @@ -#include "pch.h" +#include -FileData FileRead(const char* filename) { - FILE* f = fopen(filename, "r"); - if(f == NULL) { +FileData FileRead(const char* filename, const char* mode) { + FILE* file = fopen(filename, mode); + if(file == NULL) { perror(filename); return (FileData){ 0 }; } - fseek(f, 0, SEEK_END); - size_t length = ftell(f); - rewind(f); + fseek(file, 0, SEEK_END); + size_t length = ftell(file); + rewind(file); uint8_t* buffer = malloc(length); if(buffer == NULL) { perror("Failed to allocate memory"); return (FileData){ 0 }; } - size_t read_count = fread(buffer, sizeof(char), length, f); + + size_t read_count = fread(buffer, sizeof(char), length, file); + fclose(file); if(read_count != length) { perror("Failed to read entire file"); return (FileData){ 0 }; } return (FileData){ - .data = buffer, .length = length, + .data = buffer, }; } +FileData FileReadText(const char* filename) { + return FileRead(filename, "r"); +} + +FileData FileReadBinary(const char* filename) { + return FileRead(filename, "rb"); +} + void FileFree(FileData file) { free(file.data); } diff --git a/src/brimstone/io/file.h b/src/brimstone/io/file.h index b596f90..9c388a7 100644 --- a/src/brimstone/io/file.h +++ b/src/brimstone/io/file.h @@ -5,11 +5,14 @@ #include typedef struct { - uint8_t* data; size_t length; + uint8_t* data; } FileData; -FileData FileRead(const char* filename); +FileData FileRead(const char* filename, const char* mode); +FileData FileReadText(const char* filename); +FileData FileReadBinary(const char* filename); + void FileFree(FileData file); #endif diff --git a/src/brimstone/main.c b/src/brimstone/main.c index 896d36f..ffac10f 100644 --- a/src/brimstone/main.c +++ b/src/brimstone/main.c @@ -1,43 +1,78 @@ -#include "brimstone/graphics/pipeline.h" #include int main(int argc, char** argv) { InitSystems(); SDL_GPUDevice* device = DeviceCreate(); - SDL_assert(device != NULL); - - SDL_Window* window = SDL_CreateWindow("Brimstone", 800, 600, 0); - if(window == NULL) { - SDL_Log("SDL_CreateWindow: %s", SDL_GetError()); - exit(EXIT_FAILURE); - } - SDL_ClaimWindowForGPUDevice(device, window); + SDL_Window* window = SDL_CreateWindow("Brimstone", 800, 600, SDL_WINDOW_RESIZABLE); + LogAssertSDL(window != NULL, "Failed to create window"); + bool success = SDL_ClaimWindowForGPUDevice(device, window); + LogAssertSDL(success, "Failed to claim window for device"); Vertex vertices[] = { - { -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f }, - { 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f }, - { 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f }, + { { -0.5f, 0.5f, 0.0f }, { 1.0f, 1.0f, 1.0f }, { 0.0f, 0.0f } }, // top left + { { -0.5f, -0.5f, 0.0f }, { 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f } }, // bottom left + { { 0.5f, -0.5f, 0.0f }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f } }, // bottom right + { { 0.5f, 0.5f, 0.0f }, { 1.0f, 1.0f, 1.0f }, { 1.0f, 0.0f } }, // top right }; + int indices[] = { 0, 1, 2, 2, 3, 0 }; SDL_GPUBuffer* vertex_buffer = SDL_CreateGPUBuffer(device, &(SDL_GPUBufferCreateInfo){ .usage = SDL_GPU_BUFFERUSAGE_VERTEX, .size = sizeof(vertices), }); + LogAssertSDL(vertex_buffer != NULL, "Failed to create GPU buffer"); + UploadToBuffer(device, vertices, sizeof(vertices), vertex_buffer); - bool upload_successful = UploadToBuffer(device, vertices, sizeof(vertices), vertex_buffer); - SDL_assert(upload_successful); + SDL_GPUBuffer* index_buffer = SDL_CreateGPUBuffer(device, + &(SDL_GPUBufferCreateInfo){ + .usage = SDL_GPU_BUFFERUSAGE_INDEX, + .size = sizeof(indices), + }); + LogAssertSDL(index_buffer != NULL, "Failed to create GPU buffer"); + UploadToBuffer(device, indices, sizeof(indices), index_buffer); - SDL_GPUShader* vertex_shader = ShaderLoad(device, "shader.vert.spv", SDL_GPU_SHADERSTAGE_VERTEX); - SDL_assert(vertex_shader != NULL); + SDL_GPUShader* vertex_shader = ShaderLoad( + device, "shaders/basic.vert.spv", SDL_GPU_SHADERSTAGE_VERTEX, 1, 0); - SDL_GPUShader* fragment_shader = ShaderLoad(device, "shader.frag.spv", SDL_GPU_SHADERSTAGE_FRAGMENT); - SDL_assert(fragment_shader != NULL); + SDL_GPUShader* fragment_shader = ShaderLoad( + device, "shaders/basic.frag.spv", SDL_GPU_SHADERSTAGE_FRAGMENT, 0, 1); SDL_GPUGraphicsPipeline* pipeline = GraphicsPipelineCreate( device, window, vertex_shader, fragment_shader); - SDL_assert(pipeline != NULL); + + ShaderFree(device, vertex_shader); + ShaderFree(device, fragment_shader); + + const char* path = "image.jxl"; + SDL_Surface* image = IMG_Load(path); + LogAssertSDLf(image != NULL, "Failed to load image: %s", path); + + if(image->format != SDL_PIXELFORMAT_ABGR8888) { + SDL_Surface* converted = SDL_ConvertSurface(image, SDL_PIXELFORMAT_ABGR8888); + SDL_DestroySurface(image); + image = converted; + } + SDL_GPUTexture* texture = SDL_CreateGPUTexture(device, + &(SDL_GPUTextureCreateInfo){ + .type = SDL_GPU_TEXTURETYPE_2D, + .format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM, + .width = image->w, + .height = image->h, + .layer_count_or_depth = 1, + .num_levels = 1, + .usage = SDL_GPU_TEXTUREUSAGE_SAMPLER, + }); + LogAssertSDL(texture != NULL, "Failed to create texture"); + UploadToTexture(device, image, texture); + SDL_GPUSampler* sampler = SDL_CreateGPUSampler(device, &(SDL_GPUSamplerCreateInfo){ 0 }); + LogAssertSDL(sampler != NULL, "Failed to create sampler"); + + struct { + mat4 viewproj; + mat4 model; + } ubo; bool running = true; SDL_Event event; @@ -50,29 +85,44 @@ int main(int argc, char** argv) { } } - SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(device); - if(cmd == NULL) { - SDL_Log("SDL_AcquireGPUCommandBuffer: %s", SDL_GetError()); - exit(EXIT_FAILURE); - } + int width, height; + SDL_GetWindowSize(window, &width, &height); + + mat4 view = GLM_MAT4_IDENTITY_INIT; + mat4 projection = GLM_MAT4_IDENTITY_INIT; + + glm_perspective(glm_rad(70.0f), (float)width / (float)height, 0.1f, 1000.0f, projection); + glm_translate(view, (vec3){ 0.0f, 0.0f, -2.0f }); + glm_mat4_mul(projection, view, ubo.viewproj); + + SDL_GPUCommandBuffer* cmd = CommandBufferAcquire(device); SDL_GPUTexture* swapchain; uint32_t swapchain_width, swapchain_height; - SDL_AcquireGPUSwapchainTexture(cmd, window, &swapchain, &swapchain_width, &swapchain_height); + success = SDL_AcquireGPUSwapchainTexture( + cmd, window, &swapchain, &swapchain_width, &swapchain_height); + LogAssertSDL(success, "Failed to acquire swapchain texture"); + if(swapchain == NULL) { + SDL_CancelGPUCommandBuffer(cmd); + continue; + } + + glm_mat4_identity(ubo.model); + /*glm_rotate( + ubo.model, glm_rad(sinf(SDL_GetTicks() / 200.0f) * 50.0f), (vec3){ 0.5f, 1.0f, 0.2f });*/ + + SDL_PushGPUVertexUniformData(cmd, 0, &ubo, sizeof(ubo)); SDL_GPURenderPass* render_pass = SDL_BeginGPURenderPass(cmd, &(SDL_GPUColorTargetInfo){ .texture = swapchain, .load_op = SDL_GPU_LOADOP_CLEAR, - .clear_color = (SDL_FColor){ .r = 0.1f, .g = 0.3f, .b = 0.4f, .a = 1.0f }, + .clear_color = (SDL_FColor){ 0.1f, 0.3f, 0.4f, 1.0f }, }, 1, NULL); - if(render_pass == NULL) { - SDL_Log("SDL_BeginGPURenderPass: %s", SDL_GetError()); - exit(EXIT_FAILURE); - } + LogAssertSDL(render_pass != NULL, "Failed to begin render pass"); - SDL_BindGPUGraphicsPipeline(render_pass, pipeline); + GraphicsPipelineBind(render_pass, pipeline); SDL_BindGPUVertexBuffers(render_pass, 0, (SDL_GPUBufferBinding[]){ { @@ -81,15 +131,25 @@ int main(int argc, char** argv) { }, }, 1); - SDL_DrawGPUPrimitives(render_pass, 3, 1, 0, 0); - + SDL_BindGPUIndexBuffer(render_pass, + &(SDL_GPUBufferBinding){ + .buffer = index_buffer, + .offset = 0, + }, + 1); + SDL_BindGPUFragmentSamplers(render_pass, 0, + &(SDL_GPUTextureSamplerBinding){ + .texture = texture, + .sampler = sampler, + }, + 1); + SDL_DrawGPUIndexedPrimitives(render_pass, sizeof(indices), 1, 0, 0, 0); SDL_EndGPURenderPass(render_pass); - if(!SDL_SubmitGPUCommandBuffer(cmd)) { - SDL_Log("SDL_SubmitGPUCommandBuffer: %s", SDL_GetError()); - exit(EXIT_FAILURE); - } + CommandBufferSubmit(cmd); } + GraphicsPipelineFree(device, pipeline); + return 0; } diff --git a/src/brimstone/misc/log.h b/src/brimstone/misc/log.h new file mode 100644 index 0000000..a8585f7 --- /dev/null +++ b/src/brimstone/misc/log.h @@ -0,0 +1,41 @@ +#ifndef LOG_H +#define LOG_H + +#include +#include +#include +#include + +#define LogInfof(fmt, ...) SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, fmt, __VA_ARGS__) +#define LogDebugf(fmt, ...) SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, fmt, __VA_ARGS__) +#define LogWarnf(fmt, ...) SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, fmt, __VA_ARGS__) +#define LogErrorf(fmt, ...) SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, fmt, __VA_ARGS__) +#define LogCriticalf(fmt, ...) SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, fmt, __VA_ARGS__) +#define LogTracef(fmt, ...) SDL_LogTrace(SDL_LOG_CATEGORY_APPLICATION, fmt, __VA_ARGS__) +#define LogVerbosef(fmt, ...) SDL_LogVerbose(SDL_LOG_CATEGORY_APPLICATION, fmt, __VA_ARGS__) + +#define LogAssertf(condition, fmt, ...) \ + do { \ + if(!(condition)) { \ + LogErrorf(fmt, __VA_ARGS__); \ + SDL_assert(condition); \ + } \ + } while(0) + +#define LogAssert(condition, msg) LogAssertf(condition, "%s", msg) +#define LogAssertSDLf(condition, fmt, ...) LogAssertf(condition, fmt ": %s", __VA_ARGS__, SDL_GetError()) +#define LogAssertErrnof(condition, fmt, ...) \ + LogAssertf(condition, fmt ": %s", __VA_ARGS__, strerror(errno)) + +#define LogAssertSDL(condition, msg) LogAssertSDLf(condition, "%s", msg) +#define LogAssertErrno(condition, msg) LogAssertErrnof(condition, "%s", msg) + +#define LogInfo(msg) LogInfof("%s", msg) +#define LogDebug(msg) LogDebugf("%s", msg) +#define LogWarn(msg) LogWarnf("%s", msg) +#define LogError(msg) LogErrorf("%s", msg) +#define LogCritical(msg) LogCritical("%s", msg) +#define LogTrace(msg) LogTrace("%s", msg) +#define LogVerbose(msg) LogVerbose("%s", msg) + +#endif diff --git a/src/brimstone/misc/malloc.c b/src/brimstone/misc/malloc.c new file mode 100644 index 0000000..5d1f790 --- /dev/null +++ b/src/brimstone/misc/malloc.c @@ -0,0 +1,21 @@ +#include + +/*#define i_type TagMap +#define i_key_str +#define i_val void* +#include + +TagMap tags = { 0 };*/ + +void* Malloc(size_t size) { + return MallocTag(size, "untagged"); +} + +void* MallocTag(size_t size, const char* tag) { + MallocHeader* ptr = malloc(sizeof(MallocHeader) + size); + LogAssertErrnof(ptr != NULL, "Failed to allocate %zu bytes (%s)", size, tag); + + ptr->size = size; + + return ptr + 1; +} diff --git a/src/brimstone/misc/malloc.h b/src/brimstone/misc/malloc.h new file mode 100644 index 0000000..c3de6b3 --- /dev/null +++ b/src/brimstone/misc/malloc.h @@ -0,0 +1,13 @@ +#ifndef MALLOC_H +#define MALLOC_H + +#include + +typedef struct { + size_t size; +} MallocHeader; + +void* Malloc(size_t size); +void* MallocTag(size_t size, const char* tag); + +#endif diff --git a/src/pch.h b/src/pch.h index dfc7a79..83dbd2e 100644 --- a/src/pch.h +++ b/src/pch.h @@ -1,31 +1,27 @@ #ifndef PCH_H #define PCH_H -#include #include #include #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include #include #include #include +#include #include #include #include #include #include +#include +#include + +#include #endif diff --git a/xmake.lua b/xmake.lua index 8608525..df5a4d2 100644 --- a/xmake.lua +++ b/xmake.lua @@ -1,12 +1,21 @@ add_rules("mode.debug", "mode.release") -add_requires("stc") +add_requires("stc", "cglm") +add_requires("glslang", {configs = {binaryonly = true}}) target("brimstone") set_kind("binary") - set_rundir(".") - add_files("src/**.c") - add_links("SDL3") - add_includedirs("src") set_pcheader("src/pch.h") - add_packages("stc") + set_rundir("build") + + add_files("src/**.c") + add_links("SDL3", "SDL3_image") + add_includedirs("src") + add_packages("stc", "glslang", "cglm") + + add_rules("utils.glsl2spv", {outputdir = "build/shaders"}) + add_files("shaders/**.vert", "shaders/**.frag") + + if is_mode("debug") then + add_defines("DEBUG") + end