From 5a079a2d114f96d4847d1ee305d5b7c16eeec50e Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 27 Dec 2025 12:03:39 -0800 Subject: Initial commit --- .../SDL-3.2.8/src/render/gpu/SDL_pipeline_gpu.c | 202 +++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 contrib/SDL-3.2.8/src/render/gpu/SDL_pipeline_gpu.c (limited to 'contrib/SDL-3.2.8/src/render/gpu/SDL_pipeline_gpu.c') diff --git a/contrib/SDL-3.2.8/src/render/gpu/SDL_pipeline_gpu.c b/contrib/SDL-3.2.8/src/render/gpu/SDL_pipeline_gpu.c new file mode 100644 index 0000000..0783374 --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/gpu/SDL_pipeline_gpu.c @@ -0,0 +1,202 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifdef SDL_VIDEO_RENDER_GPU + +#include "SDL_gpu_util.h" +#include "SDL_pipeline_gpu.h" + +#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); +} + +static bool SDLCALL MatchPipelineCacheKey(void *userdata, const void *a, const void *b) +{ + return (SDL_memcmp(a, b, sizeof (GPU_PipelineParameters)) == 0); +} + +static void SDLCALL DestroyPipelineCacheHashItem(void *userdata, const void *key, const void *value) +{ + SDL_GPUGraphicsPipeline *pipeline = (SDL_GPUGraphicsPipeline *) value; + SDL_GPUDevice *device = (SDL_GPUDevice *) userdata; + SDL_ReleaseGPUGraphicsPipeline(device, pipeline); + SDL_free((GPU_PipelineParameters *) key); +} + +bool GPU_InitPipelineCache(GPU_PipelineCache *cache, SDL_GPUDevice *device) +{ + cache->table = SDL_CreateHashTable(0, false, HashPipelineCacheKey, MatchPipelineCacheKey, DestroyPipelineCacheHashItem, device); + return (cache->table != NULL); +} + +void GPU_DestroyPipelineCache(GPU_PipelineCache *cache) +{ + SDL_DestroyHashTable(cache->table); +} + +static SDL_GPUGraphicsPipeline *MakePipeline(SDL_GPUDevice *device, GPU_Shaders *shaders, const GPU_PipelineParameters *params) +{ + SDL_GPUColorTargetDescription ad; + SDL_zero(ad); + ad.format = params->attachment_format; + + SDL_BlendMode blend = params->blend_mode; + ad.blend_state.enable_blend = blend != 0; + ad.blend_state.color_write_mask = 0xF; + ad.blend_state.alpha_blend_op = GPU_ConvertBlendOperation(SDL_GetBlendModeAlphaOperation(blend)); + ad.blend_state.dst_alpha_blendfactor = GPU_ConvertBlendFactor(SDL_GetBlendModeDstAlphaFactor(blend)); + ad.blend_state.src_alpha_blendfactor = GPU_ConvertBlendFactor(SDL_GetBlendModeSrcAlphaFactor(blend)); + ad.blend_state.color_blend_op = GPU_ConvertBlendOperation(SDL_GetBlendModeColorOperation(blend)); + ad.blend_state.dst_color_blendfactor = GPU_ConvertBlendFactor(SDL_GetBlendModeDstColorFactor(blend)); + ad.blend_state.src_color_blendfactor = GPU_ConvertBlendFactor(SDL_GetBlendModeSrcColorFactor(blend)); + + SDL_GPUGraphicsPipelineCreateInfo pci; + SDL_zero(pci); + pci.target_info.has_depth_stencil_target = false; + pci.target_info.num_color_targets = 1; + pci.target_info.color_target_descriptions = &ad; + pci.vertex_shader = GPU_GetVertexShader(shaders, params->vert_shader); + pci.fragment_shader = GPU_GetFragmentShader(shaders, params->frag_shader); + pci.multisample_state.sample_count = SDL_GPU_SAMPLECOUNT_1; + pci.multisample_state.enable_mask = false; + pci.primitive_type = params->primitive_type; + + pci.rasterizer_state.cull_mode = SDL_GPU_CULLMODE_NONE; + pci.rasterizer_state.fill_mode = SDL_GPU_FILLMODE_FILL; + pci.rasterizer_state.front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE; + + SDL_GPUVertexBufferDescription vertex_buffer_desc; + SDL_zero(vertex_buffer_desc); + + Uint32 num_attribs = 0; + SDL_GPUVertexAttribute attribs[4]; + SDL_zero(attribs); + + bool have_attr_color = false; + bool have_attr_uv = false; + + switch (params->vert_shader) { + case VERT_SHADER_TRI_TEXTURE: + have_attr_uv = true; + SDL_FALLTHROUGH; + case VERT_SHADER_TRI_COLOR: + have_attr_color = true; + SDL_FALLTHROUGH; + default: + break; + } + + // Position + attribs[num_attribs].location = num_attribs; + attribs[num_attribs].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2; + attribs[num_attribs].offset = vertex_buffer_desc.pitch; + vertex_buffer_desc.pitch += 2 * sizeof(float); + num_attribs++; + + if (have_attr_color) { + // Color + attribs[num_attribs].location = num_attribs; + attribs[num_attribs].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4; + attribs[num_attribs].offset = vertex_buffer_desc.pitch; + vertex_buffer_desc.pitch += 4 * sizeof(float); + num_attribs++; + } + + if (have_attr_uv) { + // UVs + attribs[num_attribs].location = num_attribs; + attribs[num_attribs].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2; + attribs[num_attribs].offset = vertex_buffer_desc.pitch; + vertex_buffer_desc.pitch += 2 * sizeof(float); + num_attribs++; + } + + pci.vertex_input_state.num_vertex_attributes = num_attribs; + pci.vertex_input_state.vertex_attributes = attribs; + pci.vertex_input_state.num_vertex_buffers = 1; + pci.vertex_input_state.vertex_buffer_descriptions = &vertex_buffer_desc; + + return SDL_CreateGPUGraphicsPipeline(device, &pci); +} + +SDL_GPUGraphicsPipeline *GPU_GetPipeline(GPU_PipelineCache *cache, GPU_Shaders *shaders, SDL_GPUDevice *device, const GPU_PipelineParameters *params) +{ + SDL_GPUGraphicsPipeline *pipeline = NULL; + if (!SDL_FindInHashTable(cache->table, params, (const void **) &pipeline)) { + bool inserted = false; + // !!! FIXME: why don't we have an SDL_alloc_copy function/macro? + GPU_PipelineParameters *paramscpy = (GPU_PipelineParameters *) SDL_malloc(sizeof (*paramscpy)); + if (paramscpy) { + SDL_copyp(paramscpy, params); + pipeline = MakePipeline(device, shaders, params); + if (pipeline) { + inserted = SDL_InsertIntoHashTable(cache->table, paramscpy, pipeline, false); + } + } + + if (!inserted) { + SDL_free(paramscpy); + if (pipeline) { + SDL_ReleaseGPUGraphicsPipeline(device, pipeline); + pipeline = NULL; + } + } + } + + return pipeline; +} + +#endif // SDL_VIDEO_RENDER_GPU -- cgit v1.2.3