mausimus / ShaderGlass

Overlay for running GPU shaders on top of Windows desktop
GNU General Public License v3.0
1.02k stars 37 forks source link

ShaderGen crash #66

Open Lucide opened 1 year ago

Lucide commented 1 year ago

After a bit of poking around, I discovered how ShaderGen.exe expects it's input. I created a slang-shaders folder, put a test shader in it and ran ShaderGen.exe filename.slang in a debugger, with the pwd correctly set to the build folder.

I'm new to slang, I'm trying an example found in the slang guide:

#version 450
// 450 or 310 es are recommended

layout(set = 0, binding = 0, std140) uniform UBO
{
    mat4 MVP;
    vec4 SourceSize; // Not used here, but doesn't hurt
    float ColorMod;
};

#pragma name StockShader
#pragma format R8G8B8A8_UNORM
#pragma parameter ColorMod "Color intensity" 1.0 0.1 2.0 0.1

#pragma stage vertex
layout(location = 0) in vec4 Position;
layout(location = 1) in vec2 TexCoord;
layout(location = 0) out vec2 vTexCoord;
void main()
{
    gl_Position = MVP * Position;
    vTexCoord = TexCoord;
}

#pragma stage fragment
layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor;
layout(binding = 1) uniform sampler2D Source;
void main() { FragColor = texture(Source, vTexCoord) * ColorMod; }

The output I get is:

======= "test.slang"
"..\ShaderGlass\Tools\glslangValidator.exe" -V -S vert -o test.vert.spv test.vert.glsl
The system cannot find the path specified.
"..\ShaderGlass\Tools\spirv-cross.exe"  --hlsl --shader-model 50 test.vert.spv        
The system cannot find the path specified.
"..\ShaderGlass\Tools\spirv-cross.exe" test.vert.spv --reflect
The system cannot find the path specified.
"..\ShaderGlass\Tools\glslangValidator.exe" -V -S frag -o test.frag.spv test.frag.glsl
The system cannot find the path specified.
"..\ShaderGlass\Tools\spirv-cross.exe"  --hlsl --shader-model 50 test.frag.spv
The system cannot find the path specified.
"..\ShaderGlass\Tools\spirv-cross.exe" test.frag.spv --reflect
The system cannot find the path specified.
"C:\Program Files (x86)\Windows Kits\10\bin\10.0.20348.0\x64\fxc.exe"  /O3 /E main /T vs_5_0 /Fh test.vs_5_0.h test.vs_5_0.hlsl
'C:\Program' is not recognized as an internal or external command,
operable program or batch file.
"C:\Program Files (x86)\Windows Kits\10\bin\10.0.20348.0\x64\fxc.exe"  /O3 /E main /T ps_5_0 /Fh test.ps_5_0.h test.ps_5_0.hlsl
'C:\Program' is not recognized as an internal or external command,
operable program or batch file.

The program crashes at line 336:

// built-in parameters
def.params.push_back(ShaderParam("MVP", 16));

Perhaps MVP is something which is unsupported? Results are the same if I remove the vertex shader section, and MVP references.

I've seen that the tool acts as a full-blown lexer-parser-.. at once, so the code is quite beyond my capabilities. Can you reproduce?

mausimus commented 1 year ago

This sample compiles fine for me, it doesn't look like you're running it from the right directory. The default setup is for use with a debugger so it might not be very intuitive. In my case, I have ShaderGlass folder as d:\Work\ShaderGlass and created test.slang as d:\Work\slang-shaders\test.slang . Then this should work:

image

Lucide commented 1 year ago

Ok, I assumed the tool would keep files under the tree, saw that _inputPath = "..\\..\\slang-shaders" and assumed the build folder as the pwd. That is fixed, but I still get those path issues:

======= "test.slang"
"..\ShaderGlass\Tools\glslangValidator.exe" -V -S vert -o test.vert.spv test.vert.glsl
"..\ShaderGlass\Tools\spirv-cross.exe"  --hlsl --shader-model 50 test.vert.spv
"..\ShaderGlass\Tools\spirv-cross.exe" test.vert.spv --reflect
"..\ShaderGlass\Tools\glslangValidator.exe" -V -S frag -o test.frag.spv test.frag.glsl
"..\ShaderGlass\Tools\spirv-cross.exe"  --hlsl --shader-model 50 test.frag.spv
"..\ShaderGlass\Tools\spirv-cross.exe" test.frag.spv --reflect
"C:\Program Files (x86)\Windows Kits\10\bin\10.0.20348.0\x64\fxc.exe"  /O3 /E main /T vs_5_0 /Fh test.vs_5_0.h test.vs_5_0.hlsl
'C:\Program' is not recognized as an internal or external command,
operable program or batch file.
"C:\Program Files (x86)\Windows Kits\10\bin\10.0.20348.0\x64\fxc.exe"  /O3 /E main /T ps_5_0 /Fh test.ps_5_0.h test.ps_5_0.hlsl
'C:\Program' is not recognized as an internal or external command,
operable program or batch file.

