456 lines
15 KiB
CMake
456 lines
15 KiB
CMake
cmake_minimum_required(VERSION 3.25) # Debian 12 ships 3.25
|
|
project(VulkanEngine)
|
|
|
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
|
|
|
|
include(BuildInfo)
|
|
include(FetchContent)
|
|
# LTO
|
|
include(CheckIPOSupported)
|
|
check_ipo_supported(RESULT LTO_SUPPORTED OUTPUT LTO_ERROR)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Build modes
|
|
# (default) Nix dev build, deps from the Nix shell
|
|
# FETCH_DEPS + PORTABLE Single directory, everything static except
|
|
# glibc (and the Vulkan loader, loaded via volk)
|
|
# FETCH_DEPS + BUNDLE bin/ + lib/, project libs shared in lib/,
|
|
# system libstdc++ / libc / loader are used
|
|
# ---------------------------------------------------------------------------
|
|
option(VULKANENGINE_PORTABLE
|
|
"Build a Linux binary without Nix-specific runtime paths (static libs)"
|
|
OFF
|
|
)
|
|
|
|
option(VULKANENGINE_BUNDLE
|
|
"Build a Linux bundle using libraries from the bundle directory"
|
|
OFF
|
|
)
|
|
|
|
option(VULKANENGINE_FETCH_DEPS
|
|
"Fetch dependencies with FetchContent instead of using system/Nix packages"
|
|
OFF
|
|
)
|
|
|
|
set(VULKANENGINE_PREBUILT_SHADERS "" CACHE PATH
|
|
"Directory containing precompiled .spv files (skips glslang/slangc)"
|
|
)
|
|
|
|
if(VULKANENGINE_PORTABLE AND VULKANENGINE_BUNDLE)
|
|
message(FATAL_ERROR "VULKANENGINE_PORTABLE and VULKANENGINE_BUNDLE are mutually exclusive")
|
|
endif()
|
|
|
|
if((VULKANENGINE_PORTABLE OR VULKANENGINE_BUNDLE) AND NOT VULKANENGINE_FETCH_DEPS)
|
|
message(FATAL_ERROR
|
|
"PORTABLE/BUNDLE builds need -DVULKANENGINE_FETCH_DEPS=ON "
|
|
"(Nix libraries must not leak into the result)")
|
|
endif()
|
|
|
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|
|
|
# RPATH / runtime paths
|
|
if(VULKANENGINE_PORTABLE)
|
|
message(STATUS "VulkanEngine: PORTABLE build")
|
|
|
|
set(CMAKE_SKIP_RPATH TRUE)
|
|
|
|
elseif(VULKANENGINE_BUNDLE)
|
|
message(STATUS "VulkanEngine: BUNDLE build")
|
|
|
|
set(CMAKE_SKIP_BUILD_RPATH FALSE)
|
|
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
|
|
|
|
# Executables are installed in bin/
|
|
# Libraries are installed in lib/
|
|
set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")
|
|
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
|
|
|
|
# Every shared lib we build ends up here, installed as-is into lib/
|
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
|
|
|
|
else()
|
|
message(STATUS "VulkanEngine: normal build")
|
|
endif()
|
|
|
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|
find_program(GCC_AR NAMES gcc-ar REQUIRED)
|
|
find_program(GCC_RANLIB NAMES gcc-ranlib REQUIRED)
|
|
set(CMAKE_AR "${GCC_AR}")
|
|
set(CMAKE_RANLIB "${GCC_RANLIB}")
|
|
endif()
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Dependencies
|
|
# ---------------------------------------------------------------------------
|
|
set(ENGINE_EXTRA_DEFINITIONS "")
|
|
|
|
if(VULKANENGINE_FETCH_DEPS)
|
|
# Portable = static libs, bundle = shared libs (in lib/)
|
|
if(VULKANENGINE_BUNDLE)
|
|
set(BUILD_SHARED_LIBS ON)
|
|
else()
|
|
set(BUILD_SHARED_LIBS OFF)
|
|
endif()
|
|
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
|
|
|
set(VULKAN_HEADERS_ENABLE_MODULE OFF CACHE BOOL "" FORCE)
|
|
set(VULKAN_HEADERS_ENABLE_TESTS OFF CACHE BOOL "" FORCE)
|
|
set(VULKAN_HEADERS_ENABLE_INSTALL OFF CACHE BOOL "" FORCE)
|
|
set(VOLK_PULL_IN_VULKAN OFF CACHE BOOL "" FORCE)
|
|
set(VOLK_INSTALL OFF CACHE BOOL "" FORCE)
|
|
set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
|
|
set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
|
set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)
|
|
set(GLFW_INSTALL OFF CACHE BOOL "" FORCE)
|
|
set(FMT_INSTALL OFF CACHE BOOL "" FORCE)
|
|
set(FMT_TEST OFF CACHE BOOL "" FORCE)
|
|
set(SIMDJSON_DEVELOPER_MODE OFF CACHE BOOL "" FORCE)
|
|
set(CLI11_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
|
set(CLI11_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
|
|
set(GLM_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
|
set(GLM_BUILD_LIBRARY OFF CACHE BOOL "" FORCE)
|
|
|
|
# Keep these versions in sync with your nixpkgs (check the tags exist)
|
|
FetchContent_Declare(VulkanHeaders
|
|
GIT_REPOSITORY https://github.com/KhronosGroup/Vulkan-Headers.git
|
|
GIT_TAG v1.4.309)
|
|
FetchContent_Declare(volk
|
|
GIT_REPOSITORY https://github.com/zeux/volk.git
|
|
GIT_TAG 1.4.304)
|
|
FetchContent_Declare(VMA
|
|
GIT_REPOSITORY https://github.com/GPUOpen-LibrariesAndPatches/VulkanMemoryAllocator.git
|
|
GIT_TAG v3.2.1)
|
|
FetchContent_Declare(glfw
|
|
GIT_REPOSITORY https://github.com/glfw/glfw.git
|
|
GIT_TAG 3.4)
|
|
FetchContent_Declare(vk-bootstrap
|
|
GIT_REPOSITORY https://github.com/charles-lunarg/vk-bootstrap.git
|
|
GIT_TAG v1.4.309)
|
|
FetchContent_Declare(fmt
|
|
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
|
|
GIT_TAG 11.0.2)
|
|
FetchContent_Declare(CLI11
|
|
GIT_REPOSITORY https://github.com/CLIUtils/CLI11.git
|
|
GIT_TAG v2.4.2)
|
|
FetchContent_Declare(glm
|
|
GIT_REPOSITORY https://github.com/g-truc/glm.git
|
|
GIT_TAG 1.0.1)
|
|
FetchContent_Declare(simdjson
|
|
GIT_REPOSITORY https://github.com/simdjson/simdjson.git
|
|
GIT_TAG v3.10.1)
|
|
|
|
# Vulkan headers first: vk-bootstrap and volk pick up Vulkan::Headers
|
|
FetchContent_MakeAvailable(VulkanHeaders)
|
|
FetchContent_MakeAvailable(volk VMA glfw vk-bootstrap fmt CLI11 glm simdjson)
|
|
|
|
target_link_libraries(volk PUBLIC Vulkan::Headers)
|
|
|
|
# No link-time dependency on libvulkan: functions come from volk
|
|
list(APPEND ENGINE_EXTRA_DEFINITIONS
|
|
VK_NO_PROTOTYPES
|
|
VMA_STATIC_VULKAN_FUNCTIONS=0
|
|
VMA_DYNAMIC_VULKAN_FUNCTIONS=1
|
|
)
|
|
else()
|
|
# Nix path (unchanged)
|
|
find_package( glfw3 REQUIRED )
|
|
find_package( glm REQUIRED )
|
|
find_package( VulkanMemoryAllocator CONFIG REQUIRED )
|
|
find_package( CLI11 REQUIRED )
|
|
find_package( simdjson REQUIRED )
|
|
endif()
|
|
|
|
# fastgltf because it's not in nixpkgs (declared after the switch above so it
|
|
# inherits BUILD_SHARED_LIBS)
|
|
FetchContent_Declare(
|
|
fastgltf
|
|
GIT_REPOSITORY https://github.com/spnda/fastgltf.git
|
|
GIT_TAG v0.8.0
|
|
)
|
|
FetchContent_MakeAvailable(fastgltf)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Shader compilers (not needed when precompiled shaders are provided)
|
|
# ---------------------------------------------------------------------------
|
|
if(NOT VULKANENGINE_PREBUILT_SHADERS)
|
|
add_executable (glslang::validator IMPORTED)
|
|
find_program (
|
|
GLSLANG_VALIDATOR
|
|
"glslangValidator"
|
|
HINTS $ENV{VULKAN_SDK}/bin
|
|
REQUIRED
|
|
)
|
|
|
|
set_property (
|
|
TARGET glslang::validator
|
|
PROPERTY IMPORTED_LOCATION "${GLSLANG_VALIDATOR}"
|
|
)
|
|
|
|
find_program(SLANGC_EXECUTABLE slangc HINTS $ENV{VULKAN_SDK}/bin REQUIRED)
|
|
endif()
|
|
|
|
|
|
# Helper functions to build shaders
|
|
function(addGlslShader SOURCE OUTPUT_DIR)
|
|
get_filename_component(SHADER_NAME ${SOURCE} NAME_WE)
|
|
set(SPV_FILE "${OUTPUT_DIR}/${SHADER_NAME}.spv")
|
|
add_custom_command(
|
|
OUTPUT ${SPV_FILE}
|
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${OUTPUT_DIR}
|
|
COMMAND glslang::validator
|
|
-V
|
|
--target-env vulkan1.4 # Change if needed
|
|
-o ${SPV_FILE}
|
|
${SOURCE}
|
|
DEPENDS ${SOURCE}
|
|
COMMENT "Compiling GLSL shader: ${SOURCE} -> ${SPV_FILE}"
|
|
VERBATIM
|
|
)
|
|
set(SPV_FILE ${SPV_FILE} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
|
|
function(addSlangShader SOURCES ENTRY_POINTS OUTPUT_DIR)
|
|
set(SPV_FILE "${OUTPUT_DIR}/slang.spv")
|
|
add_custom_command(
|
|
OUTPUT ${SPV_FILE}
|
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${OUTPUT_DIR}
|
|
COMMAND ${SLANGC_EXECUTABLE}
|
|
${SOURCES}
|
|
-target spirv
|
|
-profile spirv_1_6+spvRayQueryKHR # Change if needed
|
|
-emit-spirv-directly
|
|
-fvk-use-entrypoint-name
|
|
${ENTRY_POINTS}
|
|
-o ${SPV_FILE}
|
|
DEPENDS ${SOURCES}
|
|
COMMENT "Compiling Slang shaders -> ${SPV_FILE}"
|
|
VERBATIM
|
|
)
|
|
set(SPV_FILE ${SPV_FILE} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
|
|
# A function to automate executables aditions
|
|
function ( addBinary BINARY_NAME )
|
|
cmake_parse_arguments ( BINARY "IMGUI;LICENSE" "SOURCE" "SHADERS;SLANG_SHADERS;SLANG_ENTRIES;LIBS;TEXTURES;MODELS" ${ARGN} )
|
|
if (DEFINED BINARY_SOURCE)
|
|
add_executable ( ${BINARY_NAME} src/${BINARY_SOURCE}.cpp )
|
|
endif()
|
|
|
|
target_include_directories( ${BINARY_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/src )
|
|
# Sets the output dir to have clear separation between binaries
|
|
set_target_properties (
|
|
${BINARY_NAME}
|
|
PROPERTIES
|
|
RUNTIME_OUTPUT_DIRECTORY
|
|
${CMAKE_BINARY_DIR}/${BINARY_NAME}
|
|
CXX_STANDARD
|
|
20 # C++ 20
|
|
CXX_STANDARD_REQUIRED
|
|
ON
|
|
CXX_EXTENSIONS
|
|
OFF
|
|
CXX_SCAN_FOR_MODULES
|
|
OFF
|
|
)
|
|
# Sets per binary LTO
|
|
if(LTO_SUPPORTED AND CMAKE_BUILD_TYPE STREQUAL "Release")
|
|
set_target_properties(${BINARY_NAME} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
|
|
message("Enabled LTO")
|
|
endif()
|
|
|
|
# Portable: libstdc++/libgcc statically linked so the binary does not depend
|
|
# on the host's version. NOT done for bundle: the shared libs in lib/ use the
|
|
# system libstdc++, and mixing two copies in one process is asking for trouble.
|
|
if(VULKANENGINE_PORTABLE)
|
|
target_link_options(${BINARY_NAME} PRIVATE -static-libstdc++ -static-libgcc)
|
|
endif()
|
|
|
|
# Define VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS to treat VK_ERROR_OUT_OF_DATE_KHR as a success code
|
|
target_compile_definitions (
|
|
${BINARY_NAME}
|
|
PRIVATE
|
|
"VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS"
|
|
$<$<CONFIG:Debug>:DEBUG> # So CMAKE expose a #define DEBUG for debug builds
|
|
# Exposes versions
|
|
BUILD_ID="${ENGINE_VERSION}"
|
|
${ENGINE_EXTRA_DEFINITIONS}
|
|
)
|
|
|
|
if(BINARY_IMGUI)
|
|
target_include_directories(${BINARY_NAME} PRIVATE
|
|
${CMAKE_SOURCE_DIR}/include/imgui
|
|
${CMAKE_SOURCE_DIR}/include/imgui/backends
|
|
)
|
|
|
|
target_sources(${BINARY_NAME} PRIVATE
|
|
${CMAKE_SOURCE_DIR}/include/imgui/imgui.cpp
|
|
|
|
${CMAKE_SOURCE_DIR}/include/imgui/imgui_draw.cpp
|
|
${CMAKE_SOURCE_DIR}/include/imgui/imgui_tables.cpp
|
|
${CMAKE_SOURCE_DIR}/include/imgui/imgui_widgets.cpp
|
|
${CMAKE_SOURCE_DIR}/include/imgui/imgui_demo.cpp
|
|
#${CMAKE_SOURCE_DIR}/include/imgui/imgui_memory_editor.h
|
|
|
|
${CMAKE_SOURCE_DIR}/include/imgui/backends/imgui_impl_glfw.cpp
|
|
${CMAKE_SOURCE_DIR}/include/imgui/backends/imgui_impl_vulkan.cpp
|
|
)
|
|
|
|
# imgui's Vulkan backend must use volk when there is no linked loader
|
|
if(VULKANENGINE_FETCH_DEPS)
|
|
target_compile_definitions(${BINARY_NAME} PRIVATE IMGUI_IMPL_VULKAN_USE_VOLK)
|
|
endif()
|
|
endif()
|
|
|
|
|
|
if(BINARY_LICENSE)
|
|
file(COPY ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION ${CMAKE_BINARY_DIR}/${BINARY_NAME})
|
|
endif()
|
|
|
|
|
|
if(DEFINED BINARY_SHADERS)
|
|
set(SHADER_OUTPUT_DIR ${CMAKE_BINARY_DIR}/${BINARY_NAME}/shaders)
|
|
|
|
if(VULKANENGINE_PREBUILT_SHADERS)
|
|
# Copy the .spv produced by the Nix job instead of compiling them
|
|
file(GLOB PREBUILT_SPV CONFIGURE_DEPENDS "${VULKANENGINE_PREBUILT_SHADERS}/*.spv")
|
|
if(NOT PREBUILT_SPV)
|
|
message(FATAL_ERROR "No .spv found in ${VULKANENGINE_PREBUILT_SHADERS}")
|
|
endif()
|
|
file(COPY ${PREBUILT_SPV} DESTINATION ${SHADER_OUTPUT_DIR})
|
|
else()
|
|
set(ALL_SPV_FILES "")
|
|
set(EXPANDED_SHADERS "")
|
|
|
|
foreach(SHADER_PATTERN ${BINARY_SHADERS})
|
|
if(SHADER_PATTERN MATCHES "[*?]")
|
|
file(GLOB SHADER_FILES CONFIGURE_DEPENDS ${SHADER_PATTERN})
|
|
list(APPEND EXPANDED_SHADERS ${SHADER_FILES})
|
|
else()
|
|
list(APPEND EXPANDED_SHADERS ${SHADER_PATTERN})
|
|
endif()
|
|
endforeach()
|
|
|
|
foreach(SHADER_SRC ${EXPANDED_SHADERS})
|
|
if(NOT IS_ABSOLUTE ${SHADER_SRC})
|
|
set(SHADER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER_SRC})
|
|
endif()
|
|
get_filename_component(EXT ${SHADER_SRC} EXT)
|
|
if(EXT STREQUAL ".slang")
|
|
addSlangShader(${SHADER_SRC} "${BINARY_SLANG_ENTRIES}" ${SHADER_OUTPUT_DIR})
|
|
list(APPEND ALL_SPV_FILES ${SPV_FILE})
|
|
else()
|
|
addGlslShader(${SHADER_SRC} ${SHADER_OUTPUT_DIR})
|
|
list(APPEND ALL_SPV_FILES ${SPV_FILE})
|
|
endif()
|
|
endforeach()
|
|
|
|
add_custom_target(shaders_${BINARY_NAME} DEPENDS ${ALL_SPV_FILES})
|
|
add_dependencies(${BINARY_NAME} shaders_${BINARY_NAME})
|
|
endif()
|
|
endif()
|
|
|
|
if (DEFINED BINARY_LIBS)
|
|
target_link_libraries ( ${BINARY_NAME} PRIVATE ${BINARY_LIBS} )
|
|
endif()
|
|
|
|
if (DEFINED BINARY_MODELS) # Adds the 3D models in the binary folder
|
|
set(RESOLVED_MODELS "")
|
|
foreach(MODEL_PATTERN ${BINARY_MODELS})
|
|
file(GLOB MATCHED_MODELS CONFIGURE_DEPENDS
|
|
"${CMAKE_SOURCE_DIR}/assets/models/${MODEL_PATTERN}"
|
|
)
|
|
list(APPEND RESOLVED_MODELS ${MATCHED_MODELS})
|
|
endforeach()
|
|
|
|
if (RESOLVED_MODELS)
|
|
file(COPY ${RESOLVED_MODELS} DESTINATION ${CMAKE_BINARY_DIR}/${BINARY_NAME}/models)
|
|
endif()
|
|
endif()
|
|
|
|
if (DEFINED BINARY_TEXTURES) # Adds the textures in the binary folder
|
|
set(RESOLVED_TEXTURES "")
|
|
foreach(TEX_PATTERN ${BINARY_TEXTURES})
|
|
file(GLOB MATCHED_TEXTURES CONFIGURE_DEPENDS
|
|
"${CMAKE_SOURCE_DIR}/assets/textures/${TEX_PATTERN}"
|
|
)
|
|
list(APPEND RESOLVED_TEXTURES ${MATCHED_TEXTURES})
|
|
endforeach()
|
|
|
|
if (RESOLVED_TEXTURES)
|
|
file(COPY ${RESOLVED_TEXTURES} DESTINATION ${CMAKE_BINARY_DIR}/${BINARY_NAME}/textures)
|
|
endif()
|
|
endif ()
|
|
endfunction()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Binaries
|
|
# ---------------------------------------------------------------------------
|
|
list(
|
|
APPEND
|
|
lib_list
|
|
# Libs used
|
|
glfw
|
|
fmt
|
|
vk-bootstrap
|
|
CLI11::CLI11
|
|
fastgltf
|
|
)
|
|
|
|
if(VULKANENGINE_FETCH_DEPS)
|
|
# No libvulkan at link time: volk loads libvulkan.so.1 at runtime.
|
|
# Remove what your code does not use (simdjson, glm...).
|
|
list(APPEND lib_list
|
|
volk
|
|
Vulkan::Headers
|
|
GPUOpen::VulkanMemoryAllocator
|
|
glm::glm-header-only
|
|
simdjson::simdjson
|
|
)
|
|
else()
|
|
list(APPEND lib_list vulkan)
|
|
endif()
|
|
|
|
addBinary (
|
|
engine
|
|
SOURCE Engine/main
|
|
# Flags
|
|
IMGUI
|
|
LICENSE
|
|
|
|
SHADERS shaders/*
|
|
MODELS *
|
|
|
|
LIBS ${lib_list}
|
|
)
|
|
|
|
addBinary (
|
|
server
|
|
SOURCE Server/main
|
|
)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Install (used for portable / bundle packaging)
|
|
# dist/bin/{engine,server,shaders,models,textures}
|
|
# dist/lib/*.so* (bundle only)
|
|
# dist/LICENSE
|
|
# Never bundled: libc, libstdc++, libvulkan, GL, X11, Wayland.
|
|
# ---------------------------------------------------------------------------
|
|
install(TARGETS engine server RUNTIME DESTINATION bin)
|
|
install(DIRECTORY ${CMAKE_BINARY_DIR}/engine/shaders DESTINATION bin OPTIONAL)
|
|
install(DIRECTORY ${CMAKE_BINARY_DIR}/engine/models DESTINATION bin OPTIONAL)
|
|
install(DIRECTORY ${CMAKE_BINARY_DIR}/engine/textures DESTINATION bin OPTIONAL)
|
|
install(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION .)
|
|
|
|
if(VULKANENGINE_BUNDLE)
|
|
# Every shared lib built from fetched deps (glfw, fmt, fastgltf and its own
|
|
# simdjson, ...) with its symlinks. libstdc++ etc. are not built here.
|
|
install(DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/
|
|
DESTINATION lib
|
|
USE_SOURCE_PERMISSIONS
|
|
FILES_MATCHING PATTERN "*.so*"
|
|
)
|
|
endif()
|