Open danielchasehooper opened 11 months ago
Hmm ok, I actually need to check how SPIRVCross assigns precision qualifiers and how much control we actually have over the process, e.g. in the regular texcube-sapp shader (which doesn't have any manual precision qualifiers) it looks like this (e.g. a global specifier which sets floats to mediump, but then specific highp specifiers in various places).
#version 300 es
precision mediump float;
precision highp int;
uniform highp sampler2D tex_smp;
layout(location = 0) out highp vec4 frag_color;
in highp vec2 uv;
in highp vec4 color;
PS: apart from that, SPIRVCross allows to configure the default precision, but sokol-shdc currently doesn't expose that and uses the default settings (we could do this by extending the existing @glsl_options
I guess:
Btw, here's a fragment shader code snippet from the mandelbulb sample (sdf-sapp, input shader code: https://github.com/floooh/sokol-samples/blob/master/sapp/sdf-sapp.glsl), I looked at this specifically, because the mediump precision would be too low for that shader.
highp float sd_mandelbulb(highp vec3 p, inout highp vec4 res_color)
{
highp vec3 w = p;
highp float _49 = dot(p, p);
highp float m = _49;
highp vec4 trap = vec4(abs(p), _49);
highp float dz = 1.0;
for (int i = 0; i < 4; i++)
{
highp float _76 = m * m;
dz = (8.0 * sqrt(((_76 * _76) * _76) * m)) * dz + 1.0;
highp vec3 _653 = w;
highp float _100 = _653.x * _653.x;
highp float _104 = _100 * _100;
highp float _112 = _653.y * _653.y;
highp float _124 = _653.z * _653.z;
highp float _128 = _124 * _124;
highp float _132 = _653.x * _653.x + _124;
...looks like SPIRVCross forces anything to highp precision anyway, so putting any precision qualifiers into the input source code will probably be ignored.
Also, SPIRVCross actually allows to configure the global precision qualifier, but sokol-shdc currently doesn't expose that and instead uses the default settings (we could extend the existing @glsl_options
tag for that though):
Not sure how much the global precision mediump float;
statement matters though if everything is explicitely forced to highp
anyway.
Being able to specify a reduced global precision to sokol-shdc wouldn't be that useful, because there are usually only some variables in a shader that can fit their values in a reduced precision range.
Are you saying that SPIRVCross doesn't support tracking per-variable precision qualifiers?
Are you saying that SPIRVCross doesn't support tracking per-variable precision qualifiers?
I'm not sure actually, what it does seem to do is slap a highp
to every local variable despite the default global specifier being mediump
.
I'll need to check what happens when explicitly setting a local variable to mediump
in the input source code (e.g. will SPIRVCross preserve that, or overwrite it to highp
)
I'm currently tinkering around with this, and the behaviour is "interesting".
First, that warning isn't actually coming out of SPIRVCross, but is from the first compile pass from GLSL to SPIRV which is handled by glslang (https://github.com/KhronosGroup/glslang), and I wasn't able to silence this warning in any way, it shows up as soon as local precision qualifiers on variables are used.
SPIRVCross on the other hand seems to behave correctly, and the rule seems to be like this:
precision mediump float
or precision highp float
, and this doesn't correspond with any global precision qualifiers in the input SPIRV but is instead configured in the SPIRVCross compiler API.Meaning:
if you write precision highp float
in the input shader, and SPIRVCross is configured to write a global precision highp float
, then SPIRVCross will not write individual precision qualifiers (and the same for medium if both the input GLSL and the SPIRVCross default config agree on 'mediump')
SPIRVCross honors individual precision qualifiers if they differ from the default.
I suspect that the SPIRV spec doesn't have the concept of "global precision qualifiers" and only carries that information for each variable, and that's why SPIRVCross has to use a config option to assume a "default precision", and then annotates all variables that differ from the default precision.
...so apart from that warning in glslangValidator everything appears to work as expected (e.g. you can set a global precision qualifier at the top of an @fs
shader snippet (the default is highp), and then annotate individual variables that differ from that precision. So in the default case (no global precision in the input GLSL) it only makes sense to annoate variables with mediump.
Next I'll need to check what to do about that warning (it's not only confusing, but also clipped)
Apple says that 16 bit floats are twice as fast as 32 bit floats - I'd love to optimize some of our shaders with them but I'm unable to get sokol-shdc
to emit the half
type in its metal output. Am I missing something, or is there in fact a problem related to the interesting behavior you found?
for example, if you compile the below code with sokol-shdc -l metal_macos -i test.glsl -o out.h
none of the variables will be of type half
or half2
@vs layer_vs
in mat2 aRotateScale;
in vec4 aColor; // premultiplied alpha
in vec2 aVertexPosition;
in vec2 aTranslate;
in vec2 aSize;
in float aCornerRadius;
out lowp vec4 color;
out lowp vec2 coord;
out lowp vec2 half_size;
out lowp float cornerRadius;
void main(void) {
color = aColor;
half_size = aSize/2.0;
cornerRadius = aCornerRadius;
gl_Position = vec4(aRotateScale * aVertexPosition + aTranslate, 1, 1);
coord = (aVertexPosition - 0.5) * aSize;
}
@end
@fs layer_fs
in lowp vec4 color; // must be premultiplied alpha
in lowp vec2 coord;
in lowp vec2 half_size;
in lowp float cornerRadius;
out vec4 FragColor;
lowp float round_rect_sdf(lowp vec2 p,lowp vec2 rect_half_size,lowp float radius){
lowp vec2 d = abs(p) - rect_half_size + radius;
return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - radius;
}
void main(void) {
lowp float b = round_rect_sdf( coord, half_size, cornerRadius );
lowp float alpha = (1.-clamp(b+1.5,0.,1.));
FragColor = color * alpha;
}
@end
@program layer layer_vs layer_fs
Found this: https://gist.github.com/zeux/c83001968e06fe0b789fa4bd513860c6
Unfortunately, SPIRV-Cross doesn't support RelaxedPrecision for Metal Shading Language. To get around that, you need to enable 16-bit type support when building SPIRV for use with SPIRV-Cross, which will result in the actual half-precision types being emitted
Right. As far as I'm aware I'm not doing anything in sokol-shdc to prevent half precision. I would have recommended to check the SPIRVCross issue tracker and documentation though, such limitations are usually mentioned there.
The SPIRV compilation happens here:
...maybe there's an option on glslang::TShader
to enable this 16-bit type support
for GLSL input?
Hmm, on the other hand: https://gist.github.com/zeux/c83001968e06fe0b789fa4bd513860c6?permalink_comment_id=2942898#gistcomment-2942898
(PS: I'm actually surprised that Vulkan-style GLSL didn't add a proper half
type)
I've found that putting:
#extension GL_EXT_shader_explicit_arithmetic_types_float16 : enable
in your shader code, and use any of the 16 bit types mentioned here: https://github.com/KhronosGroup/GLSL/blob/main/extensions/ext/GL_EXT_shader_explicit_arithmetic_types.txt
(for example f16vec4
instead of vec4
), then the emitted metal shader code uses half precision
compiling the shader below warns:
warning: '' : all default precisions are highp; use precision statements to quiet warning, e.g.:
which seems wrong because we are using precision statements
compiled with
sokol-shdc -l glsl330:metal_macos:glsl300es -i precision.glsl -o out.h