add basic texture stuff

This commit is contained in:
sam 2024-11-10 10:04:32 +13:00
parent c0b7845215
commit 81bdfd478c
29 changed files with 454 additions and 159 deletions

View file

@ -1,21 +1,51 @@
[ [
{ {
"directory": "/home/sam/Documents/Projects/brimstone", "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" "file": "src/brimstone/io/file.c"
}, },
{ {
"directory": "/home/sam/Documents/Projects/brimstone", "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"], "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/shaders/shaders.c" "file": "src/brimstone/io/copy_pass.c"
}, },
{ {
"directory": "/home/sam/Documents/Projects/brimstone", "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"], "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/device/device.c" "file": "src/brimstone/graphics/transfer_buffer.c"
}, },
{ {
"directory": "/home/sam/Documents/Projects/brimstone", "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" "file": "src/brimstone/main.c"
}] }]

View file

@ -1,10 +0,0 @@
#version 460
layout(location = 0) in vec4 vertColor;
layout(location = 0) out vec4 fragColor;
void main() {
fragColor = vertColor;
}

Binary file not shown.

Binary file not shown.

View file

@ -1,12 +0,0 @@
#version 460
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor;
layout(location = 0) out vec4 vertColor;
void main() {
vertColor = vec4(aColor, 1.0f);
gl_Position = vec4(aPos, 1.0f);
}

Binary file not shown.

13
shaders/basic.frag Normal file
View file

@ -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;
}

21
shaders/basic.vert Normal file
View file

@ -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);
}

View file

@ -1,13 +1,10 @@
#include <SDL3/SDL_gpu.h>
#include <pch.h> #include <pch.h>
SDL_GPUCommandBuffer* CommandBufferAcquire(SDL_GPUDevice* device) { SDL_GPUCommandBuffer* CommandBufferAcquire(SDL_GPUDevice* device) {
SDL_assert(device != NULL); SDL_assert(device != NULL);
SDL_GPUCommandBuffer* command_buffer = SDL_AcquireGPUCommandBuffer(device); SDL_GPUCommandBuffer* command_buffer = SDL_AcquireGPUCommandBuffer(device);
if(command_buffer == NULL) { LogAssertSDL(command_buffer != NULL, "Failed to acquire GPU command buffer");
SDL_Log("Failed to acquire command buffer: %s", SDL_GetError());
}
return command_buffer; return command_buffer;
} }
@ -16,9 +13,7 @@ bool CommandBufferSubmit(SDL_GPUCommandBuffer* command_buffer) {
SDL_assert(command_buffer != NULL); SDL_assert(command_buffer != NULL);
bool success = SDL_SubmitGPUCommandBuffer(command_buffer); bool success = SDL_SubmitGPUCommandBuffer(command_buffer);
if(!success) { LogAssertSDL(success, "Failed to submit command buffer");
SDL_Log("Failed to submit command buffer: %s", SDL_GetError());
}
return success; return success;
} }

View file

@ -1,14 +1,12 @@
#include <SDL3/SDL_gpu.h>
#include <SDL3/SDL_log.h>
#include <pch.h> #include <pch.h>
SDL_GPUDevice* DeviceCreate() { 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); SDL_GPUDevice* device = SDL_CreateGPUDevice(SDL_GPU_SHADERFORMAT_SPIRV, true, NULL);
if(device == NULL) { LogAssertSDL(device != NULL, "Failed to create device");
SDL_Log("Failed to create device: %s", SDL_GetError());
} else {
SDL_Log("Created GPU device using %s", SDL_GetGPUDeviceDriver(device)); SDL_Log("Created GPU device using %s", SDL_GetGPUDeviceDriver(device));
}
return device; return device;
} }

View file

@ -27,7 +27,7 @@ SDL_GPUGraphicsPipeline* GraphicsPipelineCreate(SDL_GPUDevice* device, SDL_Windo
.pitch = sizeof(Vertex), .pitch = sizeof(Vertex),
}, },
}, },
.num_vertex_attributes = 2, .num_vertex_attributes = 3,
.vertex_attributes = (SDL_GPUVertexAttribute[]){ .vertex_attributes = (SDL_GPUVertexAttribute[]){
{ {
.buffer_slot = 0, .buffer_slot = 0,
@ -40,6 +40,12 @@ SDL_GPUGraphicsPipeline* GraphicsPipelineCreate(SDL_GPUDevice* device, SDL_Windo
.format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3, .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3,
.location = 1, .location = 1,
.offset = offsetof(Vertex, color), .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, .vertex_shader = vertex_shader,
.fragment_shader = fragment_shader, .fragment_shader = fragment_shader,
}); });
if(pipeline == NULL) { LogAssertSDL(pipeline != NULL, "Failed to create pipeline");
SDL_Log("Failed to create pipeline: %s", SDL_GetError());
}
return 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);
}

