-
Notifications
You must be signed in to change notification settings - Fork 2
/
CMakeLists.txt
182 lines (151 loc) · 8.61 KB
/
CMakeLists.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
cmake_minimum_required(VERSION 3.27)
project(vk_gltf_viewer)
option(ENABLE_NV_AFTERMATH "Enables NV Aftermath functionality" OFF)
set(SHADER_INCLUDE_DIRS "") # So that the submodule script can update the variable
include(cmake/add_source_directory.cmake)
add_subdirectory(submodules)
add_executable(vk_gltf_viewer EXCLUDE_FROM_ALL)
target_compile_features(vk_gltf_viewer PUBLIC cxx_std_23)
target_link_libraries(vk_gltf_viewer PRIVATE fastgltf wuffs dds_image ktx_read::ktx_read meshoptimizer)
target_link_libraries(vk_gltf_viewer PRIVATE glfw::glfw imgui::imgui enkiTS::enkiTS Tracy::Client fmt::fmt glm::glm)
target_link_libraries(vk_gltf_viewer PRIVATE Vulkan::Headers Vulkan::Utils volk::volk_headers vk-bootstrap::vk-bootstrap Vulkan::MemoryAllocator)
if (ENABLE_NV_AFTERMATH AND TARGET nv::aftermath)
message(STATUS "vk_gltf_viewer: Enabling use of NV Aftermath")
target_link_libraries(vk_gltf_viewer PRIVATE nv::aftermath)
target_compile_definitions(vk_gltf_viewer PRIVATE "VKV_NV_AFTERMATH=1")
endif()
if(TARGET nv::dlss)
target_link_libraries(vk_gltf_viewer PRIVATE nv::dlss)
target_compile_definitions(vk_gltf_viewer PRIVATE "VKV_NV_DLSS=1")
endif()
add_source_directory(TARGET vk_gltf_viewer FOLDER "src/imgui")
add_source_directory(TARGET vk_gltf_viewer FOLDER "src/nvidia")
add_source_directory(TARGET vk_gltf_viewer FOLDER "src/vk_gltf_viewer")
add_source_directory(TARGET vk_gltf_viewer FOLDER "src/vulkan")
add_source_directory(TARGET vk_gltf_viewer FOLDER "src")
add_source_directory(TARGET vk_gltf_viewer FOLDER "include/imgui")
add_source_directory(TARGET vk_gltf_viewer FOLDER "include/nvidia")
add_source_directory(TARGET vk_gltf_viewer FOLDER "include/vk_gltf_viewer")
add_source_directory(TARGET vk_gltf_viewer FOLDER "include/vulkan")
add_source_directory(TARGET vk_gltf_viewer FOLDER "include")
target_include_directories(vk_gltf_viewer PRIVATE "include")
# Set compile flags. We target AVX2 as a minimum
fastgltf_compiler_flags(vk_gltf_viewer)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)")
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_compile_options(vk_gltf_viewer PRIVATE "-mavx2")
elseif(MSVC)
target_compile_options(vk_gltf_viewer PRIVATE "/arch:AVX")
endif()
endif()
# Add the shaders directory as an include directory
target_include_directories(vk_gltf_viewer PRIVATE "shaders")
file (GLOB_RECURSE SHADER_HEADER_FILES "shaders/*.h" "shaders/**/*.h")
foreach(HEADER_FILE ${SHADER_HEADER_FILES})
target_sources(vk_gltf_viewer PUBLIC ${HEADER_FILE})
endforeach()
# Try and search for glslangValidator, which we use to compile shaders
find_program(GLSLANG_EXECUTABLE glslangValidator)
if (NOT GLSLANG_EXECUTABLE)
message(FATAL_ERROR "Failed to find glslangValidator executable required for compiling shaders")
endif()
message(STATUS "vk_gltf_viewer: Found glslangValidator: ${GLSLANG_EXECUTABLE}")
list(APPEND SHADER_INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}/shaders")
# Get a list of all GLSL shaders in the shaders directory and generate CMake targets for them
# This piece of code is largely copied/refactored from my shader_processor project.
# https://github.com/spnda/shader_processor/blob/a4a2fe2a60549b245503c4c9f6c2a4dfff19eb44/CMakeLists.txt#L9-L71
file(GLOB_RECURSE SHADER_FILES "shaders/*.glsl" "shaders/**/*.glsl")
set(SHADER_C_NAMES "") # List holding all compiled shader names
foreach(SHADER_FILE ${SHADER_FILES})
cmake_path(GET SHADER_FILE FILENAME SHADER_FILENAME)
# Rudimentary parsing to detect if this file is a header or not
string(FIND ${SHADER_FILENAME} "." FILE_EXTENSION_BEGIN)
string(FIND ${SHADER_FILENAME} "." FILE_EXTENSION_END REVERSE)
math(EXPR FILE_EXTENSION_LENGTH "${FILE_EXTENSION_END}-${FILE_EXTENSION_BEGIN}")
string(SUBSTRING ${SHADER_FILENAME} ${FILE_EXTENSION_BEGIN} ${FILE_EXTENSION_LENGTH} EXTENSION_TYPE)
if (${EXTENSION_TYPE} STREQUAL ".h")
continue()
endif()
message(STATUS "vk_gltf_viewer: Found shader: ${SHADER_FILE}")
string(SHA1 PATH_HASH ${SHADER_FILE})
set(SHADER_TIMESTAMP_NAME "shaders/${PATH_HASH}.timestamp")
cmake_path(GET SHADER_FILE PARENT_PATH SHADER_FOLDER)
# Match glslang's behaviour by first searching the shader's directory, and then
# searching the root shaders directory and other include directories.
set(LOCAL_INCLUDE_DIRS "${SHADER_FOLDER};${SHADER_INCLUDE_DIRS}")
# Recursively parses file includes
function(parse_includes RETURN_LIST CONTENTS)
foreach(LINE IN LISTS ${CONTENTS})
if (LINE MATCHES "^#include ")
string(LENGTH ${LINE} LINE_LENGTH)
math(EXPR LINE_LENGTH "${LINE_LENGTH}-10-1") # Remove #include and the last "
string(SUBSTRING ${LINE} 10 ${LINE_LENGTH} INCLUDED_FILE)
string(SUBSTRING ${LINE} 9 1 INCLUDE_CHAR)
# We'll ignore files which are included with <> instead of "".
# We consider these to be C++ header includes wrapped in defined(__cplusplus) guards.
string(SUBSTRING ${LINE} 9 1 INCLUDE_CHAR)
if (${INCLUDE_CHAR} STREQUAL "<")
continue()
endif()
# Search for the shader in the include directories (note that these are ordered).
foreach(INCL_DIR IN LISTS LOCAL_INCLUDE_DIRS)
set(INCLUDED_FILE_ABS ${INCL_DIR}/${INCLUDED_FILE})
if(EXISTS ${INCLUDED_FILE_ABS})
list(APPEND ${RETURN_LIST} ${INCLUDED_FILE_ABS})
# Load the included file, and parse it recursively
file(STRINGS ${INCLUDED_FILE_ABS} INCLUDED_FILE_CONTENTS)
parse_includes(${RETURN_LIST} INCLUDED_FILE_CONTENTS)
set(SHADER_FOUND TRUE)
endif()
endforeach()
if (NOT ${SHADER_FOUND})
message(STATUS "Failed to find included file: ${INCLUDED_FILE}")
endif()
set(SHADER_FOUND "")
endif()
endforeach()
return(PROPAGATE ${RETURN_LIST})
endfunction()
# Read the file and parse includes recursively
file(STRINGS ${SHADER_FILE} FILE_CONTENTS)
set(FILE_INCLUDES "")
parse_includes(FILE_INCLUDES FILE_CONTENTS)
list(REMOVE_DUPLICATES FILE_INCLUDES)
# Add a custom command to compile the shader
set(COMPILED_SHADER_FILE "shaders/${PATH_HASH}.spirv")
add_custom_command(
OUTPUT ${SHADER_TIMESTAMP_NAME} ${COMPILED_SHADER_FILE}
COMMAND ${GLSLANG_EXECUTABLE} $<$<CONFIG:DEBUG>:-g> --target-env vulkan1.3 "-I$<JOIN:${LOCAL_INCLUDE_DIRS},;-I>" -o ${COMPILED_SHADER_FILE} ${SHADER_FILE}
COMMAND ${CMAKE_COMMAND} -E copy ${COMPILED_SHADER_FILE} shaders/${SHADER_FILENAME}.spirv
COMMAND ${CMAKE_COMMAND} -E touch ${SHADER_TIMESTAMP_NAME}
DEPENDS ${SHADER_FILE} ${FILE_INCLUDES}
COMMAND_EXPAND_LISTS
COMMENT "Processing ${SHADER_FILE}"
)
# Add a custom command that copies the generated SPIR-V into a .cpp file
set(SPIRV_CPP_FILE "shaders/${PATH_HASH}.cpp")
string(MAKE_C_IDENTIFIER ${SHADER_FILENAME} SHADER_FILENAME_C)
add_custom_command(
OUTPUT ${SPIRV_CPP_FILE}
COMMAND ${CMAKE_COMMAND} -DPROCESSED_FILE_NAME=${SHADER_FILENAME_C} -DINPUT_FILE=${COMPILED_SHADER_FILE} -DOUTPUT_FILE=${SPIRV_CPP_FILE} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/configure_spirv.cmake
DEPENDS ${SHADER_TIMESTAMP_NAME} ${COMPILED_SHADER_FILE}
COMMENT "Packaging ${SHADER_FILE}"
)
list(APPEND SHADER_C_NAMES ${SHADER_FILENAME_C})
# Finally, add the generated source file as a target source
target_sources(vk_gltf_viewer PRIVATE ${SPIRV_CPP_FILE})
endforeach()
# Create a single header acting as a shader manifest which holds references to all shader data
# This effectively creates a list of "extern std::span" for each shader, which are all defined in
# their respective cpp files, as generated above.
set(SHADER_DATA_SPANS "")
foreach(SHADER_NAME IN LISTS SHADER_C_NAMES)
list(APPEND SHADER_DATA_SPANS "\nextern const std::span<const std::uint32_t> ${SHADER_NAME}")
endforeach()
configure_file("${CMAKE_CURRENT_LIST_DIR}/cmake/spirv_manifest.hpp.in" "${CMAKE_CURRENT_BINARY_DIR}/include/spirv_manifest.hpp")
target_include_directories(vk_gltf_viewer PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/include)
# Copy all required runtime DLLs into the build directory
add_custom_command(TARGET vk_gltf_viewer POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy -t $<TARGET_FILE_DIR:vk_gltf_viewer> $<TARGET_RUNTIME_DLLS:vk_gltf_viewer>
COMMAND_EXPAND_LISTS
)