Very curious, as I see the code does

    stringstream cmd;
    cmd << "\"" << _fxcPath << "\" "
        << " /O3 /E main /T " << profile << " /Fh " << output.string() << " " << input.string();
    exec(cmd.str().c_str());

I'll investigate 🤔 I suspect it's a shell issue, I think it's defaulting to powershell on my machine.

mausimus commented 1 year ago

Interesting, check if you have fxc.exe at that path, if not you'll need to install Windows SDK.

Lucide commented 1 year ago

Yes, that was also an issue, but I had already replaced the hardcoded version with "10.0.22000.0", which is stated as a dependency of the project anyway. The real issue was indeed the shell, I band-aided it with

    stringstream cmd;
    cmd << "cmd /c \"\"" << _fxcPath << "\" "
        << " /O3 /E main /T " << profile << " /Fh " << output.string() << " " << input.string() << "\"";
    exec(cmd.str().c_str());

I can make a pull request if you want, but that should be a valid pws command too, not sure of what's happening.

I'll piggyback this custom shader-related issue to ask some questions, if you don't mind. Now that I have my header file shader, excluding build-related stuff, what to do? 🦧 I included it in ShaderList.h.I see there's also a ShaderList.cpp which imports shaders\RetroArch.h. Do I have to instantiate shader metadata somewhere?

Lucide commented 1 year ago

I've put some hours trying to figure out the code and I've managed to write a sample shader header. I've made an attempt to remove the vertex shader part because I won't need it, I need to add a small pixel shader.

Shaders/Custom/TestShaderDef.h

#pragma once

namespace TestShaderDefs{

static const BYTE sFragmentByteCode[] = {
     68,  88,  66,  67, 135, 176, 
     ...
      0,   0,   0,   0
};
}

class TestShaderDef : public ShaderDef{
public:
    TestShaderDef() : ShaderDef{}{
        Name = "test";
        VertexByteCode = NULL;
        VertexLength = 0;
        FragmentByteCode = TestShaderDefs::sFragmentByteCode;
        FragmentLength = sizeof(TestShaderDefs::sFragmentByteCode);
        Params.push_back(ShaderParam("MVP", 0, 0, 64, 0.000000f, 0.000000f, 0.000000f));
        Params.push_back(ShaderParam("SourceSize", -1, 0, 16, 0.000000f, 0.000000f, 0.000000f));
        Params.push_back(ShaderParam("OriginalSize", -1, 16, 16, 0.000000f, 0.000000f, 0.000000f));
        Params.push_back(ShaderParam("OutputSize", -1, 32, 16, 0.000000f, 0.000000f, 0.000000f));
        Params.push_back(ShaderParam("FrameCount", -1, 48, 4, 0.000000f, 0.000000f, 0.000000f));
        Samplers.push_back(ShaderSampler("Source", 2));

    VertexSource = "";
    FragmentSource = "";
    }
};

I'm not sure what VertexSource and VertexSource are for, in the case of the RetroArch shaders they seem to be generated by something.. MSBuild?

I've also added

    <ClInclude Include="Shaders\Custom\TestShaderDef.h" />

and

    <ClInclude Include="Shaders\Custom\TestShaderDef.h">
      <Filter>Shaders</Filter>

Respectively in ShaderGlass.vcxproj and ShaderGlass.vcxproj.filters. I'm really guessing here. But, for the life of me, I can't find where the shaders are actually instantiated, i.e., where their constructor is called 😥

mausimus commented 1 year ago

To include a new shader you need to create a Slang profile file (.slangp) and run that through ShaderGen as well. It will automatically add the the profile and shader to the lists/menus, you don't need to modify code in ShaderGlass manually.

The source fields will stay blank, it's a remainder of old functionality where I was compiling shaders on-the-fly, not used anymore.

Feel free to raise a PR for the shell call, I will test it in the next release :thumbsup: