Skip to content

Commit a292d43

Browse files
committed
Wicked moah bettah.
1 parent cd93deb commit a292d43

6 files changed

Lines changed: 144 additions & 265 deletions

File tree

Sources/ObjectivelyGPU/ComputePipeline.c

Lines changed: 0 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323

2424
#include <assert.h>
2525

26-
#include <Objectively/Resource.h>
27-
2826
#include "ComputePipeline.h"
2927
#include "RenderDevice.h"
3028

@@ -60,9 +58,7 @@ static ComputePipeline *initWithDevice(ComputePipeline *self, RenderDevice *devi
6058

6159
self = (ComputePipeline *) super(Object, self, init);
6260
if (self) {
63-
6461
self->device = retain(device);
65-
assert(self->device);
6662

6763
self->pipeline = SDL_CreateGPUComputePipeline(device->device, info);
6864
GPU_Assert(self->pipeline, "SDL_CreateGPUComputePipeline");
@@ -71,74 +67,6 @@ static ComputePipeline *initWithDevice(ComputePipeline *self, RenderDevice *devi
7167
return self;
7268
}
7369

74-
/**
75-
* @fn ComputePipeline *ComputePipeline::initWithResource(ComputePipeline *self, RenderDevice *device, const Resource *resource, SDL_GPUShaderFormat format, const SDL_GPUComputePipelineCreateInfo *info)
76-
* @memberof ComputePipeline
77-
*/
78-
static ComputePipeline *initWithResource(ComputePipeline *self, RenderDevice *device, const Resource *resource, SDL_GPUShaderFormat format, const SDL_GPUComputePipelineCreateInfo *info) {
79-
80-
assert(device);
81-
assert(resource && resource->data && resource->data->length);
82-
assert(info);
83-
84-
SDL_GPUComputePipelineCreateInfo create = *info;
85-
create.code = resource->data->bytes;
86-
create.code_size = resource->data->length;
87-
create.format = format;
88-
create.entrypoint = create.entrypoint ?: (format == SDL_GPU_SHADERFORMAT_MSL) ? "main0" : "main";
89-
90-
return $(self, initWithDevice, device, &create);
91-
}
92-
93-
/**
94-
* @fn ComputePipeline *ComputePipeline::initWithResourceName(ComputePipeline *self, RenderDevice *device, const char *name, const SDL_GPUComputePipelineCreateInfo *info)
95-
* @memberof ComputePipeline
96-
*/
97-
static ComputePipeline *initWithResourceName(ComputePipeline *self, RenderDevice *device, const char *name, const SDL_GPUComputePipelineCreateInfo *info) {
98-
99-
assert(device);
100-
assert(name);
101-
assert(info);
102-
103-
static const struct {
104-
SDL_GPUShaderFormat format;
105-
const char *ext;
106-
} formats[] = {
107-
{ SDL_GPU_SHADERFORMAT_MSL, ".metal" },
108-
{ SDL_GPU_SHADERFORMAT_DXIL, ".dxil" },
109-
{ SDL_GPU_SHADERFORMAT_SPIRV,".spv" },
110-
};
111-
112-
const SDL_GPUShaderFormat supported = SDL_GetGPUShaderFormats(device->device);
113-
114-
for (size_t i = 0; i < SDL_arraysize(formats); i++) {
115-
116-
if (!(supported & formats[i].format)) {
117-
continue;
118-
}
119-
120-
char path[256];
121-
SDL_snprintf(path, sizeof(path), "%s%s", name, formats[i].ext);
122-
123-
Resource *res = $$(Resource, resourceWithName, path);
124-
if (!res) {
125-
continue;
126-
}
127-
128-
if (!res->data || res->data->length == 0) {
129-
release(res);
130-
continue;
131-
}
132-
133-
self = $(self, initWithResource, device, res, formats[i].format, info);
134-
release(res);
135-
return self;
136-
}
137-
138-
GPU_Assert(false, "no supported shader format found for '%s'", name);
139-
return NULL;
140-
}
141-
14270
#pragma mark - Class lifecycle
14371

14472
/**
@@ -149,8 +77,6 @@ static void initialize(Class *clazz) {
14977
((ObjectInterface *) clazz->interface)->dealloc = dealloc;
15078

15179
((ComputePipelineInterface *) clazz->interface)->initWithDevice = initWithDevice;
152-
((ComputePipelineInterface *) clazz->interface)->initWithResource = initWithResource;
153-
((ComputePipelineInterface *) clazz->interface)->initWithResourceName = initWithResourceName;
15480
}
15581

15682
/**

Sources/ObjectivelyGPU/ComputePipeline.h

Lines changed: 6 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
#include <SDL3/SDL_gpu.h>
2727

2828
#include <Objectively/Object.h>
29-
#include <Objectively/Resource.h>
3029

3130
#include <ObjectivelyGPU/Types.h>
3231

@@ -91,55 +90,18 @@ struct ComputePipelineInterface {
9190
/**
9291
* @fn ComputePipeline *ComputePipeline::initWithDevice(ComputePipeline *self, RenderDevice *device, const SDL_GPUComputePipelineCreateInfo *info)
9392
* @brief Initializes this ComputePipeline from a fully-populated `SDL_GPUComputePipelineCreateInfo`.
94-
* @details This is the designated initializer. All fields of @p info, including
95-
* `code`, `code_size`, and `format`, must be set by the caller. Prefer
96-
* `initWithResourceName` to load a compiled blob from the Resource system with
97-
* automatic format selection.
93+
* @details The designated (and only) initializer: a thin wrapper over
94+
* `SDL_CreateGPUComputePipeline`. All fields of @p info, including `code`,
95+
* `code_size`, `format`, and `entrypoint`, must be set by the caller. Prefer
96+
* `RenderDevice::loadComputePipeline`, which resolves a compiled blob from the
97+
* Resource system, selects the device-appropriate format, and fills these in.
9898
* @param self The ComputePipeline.
9999
* @param device The RenderDevice used to create and release the pipeline. Retained.
100-
* @param info Compute pipeline creation parameters with all fields populated.
100+
* @param info The ComputePipeline creation parameters with all fields populated.
101101
* @return The initialized ComputePipeline, or `NULL` on failure.
102102
* @memberof ComputePipeline
103103
*/
104104
ComputePipeline *(*initWithDevice)(ComputePipeline *self, RenderDevice *device, const SDL_GPUComputePipelineCreateInfo *info);
105-
106-
/**
107-
* @fn ComputePipeline *ComputePipeline::initWithResource(ComputePipeline *self, RenderDevice *device, const Resource *resource, SDL_GPUShaderFormat format, const SDL_GPUComputePipelineCreateInfo *info)
108-
* @brief Initializes this ComputePipeline from an already-loaded compiled blob.
109-
* @details Uses @p resource's data as the pipeline `code` for the given @p format.
110-
* `entrypoint` defaults to `main0` (MSL) or `main` when not set; the `code`,
111-
* `code_size`, and `format` fields of @p info are ignored. `initWithResourceName`
112-
* resolves a name to a resource and format, then delegates here.
113-
* @param self The ComputePipeline.
114-
* @param device The RenderDevice used to create and release the pipeline. Retained.
115-
* @param resource The loaded shader blob; must have non-empty data.
116-
* @param format The shader format of @p resource's data.
117-
* @param info Compute pipeline creation parameters; `code`, `code_size`, and `format` are ignored.
118-
* @return The initialized ComputePipeline, or `NULL` on failure.
119-
* @memberof ComputePipeline
120-
*/
121-
ComputePipeline *(*initWithResource)(ComputePipeline *self, RenderDevice *device, const Resource *resource, SDL_GPUShaderFormat format, const SDL_GPUComputePipelineCreateInfo *info);
122-
123-
/**
124-
* @fn ComputePipeline *ComputePipeline::initWithResourceName(ComputePipeline *self, RenderDevice *device, const char *name, const SDL_GPUComputePipelineCreateInfo *info)
125-
* @brief Initializes this ComputePipeline from a compiled blob loaded via the Resource system.
126-
* @details Appends the platform-appropriate extension to @p name and resolves it via
127-
* Objectively's ResourceProvider chain:
128-
* - Metal (macOS/iOS): `.metal`
129-
* - Vulkan (Linux/Android): `.spv`
130-
* - D3D12 (Windows): `.dxil`
131-
* The first supported, resolvable, non-empty blob is selected and passed to
132-
* `initWithResource` with its format. The caller fills in @c entrypoint, thread
133-
* counts, and binding counts in @p info; `code`, `code_size`, `format`, and a default
134-
* `entrypoint` are supplied. Shader blobs are produced offline by @c sdl-shadercross.
135-
* @param self The ComputePipeline.
136-
* @param device The RenderDevice used to create and release the pipeline. Retained.
137-
* @param name Shader base name without extension, e.g. @c "HelloCompute.comp".
138-
* @param info Compute pipeline creation parameters; `code`, `code_size`, and `format` are ignored.
139-
* @return The initialized ComputePipeline. GPU_Asserts if no supported blob is found.
140-
* @memberof ComputePipeline
141-
*/
142-
ComputePipeline *(*initWithResourceName)(ComputePipeline *self, RenderDevice *device, const char *name, const SDL_GPUComputePipelineCreateInfo *info);
143105
};
144106

145107
/**

Sources/ObjectivelyGPU/RenderDevice.c

Lines changed: 99 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626

2727
#include <SDL3/SDL_surface.h>
2828

29-
#include <Objectively/Data.h>
3029
#include <Objectively/Resource.h>
3130

3231
#include "Buffer.h"
@@ -53,6 +52,59 @@
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
*/
298354
static 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
*/
307386
static 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
/**

Sources/ObjectivelyGPU/RenderDevice.h

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ struct RenderDevice {
7979
* @brief The `SDL_Window` associated with @c device.
8080
*/
8181
SDL_Window *window;
82+
83+
/**
84+
* The bitmask of supported shader formats.
85+
*/
86+
SDL_GPUShaderFormat shaderFormats;
8287

8388
/**
8489
* @brief The present-target Framebuffer driven by `beginFrame`/`endFrame`, or `NULL`.
@@ -333,16 +338,16 @@ struct RenderDeviceInterface {
333338

334339
/**
335340
* @fn Shader *RenderDevice::loadShader(RenderDevice *self, const char *name, const SDL_GPUShaderCreateInfo *info)
336-
* @brief Loads a compiled shader blob via the Resource system and creates a Shader.
337-
* @details Convenience factory for `Shader::initWithResourceName`. Appends the
338-
* platform-appropriate extension to @c name and resolves it via Objectively's
339-
* ResourceProvider chain:
340-
* - Metal (macOS/iOS): `.metal`
341+
* @brief Loads a shader blob via the Resource system and creates a Shader.
342+
* @details Appends each supported format's extension to @c name and resolves it via
343+
* Objectively's ResourceProvider chain:
344+
* - Metal (macOS/iOS): `.metallib`, then `.metal`
341345
* - Vulkan (Linux/Android): `.spv`
342346
* - D3D12 (Windows): `.dxil`
343347
* The caller fills in @c stage, @c entrypoint, and binding counts in @c info.
344-
* @c code, @c code_size, and @c format are filled in for you.
345-
* Shader blobs are produced offline by @c sdl-shadercross from HLSL source.
348+
* @c code, @c code_size, @c format, and a default @c entrypoint are filled in for you,
349+
* then the completed info is passed to `Shader::initWithDevice`.
350+
* Shader blobs are produced offline by @c sdl-shadercross.
346351
* @param self The RenderDevice.
347352
* @param name Shader base name without extension, e.g. @c "shaders/Renderer.vert".
348353
* @param info Shader creation parameters. @c code, @c code_size, and @c format
@@ -355,15 +360,15 @@ struct RenderDeviceInterface {
355360
/**
356361
* @fn ComputePipeline *RenderDevice::loadComputePipeline(RenderDevice *self, const char *name, const SDL_GPUComputePipelineCreateInfo *info)
357362
* @brief Loads a compiled compute shader blob via the Resource system and creates a ComputePipeline.
358-
* @details Convenience factory for `ComputePipeline::initWithResourceName`. Parallel to
359-
* `loadShader` for compute stages. Appends the platform-appropriate extension to
360-
* @c name and resolves it via Objectively's ResourceProvider chain:
361-
* - Metal (macOS/iOS): `.metal`
363+
* @details Parallel to `loadShader` for compute stages. Appends each supported format's
364+
* extension to @c name and resolves it via Objectively's ResourceProvider chain:
365+
* - Metal (macOS/iOS): `.metallib`, then `.metal`
362366
* - Vulkan (Linux/Android): `.spv`
363367
* - D3D12 (Windows): `.dxil`
364368
* The caller fills in @c entrypoint, thread counts, and binding counts in @c info.
365-
* @c code, @c code_size, and @c format are filled in for you.
366-
* Shader blobs are produced offline by @c sdl-shadercross from HLSL source.
369+
* @c code, @c code_size, @c format, and a default @c entrypoint are filled in for you,
370+
* then the completed info is passed to `ComputePipeline::initWithDevice`.
371+
* Shader blobs are produced offline by @c sdl-shadercross.
367372
* @param self The RenderDevice.
368373
* @param name Shader base name without extension, e.g. @c "HelloCompute.comp".
369374
* @param info Compute pipeline creation parameters. @c code, @c code_size, and
@@ -414,7 +419,7 @@ struct RenderDeviceInterface {
414419
* @memberof RenderDevice
415420
*/
416421
void (*releaseTransferBuffer)(const RenderDevice *self, SDL_GPUTransferBuffer *tbuf);
417-
422+
418423
/**
419424
* @fn bool RenderDevice::setAllowedFramesInFlight(const RenderDevice *self, Uint32 allowed)
420425
* @brief Sets the maximum number of GPU frames that may be in flight concurrently.

0 commit comments

Comments
 (0)