View file

@ -5,5 +5,7 @@
SDL_GPUGraphicsPipeline* GraphicsPipelineCreate(SDL_GPUDevice* device, SDL_Window* window, SDL_GPUGraphicsPipeline* GraphicsPipelineCreate(SDL_GPUDevice* device, SDL_Window* window,
SDL_GPUShader* vertex_shader, SDL_GPUShader* fragment_shader); 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 #endif

View file

@ -1,9 +1,12 @@
#include <pch.h> #include <pch.h>
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); 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_GPUShader* shader = SDL_CreateGPUShader(device,
&(SDL_GPUShaderCreateInfo){ &(SDL_GPUShaderCreateInfo){
.code = file.data, .code = file.data,
@ -11,10 +14,20 @@ SDL_GPUShader* ShaderLoad(SDL_GPUDevice* device, const char* filename, SDL_GPUSh
.stage = stage, .stage = stage,
.format = SDL_GPU_SHADERFORMAT_SPIRV, .format = SDL_GPU_SHADERFORMAT_SPIRV,
.entrypoint = "main", .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; return shader;
} }
void ShaderFree(SDL_GPUDevice* device, SDL_GPUShader* shader) {
SDL_assert(device != NULL);
SDL_assert(shader != NULL);
SDL_ReleaseGPUShader(device, shader);
}

View file

@ -3,6 +3,9 @@
#include <SDL3/SDL_gpu.h> #include <SDL3/SDL_gpu.h>
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 #endif

View file

@ -0,0 +1,33 @@
#include <pch.h>
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);
}

View file

@ -0,0 +1,12 @@
#ifndef TRANSFER_BUFFER_H
#define TRANSFER_BUFFER_H
#include <SDL3/SDL_gpu.h>
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

View file

@ -1,41 +1,36 @@
#include "brimstone/graphics/command_buffer.h"
#include <SDL3/SDL_gpu.h>
#include <pch.h> #include <pch.h>
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(device != NULL);
SDL_assert(data != NULL); SDL_assert(data != NULL);
SDL_assert(byte_size > 0);
SDL_assert(buffer != NULL); SDL_assert(buffer != NULL);
SDL_GPUTransferBuffer* transfer_buffer = SDL_CreateGPUTransferBuffer(device, UploadState upload_state = UploadBegin(device, data, byte_size);
&(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;
}
void* mapped_buffer = SDL_MapGPUTransferBuffer(device, transfer_buffer, false); SDL_UploadToGPUBuffer(upload_state.copy_pass,
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_GPUTransferBufferLocation){ &(SDL_GPUTransferBufferLocation){
.transfer_buffer = transfer_buffer, .transfer_buffer = upload_state.transfer_buffer,
.offset = 0, .offset = 0,
}, },
&(SDL_GPUBufferRegion){ &(SDL_GPUBufferRegion){
@ -45,9 +40,35 @@ bool UploadToBuffer(SDL_GPUDevice* device, const void* data, size_t byte_size, S
}, },
false); false);
CopyPassEnd(copy_pass); UploadEnd(device, &upload_state);
bool submit_success = CommandBufferSubmit(copy_command_buffer); }
SDL_ReleaseGPUTransferBuffer(device, transfer_buffer);
void UploadToTexture(SDL_GPUDevice* device, SDL_Surface* surface, SDL_GPUTexture* texture) {
return submit_success; 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);
} }

View file

@ -3,6 +3,15 @@
#include <SDL3/SDL_gpu.h> #include <SDL3/SDL_gpu.h>
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 #endif

View file

@ -8,6 +8,9 @@ typedef struct {
struct { struct {
float r, g, b; float r, g, b;
} color; } color;
struct {
float x, y;
} texcoords;
} Vertex; } Vertex;
#endif #endif

View file

@ -1,8 +1,6 @@
#include <pch.h> #include <pch.h>
void InitSystems() { void InitSystems() {
if(!SDL_Init(SDL_INIT_VIDEO)) { bool success = SDL_Init(SDL_INIT_VIDEO);
SDL_Log("Failed to initialize SDL: %s", SDL_GetError()); LogAssertSDL(success, "Failed to initialize SDL");
exit(EXIT_FAILURE);
}
} }

View file

