floooh / sokol

minimal cross-platform standalone C headers

Home Page:https://floooh.github.io/sokol-html5

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Can't Set Float Uniform Variable

Voxi0 opened this issue · comments

This is a .glsl shader file that I'm compiling using sokol-shdc I grabbed from the sokol-tools-bin repo. You can see in the fragment shader that I have a uniform block with a float variable called time which I set to '(float)glfwGetTime()'. I am using this variable to just play with the colors. This shader works perfectly fine when embedding this code in the shader desc, but compiling it with sokol-shdc into a header file just does not work. Setting the uniform variable says that the block size does not match and after going through the generated header file, the float variable in the fragment shader is getting converted into a vec4 for whatever reason. And sure enough, it works perfectly when I set a vec4, no block size errors.

This is the first time I've ever reported an issue on GitHub so excuse me if it's not formatted nicely. I'm really loving sokol by the way, it's great. Also I think it would be kinda cool if there was a discord server or something no?

#version 330 core

@ctype mat4 glm::mat4
@ctype vec3 glm::vec3
@ctype vec4 glm::vec4

@vs vs
// Vertex Attributes
layout(location = 0) in vec3 vertexPos;

// Uniform Variables
uniform vsParams {
    mat4 pvm;
};

// Main
void main() {
    gl_Position = pvm * vec4(vertexPos, 1.0f);
}
@end

@fs fs
// Uniform Variables
uniform fsParams {
    float time;
};

// Output
out vec4 fragColor;

// Main
void main() {
    // Set Final Fragment Color
    vec3 color = vec3(abs(sin(time)), 0.0f, 0.0f);
    fragColor = vec4(color, 1.0f);
}
@end

@program testShaders vs fs

Do you use the code-generated struct or your own (in the sg_apply_uniforms call)? E.g. in the sokol-shdc output there's the following struct generated:

#pragma pack(push,1)
SOKOL_SHDC_ALIGN(16) typedef struct fsParams_t {
    float time;
    uint8_t _pad_4[12];
} fsParams_t;
#pragma pack(pop

Note how this is padded to a multiple of 16 bytes. This is a side effect of 'flattening' uniform blocks into a vec4 array via SPIRVCross, which allows to update uniforms with a single glUniform4fv() call per uniform-block in the GL backend (instead of one individual glUniform call per uniform block member which is otherwise used).

PS: the #version 330 core at the top of your shader isn't necessary (and might even confuse sokol-shdc in some cases).

PPS: in general, and if possible, you should use the code-generated structs for passing uniforms into sokol-gfx, since the alignment and padding rules for uniform blocks are non-trivial, and very different from vanilla C structs.

PPPS: code example

const fsParams_t fs_params = { .time = (float)glfwGetTime() };
sg_apply_uniforms(SG_SHADERSTAGE_FS, SLOT_fsParams, &SG_RANGE(fs_params));

I know the #version 330 core isn't necessary but I was pretty desperate to get it working. I am using the generated struct yes, I'd rather not make my own or mess with the generated one. And, oh, the code example you provided actually works. I guess that's it, thanks.

By the way, using the '&' before 'SG_RANGE' gives me an error. I've seen it being used every example though. The error is 'Taking address of rvalue [-fpermissive]', the program runs fine regardless of this error. I have all warnings and errors enabled so that must be the case.

By the way, using the '&' before 'SG_RANGE' gives me an error.

Ah right, that's a C vs C++ thing. In C++ you can do this instead (just drop the '&'):

sg_apply_uniforms(SG_SHADERSTAGE_FS, SLOT_fsParams, SG_RANGE(fs_params));

...or use the SG_RANGE_REF() macro which does the right thing both in C and C++:

sg_apply_uniforms(SG_SHADERSTAGE_FS, SLOT_fsParams, SG_RANGE_REF(fs_params));