Files
Mikemon/src/renderer_sdlgpu.c
T
2026-08-01 09:37:43 +02:00

858 lines
32 KiB
C

#include "renderer.h"
#include <dcimgui_impl_sdlgpu3.h>
static bool enable_debug_mode = false;
typedef struct R_Buffer_Impl {
SDL_GPUBuffer *buffer;
void *cpu_uniform_data;
Uint32 num_bytes;
R_Buffer_Usage usage;
} R_Buffer_Impl;
typedef struct R_Texture_Impl {
SDL_GPUTexture *texture;
Uint32 width;
Uint32 height;
bool multisampled;
R_Texture_Format format;
} R_Texture_Impl;
R_Texture R_surface;
static SDL_Window *window;
static SDL_GPUDevice *device;
static R_Texture_Impl surface;
static SDL_GPUTransferBuffer *transfer_buffer;
static SDL_GPUCommandBuffer *copy_command_buffer;
static SDL_GPUCopyPass *copy_pass;
static SDL_GPUCommandBuffer *render_command_buffer;
static SDL_GPURenderPass *render_pass;
static SDL_GPUSampler *bilinear_sampler;
static SDL_GPUGraphicsPipeline *shaders[R_SHADER_COUNT];
static SDL_GPUTextureFormat texture_formats[] = {
[R_TEXTURE_FORMAT_R8_UNORM] = SDL_GPU_TEXTUREFORMAT_R8_UNORM,
[R_TEXTURE_FORMAT_R16_UINT] = SDL_GPU_TEXTUREFORMAT_R16_UINT,
[R_TEXTURE_FORMAT_RGBA8_UNORM] = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM,
[R_TEXTURE_FORMAT_RGBA8_UNORM_SRGB] = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB,
[R_TEXTURE_FORMAT_BGRA8_UNORM] = SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM,
[R_TEXTURE_FORMAT_BGRA8_UNORM_SRGB] = SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB,
};
static_assert(SDL_arraysize(texture_formats) == R_TEXTURE_FORMAT_COUNT);
static Uint32 texel_sizes[] = {
[R_TEXTURE_FORMAT_R8_UNORM] = 1,
[R_TEXTURE_FORMAT_R16_UINT] = 2,
[R_TEXTURE_FORMAT_RGBA8_UNORM] = 4,
[R_TEXTURE_FORMAT_RGBA8_UNORM_SRGB] = 4,
[R_TEXTURE_FORMAT_BGRA8_UNORM] = 4,
[R_TEXTURE_FORMAT_BGRA8_UNORM_SRGB] = 4,
};
static_assert(SDL_arraysize(texel_sizes) == R_TEXTURE_FORMAT_COUNT);
static SDL_GPUTextureUsageFlags texture_usages[] = {
[R_TEXTURE_USAGE_SAMPLED] = SDL_GPU_TEXTUREUSAGE_SAMPLER,
[R_TEXTURE_USAGE_STORAGE] = SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ,
[R_TEXTURE_USAGE_TARGET] = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET,
};
static_assert(SDL_arraysize(texture_usages) == R_TEXTURE_USAGE_COUNT);
static SDL_GPUBufferUsageFlags buffer_usages[] = {
[R_BUFFER_USAGE_UNIFORM] = 0,
[R_BUFFER_USAGE_STORAGE] = SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ,
[R_BUFFER_USAGE_VERTEX] = SDL_GPU_BUFFERUSAGE_VERTEX,
[R_BUFFER_USAGE_INDEX] = SDL_GPU_BUFFERUSAGE_INDEX,
};
static_assert(SDL_arraysize(buffer_usages) == R_BUFFER_USAGE_COUNT);
static SDL_GPULoadOp load_ops[] = {
[R_LOAD_OP_LOAD] = SDL_GPU_LOADOP_LOAD,
[R_LOAD_OP_CLEAR] = SDL_GPU_LOADOP_CLEAR,
};
static_assert(SDL_arraysize(load_ops) == R_LOAD_OP_COUNT);
static SDL_GPUStoreOp store_ops[] = {
[R_STORE_OP_STORE] = SDL_GPU_STOREOP_STORE,
[R_STORE_OP_DISCARD] = SDL_GPU_STOREOP_DONT_CARE,
};
static_assert(SDL_arraysize(store_ops) == R_STORE_OP_COUNT);
R_Texture renderer_texture_create(R_Texture_Format format, R_Texture_Usage usage, bool multisampled, Uint32 width, Uint32 height, void *data, const char *debug_name) {
SDL_PropertiesID properties = SDL_CreateProperties();
SDL_SetStringProperty(properties, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING, debug_name);
SDL_GPUTexture *texture = SDL_CreateGPUTexture(device, &(SDL_GPUTextureCreateInfo){
.type = SDL_GPU_TEXTURETYPE_2D,
.format = texture_formats[format],
.usage = texture_usages[usage],
.width = width,
.height = height,
.layer_count_or_depth = 1,
.num_levels = 1,
.sample_count = multisampled ? SDL_GPU_SAMPLECOUNT_8 : SDL_GPU_SAMPLECOUNT_1,
.props = properties,
});
SDL_DestroyProperties(properties);
if (!texture) return NULL;
R_Texture_Impl *result = SDL_calloc(1, sizeof(R_Texture_Impl));
if (!result) {
SDL_ReleaseGPUTexture(device, texture);
return NULL;
}
*result = (R_Texture_Impl){
.texture = texture,
.width = width,
.height = height,
.multisampled = multisampled,
.format = format,
};
if (data) {
renderer_texture_update(result, 0, 0, width, height, data, width * texel_sizes[format]);
}
return result;
}
void renderer_texture_update(R_Texture texture, Uint32 offset_x, Uint32 offset_y, Uint32 width, Uint32 height, void *data, Uint32 bytes_per_row) {
void *gpu_mem = SDL_MapGPUTransferBuffer(device, transfer_buffer, true);
SDL_memcpy(gpu_mem, data, bytes_per_row * height);
SDL_UnmapGPUTransferBuffer(device, transfer_buffer);
SDL_UploadToGPUTexture(copy_pass,
&(SDL_GPUTextureTransferInfo){
.transfer_buffer = transfer_buffer,
.offset = 0,
.pixels_per_row = width,
.rows_per_layer = height,
},
&(SDL_GPUTextureRegion){
.texture = texture->texture,
.mip_level = 0,
.layer = 0,
.x = offset_x,
.y = offset_y,
.z = 0,
.w = width,
.h = height,
.d = 1,
},
false
);
}
void renderer_texture_destroy(R_Texture texture) {
SDL_ReleaseGPUTexture(device, texture->texture);
SDL_free(texture);
}
Uint32 renderer_texture_get_width(R_Texture texture) {
return texture->width;
}
Uint32 renderer_texture_get_height(R_Texture texture) {
return texture->height;
}
bool renderer_texture_get_multisampled(R_Texture texture) {
return texture->multisampled;
}
R_Texture_Format renderer_texture_get_format(R_Texture texture) {
return texture->format;
}
R_Buffer renderer_buffer_create(R_Buffer_Usage usage, Uint32 num_bytes, void *data, const char *debug_name) {
R_Buffer_Impl *result = SDL_calloc(1, sizeof(R_Buffer_Impl));
if (!result) return NULL;
if (usage == R_BUFFER_USAGE_UNIFORM) {
*result = (R_Buffer_Impl){
.cpu_uniform_data = SDL_calloc(1, num_bytes),
.num_bytes = num_bytes,
.usage = usage,
};
if (!result->cpu_uniform_data) {
SDL_free(result);
return NULL;
}
if (data) {
renderer_buffer_update(result, 0, num_bytes, data);
}
} else {
SDL_PropertiesID properties = SDL_CreateProperties();
SDL_SetStringProperty(properties, SDL_PROP_GPU_BUFFER_CREATE_NAME_STRING, debug_name);
SDL_GPUBuffer *buffer = SDL_CreateGPUBuffer(device, &(SDL_GPUBufferCreateInfo){
.usage = buffer_usages[usage],
.size = num_bytes,
.props = properties,
});
SDL_DestroyProperties(properties);
if (!buffer) {
SDL_free(result);
return NULL;
}
*result = (R_Buffer_Impl){
.buffer = buffer,
.num_bytes = num_bytes,
.usage = usage,
};
if (data) {
renderer_buffer_update(result, 0, num_bytes, data);
}
}
return result;
}
void renderer_buffer_update(R_Buffer buffer, Uint32 offset, Uint32 num_bytes, void *data) {
SDL_assert(offset + num_bytes <= buffer->num_bytes);
if (buffer->usage == R_BUFFER_USAGE_UNIFORM) {
memcpy(buffer->cpu_uniform_data, data + offset, num_bytes);
} else {
void *gpu_mem = SDL_MapGPUTransferBuffer(device, transfer_buffer, true);
SDL_memcpy(gpu_mem, data, num_bytes);
SDL_UnmapGPUTransferBuffer(device, transfer_buffer);
SDL_UploadToGPUBuffer(copy_pass,
&(SDL_GPUTransferBufferLocation) {
.transfer_buffer = transfer_buffer,
.offset = 0,
},
&(SDL_GPUBufferRegion){
.buffer = buffer->buffer,
.offset = offset,
.size = num_bytes,
},
false
);
}
}
void renderer_buffer_destroy(R_Buffer buffer) {
if (buffer->buffer) SDL_ReleaseGPUBuffer(device, buffer->buffer);
if (buffer->cpu_uniform_data) SDL_free(buffer->cpu_uniform_data);
SDL_free(buffer);
}
Uint32 renderer_buffer_get_size(R_Buffer buffer) {
return buffer->num_bytes;
}
R_Buffer_Usage renderer_buffer_get_usage(R_Buffer buffer){
return buffer->usage;
}
void renderer_frame_begin() {
SDL_assert(R_surface == NULL);
Uint32 surface_width = 0, surface_height = 0;
SDL_WaitAndAcquireGPUSwapchainTexture(render_command_buffer, window, &surface.texture, &surface.width, &surface.height);
R_surface = &surface;
}
void renderer_frame_end() {
SDL_EndGPUCopyPass(copy_pass);
SDL_SubmitGPUCommandBuffer(copy_command_buffer);
if (render_pass) {
SDL_EndGPURenderPass(render_pass);
render_pass = NULL;
}
SDL_GPUFence *frame_fence = SDL_SubmitGPUCommandBufferAndAcquireFence(render_command_buffer);
SDL_WaitForGPUFences(device, true, &frame_fence, 1);
copy_command_buffer = SDL_AcquireGPUCommandBuffer(device);
render_command_buffer = SDL_AcquireGPUCommandBuffer(device);
R_surface = NULL;
copy_pass = SDL_BeginGPUCopyPass(copy_command_buffer);
}
void renderer_frame_set_target(R_Texture target, R_Texture resolve_target, R_Load_Op load_op, R_Store_Op store_op, R_Color clear_color) {
if (render_pass) {
SDL_EndGPURenderPass(render_pass);
render_pass = NULL;
}
render_pass = SDL_BeginGPURenderPass(render_command_buffer,
&(SDL_GPUColorTargetInfo){
.texture = target->texture,
.mip_level = 0,
.layer_or_depth_plane = 0,
.clear_color = { clear_color.r, clear_color.g, clear_color.b, clear_color.a },
.load_op = load_ops[load_op],
.store_op = resolve_target ? (store_op == R_STORE_OP_STORE ? SDL_GPU_STOREOP_RESOLVE_AND_STORE : SDL_GPU_STOREOP_RESOLVE) : store_ops[store_op],
.resolve_texture = resolve_target ? resolve_target->texture : NULL,
.resolve_mip_level = 0,
.resolve_layer = 0,
.cycle = false,
.cycle_resolve_texture = false,
},
1,
NULL
);
}
void renderer_frame_set_shader(R_Shader shader) {
SDL_BindGPUGraphicsPipeline(render_pass, shaders[shader]);
}
void renderer_frame_draw(R_Buffer vertex_buffer, R_Buffer index_buffer, R_Buffer instance_buffer, Uint32 num_indices, Uint32 num_instances, const R_Draw_Resources *resources) {
SDL_assert(render_pass);
for (int i = 0; i < resources->num_vertex_sampled_textures; i++) SDL_BindGPUVertexSamplers(render_pass, i, &(SDL_GPUTextureSamplerBinding){ .texture = resources->vertex_sampled_textures[i]->texture, .sampler = bilinear_sampler }, 1);
for (int i = 0; i < resources->num_vertex_storage_textures; i++) SDL_BindGPUVertexStorageTextures(render_pass, i, &resources->vertex_storage_textures[i]->texture, 1);
for (int i = 0; i < resources->num_vertex_storage_buffers; i++) SDL_BindGPUVertexStorageBuffers(render_pass, i, &resources->vertex_storage_buffers[i]->buffer, 1);
for (int i = 0; i < resources->num_vertex_uniform_buffers; i++) SDL_PushGPUVertexUniformData(render_command_buffer, i, resources->vertex_uniform_buffers[i]->cpu_uniform_data, resources->vertex_uniform_buffers[i]->num_bytes);
for (int i = 0; i < resources->num_fragment_sampled_textures; i++) SDL_BindGPUFragmentSamplers(render_pass, i, &(SDL_GPUTextureSamplerBinding){ .texture = resources->fragment_sampled_textures[i]->texture, .sampler = bilinear_sampler }, 1);
for (int i = 0; i < resources->num_fragment_storage_textures; i++) SDL_BindGPUFragmentStorageTextures(render_pass, i, &resources->fragment_storage_textures[i]->texture, 1);
for (int i = 0; i < resources->num_fragment_storage_buffers; i++) SDL_BindGPUFragmentStorageBuffers(render_pass, i, &resources->fragment_storage_buffers[i]->buffer, 1);
for (int i = 0; i < resources->num_fragment_uniform_buffers; i++) SDL_PushGPUFragmentUniformData(render_command_buffer, i, resources->fragment_uniform_buffers[i]->cpu_uniform_data, resources->fragment_uniform_buffers[i]->num_bytes);
if (vertex_buffer) SDL_BindGPUVertexBuffers(render_pass, 0, &(SDL_GPUBufferBinding){ .buffer = vertex_buffer->buffer, .offset = 0 }, 1);
if (instance_buffer) SDL_BindGPUVertexBuffers(render_pass, 1, &(SDL_GPUBufferBinding){ .buffer = instance_buffer->buffer, .offset = 0 }, 1);
if (index_buffer) {
SDL_BindGPUIndexBuffer(render_pass, &(SDL_GPUBufferBinding){ .buffer = index_buffer->buffer, .offset = 0 }, SDL_GPU_INDEXELEMENTSIZE_16BIT);
SDL_DrawGPUIndexedPrimitives(render_pass, num_indices, num_instances, 0, 0, 0);
} else {
SDL_DrawGPUPrimitives(render_pass, num_indices, num_instances, 0, 0);
}
}
static R_Texture_Format R_Texture_Format_from_SDL_GPUTextureFormat(SDL_GPUTextureFormat format) {
switch (format) {
case SDL_GPU_TEXTUREFORMAT_R8_UNORM: return R_TEXTURE_FORMAT_R8_UNORM;
case SDL_GPU_TEXTUREFORMAT_R16_UINT: return R_TEXTURE_FORMAT_R16_UINT;
case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM: return R_TEXTURE_FORMAT_RGBA8_UNORM;
case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB: return R_TEXTURE_FORMAT_RGBA8_UNORM_SRGB;
case SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM: return R_TEXTURE_FORMAT_BGRA8_UNORM;
case SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB: return R_TEXTURE_FORMAT_BGRA8_UNORM_SRGB;
default: {
SDL_assert_always(false);
return R_TEXTURE_FORMAT_BGRA8_UNORM_SRGB;
};
};
}
bool renderer_init(SDL_Window *window_) {
window = window_;
device = SDL_CreateGPUDevice(SDL_GPU_SHADERFORMAT_SPIRV, enable_debug_mode, NULL);
if (!device) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create gpu device.");
return false;
}
if (!SDL_ClaimWindowForGPUDevice(device, window)) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to claim window for gpu device.");
SDL_DestroyGPUDevice(device);
return false;
}
SDL_SetGPUSwapchainParameters(device, window, SDL_GPU_SWAPCHAINCOMPOSITION_SDR_LINEAR, SDL_GPU_PRESENTMODE_VSYNC);
surface.format = R_Texture_Format_from_SDL_GPUTextureFormat(SDL_GetGPUSwapchainTextureFormat(device, window));
bilinear_sampler = SDL_CreateGPUSampler(device, &(SDL_GPUSamplerCreateInfo){
.min_filter = SDL_GPU_FILTER_LINEAR,
.mag_filter = SDL_GPU_FILTER_LINEAR,
.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST,
.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE,
.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE,
.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE,
.mip_lod_bias = 0.0f,
.max_anisotropy = 1.0f,
.compare_op = SDL_GPU_COMPAREOP_INVALID,
.min_lod = 0.0f,
.max_lod = 0.0f,
.enable_anisotropy = false,
.enable_compare = false,
});
// Shaders
{ // Basic
const Uint8 shader_source[] = {
#embed "shaders/spirv/basic.spv"
};
SDL_GPUShader *vertex_shader = SDL_CreateGPUShader(device, &(SDL_GPUShaderCreateInfo){
.code_size = sizeof(shader_source),
.code = shader_source,
.entrypoint = "main_vertex",
.format = SDL_GPU_SHADERFORMAT_SPIRV,
.stage = SDL_GPU_SHADERSTAGE_VERTEX,
.num_samplers = 0,
.num_storage_textures = 0,
.num_storage_buffers = 0,
.num_uniform_buffers = 1,
});
SDL_GPUShader *fragment_shader = SDL_CreateGPUShader(device, &(SDL_GPUShaderCreateInfo){
.code_size = sizeof(shader_source),
.code = shader_source,
.entrypoint = "main_fragment",
.format = SDL_GPU_SHADERFORMAT_SPIRV,
.stage = SDL_GPU_SHADERSTAGE_FRAGMENT,
.num_samplers = 1,
.num_storage_textures = 0,
.num_storage_buffers = 0,
.num_uniform_buffers = 1,
});
SDL_PropertiesID properties = SDL_CreateProperties();
SDL_SetStringProperty(properties, SDL_PROP_GPU_BUFFER_CREATE_NAME_STRING, "R_SHADER basic");
shaders[R_SHADER_BASIC] = SDL_CreateGPUGraphicsPipeline(device, &(SDL_GPUGraphicsPipelineCreateInfo){
.vertex_shader = vertex_shader,
.fragment_shader = fragment_shader,
.vertex_input_state = {
.vertex_buffer_descriptions = (SDL_GPUVertexBufferDescription[]){
{
.slot = 0,
.pitch = 20,
.input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX,
.instance_step_rate = 0,
},
{
.slot = 1,
.pitch = 8,
.input_rate = SDL_GPU_VERTEXINPUTRATE_INSTANCE,
.instance_step_rate = 0,
},
},
.num_vertex_buffers = 2,
.vertex_attributes = (SDL_GPUVertexAttribute[]){
{
.location = 0,
.buffer_slot = 0,
.format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3,
.offset = 0,
},
{
.location = 1,
.buffer_slot = 0,
.format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2,
.offset = 12,
},
{
.location = 2,
.buffer_slot = 1,
.format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2,
.offset = 0,
},
},
.num_vertex_attributes = 3,
},
.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST,
.rasterizer_state = {
.fill_mode = SDL_GPU_FILLMODE_FILL,
.cull_mode = SDL_GPU_CULLMODE_BACK,
.front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE,
.depth_bias_constant_factor = 0.0f,
.depth_bias_clamp = 0.0f,
.depth_bias_slope_factor = 0.0f,
.enable_depth_bias = false,
.enable_depth_clip = false,
},
.multisample_state = {
.sample_count = SDL_GPU_SAMPLECOUNT_8,
.sample_mask = 0,
.enable_mask = 0,
.enable_alpha_to_coverage = false,
},
.depth_stencil_state = {
.compare_op = SDL_GPU_COMPAREOP_GREATER_OR_EQUAL,
.back_stencil_state = { .fail_op = SDL_GPU_STENCILOP_INVALID, .pass_op = SDL_GPU_STENCILOP_INVALID, .depth_fail_op = SDL_GPU_STENCILOP_INVALID, .compare_op = SDL_GPU_COMPAREOP_INVALID, },
.front_stencil_state = { .fail_op = SDL_GPU_STENCILOP_INVALID, .pass_op = SDL_GPU_STENCILOP_INVALID, .depth_fail_op = SDL_GPU_STENCILOP_INVALID, .compare_op = SDL_GPU_COMPAREOP_INVALID, },
.compare_mask = 0,
.write_mask = 0,
.enable_depth_test = false,
.enable_depth_write = false,
.enable_stencil_test = false,
},
.target_info = {
.color_target_descriptions = (SDL_GPUColorTargetDescription[]){
{
.format = texture_formats[surface.format],
.blend_state = {
.src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA,
.dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
.color_blend_op = SDL_GPU_BLENDOP_ADD,
.src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA,
.dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
.alpha_blend_op = SDL_GPU_BLENDOP_ADD,
.color_write_mask = 0,
.enable_blend = true,
.enable_color_write_mask = false,
},
}
},
.num_color_targets = 1,
.depth_stencil_format = SDL_GPU_TEXTUREFORMAT_INVALID,
.has_depth_stencil_target = false,
},
});
SDL_DestroyProperties(properties);
SDL_ReleaseGPUShader(device, vertex_shader);
SDL_ReleaseGPUShader(device, fragment_shader);
}
{ // World
const Uint8 shader_source[] = {
#embed "shaders/spirv/world.spv"
};
SDL_GPUShader *vertex_shader = SDL_CreateGPUShader(device, &(SDL_GPUShaderCreateInfo){
.code_size = sizeof(shader_source),
.code = shader_source,
.entrypoint = "main_vertex",
.format = SDL_GPU_SHADERFORMAT_SPIRV,
.stage = SDL_GPU_SHADERSTAGE_VERTEX,
.num_samplers = 0,
.num_storage_textures = 1,
.num_storage_buffers = 0,
.num_uniform_buffers = 2,
});
SDL_GPUShader *fragment_shader = SDL_CreateGPUShader(device, &(SDL_GPUShaderCreateInfo){
.code_size = sizeof(shader_source),
.code = shader_source,
.entrypoint = "main_fragment",
.format = SDL_GPU_SHADERFORMAT_SPIRV,
.stage = SDL_GPU_SHADERSTAGE_FRAGMENT,
.num_samplers = 1,
.num_storage_textures = 0,
.num_storage_buffers = 1,
.num_uniform_buffers = 1,
});
SDL_PropertiesID properties = SDL_CreateProperties();
SDL_SetStringProperty(properties, SDL_PROP_GPU_BUFFER_CREATE_NAME_STRING, "R_SHADER world");
shaders[R_SHADER_WORLD] = SDL_CreateGPUGraphicsPipeline(device, &(SDL_GPUGraphicsPipelineCreateInfo){
.vertex_shader = vertex_shader,
.fragment_shader = fragment_shader,
.vertex_input_state = {
.vertex_buffer_descriptions = (SDL_GPUVertexBufferDescription[]){
{
.slot = 0,
.pitch = 20,
.input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX,
.instance_step_rate = 0,
},
},
.num_vertex_buffers = 1,
.vertex_attributes = (SDL_GPUVertexAttribute[]){
{
.location = 0,
.buffer_slot = 0,
.format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3,
.offset = 0,
},
},
.num_vertex_attributes = 1,
},
.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST,
.rasterizer_state = {
.fill_mode = SDL_GPU_FILLMODE_FILL,
.cull_mode = SDL_GPU_CULLMODE_BACK,
.front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE,
.depth_bias_constant_factor = 0.0f,
.depth_bias_clamp = 0.0f,
.depth_bias_slope_factor = 0.0f,
.enable_depth_bias = false,
.enable_depth_clip = false,
},
.multisample_state = {
.sample_count = SDL_GPU_SAMPLECOUNT_8,
.sample_mask = 0,
.enable_mask = 0,
.enable_alpha_to_coverage = false,
},
.depth_stencil_state = {
.compare_op = SDL_GPU_COMPAREOP_GREATER_OR_EQUAL,
.back_stencil_state = { .fail_op = SDL_GPU_STENCILOP_INVALID, .pass_op = SDL_GPU_STENCILOP_INVALID, .depth_fail_op = SDL_GPU_STENCILOP_INVALID, .compare_op = SDL_GPU_COMPAREOP_INVALID, },
.front_stencil_state = { .fail_op = SDL_GPU_STENCILOP_INVALID, .pass_op = SDL_GPU_STENCILOP_INVALID, .depth_fail_op = SDL_GPU_STENCILOP_INVALID, .compare_op = SDL_GPU_COMPAREOP_INVALID, },
.compare_mask = 0,
.write_mask = 0,
.enable_depth_test = false,
.enable_depth_write = false,
.enable_stencil_test = false,
},
.target_info = {
.color_target_descriptions = (SDL_GPUColorTargetDescription[]){
{
.format = texture_formats[surface.format],
.blend_state = {
.src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA,
.dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
.color_blend_op = SDL_GPU_BLENDOP_ADD,
.src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA,
.dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
.alpha_blend_op = SDL_GPU_BLENDOP_ADD,
.color_write_mask = 0,
.enable_blend = true,
.enable_color_write_mask = false,
},
}
},
.num_color_targets = 1,
.depth_stencil_format = SDL_GPU_TEXTUREFORMAT_INVALID,
.has_depth_stencil_target = false,
},
});
SDL_DestroyProperties(properties);
SDL_ReleaseGPUShader(device, vertex_shader);
SDL_ReleaseGPUShader(device, fragment_shader);
}
{ // Grid
const Uint8 shader_source[] = {
#embed "shaders/spirv/grid.spv"
};
SDL_GPUShader *vertex_shader = SDL_CreateGPUShader(device, &(SDL_GPUShaderCreateInfo){
.code_size = sizeof(shader_source),
.code = shader_source,
.entrypoint = "main_vertex",
.format = SDL_GPU_SHADERFORMAT_SPIRV,
.stage = SDL_GPU_SHADERSTAGE_VERTEX,
.num_samplers = 0,
.num_storage_textures = 0,
.num_storage_buffers = 0,
.num_uniform_buffers = 2,
});
SDL_GPUShader *fragment_shader = SDL_CreateGPUShader(device, &(SDL_GPUShaderCreateInfo){
.code_size = sizeof(shader_source),
.code = shader_source,
.entrypoint = "main_fragment",
.format = SDL_GPU_SHADERFORMAT_SPIRV,
.stage = SDL_GPU_SHADERSTAGE_FRAGMENT,
.num_samplers = 0,
.num_storage_textures = 0,
.num_storage_buffers = 0,
.num_uniform_buffers = 0,
});
SDL_PropertiesID properties = SDL_CreateProperties();
SDL_SetStringProperty(properties, SDL_PROP_GPU_BUFFER_CREATE_NAME_STRING, "R_SHADER grid");
shaders[R_SHADER_GRID] = SDL_CreateGPUGraphicsPipeline(device, &(SDL_GPUGraphicsPipelineCreateInfo){
.vertex_shader = vertex_shader,
.fragment_shader = fragment_shader,
.vertex_input_state = {
.vertex_buffer_descriptions = (SDL_GPUVertexBufferDescription[]){},
.num_vertex_buffers = 0,
.vertex_attributes = (SDL_GPUVertexAttribute[]){},
.num_vertex_attributes = 0,
},
.primitive_type = SDL_GPU_PRIMITIVETYPE_LINELIST,
.rasterizer_state = {
.fill_mode = SDL_GPU_FILLMODE_FILL,
.cull_mode = SDL_GPU_CULLMODE_BACK,
.front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE,
.depth_bias_constant_factor = 0.0f,
.depth_bias_clamp = 0.0f,
.depth_bias_slope_factor = 0.0f,
.enable_depth_bias = false,
.enable_depth_clip = false,
},
.multisample_state = {
.sample_count = SDL_GPU_SAMPLECOUNT_8,
.sample_mask = 0,
.enable_mask = 0,
.enable_alpha_to_coverage = false,
},
.depth_stencil_state = {
.compare_op = SDL_GPU_COMPAREOP_GREATER_OR_EQUAL,
.back_stencil_state = { .fail_op = SDL_GPU_STENCILOP_INVALID, .pass_op = SDL_GPU_STENCILOP_INVALID, .depth_fail_op = SDL_GPU_STENCILOP_INVALID, .compare_op = SDL_GPU_COMPAREOP_INVALID, },
.front_stencil_state = { .fail_op = SDL_GPU_STENCILOP_INVALID, .pass_op = SDL_GPU_STENCILOP_INVALID, .depth_fail_op = SDL_GPU_STENCILOP_INVALID, .compare_op = SDL_GPU_COMPAREOP_INVALID, },
.compare_mask = 0,
.write_mask = 0,
.enable_depth_test = false,
.enable_depth_write = false,
.enable_stencil_test = false,
},
.target_info = {
.color_target_descriptions = (SDL_GPUColorTargetDescription[]){
{
.format = texture_formats[surface.format],
.blend_state = {
.src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA,
.dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
.color_blend_op = SDL_GPU_BLENDOP_ADD,
.src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA,
.dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
.alpha_blend_op = SDL_GPU_BLENDOP_ADD,
.color_write_mask = 0,
.enable_blend = true,
.enable_color_write_mask = false,
},
}
},
.num_color_targets = 1,
.depth_stencil_format = SDL_GPU_TEXTUREFORMAT_INVALID,
.has_depth_stencil_target = false,
},
});
SDL_DestroyProperties(properties);
SDL_ReleaseGPUShader(device, vertex_shader);
SDL_ReleaseGPUShader(device, fragment_shader);
}
for (int i = 0; i < R_SHADER_COUNT; i++) {
SDL_assert(shaders[i]);
}
transfer_buffer = SDL_CreateGPUTransferBuffer(device, &(SDL_GPUTransferBufferCreateInfo){
.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD,
.size = 64 * 1024,
});
copy_command_buffer = SDL_AcquireGPUCommandBuffer(device);
render_command_buffer = SDL_AcquireGPUCommandBuffer(device);
copy_pass = SDL_BeginGPUCopyPass(copy_command_buffer);
return true;
}
void ImGui_ImplRenderer_Init() {
cImGui_ImplSDLGPU3_Init(&(ImGui_ImplSDLGPU3_InitInfo){
.Device = device,
.ColorTargetFormat = texture_formats[surface.format],
.MSAASamples = SDL_GPU_SAMPLECOUNT_8,
.SwapchainComposition = SDL_GPU_SWAPCHAINCOMPOSITION_SDR,
.PresentMode = SDL_GPU_PRESENTMODE_VSYNC,
});
}
void ImGui_ImplRenderer_NewFrame() {
cImGui_ImplSDLGPU3_NewFrame();
}
void ImGui_ImplRenderer_Shutdown() {
cImGui_ImplSDLGPU3_Shutdown();
}
void ImGui_ImplRenderer_RenderDrawData(void* draw_data) {
SDL_EndGPUCopyPass(copy_pass);
cImGui_ImplSDLGPU3_PrepareDrawData(draw_data, copy_command_buffer);
copy_pass = SDL_BeginGPUCopyPass(copy_command_buffer);
cImGui_ImplSDLGPU3_RenderDrawData(draw_data, render_command_buffer, render_pass);
}
Uint64 ImGui_ImplRenderer_GetTextureID(R_Texture texture) {
return (Uint64)texture->texture;
}