2626
2727#include <SDL3/SDL_surface.h>
2828
29- #include <Objectively/Data.h>
3029#include <Objectively/Resource.h>
3130
3231#include "Buffer.h"
5352 #endif
5453#endif
5554
55+ /**
56+ * @brief Metadata for a shader binary format: its SDL enum, the file extension
57+ * of the transpiled blob, and the entry-point name the toolchain emits for each
58+ * stage. shadercross names every MSL (and hence metallib) entry point "main0";
59+ * SPIR-V and DXIL keep the GLSL/HLSL default "main".
60+ * @see RenderDevice::loadShader
61+ */
62+ typedef struct {
63+ SDL_GPUShaderFormat format ;
64+ const char * ext ;
65+ const char * vertexEntrypoint ;
66+ const char * fragmentEntrypoint ;
67+ const char * computeEntrypoint ;
68+ } GPU_ShaderFormat ;
69+
70+ /**
71+ * @brief The shader formats supported by ObjectivelyGPU.
72+ */
73+ static const GPU_ShaderFormat GPU_ShaderFormats [] = {
74+ { SDL_GPU_SHADERFORMAT_METALLIB , ".metallib" , "main0" , "main0" , "main0" },
75+ { SDL_GPU_SHADERFORMAT_MSL , ".metal" , "main0" , "main0" , "main0" },
76+ { SDL_GPU_SHADERFORMAT_DXIL , ".dxil" , "main" , "main" , "main" },
77+ { SDL_GPU_SHADERFORMAT_SPIRV , ".spv" , "main" , "main" , "main" },
78+ };
79+
80+ /**
81+ * @brief A helper
82+ */
83+ static Resource * resolveShaderResource (const char * name , SDL_GPUShaderFormat supported , GPU_ShaderFormat * resolved ) {
84+
85+ for (size_t i = 0 ; i < lengthof (GPU_ShaderFormats ); i ++ ) {
86+
87+ const GPU_ShaderFormat * fmt = & GPU_ShaderFormats [i ];
88+ if (!(fmt -> format & supported )) {
89+ continue ;
90+ }
91+
92+ char path [256 ];
93+ SDL_snprintf (path , sizeof (path ), "%s%s" , name , fmt -> ext );
94+
95+ Resource * res = $$ (Resource , resourceWithName , path );
96+ if (!res ) {
97+ continue ;
98+ }
99+
100+ * resolved = * fmt ;
101+ return res ;
102+ }
103+
104+ GPU_Assert (false, "Failed to resolve shader '%s'" , name );
105+ return NULL ;
106+ }
107+
56108#define _Class _RenderDevice
57109
58110#pragma mark - Object
@@ -266,13 +318,17 @@ static RenderDevice *init(RenderDevice *self) {
266318 self = (RenderDevice * ) super (Object , self , init );
267319 if (self ) {
268320
269- const SDL_GPUShaderFormat formats =
321+ const SDL_GPUShaderFormat requested =
322+ SDL_GPU_SHADERFORMAT_METALLIB |
270323 SDL_GPU_SHADERFORMAT_MSL |
271324 SDL_GPU_SHADERFORMAT_SPIRV |
272325 SDL_GPU_SHADERFORMAT_DXIL ;
273326
274- self -> device = SDL_CreateGPUDevice (formats , GPU_DEBUG , NULL );
327+ self -> device = SDL_CreateGPUDevice (requested , GPU_DEBUG , NULL );
275328 GPU_Assert (self -> device , "SDL_CreateGPUDevice" );
329+
330+ self -> shaderFormats = SDL_GetGPUShaderFormats (self -> device );
331+ GPU_Assert (self -> shaderFormats , "SDL_GetGPUShaderFormats" );
276332 }
277333
278334 return self ;
@@ -297,7 +353,30 @@ static RenderDevice *initWithWindow(RenderDevice *self, SDL_Window *window) {
297353 */
298354static Shader * loadShader (RenderDevice * self , const char * name , const SDL_GPUShaderCreateInfo * info ) {
299355
300- return $ (alloc (Shader ), initWithResourceName , self , name , info );
356+ GPU_ShaderFormat resolved ;
357+ Resource * resource = resolveShaderResource (name , self -> shaderFormats , & resolved );
358+
359+ SDL_GPUShaderCreateInfo create = * info ;
360+
361+ create .code = resource -> data -> bytes ;
362+ create .code_size = resource -> data -> length ;
363+ create .format = resolved .format ;
364+
365+ if (!create .entrypoint ) {
366+ switch (create .stage ) {
367+ case SDL_GPU_SHADERSTAGE_VERTEX :
368+ create .entrypoint = resolved .vertexEntrypoint ;
369+ break ;
370+ case SDL_GPU_SHADERSTAGE_FRAGMENT :
371+ create .entrypoint = resolved .fragmentEntrypoint ;
372+ break ;
373+ }
374+ }
375+
376+ Shader * shader = $ (alloc (Shader ), initWithDevice , self , & create );
377+
378+ release (resource );
379+ return shader ;
301380}
302381
303382/**
@@ -306,7 +385,22 @@ static Shader *loadShader(RenderDevice *self, const char *name, const SDL_GPUSha
306385 */
307386static ComputePipeline * loadComputePipeline (RenderDevice * self , const char * name , const SDL_GPUComputePipelineCreateInfo * info ) {
308387
309- return $ (alloc (ComputePipeline ), initWithResourceName , self , name , info );
388+ GPU_ShaderFormat resolved ;
389+ Resource * resource = resolveShaderResource (name , self -> shaderFormats , & resolved );
390+
391+ SDL_GPUComputePipelineCreateInfo create = * info ;
392+ create .code = resource -> data -> bytes ;
393+ create .code_size = resource -> data -> length ;
394+ create .format = resolved .format ;
395+
396+ if (!create .entrypoint ) {
397+ create .entrypoint = resolved .computeEntrypoint ;
398+ }
399+
400+ ComputePipeline * pipeline = $ (alloc (ComputePipeline ), initWithDevice , self , & create );
401+
402+ release (resource );
403+ return pipeline ;
310404}
311405
312406/**
0 commit comments