402 lines
14 KiB
CMake
402 lines
14 KiB
CMake
cmake_minimum_required(VERSION 3.24)
|
|
|
|
project(window_renderer_test VERSION 0.1.0 LANGUAGES C CXX)
|
|
|
|
set(CMAKE_C_STANDARD 11)
|
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
|
set(CMAKE_CXX_STANDARD 17)
|
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
|
|
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
|
set(CMAKE_BUILD_TYPE Debug CACHE STRING "Build type" FORCE)
|
|
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Debug Release RelWithDebInfo MinSizeRel)
|
|
endif()
|
|
|
|
option(WR_FETCH_MISSING_DEPENDENCIES
|
|
"Download and build dependencies (SDL3, Vulkan, Slang) that are not installed" ON)
|
|
option(WR_COMPILE_SHADERS
|
|
"Compile the Slang shader during the build (requires slangc)" ON)
|
|
|
|
include(FetchContent)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# SDL3
|
|
# ---------------------------------------------------------------------------
|
|
find_package(SDL3 3.2 CONFIG QUIET)
|
|
|
|
if(NOT SDL3_FOUND)
|
|
if(NOT WR_FETCH_MISSING_DEPENDENCIES)
|
|
message(FATAL_ERROR
|
|
"SDL3 was not found. Install SDL3, or configure with "
|
|
"-DWR_FETCH_MISSING_DEPENDENCIES=ON.")
|
|
endif()
|
|
|
|
message(STATUS "SDL3 not found; fetching and building it from source")
|
|
|
|
# Build a static SDL3 so the result does not depend on a system SDL3
|
|
# runtime being present when the application is run.
|
|
set(SDL_SHARED OFF CACHE BOOL "Build the SDL3 shared library")
|
|
set(SDL_STATIC ON CACHE BOOL "Build the SDL3 static library")
|
|
set(SDL_TEST_LIBRARY OFF CACHE BOOL "Build the SDL3 test library")
|
|
set(SDL_TESTS OFF CACHE BOOL "Build the SDL3 tests")
|
|
set(SDL_EXAMPLES OFF CACHE BOOL "Build the SDL3 examples")
|
|
set(SDL_INSTALL OFF CACHE BOOL "Enable SDL3 install rules")
|
|
|
|
FetchContent_Declare(SDL3
|
|
GIT_REPOSITORY https://github.com/libsdl-org/SDL.git
|
|
GIT_TAG release-3.4.18
|
|
GIT_SHALLOW TRUE
|
|
)
|
|
FetchContent_MakeAvailable(SDL3)
|
|
endif()
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Vulkan headers
|
|
# ---------------------------------------------------------------------------
|
|
find_package(Vulkan QUIET)
|
|
|
|
if(Vulkan_FOUND AND Vulkan_INCLUDE_DIRS)
|
|
set(WR_VULKAN_INCLUDE_DIRS ${Vulkan_INCLUDE_DIRS})
|
|
else()
|
|
if(NOT WR_FETCH_MISSING_DEPENDENCIES)
|
|
message(FATAL_ERROR
|
|
"Vulkan headers were not found. Install the Vulkan SDK, or configure "
|
|
"with -DWR_FETCH_MISSING_DEPENDENCIES=ON.")
|
|
endif()
|
|
|
|
message(STATUS "Vulkan headers not found; fetching Vulkan-Headers")
|
|
|
|
FetchContent_Declare(vulkan_headers
|
|
GIT_REPOSITORY https://github.com/KhronosGroup/Vulkan-Headers.git
|
|
GIT_TAG vulkan-sdk-1.4.350.0
|
|
GIT_SHALLOW TRUE
|
|
)
|
|
FetchContent_MakeAvailable(vulkan_headers)
|
|
|
|
set(WR_VULKAN_INCLUDE_DIRS ${vulkan_headers_SOURCE_DIR}/include)
|
|
endif()
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# volk (Vulkan meta-loader)
|
|
#
|
|
# volk is not guaranteed to be shipped with Vulkan headers. The project
|
|
# includes <volk/volk.h>, so a fetched volk checkout is placed in a generated
|
|
# include directory with the expected layout.
|
|
# ---------------------------------------------------------------------------
|
|
find_path(WR_VOLK_INCLUDE_DIR
|
|
NAMES volk/volk.h
|
|
HINTS ${WR_VULKAN_INCLUDE_DIRS}
|
|
)
|
|
find_file(WR_VOLK_SOURCE_FILE
|
|
NAMES volk.c
|
|
HINTS ${WR_VULKAN_INCLUDE_DIRS}
|
|
PATH_SUFFIXES volk
|
|
)
|
|
|
|
if(NOT WR_VOLK_INCLUDE_DIR OR NOT WR_VOLK_SOURCE_FILE)
|
|
if(NOT WR_FETCH_MISSING_DEPENDENCIES)
|
|
message(FATAL_ERROR
|
|
"volk was not found in the Vulkan headers. Install volk, or configure "
|
|
"with -DWR_FETCH_MISSING_DEPENDENCIES=ON.")
|
|
endif()
|
|
|
|
message(STATUS "volk not found; fetching it")
|
|
|
|
FetchContent_Declare(volk
|
|
GIT_REPOSITORY https://github.com/zeux/volk.git
|
|
GIT_TAG vulkan-sdk-1.4.350.0
|
|
GIT_SHALLOW TRUE
|
|
SOURCE_SUBDIR _disable_add_subdirectory
|
|
)
|
|
FetchContent_MakeAvailable(volk)
|
|
|
|
set(WR_VOLK_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated/include)
|
|
file(MAKE_DIRECTORY ${WR_VOLK_INCLUDE_DIR}/volk)
|
|
configure_file(
|
|
${volk_SOURCE_DIR}/volk.h
|
|
${WR_VOLK_INCLUDE_DIR}/volk/volk.h
|
|
COPYONLY
|
|
)
|
|
set(WR_VOLK_SOURCE_FILE ${volk_SOURCE_DIR}/volk.c)
|
|
endif()
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Vulkan Memory Allocator (VMA)
|
|
#
|
|
# VMA is not part of the Vulkan headers either. The project includes
|
|
# <vma/vk_mem_alloc.h>, so a fetched copy is placed in the same generated
|
|
# include directory.
|
|
# ---------------------------------------------------------------------------
|
|
find_path(WR_VMA_INCLUDE_DIR
|
|
NAMES vma/vk_mem_alloc.h
|
|
HINTS ${WR_VULKAN_INCLUDE_DIRS}
|
|
)
|
|
|
|
if(NOT WR_VMA_INCLUDE_DIR)
|
|
if(NOT WR_FETCH_MISSING_DEPENDENCIES)
|
|
message(FATAL_ERROR
|
|
"Vulkan Memory Allocator (VMA) was not found. Install VMA, or configure "
|
|
"with -DWR_FETCH_MISSING_DEPENDENCIES=ON.")
|
|
endif()
|
|
|
|
message(STATUS "Vulkan Memory Allocator not found; fetching it")
|
|
|
|
FetchContent_Declare(vma
|
|
GIT_REPOSITORY https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
|
|
GIT_TAG v3.5.0
|
|
GIT_SHALLOW TRUE
|
|
SOURCE_SUBDIR _disable_add_subdirectory
|
|
)
|
|
FetchContent_MakeAvailable(vma)
|
|
|
|
set(WR_VMA_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated/include)
|
|
file(MAKE_DIRECTORY ${WR_VMA_INCLUDE_DIR}/vma)
|
|
configure_file(
|
|
${vma_SOURCE_DIR}/include/vk_mem_alloc.h
|
|
${WR_VMA_INCLUDE_DIR}/vma/vk_mem_alloc.h
|
|
COPYONLY
|
|
)
|
|
endif()
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Application
|
|
# ---------------------------------------------------------------------------
|
|
add_executable(main
|
|
src/main.c
|
|
src/wapp/wapp.c
|
|
src/config/config_src.c
|
|
src/window/window_src.c
|
|
src/gpu/gpu_c_src.c
|
|
src/gpu/gpu_cc_src.cpp
|
|
${WR_VOLK_SOURCE_FILE}
|
|
)
|
|
|
|
target_include_directories(main PRIVATE
|
|
${CMAKE_CURRENT_SOURCE_DIR}/src
|
|
${WR_VULKAN_INCLUDE_DIRS}
|
|
${WR_VOLK_INCLUDE_DIR}
|
|
${WR_VMA_INCLUDE_DIR}
|
|
)
|
|
|
|
target_compile_definitions(main PRIVATE
|
|
WP_DEBUG_ASSERT
|
|
CGLM_DEFINE_PRINTS
|
|
USE_SDL_WINDOW_BACKEND
|
|
USE_VULKAN_RENDER_BACKEND
|
|
VK_NO_PROTOTYPES
|
|
)
|
|
|
|
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
|
target_compile_options(main PRIVATE
|
|
$<$<COMPILE_LANGUAGE:CXX>:-Wno-nullability-completeness>
|
|
)
|
|
endif()
|
|
|
|
target_link_libraries(main PRIVATE
|
|
SDL3::SDL3
|
|
${CMAKE_DL_LIBS}
|
|
)
|
|
|
|
if(UNIX AND NOT APPLE)
|
|
target_link_libraries(main PRIVATE m)
|
|
endif()
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Shaders
|
|
#
|
|
# The application loads "shaders/shader.spv" relative to its working directory,
|
|
# so the SPIR-V output is placed in <build-dir>/shaders.
|
|
# ---------------------------------------------------------------------------
|
|
if(WR_COMPILE_SHADERS)
|
|
find_program(SLANGC_EXECUTABLE NAMES slangc)
|
|
|
|
if(NOT SLANGC_EXECUTABLE AND WR_FETCH_MISSING_DEPENDENCIES)
|
|
# Download the prebuilt Slang release instead of requiring the user to
|
|
# install the compiler. Asset names and hashes come from the pinned
|
|
# GitHub release below.
|
|
set(WR_SLANG_VERSION "2026.20")
|
|
|
|
string(TOLOWER "${CMAKE_HOST_SYSTEM_PROCESSOR}" WR_SLANG_ARCH)
|
|
if(WR_SLANG_ARCH MATCHES "^(x86_64|amd64|x64)$")
|
|
set(WR_SLANG_ARCH "x86_64")
|
|
elseif(WR_SLANG_ARCH MATCHES "^(aarch64|arm64|arm64e)$")
|
|
set(WR_SLANG_ARCH "aarch64")
|
|
else()
|
|
set(WR_SLANG_ARCH "")
|
|
endif()
|
|
|
|
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
|
|
set(WR_SLANG_OS "linux")
|
|
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
|
|
set(WR_SLANG_OS "macos")
|
|
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
|
|
set(WR_SLANG_OS "windows")
|
|
else()
|
|
set(WR_SLANG_OS "")
|
|
endif()
|
|
|
|
if(WR_SLANG_OS AND WR_SLANG_ARCH)
|
|
set(WR_SLANG_PLATFORM "${WR_SLANG_OS}-${WR_SLANG_ARCH}")
|
|
else()
|
|
set(WR_SLANG_PLATFORM "")
|
|
endif()
|
|
|
|
if(WR_SLANG_PLATFORM STREQUAL "linux-x86_64")
|
|
set(WR_SLANG_ASSET
|
|
"slang-${WR_SLANG_VERSION}-linux-x86_64-glibc-2.28.tar.gz")
|
|
set(WR_SLANG_SHA256
|
|
"84ebd777968caceea26b21bfd014341078be6047be6c5a963a69f984f896cebd")
|
|
elseif(WR_SLANG_PLATFORM STREQUAL "linux-aarch64")
|
|
set(WR_SLANG_ASSET
|
|
"slang-${WR_SLANG_VERSION}-linux-aarch64-glibc-2.28.tar.gz")
|
|
set(WR_SLANG_SHA256
|
|
"9959d741713162efdbd863ff6d32400432b6e103eae3a9ee0afbdba6a00c6a9e")
|
|
elseif(WR_SLANG_PLATFORM STREQUAL "macos-x86_64")
|
|
set(WR_SLANG_ASSET
|
|
"slang-${WR_SLANG_VERSION}-macos-x86_64.tar.gz")
|
|
set(WR_SLANG_SHA256
|
|
"b4f01f615dc625f60c593d7d0a4bbd38e05dfa2a34bfd3973017c309d866feaa")
|
|
elseif(WR_SLANG_PLATFORM STREQUAL "macos-aarch64")
|
|
set(WR_SLANG_ASSET
|
|
"slang-${WR_SLANG_VERSION}-macos-aarch64.tar.gz")
|
|
set(WR_SLANG_SHA256
|
|
"07fa8833fdbb343c3674c84fdd885910f495f3daaaa0c732b32980151e8b58c4")
|
|
elseif(WR_SLANG_PLATFORM STREQUAL "windows-x86_64")
|
|
set(WR_SLANG_ASSET
|
|
"slang-${WR_SLANG_VERSION}-windows-x86_64.zip")
|
|
set(WR_SLANG_SHA256
|
|
"e6dd32bbddf1720ebb4e679d55e9635ce792865a5bd84f3d2cd9af28647c0174")
|
|
elseif(WR_SLANG_PLATFORM STREQUAL "windows-aarch64")
|
|
set(WR_SLANG_ASSET
|
|
"slang-${WR_SLANG_VERSION}-windows-aarch64.zip")
|
|
set(WR_SLANG_SHA256
|
|
"4f18a7e76a59969bc9bf6ea596bd9e496a3c689af173990ae028b18f03e1ac1a")
|
|
else()
|
|
set(WR_SLANG_ASSET "")
|
|
endif()
|
|
|
|
if(NOT WR_SLANG_ASSET)
|
|
message(FATAL_ERROR
|
|
"slangc was not found, and no prebuilt Slang archive is available "
|
|
"for ${CMAKE_HOST_SYSTEM_NAME}/${CMAKE_HOST_SYSTEM_PROCESSOR}. "
|
|
"Install the Slang compiler, or configure with "
|
|
"-DWR_COMPILE_SHADERS=OFF.")
|
|
endif()
|
|
|
|
set(WR_SLANG_DOWNLOAD_DIR "${CMAKE_CURRENT_BINARY_DIR}/_deps/slang")
|
|
set(WR_SLANG_ARCHIVE
|
|
"${WR_SLANG_DOWNLOAD_DIR}/${WR_SLANG_ASSET}")
|
|
set(WR_SLANG_URL
|
|
"https://github.com/shader-slang/slang/releases/download/v${WR_SLANG_VERSION}/${WR_SLANG_ASSET}")
|
|
|
|
if(EXISTS "${WR_SLANG_ARCHIVE}")
|
|
file(SHA256 "${WR_SLANG_ARCHIVE}" WR_SLANG_ACTUAL_SHA256)
|
|
if(NOT WR_SLANG_ACTUAL_SHA256 STREQUAL WR_SLANG_SHA256)
|
|
message(STATUS "Removing corrupt Slang archive")
|
|
file(REMOVE "${WR_SLANG_ARCHIVE}")
|
|
endif()
|
|
endif()
|
|
|
|
if(NOT EXISTS "${WR_SLANG_ARCHIVE}")
|
|
message(STATUS "Downloading Slang ${WR_SLANG_VERSION} for ${WR_SLANG_PLATFORM}")
|
|
file(DOWNLOAD
|
|
"${WR_SLANG_URL}"
|
|
"${WR_SLANG_ARCHIVE}"
|
|
EXPECTED_HASH SHA256=${WR_SLANG_SHA256}
|
|
STATUS WR_SLANG_DOWNLOAD_STATUS
|
|
TLS_VERIFY ON
|
|
)
|
|
list(GET WR_SLANG_DOWNLOAD_STATUS 0 WR_SLANG_DOWNLOAD_CODE)
|
|
list(GET WR_SLANG_DOWNLOAD_STATUS 1 WR_SLANG_DOWNLOAD_MESSAGE)
|
|
if(NOT WR_SLANG_DOWNLOAD_CODE EQUAL 0)
|
|
file(REMOVE "${WR_SLANG_ARCHIVE}")
|
|
message(FATAL_ERROR
|
|
"Failed to download Slang from ${WR_SLANG_URL}: "
|
|
"${WR_SLANG_DOWNLOAD_MESSAGE}")
|
|
endif()
|
|
endif()
|
|
|
|
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
|
|
set(WR_SLANG_EXECUTABLE
|
|
"${WR_SLANG_DOWNLOAD_DIR}/bin/slangc.exe")
|
|
else()
|
|
set(WR_SLANG_EXECUTABLE
|
|
"${WR_SLANG_DOWNLOAD_DIR}/bin/slangc")
|
|
endif()
|
|
|
|
if(NOT EXISTS "${WR_SLANG_EXECUTABLE}")
|
|
message(STATUS "Extracting Slang ${WR_SLANG_VERSION}")
|
|
file(ARCHIVE_EXTRACT
|
|
INPUT "${WR_SLANG_ARCHIVE}"
|
|
DESTINATION "${WR_SLANG_DOWNLOAD_DIR}"
|
|
)
|
|
endif()
|
|
|
|
if(NOT EXISTS "${WR_SLANG_EXECUTABLE}")
|
|
message(FATAL_ERROR
|
|
"The Slang archive did not contain bin/slangc")
|
|
endif()
|
|
|
|
set(SLANGC_EXECUTABLE "${WR_SLANG_EXECUTABLE}")
|
|
message(STATUS "Using downloaded Slang compiler: ${SLANGC_EXECUTABLE}")
|
|
endif()
|
|
|
|
if(NOT SLANGC_EXECUTABLE)
|
|
message(FATAL_ERROR
|
|
"slangc was not found. Install the Slang compiler, configure with "
|
|
"-DWR_FETCH_MISSING_DEPENDENCIES=ON to download it, or configure with "
|
|
"-DWR_COMPILE_SHADERS=OFF.")
|
|
endif()
|
|
|
|
set(WR_SHADER_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/src/shaders/shader.slang)
|
|
set(WR_SHADER_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/shaders)
|
|
set(WR_SHADER_OUTPUT ${WR_SHADER_OUTPUT_DIR}/shader.spv)
|
|
|
|
add_custom_command(
|
|
OUTPUT ${WR_SHADER_OUTPUT}
|
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${WR_SHADER_OUTPUT_DIR}
|
|
COMMAND ${SLANGC_EXECUTABLE}
|
|
${WR_SHADER_SOURCE}
|
|
-entry vertMain
|
|
-entry fragMain
|
|
-o ${WR_SHADER_OUTPUT}
|
|
DEPENDS ${WR_SHADER_SOURCE}
|
|
COMMENT "Compiling shader.slang"
|
|
VERBATIM
|
|
)
|
|
|
|
add_custom_target(shaders ALL DEPENDS ${WR_SHADER_OUTPUT})
|
|
add_dependencies(main shaders)
|
|
endif()
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Assets
|
|
#
|
|
# The application loads "assets/collections.png" relative to its working
|
|
# directory, so the assets directory is copied into <build-dir>/assets.
|
|
# ---------------------------------------------------------------------------
|
|
set(WR_ASSETS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/assets)
|
|
set(WR_ASSETS_DEST_DIR ${CMAKE_CURRENT_BINARY_DIR}/assets)
|
|
|
|
if(EXISTS ${WR_ASSETS_SOURCE_DIR})
|
|
add_custom_target(copy_assets ALL
|
|
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
|
${WR_ASSETS_SOURCE_DIR}
|
|
${WR_ASSETS_DEST_DIR}
|
|
COMMENT "Copying assets"
|
|
VERBATIM
|
|
)
|
|
add_dependencies(main copy_assets)
|
|
endif()
|
|
|
|
add_custom_target(run
|
|
COMMAND $<TARGET_FILE:main>
|
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
|
DEPENDS main
|
|
USES_TERMINAL
|
|
)
|
|
|
|
if(TARGET shaders)
|
|
add_dependencies(run shaders)
|
|
endif()
|