Added support for custom shaders with the GPU renderer

Added an example of MSDF font rendering with the SDL 2D renderer
This commit is contained in:
Sam Lantinga
2025-03-13 16:41:58 -07:00
parent eb56c8af85
commit 2aee105b43
19 changed files with 1460 additions and 34 deletions

View File

@@ -27,40 +27,10 @@
#include "../SDL_sysrender.h"
struct GPU_PipelineCacheKeyStruct
{
Uint64 blend_mode : 28;
Uint64 frag_shader : 4;
Uint64 vert_shader : 4;
Uint64 attachment_format : 6;
Uint64 primitive_type : 3;
};
typedef union GPU_PipelineCacheKeyConverter
{
struct GPU_PipelineCacheKeyStruct as_struct;
Uint64 as_uint64;
} GPU_PipelineCacheKeyConverter;
SDL_COMPILE_TIME_ASSERT(GPU_PipelineCacheKeyConverter_Size, sizeof(GPU_PipelineCacheKeyConverter) <= sizeof(Uint64));
static Uint32 SDLCALL HashPipelineCacheKey(void *userdata, const void *key)
{
const GPU_PipelineParameters *params = (const GPU_PipelineParameters *) key;
GPU_PipelineCacheKeyConverter cvt;
cvt.as_uint64 = 0;
cvt.as_struct.blend_mode = params->blend_mode;
cvt.as_struct.frag_shader = params->frag_shader;
cvt.as_struct.vert_shader = params->vert_shader;
cvt.as_struct.attachment_format = params->attachment_format;
cvt.as_struct.primitive_type = params->primitive_type;
// 64-bit uint hash function stolen from taisei (which stole it from somewhere else)
Uint64 x = cvt.as_uint64;
x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);
x = x ^ (x >> 31);
return (Uint32)(x & 0xffffffff);
return SDL_murmur3_32(params, sizeof(*params), 0);
}
static bool SDLCALL MatchPipelineCacheKey(void *userdata, const void *a, const void *b)

View File

@@ -33,6 +33,7 @@ typedef struct GPU_PipelineParameters
GPU_VertexShaderID vert_shader;
SDL_GPUTextureFormat attachment_format;
SDL_GPUPrimitiveType primitive_type;
SDL_GPUShader *custom_frag_shader;
} GPU_PipelineParameters;
typedef struct GPU_PipelineCache

View File

@@ -541,6 +541,8 @@ static void Draw(
}
SDL_GPURenderPass *pass = data->state.render_pass;
SDL_GPURenderState *custom_state = cmd->data.draw.gpu_render_state;
SDL_GPUShader *custom_frag_shader = custom_state ? custom_state->fragment_shader : NULL;
GPU_VertexShaderID v_shader;
GPU_FragmentShaderID f_shader;
@@ -570,12 +572,18 @@ static void Draw(
f_shader = FRAG_SHADER_COLOR;
}
if (custom_frag_shader) {
f_shader = FRAG_SHADER_TEXTURE_CUSTOM;
data->shaders.frag_shaders[FRAG_SHADER_TEXTURE_CUSTOM] = custom_frag_shader;
}
GPU_PipelineParameters pipe_params;
SDL_zero(pipe_params);
pipe_params.blend_mode = cmd->data.draw.blend;
pipe_params.vert_shader = v_shader;
pipe_params.frag_shader = f_shader;
pipe_params.primitive_type = prim;
pipe_params.custom_frag_shader = custom_frag_shader;
if (data->state.render_target) {
pipe_params.attachment_format = ((GPU_TextureData *)data->state.render_target->internal)->format;
@@ -590,15 +598,34 @@ static void Draw(
SDL_BindGPUGraphicsPipeline(pass, pipe);
Uint32 sampler_slot = 0;
if (cmd->data.draw.texture) {
GPU_TextureData *tdata = (GPU_TextureData *)cmd->data.draw.texture->internal;
SDL_GPUTextureSamplerBinding sampler_bind;
SDL_zero(sampler_bind);
sampler_bind.sampler = *SamplerPointer(data, cmd->data.draw.texture_address_mode, cmd->data.draw.texture_scale_mode);
sampler_bind.texture = tdata->texture;
SDL_BindGPUFragmentSamplers(pass, 0, &sampler_bind, 1);
SDL_BindGPUFragmentSamplers(pass, sampler_slot++, &sampler_bind, 1);
}
if (custom_state) {
if (custom_state->num_sampler_bindings > 0) {
SDL_BindGPUFragmentSamplers(pass, sampler_slot, custom_state->sampler_bindings, custom_state->num_sampler_bindings);
}
if (custom_state->num_storage_textures > 0) {
SDL_BindGPUFragmentStorageTextures(pass, 0, custom_state->storage_textures, custom_state->num_storage_textures);
}
if (custom_state->num_storage_buffers > 0) {
SDL_BindGPUFragmentStorageBuffers(pass, 0, custom_state->storage_buffers, custom_state->num_storage_buffers);
}
if (custom_state->num_uniform_buffers > 0) {
for (int i = 0; i < custom_state->num_uniform_buffers; i++) {
SDL_GPURenderStateUniformBuffer *ub = &custom_state->uniform_buffers[i];
SDL_PushGPUFragmentUniformData(data->state.command_buffer, ub->slot_index, ub->data, ub->length);
}
}
} else {
PushFragmentUniforms(data, cmd);
}
PushFragmentUniforms(data, cmd);
SDL_GPUBufferBinding buffer_bind;
SDL_zero(buffer_bind);

View File

@@ -196,6 +196,9 @@ bool GPU_InitShaders(GPU_Shaders *shaders, SDL_GPUDevice *device)
}
for (int i = 0; i < SDL_arraysize(frag_shader_sources); ++i) {
if (i == FRAG_SHADER_TEXTURE_CUSTOM) {
continue;
}
shaders->frag_shaders[i] = CompileShader(
&frag_shader_sources[i], device, SDL_GPU_SHADERSTAGE_FRAGMENT);
if (shaders->frag_shaders[i] == NULL) {
@@ -215,6 +218,9 @@ void GPU_ReleaseShaders(GPU_Shaders *shaders, SDL_GPUDevice *device)
}
for (int i = 0; i < SDL_arraysize(shaders->frag_shaders); ++i) {
if (i == FRAG_SHADER_TEXTURE_CUSTOM) {
continue;
}
SDL_ReleaseGPUShader(device, shaders->frag_shaders[i]);
shaders->frag_shaders[i] = NULL;
}

View File

@@ -44,6 +44,7 @@ typedef enum
FRAG_SHADER_TEXTURE_RGBA,
FRAG_SHADER_TEXTURE_RGB_PIXELART,
FRAG_SHADER_TEXTURE_RGBA_PIXELART,
FRAG_SHADER_TEXTURE_CUSTOM,
NUM_FRAG_SHADERS,
} GPU_FragmentShaderID;