@ -4,9 +4,7 @@ SDL_GPUCopyPass* CopyPassBegin(SDL_GPUCommandBuffer* copy_command_buffer) {
SDL_assert(copy_command_buffer != NULL); SDL_assert(copy_command_buffer != NULL);
SDL_GPUCopyPass* copy_pass = SDL_BeginGPUCopyPass(copy_command_buffer); SDL_GPUCopyPass* copy_pass = SDL_BeginGPUCopyPass(copy_command_buffer);
if(copy_pass == NULL) { LogAssertSDL(copy_pass != NULL, "Failed to begin copy pass");
SDL_Log("Failed to begin copy pass: %s", SDL_GetError());
}
return copy_pass; return copy_pass;
} }

View file

@ -1,32 +1,42 @@
#include "pch.h" #include <pch.h>
FileData FileRead(const char* filename) { FileData FileRead(const char* filename, const char* mode) {
FILE* f = fopen(filename, "r"); FILE* file = fopen(filename, mode);
if(f == NULL) { if(file == NULL) {
perror(filename); perror(filename);
return (FileData){ 0 }; return (FileData){ 0 };
} }
fseek(f, 0, SEEK_END); fseek(file, 0, SEEK_END);
size_t length = ftell(f); size_t length = ftell(file);
rewind(f); rewind(file);
uint8_t* buffer = malloc(length); uint8_t* buffer = malloc(length);
if(buffer == NULL) { if(buffer == NULL) {
perror("Failed to allocate memory"); perror("Failed to allocate memory");
return (FileData){ 0 }; 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) { if(read_count != length) {
perror("Failed to read entire file"); perror("Failed to read entire file");
return (FileData){ 0 }; return (FileData){ 0 };
} }
return (FileData){ return (FileData){
.data = buffer,
.length = length, .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) { void FileFree(FileData file) {
free(file.data); free(file.data);
} }

View file

@ -5,11 +5,14 @@
#include <stdint.h> #include <stdint.h>
typedef struct { typedef struct {
uint8_t* data;
size_t length; size_t length;
uint8_t* data;
} FileData; } 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); void FileFree(FileData file);
#endif #endif

View file

@ -1,43 +1,78 @@
#include "brimstone/graphics/pipeline.h"
#include <pch.h> #include <pch.h>
int main(int argc, char** argv) { int main(int argc, char** argv) {
InitSystems(); InitSystems();
SDL_GPUDevice* device = DeviceCreate(); SDL_GPUDevice* device = DeviceCreate();
SDL_assert(device != NULL); SDL_Window* window = SDL_CreateWindow("Brimstone", 800, 600, SDL_WINDOW_RESIZABLE);
LogAssertSDL(window != NULL, "Failed to create window");
SDL_Window* window = SDL_CreateWindow("Brimstone", 800, 600, 0); bool success = SDL_ClaimWindowForGPUDevice(device, window);
if(window == NULL) { LogAssertSDL(success, "Failed to claim window for device");
SDL_Log("SDL_CreateWindow: %s", SDL_GetError());
exit(EXIT_FAILURE);
}
SDL_ClaimWindowForGPUDevice(device, window);
Vertex vertices[] = { Vertex vertices[] = {
{ -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.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, 0.0f, 1.0f, 0.0f }, { { -0.5f, -0.5f, 0.0f }, { 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f } }, // bottom left
{ 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f }, { { 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_GPUBuffer* vertex_buffer = SDL_CreateGPUBuffer(device,
&(SDL_GPUBufferCreateInfo){ &(SDL_GPUBufferCreateInfo){
.usage = SDL_GPU_BUFFERUSAGE_VERTEX, .usage = SDL_GPU_BUFFERUSAGE_VERTEX,
.size = sizeof(vertices), .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_GPUBuffer* index_buffer = SDL_CreateGPUBuffer(device,
SDL_assert(upload_successful); &(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_GPUShader* vertex_shader = ShaderLoad(
SDL_assert(vertex_shader != NULL); 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_GPUShader* fragment_shader = ShaderLoad(
SDL_assert(fragment_shader != NULL); device, "shaders/basic.frag.spv", SDL_GPU_SHADERSTAGE_FRAGMENT, 0, 1);
SDL_GPUGraphicsPipeline* pipeline = GraphicsPipelineCreate( SDL_GPUGraphicsPipeline* pipeline = GraphicsPipelineCreate(
device, window, vertex_shader, fragment_shader); 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; bool running = true;
SDL_Event event; SDL_Event event;
@ -50,29 +85,44 @@ int main(int argc, char** argv) {
} }
} }
SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(device); int width, height;
if(cmd == NULL) { SDL_GetWindowSize(window, &width, &height);
SDL_Log("SDL_AcquireGPUCommandBuffer: %s", SDL_GetError());
exit(EXIT_FAILURE); 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; SDL_GPUTexture* swapchain;
uint32_t swapchain_width, swapchain_height; 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_GPURenderPass* render_pass = SDL_BeginGPURenderPass(cmd,
&(SDL_GPUColorTargetInfo){ &(SDL_GPUColorTargetInfo){
.texture = swapchain, .texture = swapchain,
.load_op = SDL_GPU_LOADOP_CLEAR, .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); 1, NULL);
if(render_pass == NULL) { LogAssertSDL(render_pass != NULL, "Failed to begin render pass");
SDL_Log("SDL_BeginGPURenderPass: %s", SDL_GetError());
exit(EXIT_FAILURE);
}
SDL_BindGPUGraphicsPipeline(render_pass, pipeline); GraphicsPipelineBind(render_pass, pipeline);
SDL_BindGPUVertexBuffers(render_pass, 0, SDL_BindGPUVertexBuffers(render_pass, 0,
(SDL_GPUBufferBinding[]){ (SDL_GPUBufferBinding[]){
{ {
@ -81,15 +131,25 @@ int main(int argc, char** argv) {
}, },
}, },
1); 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); SDL_EndGPURenderPass(render_pass);
if(!SDL_SubmitGPUCommandBuffer(cmd)) { CommandBufferSubmit(cmd);
SDL_Log("SDL_SubmitGPUCommandBuffer: %s", SDL_GetError());
exit(EXIT_FAILURE);
}
} }
GraphicsPipelineFree(device, pipeline);
return 0; return 0;
} }

41
src/brimstone/misc/log.h Normal file
View file

@ -0,0 +1,41 @@
#ifndef LOG_H
#define LOG_H
#include <SDL3/SDL_assert.h>
#include <SDL3/SDL_error.h>
#include <SDL3/SDL_log.h>
#include <errno.h>
#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

View file

@ -0,0 +1,21 @@
#include <pch.h>
/*#define i_type TagMap
#define i_key_str
#define i_val void*
#include <stc/cmap.h>
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;
}

View file

@ -0,0 +1,13 @@
#ifndef MALLOC_H
#define MALLOC_H
#include <stddef.h>
typedef struct {
size_t size;
} MallocHeader;
void* Malloc(size_t size);
void* MallocTag(size_t size, const char* tag);
#endif

View file

@ -1,31 +1,27 @@
#ifndef PCH_H #ifndef PCH_H
#define PCH_H #define PCH_H
#include <assert.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include <SDL3/SDL_assert.h> #include <SDL3_image/SDL_image.h>
#include <SDL3/SDL_error.h>
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_gpu.h>
#include <SDL3/SDL_init.h>
#include <SDL3/SDL_log.h>
#include <SDL3/SDL_main.h>
#include <SDL3/SDL_pixels.h>
#include <SDL3/SDL_video.h>
#include <brimstone/graphics/command_buffer.h> #include <brimstone/graphics/command_buffer.h>
#include <brimstone/graphics/device.h> #include <brimstone/graphics/device.h>
#include <brimstone/graphics/pipeline.h> #include <brimstone/graphics/pipeline.h>
#include <brimstone/graphics/shaders.h> #include <brimstone/graphics/shaders.h>
#include <brimstone/graphics/transfer_buffer.h>
#include <brimstone/graphics/upload.h> #include <brimstone/graphics/upload.h>
#include <brimstone/graphics/vertex.h> #include <brimstone/graphics/vertex.h>
#include <brimstone/init/systems.h> #include <brimstone/init/systems.h>
#include <brimstone/io/copy_pass.h> #include <brimstone/io/copy_pass.h>
#include <brimstone/io/file.h> #include <brimstone/io/file.h>
#include <brimstone/misc/log.h>
#include <brimstone/misc/malloc.h>
#include <cglm/cglm.h>
#endif #endif

View file

@ -1,12 +1,21 @@
add_rules("mode.debug", "mode.release") add_rules("mode.debug", "mode.release")
add_requires("stc") add_requires("stc", "cglm")
add_requires("glslang", {configs = {binaryonly = true}})
target("brimstone") target("brimstone")
set_kind("binary") set_kind("binary")
set_rundir(".")
add_files("src/**.c")
add_links("SDL3")
add_includedirs("src")
set_pcheader("src/pch.h") 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