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 , 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 # , 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 $<$:-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 /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 /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 $ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} DEPENDS main USES_TERMINAL ) if(TARGET shaders) add_dependencies(run shaders) endif()