2

我目前正在通过关注这个网站来学习 Vulkan 。我目前正处于需要将我的 GLSL 着色器编译为 SPIR-V 的地步。与仅为着色器创建单独的编译脚本(例如使用 bash)的网站不同,我想在我的代码中完全使用 Cmake。

因为网站推荐的 SPIR-V/GLSL 编译器 glslc 安装在我的系统路径上(稍后我会担心可移植性。),我决定add_custom_command在一个 cmake 函数中使用 Cmake,它充当包装器以添加着色器要编译。

但是,当我尝试这样做时,就好像我根本没有对 Cmake 代码进行任何更改。.spv在我的树外构建文件夹或我的源文件夹中都没有生成文件。当我VERBOSE=1 make使用 C++ 源代码在我的真实项目上运行时,我会看到 C++ 编译器的命令,但看不到任何glslc命令。

我认为罪魁祸首可能是 Cmake 函数的某种作用域,我通过复制和粘贴函数的源代码然后手动替换其参数的值,将其中一个着色器调用移到任何函数调用之外。两种样式都显示在下面的 MCVE 中。

除了add_custom_commandCmake 有一个add_custom_target功能,但Cmake 的文档说如下:

[add_custom_target] 添加具有给定名称的目标以执行给定命令。目标没有输出文件,即使命令尝试使用目标的名称创建文件,它也始终被认为是过时的。使用 add_custom_command() 命令生成具有依赖关系的文件。默认情况下,没有任何东西取决于自定义目标。这不是我想要的,因为我不希望每次运行 Cmake 时都构建我的着色器,而是仅当自上次构建以来已更改 glsl 文件时,作为链接的 C++ 应用程序的依赖项,因为这就是他们是,我希望克莱恩认识到这一点。

这是一个 MCVE:

目录结构:

$ tree
.
├── CMakeLists.txt
├── CMakeLists.txt~
├── fragmentshader.glsl
└── vertexshader.glsl

在 Linux 上重现该问题的命令:

cd /path/to/folder/with/these/files
mkdir cmake-build-test
cd cmake-build-test
cmake ..
make

CMakeLists.txt:

    cmake_minimum_required(VERSION 3.14)
    project(vulkan_cmake)

    function(add_spirv_shader SHADER_STAGE INPUT_FILE OUTPUT_FILE)
        add_custom_command(
                OUTPUT ${OUTPUT_FILE}
                COMMAND "glslc -fshader-stage=${SHADER_STAGE} ${INPUT_FILE} -o ${OUTPUT_FILE}" #glslc is on the system path on my computer, so I am not currently worried about `find_package`ing it.
                MAIN_DEPENDENCY ${INPUT_FILE}
                WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
        )
    endfunction()

    add_spirv_shader(vector vertexshader.glsl vertexshader.hpv)

    add_custom_command(
            OUTPUT fragment.spv
            COMMAND "glslc -fshader-stage=fragment fragmentshader.glsl -o fragment.spv" #glslc is on the system path on my computer, so I am not currently worried about `find_package`ing it.
            MAIN_DEPENDENCY fragmentshader.glsl
            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
    )

碎片着色器.glsl:

    #version 450
    #extension GL_ARB_separate_shader_objects : enable

    layout (location = 0) out vec4 outColor;

    void main(){
        outColor = vec4(1.0, 0.0, 0.0, 1.0);
    }

顶点着色器.glsl:

    #version 450
    #extension GL_ARB_separate_shader_objects : enable

    vec2 positions[3] = vec2[](
        vec2(0.0, -0.5),
        vec2(-0.5, 0.5),
        vec2(0.5, 0.5)
    );

    void main(){
        gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
    }
4

1 回答 1

2

我是这样做的:

[...]

find_package(Vulkan REQUIRED COMPONENTS glslc)
find_program(glslc_executable NAMES glslc HINTS Vulkan::glslc)

#==============================================================================
# COMPILE SHADERS
#

set(SHADER_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/shaders)
set(SHADER_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/shaders)

file(GLOB SHADERS
  ${SHADER_SOURCE_DIR}/*.vert
  ${SHADER_SOURCE_DIR}/*.frag
  ${SHADER_SOURCE_DIR}/*.comp
  ${SHADER_SOURCE_DIR}/*.geom
  ${SHADER_SOURCE_DIR}/*.tesc
  ${SHADER_SOURCE_DIR}/*.tese
  ${SHADER_SOURCE_DIR}/*.mesh
  ${SHADER_SOURCE_DIR}/*.task
  ${SHADER_SOURCE_DIR}/*.rgen
  ${SHADER_SOURCE_DIR}/*.rchit
  ${SHADER_SOURCE_DIR}/*.rmiss)

add_custom_command(
  COMMAND
    ${CMAKE_COMMAND} -E make_directory ${SHADER_BINARY_DIR}
  OUTPUT ${SHADER_BINARY_DIR}
  COMMENT "Creating ${SHADER_BINARY_DIR}"
)

foreach(source IN LISTS SHADERS)
  get_filename_component(FILENAME ${source} NAME)
  add_custom_command(
    COMMAND
      ${glslc_executable}
      #      -MD -MF ${SHADER_BINARY_DIR}/${FILENAME}.d
      -o ${SHADER_BINARY_DIR}/${FILENAME}.spv
      ${source}
    OUTPUT ${SHADER_BINARY_DIR}/${FILENAME}.spv
    DEPENDS ${source} ${SHADER_BINARY_DIR}
    COMMENT "Compiling ${FILENAME}"
  )
  list(APPEND SPV_SHADERS ${SHADER_BINARY_DIR}/${FILENAME}.spv)
endforeach()

add_custom_target(shaders ALL DEPENDS ${SPV_SHADERS})

请注意,我注释掉了,-MD -MF因为它似乎不需要(在我的 linux 机器上)。

有关完整(和最新)版本,请参阅我在 github 上的项目

于 2021-07-20T15:20:35.777 回答