floooh / sokol-tools

Command line tools for use with sokol headers
MIT License
229 stars 57 forks source link

sokol-shdc segfaults with --slang glsl330:hlsl5 #86

Closed nurpax closed 6 months ago

nurpax commented 1 year ago

sokol-shdc crashes for me with the following invocations:

sokol-shdc.exe --slang glsl330 --format sokol_zig -i src/shaders/texgrid.glsl -o src/shaders/texgrid.glsl.zig
sokol-shdc.exe --slang glsl330:hlsl5 --format sokol_zig -i src/shaders/texgrid.glsl -o src/shaders/texgrid.glsl.zig

The contents of texgrid.glsl are as follows:


#pragma sokol @vs vs
uniform vs_params {
    vec4 mvp[4];
};

in vec4 position;
in vec2 texcoord0;

out vec2 uv;

vec4 xform(vec4 mat[4], vec4 v) {
    return vec4(dot(mat[0], position), dot(mat[1], position), dot(mat[2], position), dot(mat[3], position));
}

void main() {
    gl_Position = xform(mvp, position);
    uv = texcoord0;
}
#pragma sokol @end

#pragma sokol @fs fs
uniform sampler2D tex;

in vec2 uv;
out vec4 frag_color;

void main() {
    frag_color = texture(tex, uv);
}
#pragma sokol @end

#pragma sokol @program texgrid vs fs

I'm not really setup with a good debugger on this host, but looks like some unhandled exception? ->

Starting program: C:\Users\janne\dev\workspace\fips-deploy\sokol-tools\win64-vstudio-release\sokol-shdc.exe --slang glsl330:hlsl5 --format sokol_zig -i src/shaders/texgrid.glsl -o src/shaders/texgrid.glsl.zig
gdb: unknown target exception 0xc0000409 at 0x7ff665c43b7d

I got the crash on Linux using sokol-tools prebuilt binaries and also on Windows when I built sokol-shdc myself.

nurpax commented 1 year ago

The following exception is thrown:

    if (!target_type.array.empty())
        SPIRV_CROSS_THROW("Access chains that result in an array can not be flattened");

Here's the stacktrace that I captured in Visual Studio debugger:

sokol-shdc.exe!issue_debug_notification(const wchar_t * const message) Line 28
    at minkernel\crts\ucrt\src\appcrt\internal\report_runtime_error.cpp(28)
sokol-shdc.exe!__acrt_report_runtime_error(const wchar_t * message) Line 154
    at minkernel\crts\ucrt\src\appcrt\internal\report_runtime_error.cpp(154)
sokol-shdc.exe!abort() Line 61
    at minkernel\crts\ucrt\src\appcrt\startup\abort.cpp(61)
sokol-shdc.exe!spirv_cross::report_and_abort(const std::string & msg) Line 58
    at C:\Users\janne\dev\workspace\sokol-tools\ext\SPIRV-Cross\spirv_cross_error_handling.hpp(58)
sokol-shdc.exe!spirv_cross::CompilerGLSL::flattened_access_chain(unsigned int base, const unsigned int * indices, unsigned int count, const spirv_cross::SPIRType & target_type, unsigned int offset, unsigned int matrix_stride, unsigned int __formal, bool need_transpose) Line 9103
    at C:\Users\janne\dev\workspace\sokol-tools\ext\SPIRV-Cross\spirv_glsl.cpp(9103)
sokol-shdc.exe!spirv_cross::CompilerGLSL::access_chain(unsigned int base, const unsigned int * indices, unsigned int count, const spirv_cross::SPIRType & target_type, spirv_cross::AccessChainMeta * meta, bool ptr_chain) Line 8992
    at C:\Users\janne\dev\workspace\sokol-tools\ext\SPIRV-Cross\spirv_glsl.cpp(8992)
sokol-shdc.exe!spirv_cross::CompilerGLSL::emit_instruction(const spirv_cross::Instruction & instruction) Line 10159
    at C:\Users\janne\dev\workspace\sokol-tools\ext\SPIRV-Cross\spirv_glsl.cpp(10159)
sokol-shdc.exe!spirv_cross::CompilerGLSL::emit_block_instructions(spirv_cross::SPIRBlock & block) Line 9860
    at C:\Users\janne\dev\workspace\sokol-tools\ext\SPIRV-Cross\spirv_glsl.cpp(9860)
sokol-shdc.exe!spirv_cross::CompilerGLSL::emit_block_chain(spirv_cross::SPIRBlock & block) Line 14704
    at C:\Users\janne\dev\workspace\sokol-tools\ext\SPIRV-Cross\spirv_glsl.cpp(14704)
sokol-shdc.exe!spirv_cross::CompilerGLSL::emit_function(spirv_cross::SPIRFunction & func, const spirv_cross::Bitset & return_flags) Line 13953
    at C:\Users\janne\dev\workspace\sokol-tools\ext\SPIRV-Cross\spirv_glsl.cpp(13953)
