为什么我的 HLSL 着色器无法编译为 SPIRV?

问题描述 投票:0回答:1

在我的上一篇文章关于直接通过Visual Studio编译HLSL文件的更新中,我最终放弃并决定使用离线编译方法。我能够将两个 HLSL 着色器编译为

.spv
文件,但现在我收到以下验证错误:

Validation Error: [ VUID-VkShaderModuleCreateInfo-pCode-01379] 
Object 0: handle = 0x1c63c99aa70, type = VK_OBJECT_TYPE_DEVICE; 
| MessageID = 0x2a1bf17f |
SPIR-V module not valid: Invalid SPIR-V magic number. The Vulkan spec states: 
If pCode is a pointer to GLSL code, it must be valid GLSL code written to the GL_KHR_vulkan_glsl GLSL extension specification
(https://vulkan.lunarg.com/doc/view/1.3.250.1/windows/1.3-extensions/vkspec.html#VUID-VkShaderModuleCreateInfo-pCode-01379)

不幸的是,

.spv
文件是从HLSL代码编译的,所以我不确定这里可能出现什么问题。

这些是我在编译

.hlsl
文件时使用的命令:

dxc.exe -spirv -T vs_6_4 -E main .\vertex_vert.hlsl -Fo .\vertex_vert.spv
dxc.exe -spirv -T ps_6_4 -E main .\pixel_frag.hlsl -Fo .\pixel_frag.spv

这是顶点着色器的内容:

struct VSInput
{
    [[vk::location(0)]] float4 Position : POSITION0;
    [[vk::location(1)]] float4 Color : COLOR0;
    [[vk::location(2)]] float2 UVcoord : TEXCOORD0;
};
struct VSOutput
{
    float4 Position : SV_POSITION;
    [[vk::location(0)]] float4 Color : COLOR0;
    [[vk::location(1)]] float2 UVcoord : TEXCOORD0;
};
struct Camera
{
    float4x4 view;
    float4x4 proj;
    float3 position;
};
struct UBO
{
    float dt;
    float4x4 model;
    Camera cam;
};
/* neither of the below options changed the outcome */
//cbuffer ubo : register(b0, space0);
//{ UBO ubo; }
ConstantBuffer <UBO> ubo : register(b0, space0);

VSOutput main(VSInput input, uint VertexIndex : SV_VertexID)
{
    VSOutput output = (VSOutput) 0;
    
    float4x4 camMatrix = mul(ubo.cam.proj, ubo.cam.view);
    output.Position = mul(camMatrix, mul(ubo.model, input.Position));
    
    output.Color = input.Color;
    output.UVcoord = input.UVcoord;
    
    return output;
}

这是像素/片段着色器 HLSL 代码:

struct PSInput
{
    float4 Position : SV_Position;
    [[vk::location(0)]] float4 Color : COLOR0;
    [[vk::location(1)]] float2 UVcoord : TEXCOORD0;
};

// Descriptor loading in HLSL
//Texture2D tex2D : register(t0); // TODO: Figure out texture loading and sampling in HLSL
//sampler sample2D : register(s0, space1); // texture sampler at (binding = 0, set = 1)

struct PSOutput
{
    [[vk::location(0)]] float4 Color : COLOR0;
};

PSOutput main(PSInput input) : SV_TARGET
{
    PSOutput output = (PSOutput) 0;
    //output.Color = tex2D.Sample(sample2D, input.UVcoord); //TODO: figure out the right syntax for this
    output.Color = input.Color;
    return output;
}

最后是我的着色器结构:

struct Shader {
    Shader(const std::string& filename, VkShaderStageFlagBits shaderStage) {
        try {
            auto shaderCode = readFile(".\\shaders\\" + filename);
            createShaderModule(shaderCode, filename);
        }
        catch (const std::exception& e) {
                std::cerr << e.what() << std::endl;
            }
        stageInfo.stage = shaderStage;
        stageInfo.module = shaderModule;
        stageInfo.pName = "main";
    }
    ~Shader() {
        vkDestroyShaderModule(GPU::device, shaderModule, nullptr);
    }
public:
    VkShaderModule shaderModule;
    VkPipelineShaderStageCreateInfo stageInfo
    { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
private:
    void createShaderModule(const std::vector<char>& code, std::string filename) {
        VkShaderModuleCreateInfo createInfo
        { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
        createInfo.codeSize = code.size();// also tried code.size()*sizeof(uint32_t) and code.size()*4
        createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());

        if (vkCreateShaderModule(GPU::device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) {
            throw std::runtime_error("failed to create shader module from " + filename + "!");
        }
    }
    // File Reader
    static std::vector<char> readFile(const std::string& filename) {
        std::ifstream file(filename, std::ios::ate | std::ios::binary);

        if (!file.is_open()) {
            throw std::runtime_error(std::format("failed to open {}!", filename));
        }

        size_t fileSize = (size_t)file.tellg();
        std::vector<char> buffer(fileSize);

        file.seekg(0);
        file.read(buffer.data(), fileSize);

        file.close();

        return buffer;
    }
};

着色器是通过以下方式创建的:

Shader vertShader("vertex_vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
Shader fragShader("pixel_frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);

我知道我的像素/片段着色器会有一些问题,因为我还没有在 C++ 方面进行纹理加载,但即使没有像素着色器,顶点着色器仍然会产生验证错误。我该如何解决这个问题?

编辑:更改了包含着色器模块功能的部分,以显示着色器加载背后的所有代码,其中大部分来自Vulkan-Tutorial指南。

编辑2: 我不确定运行调试器后要查看哪个变量,但以下是我认为感兴趣的一些变量:

当使用

code.size() * uint32_t
运行时,
createInfo.pCode
的值为
0x000001c2da20ff60
119734787
code
的值为

\x3\x2#\a\0\0\x1\0\0\0\xe\0*\0\0\0\0\0\0\0\x11\0\x2\0\x1\0\0\0\xe\0\x3\0\0\0\0\0\x1\0\0\0\xf\0\v\0\0\0\0\0\x1\0\0\0main\0\0\0\0\x2\0\0\0\x3\0\0\0\x4\0\0\0\x5\0\0\0\x6\0\0\0\a\0\0\0\x3\0\x3\0\x5\0\0\0€\x2\0\0\x5\0\x5\0\b\0\0\0type.ubo\0\0\0\0\x6\0\x4\0\b\0\0\0\0\0\0\0ubo\0\x5\0\x3\0\t\0\0\0UBO\0\x6\0\x4\0\t\0\0\0\0\0\0\0dt\0\0\x6\0\x5\0\t\0\0\0\x1\0\0\0model\0\0\0\x6\0\x4\0\t\0\0\0\x2\0\0\0cam\0\x5\0\x4\0...

当使用

code.size()
运行时,
createInfo.pCode
的值为
0x00000196624fff60
119734787
code
的值为

\x3\x2#\a\0\0\x1\0\0\0\xe\0*\0\0\0\0\0\0\0\x11\0\x2\0\x1\0\0\0\xe\0\x3\0\0\0\0\0\x1\0\0\0\xf\0\v\0\0\0\0\0\x1\0\0\0main\0\0\0\0\x2\0\0\0\x3\0\0\0\x4\0\0\0\x5\0\0\0\x6\0\0\0\a\0\0\0\x3\0\x3\0\x5\0\0\0€\x2\0\0\x5\0\x5\0\b\0\0\0type.ubo\0\0\0\0\x6\0\x4\0\b\0\0\0\0\0\0\0ubo\0\x5\0\x3\0\t\0\0\0UBO\0\x6\0\x4\0\t\0\0\0\0\0\0\0dt\0\0\x6\0\x5\0\t\0\0\0\x1\0\0\0model\0\0\0\x6\0\x4\0\t\0\0\0\x2\0\0\0cam\0\x5\0\x4\0...
c++ vulkan hlsl spir-v dxc
1个回答
0
投票

这里的实际问题是您的 Visual Studio 项目正在使用“HLSL 编译器”设置来编译着色器。 GitHub 中的

*.spv
文件没问题(我在长评论中错了)。当您构建解决方案时,Visual Studio 将调用 MSFT 编译器,该编译器可能不了解spirv。构建解决方案会导致
*.spv
文件被不正确的内容覆盖。

我认为解决此问题的最佳方法是不要在项目属性中使用“HLSL 编译器”构建步骤,因为这不是 DX 应用程序。而是使用自定义构建步骤从 Vulkan SDK 调用

dxc
编译器。

© www.soinside.com 2019 - 2024. All rights reserved.