Simple Directmedia Layer
at main 7.4 kB view raw
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23#ifdef SDL_VIDEO_RENDER_GPU 24 25#include "SDL_shaders_gpu.h" 26 27// SDL_GPU shader implementation 28 29typedef struct GPU_ShaderModuleSource 30{ 31 const unsigned char *code; 32 unsigned int code_len; 33 SDL_GPUShaderFormat format; 34} GPU_ShaderModuleSource; 35 36#if defined(SDL_GPU_VULKAN) && SDL_GPU_VULKAN 37#define IF_VULKAN(...) __VA_ARGS__ 38#define HAVE_SPIRV_SHADERS 1 39#include "shaders/spir-v.h" 40#else 41#define IF_VULKAN(...) 42#define HAVE_SPIRV_SHADERS 0 43#endif 44 45#ifdef SDL_GPU_D3D12 46#define IF_D3D12(...) __VA_ARGS__ 47#define HAVE_DXIL60_SHADERS 1 48#include "shaders/dxil60.h" 49#else 50#define IF_D3D12(...) 51#define HAVE_DXIL60_SHADERS 0 52#endif 53 54#ifdef SDL_GPU_METAL 55#define IF_METAL(...) __VA_ARGS__ 56#define HAVE_METAL_SHADERS 1 57#include "shaders/metal.h" 58#else 59#define IF_METAL(...) 60#define HAVE_METAL_SHADERS 0 61#endif 62 63typedef struct GPU_ShaderSources 64{ 65 IF_VULKAN(GPU_ShaderModuleSource spirv;) 66 IF_D3D12(GPU_ShaderModuleSource dxil60;) 67 IF_METAL(GPU_ShaderModuleSource msl;) 68 unsigned int num_samplers; 69 unsigned int num_uniform_buffers; 70} GPU_ShaderSources; 71 72#define SHADER_SPIRV(code) \ 73 IF_VULKAN(.spirv = { code, sizeof(code), SDL_GPU_SHADERFORMAT_SPIRV }, ) 74 75#define SHADER_DXIL60(code) \ 76 IF_D3D12(.dxil60 = { code, sizeof(code), SDL_GPU_SHADERFORMAT_DXIL }, ) 77 78#define SHADER_METAL(code) \ 79 IF_METAL(.msl = { code, sizeof(code), SDL_GPU_SHADERFORMAT_MSL }, ) 80 81// clang-format off 82static const GPU_ShaderSources vert_shader_sources[NUM_VERT_SHADERS] = { 83 [VERT_SHADER_LINEPOINT] = { 84 .num_samplers = 0, 85 .num_uniform_buffers = 1, 86 SHADER_SPIRV(linepoint_vert_spv) 87 SHADER_DXIL60(linepoint_vert_sm60_dxil) 88 SHADER_METAL(linepoint_vert_metal) 89 }, 90 [VERT_SHADER_TRI_COLOR] = { 91 .num_samplers = 0, 92 .num_uniform_buffers = 1, 93 SHADER_SPIRV(tri_color_vert_spv) 94 SHADER_DXIL60(tri_color_vert_sm60_dxil) 95 SHADER_METAL(tri_color_vert_metal) 96 }, 97 [VERT_SHADER_TRI_TEXTURE] = { 98 .num_samplers = 0, 99 .num_uniform_buffers = 1, 100 SHADER_SPIRV(tri_texture_vert_spv) 101 SHADER_DXIL60(tri_texture_vert_sm60_dxil) 102 SHADER_METAL(tri_texture_vert_metal) 103 }, 104}; 105 106static const GPU_ShaderSources frag_shader_sources[NUM_FRAG_SHADERS] = { 107 [FRAG_SHADER_COLOR] = { 108 .num_samplers = 0, 109 .num_uniform_buffers = 0, 110 SHADER_SPIRV(color_frag_spv) 111 SHADER_DXIL60(color_frag_sm60_dxil) 112 SHADER_METAL(color_frag_metal) 113 }, 114 [FRAG_SHADER_TEXTURE_RGB] = { 115 .num_samplers = 1, 116 .num_uniform_buffers = 0, 117 SHADER_SPIRV(texture_rgb_frag_spv) 118 SHADER_DXIL60(texture_rgb_frag_sm60_dxil) 119 SHADER_METAL(texture_rgb_frag_metal) 120 }, 121 [FRAG_SHADER_TEXTURE_RGBA] = { 122 .num_samplers = 1, 123 .num_uniform_buffers = 0, 124 SHADER_SPIRV(texture_rgba_frag_spv) 125 SHADER_DXIL60(texture_rgba_frag_sm60_dxil) 126 SHADER_METAL(texture_rgba_frag_metal) 127 }, 128}; 129// clang-format on 130 131static SDL_GPUShader *CompileShader(const GPU_ShaderSources *sources, SDL_GPUDevice *device, SDL_GPUShaderStage stage) 132{ 133 const GPU_ShaderModuleSource *sms = NULL; 134 SDL_GPUShaderFormat formats = SDL_GetGPUShaderFormats(device); 135 136 if (formats == SDL_GPU_SHADERFORMAT_INVALID) { 137 // SDL_GetGPUShaderFormats already set the error 138 return NULL; 139#if HAVE_SPIRV_SHADERS 140 } else if (formats & SDL_GPU_SHADERFORMAT_SPIRV) { 141 sms = &sources->spirv; 142#endif // HAVE_SPIRV_SHADERS 143#if HAVE_DXIL60_SHADERS 144 } else if (formats & SDL_GPU_SHADERFORMAT_DXIL) { 145 sms = &sources->dxil60; 146#endif // HAVE_DXIL60_SHADERS 147#if HAVE_METAL_SHADERS 148 } else if (formats & SDL_GPU_SHADERFORMAT_MSL) { 149 sms = &sources->msl; 150#endif // HAVE_METAL_SHADERS 151 } else { 152 SDL_SetError("Unsupported GPU backend"); 153 return NULL; 154 } 155 156 SDL_GPUShaderCreateInfo sci = { 0 }; 157 sci.code = sms->code; 158 sci.code_size = sms->code_len; 159 sci.format = sms->format; 160 // FIXME not sure if this is correct 161 sci.entrypoint = 162#if HAVE_METAL_SHADERS 163 (sms == &sources->msl) ? "main0" : 164#endif // HAVE_METAL_SHADERS 165 "main"; 166 sci.num_samplers = sources->num_samplers; 167 sci.num_uniform_buffers = sources->num_uniform_buffers; 168 sci.stage = stage; 169 170 return SDL_CreateGPUShader(device, &sci); 171} 172 173bool GPU_InitShaders(GPU_Shaders *shaders, SDL_GPUDevice *device) 174{ 175 for (int i = 0; i < SDL_arraysize(vert_shader_sources); ++i) { 176 shaders->vert_shaders[i] = CompileShader( 177 &vert_shader_sources[i], device, SDL_GPU_SHADERSTAGE_VERTEX); 178 if (shaders->vert_shaders[i] == NULL) { 179 GPU_ReleaseShaders(shaders, device); 180 return false; 181 } 182 } 183 184 for (int i = 0; i < SDL_arraysize(frag_shader_sources); ++i) { 185 shaders->frag_shaders[i] = CompileShader( 186 &frag_shader_sources[i], device, SDL_GPU_SHADERSTAGE_FRAGMENT); 187 if (shaders->frag_shaders[i] == NULL) { 188 GPU_ReleaseShaders(shaders, device); 189 return false; 190 } 191 } 192 193 return true; 194} 195 196void GPU_ReleaseShaders(GPU_Shaders *shaders, SDL_GPUDevice *device) 197{ 198 for (int i = 0; i < SDL_arraysize(shaders->vert_shaders); ++i) { 199 SDL_ReleaseGPUShader(device, shaders->vert_shaders[i]); 200 shaders->vert_shaders[i] = NULL; 201 } 202 203 for (int i = 0; i < SDL_arraysize(shaders->frag_shaders); ++i) { 204 SDL_ReleaseGPUShader(device, shaders->frag_shaders[i]); 205 shaders->frag_shaders[i] = NULL; 206 } 207} 208 209SDL_GPUShader *GPU_GetVertexShader(GPU_Shaders *shaders, GPU_VertexShaderID id) 210{ 211 SDL_assert((unsigned int)id < SDL_arraysize(shaders->vert_shaders)); 212 SDL_GPUShader *shader = shaders->vert_shaders[id]; 213 SDL_assert(shader != NULL); 214 return shader; 215} 216 217SDL_GPUShader *GPU_GetFragmentShader(GPU_Shaders *shaders, GPU_FragmentShaderID id) 218{ 219 SDL_assert((unsigned int)id < SDL_arraysize(shaders->frag_shaders)); 220 SDL_GPUShader *shader = shaders->frag_shaders[id]; 221 SDL_assert(shader != NULL); 222 return shader; 223} 224 225void GPU_FillSupportedShaderFormats(SDL_PropertiesID props) 226{ 227 SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN, HAVE_SPIRV_SHADERS); 228 SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN, HAVE_DXIL60_SHADERS); 229 SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN, HAVE_METAL_SHADERS); 230} 231 232#endif // SDL_VIDEO_RENDER_GPU