sokol-shdc.exe!spirv_cross::CompilerGLSL::compile() Line 677
    at C:\Users\janne\dev\workspace\sokol-tools\ext\SPIRV-Cross\spirv_glsl.cpp(677)
sokol-shdc.exe!shdc::to_glsl(const shdc::spirv_blob_t & blob, int glsl_version, bool is_gles, bool is_vulkan, unsigned int opt_mask, shdc::snippet_t::type_t type) Line 305
    at C:\Users\janne\dev\workspace\sokol-tools\src\shdc\spirvcross.cc(305)
sokol-shdc.exe!shdc::spirvcross_t::translate(const shdc::input_t & inp, const shdc::spirv_t & spirv, shdc::slang_t::type_t slang) Line 470
    at C:\Users\janne\dev\workspace\sokol-tools\src\shdc\spirvcross.cc(470)
sokol-shdc.exe!main(int argc, const char * * argv) Line 61
    at C:\Users\janne\dev\workspace\sokol-tools\src\shdc\main.cc(61)
[External Code]
nurpax commented 1 year ago

Perhaps it'd be fixed by upgrading some of the SPIR-V repos?

floooh commented 1 year ago

It's a bit surprising that SPIRVCross is throwing exceptions using a panic instead of a more traditional error reporting, I haven't seen that yet.

It's also strange that such a simple shader generates an error tbh...

I'll try to have a quick look, but may need a couple of days before I can do a proper investigation and fix.

floooh commented 1 year ago

...I vaguely seem to remember problems with array function args though...

floooh commented 1 year ago

Yeah, I remembered right. As a quick workaround, you need to rewrite the xform() function to not take an array arg, e.g.:

vec4 xform(vec4 mx, vec4 my, vec4 mz, vec4 mw, vec4 v) {
    return vec4(dot(mx, position), dot(my, position), dot(mz, position), dot(mw, position));
}

...and call it like this:

gl_Position = xform(mvp[0], mvp[1], mvp[2], mvp[3], position);

...doesn't help with the underlying problem of course, but hopefully unblocks you for now.

The error kinda makes sense unfortunately (I think I even reported this already to SPIRVCross, need to find the ticket though).

The GL backend flattens each uniform block into a vec4 array, but since GLSL has no array slices, it cannot access a range within this array for the function parameter (it could create a temporary array though, but I guess that's too much complexity for SPIRVCross for such an 'esoteric' feature).

Alternatively I could disable the uniform block flattening, but this would mean more runtime overhead when setting uniforms in the sokol_gfx.h GL backend.

I'll still try to set aside a bit of time 'soon-ish' to investigate the problem, maybe there's at least a way to make the error less painful (e.g. not crashing, and reporting a more helpful error message).

floooh commented 1 year ago

PS: alternatively this also works, keep the xform() function as it is, but create a temporary array at the call site:

    vec4 mat[4] = { mvp[0], mvp[1], mvp[2], mvp[3] };
    gl_Position = xform(mat, position)
nurpax commented 1 year ago

Thanks for the help! I'll workaround it like above.. I'm mainly using HLSL5 where this was not a problem, just noticed this while I tried to run my code on Linux and OpenGL.

It's probably fine to have a catch all exception handler somewhere in your CLI, then report the exception text and exit. Right now shdc crashes and it's kind of hard to know what happened.

Funny how my quest to go full row major snowballed into even problems like this.. :D

nmr8acme commented 1 year ago

FWIW you also get a segfault when using uint and glsl100 (which doesn't support uint, as expected.) Something a skosh more user friendly than a segfault might be an ergonomic improvement.

IMHO, because SPIRV-Cross seems to SPIRV_CROSS_THROW sort of zealously for error reporting, it might be worth it to just wire report_and_abort up to always print the error message. I'm having trouble thinking of a scenario where a user would want sokol-shdc to abort, but not print the underlying error message.

Just realized that it's spirv_cross_error_handling.hpp in SPIRV-Cross itself that silences the error message, I misread it and thought report_and_abort was sokol-shdc code. Whoops.

Too bad there isn't a straightforward way to persuade SPIRV-Cross to always print the error message. SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS doesn't get there does it? Maybe the default exception handler would print the uncaught std::runtime_error?

floooh commented 6 months ago

I just implemented a fix to communicate the SPIRVCross error message instead of just crashing in branch storage-buffer. In case of your example shader the error message isn't very helpful, but better than nothing I guess:

/Users/floh/projects/sokol-tools/test/issue_86.glsl:0:0: error: SPIRVCross exception: Access chains that result in an array can not be flattened

Unfortunately I don't get line information back from SPIRVCross, only an error message. Closing this ticket (even though the fix isn't in the master branch yet).