floooh / sokol

minimal cross-platform standalone C headers
https://floooh.github.io/sokol-html5
zlib License
7.06k stars 494 forks source link

More `sg_uniform_type`s #284

Closed gingerBill closed 2 years ago

gingerBill commented 4 years ago

Currently only these uniform types are supported:

typedef enum sg_uniform_type {
    SG_UNIFORMTYPE_INVALID,
    SG_UNIFORMTYPE_FLOAT,
    SG_UNIFORMTYPE_FLOAT2,
    SG_UNIFORMTYPE_FLOAT3,
    SG_UNIFORMTYPE_FLOAT4,
    SG_UNIFORMTYPE_MAT4,
    _SG_UNIFORMTYPE_NUM,
    _SG_UNIFORMTYPE_FORCE_U32 = 0x7FFFFFFF
} sg_uniform_type;

Would it be possible to support integer uniform types?

SG_UNIFORMTYPE_INT(N)
SG_UNIFORMTYPE_UINT(N)
SG_UNIFORMTYPE_MAT(N)
etc
floooh commented 4 years ago

It's somewhere down on my mental todo list, the reason why integer types haven't been in from the beginning was GLES2 and WebGL (so those new uniform types would also need a "feature flag").

Btw, if you are not using the GL backend (e.g. only D3D11 and Metal), then it should theoretically work, because from D3D11's and Metal's point of view, a uniform block is just an opaque blob of memory that's handed from the CPU side to the GPU side.

However, the sokol-shdc shader compiler would choke on integer types too though (when generating the CPU side uniform block struct).

gingerBill commented 4 years ago

Thank you for the reply. Yeah, I pretty much just bodged it in just for the OpenGL side. I dind't need the Matrix types really, I just needed the integers ones and only for OpenGL.

stephomi commented 4 years ago

It's somewhere down on my mental todo list, the reason why integer types haven't been in from the beginning was GLES2 and WebGL (so those new uniform types would also need a "feature flag").

I'm probably missing something obvious but why would it need a feature flag? Is it a limitation in how sokol is handling uniform internally, or on the GLES2/WebGL side?

floooh commented 4 years ago

Yeah I had that confused with 'varyings' (shader input/outputs) which can't be integers in WebGL/GLES2 (they can be on the CPU side for the vertex shader inputs, but they'll be converted to float in WebGL/GLES2).

One other tricky thing though is that the sokol-shdc tool generally flattens uniform blocks into vec4 arrays (which isn't a problem when using sokol_gfx.h without sokol-shdc though). I'd need to check how SPIRVCross handles this case for mixed data (my guess is that mixing data types in the same uniform block wouldn't be allowed, so one would need to "waste" one uniform block for float data and another for integer data).

stephomi commented 4 years ago

Ah indeed I was experimenting with soko-shdc and it seems I'm forced to use uniform blocks to get the reflection info.

If that's easy to do, maybe sokol-shdc could issue a warning in that case, "Uniforms should be inside blocks when writing to non-gl shaders".

floooh commented 4 years ago

The main reason why sokol-shdc is flattening the uniform blocks into vec4 arrays is to reduce glUniform() calls (it's essentially a uniform buffer "emulation" for GLES2/WebGL, which also happens to perform better than actual uniform buffers on some platforms / GL drivers). Another option is probably to not do this flattening for 'mixed-type uniform blocks' and fall back to doing single-uniform updates in sg_apply_uniforms() on GL. This would make the sokol-shdc reflection code more complicated (and the code which builds the sg_shader_desc structs), but it sounds doable.... (hmm, assuming SPIRVCross has somehow support for this... otherwise it's a bit of a chicken-egg-simulation, to tell SPIRVCross whether it should use uniform flattening, I'd first need to find out whether this flattening is necessary... and for this I first need to feed it into SPIRVCross)...

Anyway... I guess the point is that in sokol_gfx.h itself, having more uniform types shouldn't be a problem, it just gets a bit tricky in sokol-shdc :)

floooh commented 2 years ago

Related changes:

https://github.com/floooh/sokol/pull/606

TL;DR: signed-integer types are supported now, the sokol-shader compiler doesn't insist on flattening uniform blocks, and validation of uniform block interior has been tightened.

I'm closing this ticket now, because I think this is the best that can be done with the 'common subset' of the std140 uniform block layout and the glUniform calls used in the GL backend.

Once the GLES2/WebGL backends can be removed (and assuming that UBO support can be implemented that works well with dynamically updated UBOs), the entire code which deals with "uniform block interior" can be removed (so it will be irrelevant what uniform types will be supported, that's then only between shader code and 3D backend API).