From d6fc177c80bbf8cba609c94fab90f8871d1ddd4d Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Mon, 23 Jun 2025 16:28:56 +0200 Subject: [PATCH 01/13] prefix example targets with numbers and do not make them C identifiers, update examples_tests --- cmake/common.cmake | 2 -- examples_tests | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/cmake/common.cmake b/cmake/common.cmake index bb34e7979c..af3346dddf 100755 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -22,9 +22,7 @@ include(ProcessorCount) macro(nbl_create_executable_project _EXTRA_SOURCES _EXTRA_OPTIONS _EXTRA_INCLUDES _EXTRA_LIBS) get_filename_component(_NBL_PROJECT_DIRECTORY_ "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE) get_filename_component(EXECUTABLE_NAME ${_NBL_PROJECT_DIRECTORY_} NAME) - string(REGEX REPLACE "^[0-9]+\." "" EXECUTABLE_NAME ${EXECUTABLE_NAME}) string(TOLOWER ${EXECUTABLE_NAME} EXECUTABLE_NAME) - string(MAKE_C_IDENTIFIER ${EXECUTABLE_NAME} EXECUTABLE_NAME) project(${EXECUTABLE_NAME}) set_directory_properties(PROPERTIES VS_STARTUP_PROJECT ${EXECUTABLE_NAME}) diff --git a/examples_tests b/examples_tests index 1b3c19cb84..bb68b7bc66 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 1b3c19cb84d618f20c77469c86a665544889aff7 +Subproject commit bb68b7bc660b3631c2ca0d124fcf197b321cc2d0 From 055aa5dcfb2645a9f16c4bae061145cfe7b8c00f Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 25 Jun 2025 09:08:13 +0200 Subject: [PATCH 02/13] correct NBL_ADJUST_FOLDERS and update references --- CMakeLists.txt | 3 ++- cmake/common.cmake | 4 ++-- src/nbl/ext/CMakeLists.txt | 4 +++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e29839399..34a5540a9b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -285,4 +285,5 @@ add_subdirectory(artifacts) option(NBL_CPACK_INCLUDE_EXAMPLES "CPack with examples and media" ON) include(cpack/package) include(build/info) -export(TARGETS ${_NBL_3RDPARTY_TARGETS_} Nabla NAMESPACE Nabla:: APPEND FILE ${NBL_ROOT_PATH_BINARY}/NablaExport.cmake) \ No newline at end of file +export(TARGETS ${_NBL_3RDPARTY_TARGETS_} Nabla NAMESPACE Nabla:: APPEND FILE ${NBL_ROOT_PATH_BINARY}/NablaExport.cmake) +NBL_ADJUST_FOLDERS(nabla) \ No newline at end of file diff --git a/cmake/common.cmake b/cmake/common.cmake index af3346dddf..02cc4f478a 100755 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -1221,9 +1221,9 @@ function(NBL_ADJUST_FOLDERS NS) get_target_property(NBL_FOLDER ${T} FOLDER) if(NBL_FOLDER) - set_target_properties(${T} PROPERTIES FOLDER "nabla/${NS}/${NBL_FOLDER}") + set_target_properties(${T} PROPERTIES FOLDER "${NS}/${NBL_FOLDER}") else() - set_target_properties(${T} PROPERTIES FOLDER "nabla/${NS}") + set_target_properties(${T} PROPERTIES FOLDER "${NS}") endif() endforeach() endfunction() \ No newline at end of file diff --git a/src/nbl/ext/CMakeLists.txt b/src/nbl/ext/CMakeLists.txt index e2385aede5..d6d512420c 100644 --- a/src/nbl/ext/CMakeLists.txt +++ b/src/nbl/ext/CMakeLists.txt @@ -77,4 +77,6 @@ if(NBL_BUILD_TEXT_RENDERING) add_subdirectory(TextRendering) endif() -propagate_changed_variables_to_parent_scope() \ No newline at end of file +propagate_changed_variables_to_parent_scope() + +NBL_ADJUST_FOLDERS(ext) \ No newline at end of file From f18bf0c28ae36fad6d3e43a339fe681e418c72c2 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 25 Jun 2025 15:27:23 +0200 Subject: [PATCH 03/13] create NBL_REGISTER_SPIRV_SHADERS, update examples_tests submodule --- examples_tests | 2 +- src/nbl/builtin/utils.cmake | 248 ++++++++++++++++++++++++++++++++++++ 2 files changed, 249 insertions(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index bb68b7bc66..cbcc1c90a3 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit bb68b7bc660b3631c2ca0d124fcf197b321cc2d0 +Subproject commit cbcc1c90a399820939ea0dc080bea52734f39a8a diff --git a/src/nbl/builtin/utils.cmake b/src/nbl/builtin/utils.cmake index 0653ff97a2..e51012e57a 100644 --- a/src/nbl/builtin/utils.cmake +++ b/src/nbl/builtin/utils.cmake @@ -248,3 +248,251 @@ function(ADD_CUSTOM_BUILTIN_RESOURCES _TARGET_NAME_ _BUNDLE_NAME_ _BUNDLE_SEARCH set_property(TARGET ${_TARGET_NAME_} PROPERTY COMPILE_OPTIONS /fsanitize=address) endif() endfunction() + +function(NBL_REGISTER_SPIRV_SHADERS) + cmake_parse_arguments(IMPL "" "DISCARD;LINK_TO;MOUNT_POINT_DEFINE" "PERMUTE;REQUIRED;ARCHIVE;INPUTS" ${ARGN}) + + if(NOT IMPL_MOUNT_POINT_DEFINE) + message(FATAL_ERROR "MOUNT_POINT_DEFINE argument missing!") + endif() + + if(NOT IMPL_ARCHIVE) + message(FATAL_ERROR "ARCHIVE arguments missing!") + endif() + + cmake_parse_arguments(IMPL "" "TARGET;INPUT_DIRECTORY;NAMESPACE;PREFIX" "" ${IMPL_ARCHIVE}) + + if(NOT IMPL_TARGET) + message(FATAL_ERROR "Missing TARGET argument in ARCHIVE specification!") + endif() + + if(NOT IMPL_INPUT_DIRECTORY) + message(FATAL_ERROR "Missing INPUT_DIRECTORY argument in ARCHIVE specification!") + endif() + + if(NOT IMPL_NAMESPACE) + message(FATAL_ERROR "Missing NAMESPACE argument in ARCHIVE specification!") + endif() + + set(_BUNDLE_ARCHIVE_ABSOLUTE_PATH_ ${IMPL_PREFIX}) + get_filename_component(_BUNDLE_SEARCH_DIRECTORY_ "${CMAKE_CURRENT_BINARY_DIR}/builtin/spirv/shaders/mount-point" ABSOLUTE) + get_filename_component(_OUTPUT_DIRECTORY_SOURCE_ "${CMAKE_CURRENT_BINARY_DIR}/builtin/spirv/archive/src" ABSOLUTE) + get_filename_component(_OUTPUT_DIRECTORY_HEADER_ "${CMAKE_CURRENT_BINARY_DIR}/builtin/spirv/archive/include" ABSOLUTE) + + set(_BUILTIN_RESOURCES_NAMESPACE_ ${IMPL_NAMESPACE}) + set(_LINK_MODE_ STATIC) + + get_filename_component(BUILTIN_ARCHIVE_INPUT_ABS_ENTRY "${IMPL_INPUT_DIRECTORY}" ABSOLUTE) + set(BUILTIN_KEY_ENTRY_ABS "${BUILTIN_ARCHIVE_INPUT_ABS_ENTRY}/${_BUNDLE_ARCHIVE_ABSOLUTE_PATH_}") + + # REMOVE IT AND ADD "DEPENDS" to INPUTS + # file(GLOB_RECURSE _DEPENDS_ON_ CONFIGURE_DEPENDS "${BUILTIN_KEY_ENTRY_ABS}/*.hlsl") + # list(FILTER _DEPENDS_ON_ EXCLUDE REGEX /preprocessed.hlsl) + # and maybe extra DEPENDS shared for all inputs + #################### + + set(SPIRV_OUTPUT_ARCHIVE_KEY_ABS_ENTRY_DIR "${_BUNDLE_SEARCH_DIRECTORY_}/${_BUNDLE_ARCHIVE_ABSOLUTE_PATH_}") + + set(DEVICE_CONFIG_ENTRY_DIR "${_BUNDLE_SEARCH_DIRECTORY_}/PermutationCaps") + set(DEVICE_CONFIG_TEMPLATE_PATH "${DEVICE_CONFIG_ENTRY_DIR}/DeviceConfig.hlsl") + file(REMOVE_RECURSE "${DEVICE_CONFIG_ENTRY_DIR}/") + + set(DEVICE_CONFIG_VIEW +[=[ + +// -> this code has been autogenerated! +#ifndef _PERMUTATION_CAPS_AUTO_GEN_GLOBALS_INCLUDED_ +#define _PERMUTATION_CAPS_AUTO_GEN_GLOBALS_INCLUDED_ +#ifdef __HLSL_VERSION +#include +struct DeviceConfigCaps +{ +@CAPS_EVAL@ +}; +#endif // __HLSL_VERSION +#endif // _PERMUTATION_CAPS_AUTO_GEN_GLOBALS_INCLUDED_ +// <- this code has been autogenerated! + +// we inject our own config above +#define NBL_USE_SPIRV_BUILTINS + +/* +note: (**) +we have a bug and I cannot use -D to create +define with dxc options, it gets ignored, so +temporary I will create int input files and +inject this config code + +#ifndef NBL_DYMANIC_INCLUDE +#error "NBL_DYMANIC_INCLUDE must be defined!" +#endif // NBL_DYMANIC_INCLUDE + +// proxy HLSL input with #define +#include NBL_DYMANIC_INCLUDE +*/ +]=] +) + set(KEY_EXTENSION .spv) + + if(IMPL_PERMUTE) + list(LENGTH IMPL_PERMUTE KEYS_LENGTH) + math(EXPR TOTAL_INDEX_RANGE "(1 << ${KEYS_LENGTH}) - 1") + else() + set(TOTAL_INDEX_RANGE 0) + endif() + + foreach(INDEX RANGE 0 ${TOTAL_INDEX_RANGE}) + set(BIT_INDEX 0) + unset(CAPS_EVAL) + unset(POSTFIX_ACCESS_KEY) + + foreach(KEY IN LISTS IMPL_PERMUTE) + math(EXPR BIT "((${INDEX} >> ${BIT_INDEX}) & 1)") + if(BIT EQUAL 1) + set(STATE "true") + else() + set(STATE "false") + endif() + string(APPEND POSTFIX_ACCESS_KEY "_${KEY}=${STATE}") + string(APPEND CAPS_EVAL "NBL_CONSTEXPR_STATIC_INLINE bool ${KEY} = ${STATE}; // got permuted\n") + math(EXPR BIT_INDEX "${BIT_INDEX} + 1") + endforeach() + + foreach(KEY IN LISTS IMPL_REQUIRED) + string(APPEND CAPS_EVAL "NBL_CONSTEXPR_STATIC_INLINE bool ${KEY} = true; // always required\n") + endforeach() + + # generate permuted config + set(PERMUTED_DEVICE_CONFIG "${DEVICE_CONFIG_TEMPLATE_PATH}${POSTFIX_ACCESS_KEY}") + list(APPEND DEVICE_CONFIG_FILES "${PERMUTED_DEVICE_CONFIG}") + string(CONFIGURE "${DEVICE_CONFIG_VIEW}" CONFIG_CONTENT @ONLY) + file(WRITE "${PERMUTED_DEVICE_CONFIG}" "${CONFIG_CONTENT}") + + # create compile rules for given input with permuted config + set(i 0) + list(LENGTH IMPL_INPUTS LEN) + while(i LESS LEN) + list(GET IMPL_INPUTS ${i} TOKEN) + if(TOKEN STREQUAL "KEY") + math(EXPR i "${i} + 1") + list(GET IMPL_INPUTS ${i} FILEPATH) + set(COMPILE_OPTIONS "") + math(EXPR i "${i} + 1") + + list(GET IMPL_INPUTS ${i} NEXT) + if(NOT NEXT STREQUAL "COMPILE_OPTIONS") + message(FATAL_ERROR "Expected COMPILE_OPTIONS after KEY ${FILEPATH}") + endif() + math(EXPR i "${i} + 1") + + while(i LESS LEN) + list(GET IMPL_INPUTS ${i} ARG) + if(ARG STREQUAL "KEY") + break() + endif() + list(APPEND COMPILE_OPTIONS "${ARG}") + math(EXPR i "${i} + 1") + endwhile() + + set(IMPL_KEY ${FILEPATH}) + set(TARGET_KEY "${IMPL_KEY}${POSTFIX_ACCESS_KEY}${KEY_EXTENSION}") + + if(IMPL_DISCARD AND "${POSTFIX_ACCESS_KEY}" MATCHES "${IMPL_DISCARD}") + if(NBL_LOG_VERBOSE) + message(STATUS "[Nabla Builtin SPIRV]: Discarded \"${TARGET_KEY}\" key for ${IMPL_TARGET}") + endif() + continue() + endif() + + if(NBL_LOG_VERBOSE) + message(STATUS "[Nabla Builtin SPIRV]: Registered \"${TARGET_KEY}\" key ${IMPL_TARGET}") + endif() + + set(TARGET_INPUT "${BUILTIN_KEY_ENTRY_ABS}/${IMPL_KEY}") + list(APPEND REQUESTED_INPUTS "${TARGET_INPUT}") + set(TAGET_OUTPUT "${SPIRV_OUTPUT_ARCHIVE_KEY_ABS_ENTRY_DIR}/${TARGET_KEY}") + list(APPEND SPIRV_OUTPUTS "${TAGET_OUTPUT}") + + # doing as workaround for (**), dynamic define include could be better because then I don't have to generate intermediate files with glue at configure time + set(INT_INPUT "${SPIRV_OUTPUT_ARCHIVE_KEY_ABS_ENTRY_DIR}/.int/${TARGET_KEY}") + list(APPEND INT_FILES "${INT_INPUT}") + set(INT_INPUT_VIEW +[=[ + +@INPUT_CONFIG_CONTENT@ + +#include "@PERMUTED_DEVICE_CONFIG@" +#include "@TARGET_INPUT@" + +]=] + ) + + string(CONFIGURE "${INT_INPUT_VIEW}" INT_CONTENT @ONLY) + file(WRITE "${INT_INPUT}" "${INT_CONTENT}") + + # would get added by NSC anyway and spam in output + set(REQUIRED_OPTIONS + -HV 202x + -Wno-c++14-extensions + -Wno-gnu-static-float-init + -Wno-c++1z-extensions + -Wno-c++11-extensions + -fvk-use-scalar-layout + -enable-16bit-types + -Zpr + -spirv + -fspv-target-env=vulkan1.3 + ) + + set(NBL_NSC_COMPILE_COMMAND + "$" + -Fc "${TAGET_OUTPUT}" + ${COMPILE_OPTIONS} ${REQUIRED_OPTIONS} + # "-DNBL_DYMANIC_INCLUDE=<${TARGET_INPUT}>" # (**)! + "${INT_INPUT}" + ) + + add_custom_command(OUTPUT "${TAGET_OUTPUT}" + COMMAND ${NBL_NSC_COMPILE_COMMAND} + DEPENDS ${_DEPENDS_ON_} ${INT_INPUT} + COMMENT "Creating ${TAGET_OUTPUT}" + VERBATIM + COMMAND_EXPAND_LISTS + ) + + LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED ${TARGET_KEY}) + else() + math(EXPR i "${i} + 1") + endif() + endwhile() + endforeach() + + if(NBL_EMBED_BUILTIN_RESOURCES) + ADD_CUSTOM_BUILTIN_RESOURCES(${IMPL_TARGET} NBL_RESOURCES_TO_EMBED "${_BUNDLE_SEARCH_DIRECTORY_}" "${_BUNDLE_ARCHIVE_ABSOLUTE_PATH_}" "${_BUILTIN_RESOURCES_NAMESPACE_}" "${_OUTPUT_DIRECTORY_HEADER_}" "${_OUTPUT_DIRECTORY_SOURCE_}" "${_LINK_MODE_}") + else() + add_library(${IMPL_TARGET} INTERFACE) + endif() + + target_compile_definitions(${IMPL_TARGET} INTERFACE ${IMPL_MOUNT_POINT_DEFINE}="${_BUNDLE_SEARCH_DIRECTORY_}") + + if(IMPL_LINK_TO) + if(NBL_EMBED_BUILTIN_RESOURCES) + LINK_BUILTIN_RESOURCES_TO_TARGET(${IMPL_LINK_TO} ${IMPL_TARGET}) + else() + target_link_libraries(${IMPL_LINK_TO} INTERFACE ${IMPL_TARGET}) + endif() + endif() + + set(HEADER_ONLY ${INT_FILES} ${DEVICE_CONFIG_FILES} ${REQUESTED_INPUTS} ${SPIRV_OUTPUTS}) + target_sources(${IMPL_TARGET} PRIVATE ${HEADER_ONLY}) + set_source_files_properties(${HEADER_ONLY} PROPERTIES HEADER_FILE_ONLY TRUE) + + set(RTE "Resources to embed") + set(IN "${RTE}/In") + set(OUT "${RTE}/Out") + + source_group("${IN}/Intermediate" FILES ${INT_FILES}) + source_group("${IN}/Device Configs" FILES ${DEVICE_CONFIG_FILES}) + source_group("${IN}" FILES ${REQUESTED_INPUTS}) + source_group("${OUT}" FILES ${SPIRV_OUTPUTS}) +endfunction() \ No newline at end of file From 0477e5f3065c9c7c4c205f446a06463668988c9c Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 25 Jun 2025 16:54:46 +0200 Subject: [PATCH 04/13] move NBL_REGISTER_SPIRV_SHADERS to cmake/common.cmake, update examples_tests submodule --- cmake/common.cmake | 253 ++++++++++++++++++++++++++++++++++++ examples_tests | 2 +- src/nbl/builtin/utils.cmake | 248 ----------------------------------- 3 files changed, 254 insertions(+), 249 deletions(-) diff --git a/cmake/common.cmake b/cmake/common.cmake index 02cc4f478a..cb295dc79c 100755 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -1226,4 +1226,257 @@ function(NBL_ADJUST_FOLDERS NS) set_target_properties(${T} PROPERTIES FOLDER "${NS}") endif() endforeach() +endfunction() + +function(NBL_REGISTER_SPIRV_SHADERS) + cmake_parse_arguments(IMPL "" "DISCARD;LINK_TO;MOUNT_POINT_DEFINE" "PERMUTE;REQUIRED;ARCHIVE;INPUTS" ${ARGN}) + + if(NOT IMPL_MOUNT_POINT_DEFINE) + message(FATAL_ERROR "MOUNT_POINT_DEFINE argument missing!") + endif() + + if(NOT IMPL_ARCHIVE) + message(FATAL_ERROR "ARCHIVE arguments missing!") + endif() + + cmake_parse_arguments(IMPL "" "TARGET;INPUT_DIRECTORY;NAMESPACE;PREFIX" "" ${IMPL_ARCHIVE}) + + if(NOT IMPL_TARGET) + message(FATAL_ERROR "Missing TARGET argument in ARCHIVE specification!") + endif() + + if(NOT IMPL_INPUT_DIRECTORY) + message(FATAL_ERROR "Missing INPUT_DIRECTORY argument in ARCHIVE specification!") + endif() + + if(NOT IMPL_NAMESPACE) + message(FATAL_ERROR "Missing NAMESPACE argument in ARCHIVE specification!") + endif() + + set(_BUNDLE_ARCHIVE_ABSOLUTE_PATH_ ${IMPL_PREFIX}) + get_filename_component(_BUNDLE_SEARCH_DIRECTORY_ "${CMAKE_CURRENT_BINARY_DIR}/builtin/spirv/shaders/mount-point" ABSOLUTE) + get_filename_component(_OUTPUT_DIRECTORY_SOURCE_ "${CMAKE_CURRENT_BINARY_DIR}/builtin/spirv/archive/src" ABSOLUTE) + get_filename_component(_OUTPUT_DIRECTORY_HEADER_ "${CMAKE_CURRENT_BINARY_DIR}/builtin/spirv/archive/include" ABSOLUTE) + + set(_BUILTIN_RESOURCES_NAMESPACE_ ${IMPL_NAMESPACE}) + set(_LINK_MODE_ STATIC) + + get_filename_component(BUILTIN_ARCHIVE_INPUT_ABS_ENTRY "${IMPL_INPUT_DIRECTORY}" ABSOLUTE) + set(BUILTIN_KEY_ENTRY_ABS "${BUILTIN_ARCHIVE_INPUT_ABS_ENTRY}/${_BUNDLE_ARCHIVE_ABSOLUTE_PATH_}") + + # REMOVE IT AND ADD "DEPENDS" to INPUTS + # file(GLOB_RECURSE _DEPENDS_ON_ CONFIGURE_DEPENDS "${BUILTIN_KEY_ENTRY_ABS}/*.hlsl") + # list(FILTER _DEPENDS_ON_ EXCLUDE REGEX /preprocessed.hlsl) + # and maybe extra DEPENDS shared for all inputs + #################### + + set(SPIRV_OUTPUT_ARCHIVE_KEY_ABS_ENTRY_DIR "${_BUNDLE_SEARCH_DIRECTORY_}/${_BUNDLE_ARCHIVE_ABSOLUTE_PATH_}") + + set(DEVICE_CONFIG_ENTRY_DIR "${_BUNDLE_SEARCH_DIRECTORY_}/PermutationCaps") + set(DEVICE_CONFIG_TEMPLATE_PATH "${DEVICE_CONFIG_ENTRY_DIR}/DeviceConfig.hlsl") + file(REMOVE_RECURSE "${DEVICE_CONFIG_ENTRY_DIR}/") + + set(DEVICE_CONFIG_VIEW +[=[ + +// -> this code has been autogenerated! +#ifndef _PERMUTATION_CAPS_AUTO_GEN_GLOBALS_INCLUDED_ +#define _PERMUTATION_CAPS_AUTO_GEN_GLOBALS_INCLUDED_ +#ifdef __HLSL_VERSION +#include +struct DeviceConfigCaps +{ +@CAPS_EVAL@ +}; +#endif // __HLSL_VERSION +#endif // _PERMUTATION_CAPS_AUTO_GEN_GLOBALS_INCLUDED_ +// <- this code has been autogenerated! + +// we inject our own config above +#define NBL_USE_SPIRV_BUILTINS + +/* +note: (**) +we have a bug and I cannot use -D to create +define with dxc options, it gets ignored, so +temporary I will create int input files and +inject this config code + +#ifndef NBL_DYMANIC_INCLUDE +#error "NBL_DYMANIC_INCLUDE must be defined!" +#endif // NBL_DYMANIC_INCLUDE + +// proxy HLSL input with #define +#include NBL_DYMANIC_INCLUDE +*/ +]=] +) + set(KEY_EXTENSION .spv) + + if(IMPL_PERMUTE) + list(LENGTH IMPL_PERMUTE KEYS_LENGTH) + math(EXPR TOTAL_INDEX_RANGE "(1 << ${KEYS_LENGTH}) - 1") + else() + set(TOTAL_INDEX_RANGE 0) + endif() + + foreach(INDEX RANGE 0 ${TOTAL_INDEX_RANGE}) + set(BIT_INDEX 0) + unset(CAPS_EVAL) + unset(POSTFIX_ACCESS_KEY) + + foreach(KEY IN LISTS IMPL_PERMUTE) + math(EXPR BIT "((${INDEX} >> ${BIT_INDEX}) & 1)") + if(BIT EQUAL 1) + set(STATE "true") + else() + set(STATE "false") + endif() + string(APPEND POSTFIX_ACCESS_KEY "_${KEY}=${STATE}") + string(APPEND CAPS_EVAL "NBL_CONSTEXPR_STATIC_INLINE bool ${KEY} = ${STATE}; // got permuted\n") + math(EXPR BIT_INDEX "${BIT_INDEX} + 1") + endforeach() + + foreach(KEY IN LISTS IMPL_REQUIRED) + string(APPEND CAPS_EVAL "NBL_CONSTEXPR_STATIC_INLINE bool ${KEY} = true; // always required\n") + endforeach() + + # generate permuted config + set(PERMUTED_DEVICE_CONFIG "${DEVICE_CONFIG_TEMPLATE_PATH}${POSTFIX_ACCESS_KEY}") + list(APPEND DEVICE_CONFIG_FILES "${PERMUTED_DEVICE_CONFIG}") + string(CONFIGURE "${DEVICE_CONFIG_VIEW}" CONFIG_CONTENT @ONLY) + file(WRITE "${PERMUTED_DEVICE_CONFIG}" "${CONFIG_CONTENT}") + + # create compile rules for given input with permuted config + set(i 0) + list(LENGTH IMPL_INPUTS LEN) + while(i LESS LEN) + list(GET IMPL_INPUTS ${i} TOKEN) + if(TOKEN STREQUAL "KEY") + math(EXPR i "${i} + 1") + list(GET IMPL_INPUTS ${i} FILEPATH) + set(COMPILE_OPTIONS "") + math(EXPR i "${i} + 1") + + list(GET IMPL_INPUTS ${i} NEXT) + if(NOT NEXT STREQUAL "COMPILE_OPTIONS") + message(FATAL_ERROR "Expected COMPILE_OPTIONS after KEY ${FILEPATH}") + endif() + math(EXPR i "${i} + 1") + + while(i LESS LEN) + list(GET IMPL_INPUTS ${i} ARG) + if(ARG STREQUAL "KEY") + break() + endif() + list(APPEND COMPILE_OPTIONS "${ARG}") + math(EXPR i "${i} + 1") + endwhile() + + set(IMPL_KEY ${FILEPATH}) + set(TARGET_KEY "${IMPL_KEY}${POSTFIX_ACCESS_KEY}${KEY_EXTENSION}") + + if(IMPL_DISCARD AND "${POSTFIX_ACCESS_KEY}" MATCHES "${IMPL_DISCARD}") + if(NBL_LOG_VERBOSE) + message(STATUS "[Nabla Builtin SPIRV]: Discarded \"${TARGET_KEY}\" key for ${IMPL_TARGET}") + endif() + continue() + endif() + + if(NBL_LOG_VERBOSE) + message(STATUS "[Nabla Builtin SPIRV]: Registered \"${TARGET_KEY}\" key ${IMPL_TARGET}") + endif() + + set(TARGET_INPUT "${BUILTIN_KEY_ENTRY_ABS}/${IMPL_KEY}") + list(APPEND REQUESTED_INPUTS "${TARGET_INPUT}") + set(TAGET_OUTPUT "${SPIRV_OUTPUT_ARCHIVE_KEY_ABS_ENTRY_DIR}/${TARGET_KEY}") + list(APPEND SPIRV_OUTPUTS "${TAGET_OUTPUT}") + + # doing as workaround for (**), dynamic define include could be better because then I don't have to generate intermediate files with glue at configure time + set(INT_INPUT "${SPIRV_OUTPUT_ARCHIVE_KEY_ABS_ENTRY_DIR}/.int/${TARGET_KEY}") + list(APPEND INT_FILES "${INT_INPUT}") + set(INT_INPUT_VIEW +[=[ + +@INPUT_CONFIG_CONTENT@ + +#include "@PERMUTED_DEVICE_CONFIG@" +#include "@TARGET_INPUT@" + +]=] + ) + + string(CONFIGURE "${INT_INPUT_VIEW}" INT_CONTENT @ONLY) + file(WRITE "${INT_INPUT}" "${INT_CONTENT}") + + # would get added by NSC anyway and spam in output + set(REQUIRED_OPTIONS + -HV 202x + -Wno-c++14-extensions + -Wno-gnu-static-float-init + -Wno-c++1z-extensions + -Wno-c++11-extensions + -fvk-use-scalar-layout + -enable-16bit-types + -Zpr + -spirv + -fspv-target-env=vulkan1.3 + ) + + set(NBL_NSC_COMPILE_COMMAND + "$" + -Fc "${TAGET_OUTPUT}" + ${COMPILE_OPTIONS} ${REQUIRED_OPTIONS} + # "-DNBL_DYMANIC_INCLUDE=<${TARGET_INPUT}>" # (**)! + "${INT_INPUT}" + ) + + add_custom_command(OUTPUT "${TAGET_OUTPUT}" + COMMAND ${NBL_NSC_COMPILE_COMMAND} + DEPENDS ${_DEPENDS_ON_} ${INT_INPUT} + COMMENT "Creating ${TAGET_OUTPUT}" + VERBATIM + COMMAND_EXPAND_LISTS + ) + + if(NBL_EMBED_BUILTIN_RESOURCES) + LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED ${TARGET_KEY}) + endif() + else() + math(EXPR i "${i} + 1") + endif() + endwhile() + endforeach() + + set(HEADER_ONLY ${INT_FILES} ${DEVICE_CONFIG_FILES} ${REQUESTED_INPUTS} ${SPIRV_OUTPUTS}) + + if(NBL_EMBED_BUILTIN_RESOURCES) + ADD_CUSTOM_BUILTIN_RESOURCES(${IMPL_TARGET} NBL_RESOURCES_TO_EMBED "${_BUNDLE_SEARCH_DIRECTORY_}" "${_BUNDLE_ARCHIVE_ABSOLUTE_PATH_}" "${_BUILTIN_RESOURCES_NAMESPACE_}" "${_OUTPUT_DIRECTORY_HEADER_}" "${_OUTPUT_DIRECTORY_SOURCE_}" "${_LINK_MODE_}") + else() + add_library(${IMPL_TARGET} INTERFACE ${HEADER_ONLY}) + endif() + + target_compile_definitions(${IMPL_TARGET} INTERFACE ${IMPL_MOUNT_POINT_DEFINE}="${_BUNDLE_SEARCH_DIRECTORY_}") + + if(IMPL_LINK_TO) + if(NBL_EMBED_BUILTIN_RESOURCES) + LINK_BUILTIN_RESOURCES_TO_TARGET(${IMPL_LINK_TO} ${IMPL_TARGET}) + else() + target_link_libraries(${IMPL_LINK_TO} INTERFACE ${IMPL_TARGET}) + endif() + endif() + + if(NBL_EMBED_BUILTIN_RESOURCES) + target_sources(${IMPL_TARGET} PRIVATE ${HEADER_ONLY}) + endif() + set_source_files_properties(${HEADER_ONLY} PROPERTIES HEADER_FILE_ONLY TRUE) + + set(RTE "Resources to embed") + set(IN "${RTE}/In") + set(OUT "${RTE}/Out") + + source_group("${IN}/Intermediate" FILES ${INT_FILES}) + source_group("${IN}/Device Configs" FILES ${DEVICE_CONFIG_FILES}) + source_group("${IN}" FILES ${REQUESTED_INPUTS}) + source_group("${OUT}" FILES ${SPIRV_OUTPUTS}) endfunction() \ No newline at end of file diff --git a/examples_tests b/examples_tests index cbcc1c90a3..c71e38692e 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit cbcc1c90a399820939ea0dc080bea52734f39a8a +Subproject commit c71e38692e5be4a73012e937043fd9fb3f69ace2 diff --git a/src/nbl/builtin/utils.cmake b/src/nbl/builtin/utils.cmake index e51012e57a..d791cd3aa4 100644 --- a/src/nbl/builtin/utils.cmake +++ b/src/nbl/builtin/utils.cmake @@ -247,252 +247,4 @@ function(ADD_CUSTOM_BUILTIN_RESOURCES _TARGET_NAME_ _BUNDLE_NAME_ _BUNDLE_SEARCH if(MSVC AND NBL_SANITIZE_ADDRESS) set_property(TARGET ${_TARGET_NAME_} PROPERTY COMPILE_OPTIONS /fsanitize=address) endif() -endfunction() - -function(NBL_REGISTER_SPIRV_SHADERS) - cmake_parse_arguments(IMPL "" "DISCARD;LINK_TO;MOUNT_POINT_DEFINE" "PERMUTE;REQUIRED;ARCHIVE;INPUTS" ${ARGN}) - - if(NOT IMPL_MOUNT_POINT_DEFINE) - message(FATAL_ERROR "MOUNT_POINT_DEFINE argument missing!") - endif() - - if(NOT IMPL_ARCHIVE) - message(FATAL_ERROR "ARCHIVE arguments missing!") - endif() - - cmake_parse_arguments(IMPL "" "TARGET;INPUT_DIRECTORY;NAMESPACE;PREFIX" "" ${IMPL_ARCHIVE}) - - if(NOT IMPL_TARGET) - message(FATAL_ERROR "Missing TARGET argument in ARCHIVE specification!") - endif() - - if(NOT IMPL_INPUT_DIRECTORY) - message(FATAL_ERROR "Missing INPUT_DIRECTORY argument in ARCHIVE specification!") - endif() - - if(NOT IMPL_NAMESPACE) - message(FATAL_ERROR "Missing NAMESPACE argument in ARCHIVE specification!") - endif() - - set(_BUNDLE_ARCHIVE_ABSOLUTE_PATH_ ${IMPL_PREFIX}) - get_filename_component(_BUNDLE_SEARCH_DIRECTORY_ "${CMAKE_CURRENT_BINARY_DIR}/builtin/spirv/shaders/mount-point" ABSOLUTE) - get_filename_component(_OUTPUT_DIRECTORY_SOURCE_ "${CMAKE_CURRENT_BINARY_DIR}/builtin/spirv/archive/src" ABSOLUTE) - get_filename_component(_OUTPUT_DIRECTORY_HEADER_ "${CMAKE_CURRENT_BINARY_DIR}/builtin/spirv/archive/include" ABSOLUTE) - - set(_BUILTIN_RESOURCES_NAMESPACE_ ${IMPL_NAMESPACE}) - set(_LINK_MODE_ STATIC) - - get_filename_component(BUILTIN_ARCHIVE_INPUT_ABS_ENTRY "${IMPL_INPUT_DIRECTORY}" ABSOLUTE) - set(BUILTIN_KEY_ENTRY_ABS "${BUILTIN_ARCHIVE_INPUT_ABS_ENTRY}/${_BUNDLE_ARCHIVE_ABSOLUTE_PATH_}") - - # REMOVE IT AND ADD "DEPENDS" to INPUTS - # file(GLOB_RECURSE _DEPENDS_ON_ CONFIGURE_DEPENDS "${BUILTIN_KEY_ENTRY_ABS}/*.hlsl") - # list(FILTER _DEPENDS_ON_ EXCLUDE REGEX /preprocessed.hlsl) - # and maybe extra DEPENDS shared for all inputs - #################### - - set(SPIRV_OUTPUT_ARCHIVE_KEY_ABS_ENTRY_DIR "${_BUNDLE_SEARCH_DIRECTORY_}/${_BUNDLE_ARCHIVE_ABSOLUTE_PATH_}") - - set(DEVICE_CONFIG_ENTRY_DIR "${_BUNDLE_SEARCH_DIRECTORY_}/PermutationCaps") - set(DEVICE_CONFIG_TEMPLATE_PATH "${DEVICE_CONFIG_ENTRY_DIR}/DeviceConfig.hlsl") - file(REMOVE_RECURSE "${DEVICE_CONFIG_ENTRY_DIR}/") - - set(DEVICE_CONFIG_VIEW -[=[ - -// -> this code has been autogenerated! -#ifndef _PERMUTATION_CAPS_AUTO_GEN_GLOBALS_INCLUDED_ -#define _PERMUTATION_CAPS_AUTO_GEN_GLOBALS_INCLUDED_ -#ifdef __HLSL_VERSION -#include -struct DeviceConfigCaps -{ -@CAPS_EVAL@ -}; -#endif // __HLSL_VERSION -#endif // _PERMUTATION_CAPS_AUTO_GEN_GLOBALS_INCLUDED_ -// <- this code has been autogenerated! - -// we inject our own config above -#define NBL_USE_SPIRV_BUILTINS - -/* -note: (**) -we have a bug and I cannot use -D to create -define with dxc options, it gets ignored, so -temporary I will create int input files and -inject this config code - -#ifndef NBL_DYMANIC_INCLUDE -#error "NBL_DYMANIC_INCLUDE must be defined!" -#endif // NBL_DYMANIC_INCLUDE - -// proxy HLSL input with #define -#include NBL_DYMANIC_INCLUDE -*/ -]=] -) - set(KEY_EXTENSION .spv) - - if(IMPL_PERMUTE) - list(LENGTH IMPL_PERMUTE KEYS_LENGTH) - math(EXPR TOTAL_INDEX_RANGE "(1 << ${KEYS_LENGTH}) - 1") - else() - set(TOTAL_INDEX_RANGE 0) - endif() - - foreach(INDEX RANGE 0 ${TOTAL_INDEX_RANGE}) - set(BIT_INDEX 0) - unset(CAPS_EVAL) - unset(POSTFIX_ACCESS_KEY) - - foreach(KEY IN LISTS IMPL_PERMUTE) - math(EXPR BIT "((${INDEX} >> ${BIT_INDEX}) & 1)") - if(BIT EQUAL 1) - set(STATE "true") - else() - set(STATE "false") - endif() - string(APPEND POSTFIX_ACCESS_KEY "_${KEY}=${STATE}") - string(APPEND CAPS_EVAL "NBL_CONSTEXPR_STATIC_INLINE bool ${KEY} = ${STATE}; // got permuted\n") - math(EXPR BIT_INDEX "${BIT_INDEX} + 1") - endforeach() - - foreach(KEY IN LISTS IMPL_REQUIRED) - string(APPEND CAPS_EVAL "NBL_CONSTEXPR_STATIC_INLINE bool ${KEY} = true; // always required\n") - endforeach() - - # generate permuted config - set(PERMUTED_DEVICE_CONFIG "${DEVICE_CONFIG_TEMPLATE_PATH}${POSTFIX_ACCESS_KEY}") - list(APPEND DEVICE_CONFIG_FILES "${PERMUTED_DEVICE_CONFIG}") - string(CONFIGURE "${DEVICE_CONFIG_VIEW}" CONFIG_CONTENT @ONLY) - file(WRITE "${PERMUTED_DEVICE_CONFIG}" "${CONFIG_CONTENT}") - - # create compile rules for given input with permuted config - set(i 0) - list(LENGTH IMPL_INPUTS LEN) - while(i LESS LEN) - list(GET IMPL_INPUTS ${i} TOKEN) - if(TOKEN STREQUAL "KEY") - math(EXPR i "${i} + 1") - list(GET IMPL_INPUTS ${i} FILEPATH) - set(COMPILE_OPTIONS "") - math(EXPR i "${i} + 1") - - list(GET IMPL_INPUTS ${i} NEXT) - if(NOT NEXT STREQUAL "COMPILE_OPTIONS") - message(FATAL_ERROR "Expected COMPILE_OPTIONS after KEY ${FILEPATH}") - endif() - math(EXPR i "${i} + 1") - - while(i LESS LEN) - list(GET IMPL_INPUTS ${i} ARG) - if(ARG STREQUAL "KEY") - break() - endif() - list(APPEND COMPILE_OPTIONS "${ARG}") - math(EXPR i "${i} + 1") - endwhile() - - set(IMPL_KEY ${FILEPATH}) - set(TARGET_KEY "${IMPL_KEY}${POSTFIX_ACCESS_KEY}${KEY_EXTENSION}") - - if(IMPL_DISCARD AND "${POSTFIX_ACCESS_KEY}" MATCHES "${IMPL_DISCARD}") - if(NBL_LOG_VERBOSE) - message(STATUS "[Nabla Builtin SPIRV]: Discarded \"${TARGET_KEY}\" key for ${IMPL_TARGET}") - endif() - continue() - endif() - - if(NBL_LOG_VERBOSE) - message(STATUS "[Nabla Builtin SPIRV]: Registered \"${TARGET_KEY}\" key ${IMPL_TARGET}") - endif() - - set(TARGET_INPUT "${BUILTIN_KEY_ENTRY_ABS}/${IMPL_KEY}") - list(APPEND REQUESTED_INPUTS "${TARGET_INPUT}") - set(TAGET_OUTPUT "${SPIRV_OUTPUT_ARCHIVE_KEY_ABS_ENTRY_DIR}/${TARGET_KEY}") - list(APPEND SPIRV_OUTPUTS "${TAGET_OUTPUT}") - - # doing as workaround for (**), dynamic define include could be better because then I don't have to generate intermediate files with glue at configure time - set(INT_INPUT "${SPIRV_OUTPUT_ARCHIVE_KEY_ABS_ENTRY_DIR}/.int/${TARGET_KEY}") - list(APPEND INT_FILES "${INT_INPUT}") - set(INT_INPUT_VIEW -[=[ - -@INPUT_CONFIG_CONTENT@ - -#include "@PERMUTED_DEVICE_CONFIG@" -#include "@TARGET_INPUT@" - -]=] - ) - - string(CONFIGURE "${INT_INPUT_VIEW}" INT_CONTENT @ONLY) - file(WRITE "${INT_INPUT}" "${INT_CONTENT}") - - # would get added by NSC anyway and spam in output - set(REQUIRED_OPTIONS - -HV 202x - -Wno-c++14-extensions - -Wno-gnu-static-float-init - -Wno-c++1z-extensions - -Wno-c++11-extensions - -fvk-use-scalar-layout - -enable-16bit-types - -Zpr - -spirv - -fspv-target-env=vulkan1.3 - ) - - set(NBL_NSC_COMPILE_COMMAND - "$" - -Fc "${TAGET_OUTPUT}" - ${COMPILE_OPTIONS} ${REQUIRED_OPTIONS} - # "-DNBL_DYMANIC_INCLUDE=<${TARGET_INPUT}>" # (**)! - "${INT_INPUT}" - ) - - add_custom_command(OUTPUT "${TAGET_OUTPUT}" - COMMAND ${NBL_NSC_COMPILE_COMMAND} - DEPENDS ${_DEPENDS_ON_} ${INT_INPUT} - COMMENT "Creating ${TAGET_OUTPUT}" - VERBATIM - COMMAND_EXPAND_LISTS - ) - - LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED ${TARGET_KEY}) - else() - math(EXPR i "${i} + 1") - endif() - endwhile() - endforeach() - - if(NBL_EMBED_BUILTIN_RESOURCES) - ADD_CUSTOM_BUILTIN_RESOURCES(${IMPL_TARGET} NBL_RESOURCES_TO_EMBED "${_BUNDLE_SEARCH_DIRECTORY_}" "${_BUNDLE_ARCHIVE_ABSOLUTE_PATH_}" "${_BUILTIN_RESOURCES_NAMESPACE_}" "${_OUTPUT_DIRECTORY_HEADER_}" "${_OUTPUT_DIRECTORY_SOURCE_}" "${_LINK_MODE_}") - else() - add_library(${IMPL_TARGET} INTERFACE) - endif() - - target_compile_definitions(${IMPL_TARGET} INTERFACE ${IMPL_MOUNT_POINT_DEFINE}="${_BUNDLE_SEARCH_DIRECTORY_}") - - if(IMPL_LINK_TO) - if(NBL_EMBED_BUILTIN_RESOURCES) - LINK_BUILTIN_RESOURCES_TO_TARGET(${IMPL_LINK_TO} ${IMPL_TARGET}) - else() - target_link_libraries(${IMPL_LINK_TO} INTERFACE ${IMPL_TARGET}) - endif() - endif() - - set(HEADER_ONLY ${INT_FILES} ${DEVICE_CONFIG_FILES} ${REQUESTED_INPUTS} ${SPIRV_OUTPUTS}) - target_sources(${IMPL_TARGET} PRIVATE ${HEADER_ONLY}) - set_source_files_properties(${HEADER_ONLY} PROPERTIES HEADER_FILE_ONLY TRUE) - - set(RTE "Resources to embed") - set(IN "${RTE}/In") - set(OUT "${RTE}/Out") - - source_group("${IN}/Intermediate" FILES ${INT_FILES}) - source_group("${IN}/Device Configs" FILES ${DEVICE_CONFIG_FILES}) - source_group("${IN}" FILES ${REQUESTED_INPUTS}) - source_group("${OUT}" FILES ${SPIRV_OUTPUTS}) endfunction() \ No newline at end of file From 7b44d31254adb83f6861b36f9c6f71c15f796f2d Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Fri, 27 Jun 2025 11:26:02 +0200 Subject: [PATCH 05/13] make NBL_REGISTER_SPIRV_SHADERS work in mount mode, update NSC compile options, get rid of FXC entries for VS generators with VS_TOOL_OVERRIDE property, update examples_tests submodules. TODO: I need to make it more generic and allow to embed additional files next to precompiled SPIRV to share the same mount point --- CMakeLists.txt | 2 +- CMakePresets.json | 1 + cmake/common.cmake | 33 +++++++++++++++++++++------------ examples_tests | 2 +- src/nbl/builtin/CMakeLists.txt | 2 +- 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 34a5540a9b..76ddd59870 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -196,7 +196,7 @@ endif() option(NBL_BUILD_BULLET "Enable Bullet Physics building and integration?" OFF) option(NBL_BUILD_DOCS "Enable building documentation?" OFF) # No one has doxygen installed, plus we dont know when was the last time we generated working doxy and we'll use SphinX in the future option(NBL_ENABLE_PROJECT_JSON_CONFIG_VALIDATION "" ON) -option(NBL_EMBED_BUILTIN_RESOURCES "Embed built-in resources?" ON) +option(NBL_EMBED_BUILTIN_RESOURCES "Embed built-in resources?" OFF) option(NBL_ENABLE_DOCKER_INTEGRATION "Enables docker integration, if client is not found Docker Desktop will be installed" OFF) if (NBL_ENABLE_DOCKER_INTEGRATION) diff --git a/CMakePresets.json b/CMakePresets.json index ae56cf1739..718d886790 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -10,6 +10,7 @@ "name": "ci-configure-base", "hidden": true, "cacheVariables": { + "NBL_EMBED_BUILTIN_RESOURCES": "ON", "NBL_UPDATE_GIT_SUBMODULE": "OFF", "NBL_COMPILE_WITH_CUDA": "OFF", "NBL_BUILD_OPTIX": "OFF", diff --git a/cmake/common.cmake b/cmake/common.cmake index cb295dc79c..2ec9e8cfc4 100755 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -1292,15 +1292,12 @@ struct DeviceConfigCaps #endif // _PERMUTATION_CAPS_AUTO_GEN_GLOBALS_INCLUDED_ // <- this code has been autogenerated! -// we inject our own config above -#define NBL_USE_SPIRV_BUILTINS - /* note: (**) we have a bug and I cannot use -D to create define with dxc options, it gets ignored, so -temporary I will create int input files and -inject this config code +temporary I will create .int input files to +glue device permutation caps config with input #ifndef NBL_DYMANIC_INCLUDE #error "NBL_DYMANIC_INCLUDE must be defined!" @@ -1409,6 +1406,13 @@ inject this config code string(CONFIGURE "${INT_INPUT_VIEW}" INT_CONTENT @ONLY) file(WRITE "${INT_INPUT}" "${INT_CONTENT}") + set(REQUIRED_INCLUDES + -I "${NBL_ROOT_PATH}/include" + -I "${NBL_ROOT_PATH}/3rdparty/dxc/dxc/external/SPIRV-Headers/include" + -I "${NBL_ROOT_PATH}/3rdparty/boost/superproject/libs/preprocessor/include" + -I "${NBL_ROOT_PATH_BINARY}/src/nbl/device/include" + ) + # would get added by NSC anyway and spam in output set(REQUIRED_OPTIONS -HV 202x @@ -1423,6 +1427,10 @@ inject this config code -fspv-target-env=vulkan1.3 ) + if(NOT NBL_EMBED_BUILTIN_RESOURCES) + list(APPEND REQUIRED_OPTIONS ${REQUIRED_INCLUDES}) + endif() + set(NBL_NSC_COMPILE_COMMAND "$" -Fc "${TAGET_OUTPUT}" @@ -1448,12 +1456,10 @@ inject this config code endwhile() endforeach() - set(HEADER_ONLY ${INT_FILES} ${DEVICE_CONFIG_FILES} ${REQUESTED_INPUTS} ${SPIRV_OUTPUTS}) - if(NBL_EMBED_BUILTIN_RESOURCES) ADD_CUSTOM_BUILTIN_RESOURCES(${IMPL_TARGET} NBL_RESOURCES_TO_EMBED "${_BUNDLE_SEARCH_DIRECTORY_}" "${_BUNDLE_ARCHIVE_ABSOLUTE_PATH_}" "${_BUILTIN_RESOURCES_NAMESPACE_}" "${_OUTPUT_DIRECTORY_HEADER_}" "${_OUTPUT_DIRECTORY_SOURCE_}" "${_LINK_MODE_}") else() - add_library(${IMPL_TARGET} INTERFACE ${HEADER_ONLY}) + add_library(${IMPL_TARGET} INTERFACE) endif() target_compile_definitions(${IMPL_TARGET} INTERFACE ${IMPL_MOUNT_POINT_DEFINE}="${_BUNDLE_SEARCH_DIRECTORY_}") @@ -1466,10 +1472,13 @@ inject this config code endif() endif() - if(NBL_EMBED_BUILTIN_RESOURCES) - target_sources(${IMPL_TARGET} PRIVATE ${HEADER_ONLY}) - endif() - set_source_files_properties(${HEADER_ONLY} PROPERTIES HEADER_FILE_ONLY TRUE) + set(HEADER_ONLY ${INT_FILES} ${DEVICE_CONFIG_FILES} ${REQUESTED_INPUTS} ${SPIRV_OUTPUTS}) + target_sources(${IMPL_TARGET} PRIVATE ${HEADER_ONLY}) + + set_source_files_properties(${HEADER_ONLY} PROPERTIES + HEADER_FILE_ONLY ON + VS_TOOL_OVERRIDE None + ) set(RTE "Resources to embed") set(IN "${RTE}/In") diff --git a/examples_tests b/examples_tests index c71e38692e..229b5211ef 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit c71e38692e5be4a73012e937043fd9fb3f69ace2 +Subproject commit 229b5211effb676218829073cd6e1d535094efc8 diff --git a/src/nbl/builtin/CMakeLists.txt b/src/nbl/builtin/CMakeLists.txt index fcbe58eb41..9e4f35fc57 100644 --- a/src/nbl/builtin/CMakeLists.txt +++ b/src/nbl/builtin/CMakeLists.txt @@ -386,4 +386,4 @@ LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/tgmath/output_structs.hlsl") LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/prefix_sum_blur/blur.hlsl") LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/prefix_sum_blur/box_sampler.hlsl") -ADD_CUSTOM_BUILTIN_RESOURCES(nblBuiltinResourceData NBL_RESOURCES_TO_EMBED "${NBL_ROOT_PATH}/include" "nbl/builtin" "nbl::builtin" "${NBL_ROOT_PATH_BINARY}/include" "${NBL_ROOT_PATH_BINARY}/src" "STATIC" "INTERNAL") +ADD_CUSTOM_BUILTIN_RESOURCES(nblBuiltinResourceData NBL_RESOURCES_TO_EMBED "${NBL_ROOT_PATH}/include" "nbl/builtin" "nbl::builtin" "${NBL_ROOT_PATH_BINARY}/include" "${NBL_ROOT_PATH_BINARY}/src" "STATIC" "INTERNAL") \ No newline at end of file From 3718dfc5962aa9b071a9b21146f802ce422ab7f2 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sun, 29 Jun 2025 16:52:41 +0200 Subject: [PATCH 06/13] fix issues with wave config causing ABI mismatch, add new NBL_WAVE_STRING_RESOLVER_TU_DEBUG_OPTIMISATION enabled by default and force threading=0 for wave - combined gives over 3x compilation boost in Debug and its almost perf-like RWDI now, update docker/compiler-explorer submodule --- 3rdparty/boost/CMakeLists.txt | 18 +- docker/compiler-explorer | 2 +- include/nbl/asset/IShader.h | 3 +- src/nbl/CMakeLists.txt | 275 ++++++++++---------- src/nbl/asset/utils/CHLSLCompiler.cpp | 62 ++--- src/nbl/asset/utils/CWaveStringResolver.cpp | 57 ++++ src/nbl/asset/utils/waveContext.h | 16 +- tools/nsc/main.cpp | 5 + 8 files changed, 249 insertions(+), 189 deletions(-) create mode 100644 src/nbl/asset/utils/CWaveStringResolver.cpp diff --git a/3rdparty/boost/CMakeLists.txt b/3rdparty/boost/CMakeLists.txt index 3c95234b8e..1e7189fce1 100644 --- a/3rdparty/boost/CMakeLists.txt +++ b/3rdparty/boost/CMakeLists.txt @@ -110,11 +110,25 @@ add_subdirectory(superproject/libs/wave EXCLUDE_FROM_ALL) list(APPEND NBL_BOOST_TARGETS boost_wave) # wave foreach(BOOST_LIB IN LISTS NBL_BOOST_LIBS) - if(TARGET boost_${BOOST_LIB}) # wave's deps - list(APPEND NBL_BOOST_TARGETS boost_${BOOST_LIB}) + set(lib boost_${BOOST_LIB}) + if(TARGET ${lib}) # wave's deps + list(APPEND NBL_BOOST_TARGETS ${lib}) endif() endforeach() +# NOTE: wave *must* be compiled with config definitions, inserting them just before wave +# include will lead to ABI mismatch hence we update the target and let inherit options +target_compile_definitions(boost_wave + PUBLIC BOOST_WAVE_ENABLE_COMMANDLINE_MACROS=1 + PUBLIC BOOST_WAVE_SUPPORT_PRAGMA_ONCE=0 + PUBLIC BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES=1 + PUBLIC BOOST_WAVE_SERIALIZATION=0 + PUBLIC BOOST_WAVE_SUPPORT_INCLUDE_NEXT=0 + + # threading option: https://github.com/boostorg/wave/issues/237#issuecomment-2710251773 + PUBLIC BOOST_WAVE_SUPPORT_THREADING=0 +) + set(NBL_BOOST_TARGETS ${NBL_BOOST_TARGETS} PARENT_SCOPE) \ No newline at end of file diff --git a/docker/compiler-explorer b/docker/compiler-explorer index 45866dfa87..5437a9193b 160000 --- a/docker/compiler-explorer +++ b/docker/compiler-explorer @@ -1 +1 @@ -Subproject commit 45866dfa8782404fc121f25ce15ad0626b474db0 +Subproject commit 5437a9193b3765ba7b0a08894cdfcef5162e57bf diff --git a/include/nbl/asset/IShader.h b/include/nbl/asset/IShader.h index 96ff73f3f0..d553dddf62 100644 --- a/include/nbl/asset/IShader.h +++ b/include/nbl/asset/IShader.h @@ -4,7 +4,8 @@ #ifndef _NBL_ASSET_I_SHADER_H_INCLUDED_ #define _NBL_ASSET_I_SHADER_H_INCLUDED_ - +#include "nbl/asset/IAsset.h" +#include "nbl/asset/ICPUBuffer.h" #include "nbl/core/declarations.h" #include "nbl/builtin/hlsl/enums.hlsl" diff --git a/src/nbl/CMakeLists.txt b/src/nbl/CMakeLists.txt index adf320a5ee..5317b3b402 100755 --- a/src/nbl/CMakeLists.txt +++ b/src/nbl/CMakeLists.txt @@ -118,178 +118,179 @@ unset(NABLA_HEADERS_PUBLIC2 ${NBL_TMP_FULL_PATHS}) # set(NBL_CORE_SOURCES - ${NBL_ROOT_PATH}/src/nbl/core/IReferenceCounted.cpp - ${NBL_ROOT_PATH}/src/nbl/core/alloc/refctd_memory_resource.cpp - ${NBL_ROOT_PATH}/src/nbl/core/hash/blake.cpp + core/IReferenceCounted.cpp + core/alloc/refctd_memory_resource.cpp + core/hash/blake.cpp ) set(NBL_SYSTEM_SOURCES - ${NBL_ROOT_PATH}/src/nbl/system/DefaultFuncPtrLoader.cpp - ${NBL_ROOT_PATH}/src/nbl/system/IFileBase.cpp - ${NBL_ROOT_PATH}/src/nbl/system/ILogger.cpp - ${NBL_ROOT_PATH}/src/nbl/system/CArchiveLoaderZip.cpp - ${NBL_ROOT_PATH}/src/nbl/system/CArchiveLoaderTar.cpp - ${NBL_ROOT_PATH}/src/nbl/system/CAPKResourcesArchive.cpp - ${NBL_ROOT_PATH}/src/nbl/system/ISystem.cpp - ${NBL_ROOT_PATH}/src/nbl/system/IFileArchive.cpp - ${NBL_ROOT_PATH}/src/nbl/system/CColoredStdoutLoggerWin32.cpp - ${NBL_ROOT_PATH}/src/nbl/system/CStdoutLoggerAndroid.cpp - ${NBL_ROOT_PATH}/src/nbl/system/CFileViewVirtualAllocatorWin32.cpp - ${NBL_ROOT_PATH}/src/nbl/system/CFileViewVirtualAllocatorPOSIX.cpp - ${NBL_ROOT_PATH}/src/nbl/system/CFileViewAPKAllocator.cpp - ${NBL_ROOT_PATH}/src/nbl/system/CFileWin32.cpp - ${NBL_ROOT_PATH}/src/nbl/system/CFilePOSIX.cpp - ${NBL_ROOT_PATH}/src/nbl/system/CSystemWin32.cpp - ${NBL_ROOT_PATH}/src/nbl/system/CSystemAndroid.cpp - ${NBL_ROOT_PATH}/src/nbl/system/ISystemPOSIX.cpp - ${NBL_ROOT_PATH}/src/nbl/system/CSystemLinux.cpp + system/DefaultFuncPtrLoader.cpp + system/IFileBase.cpp + system/ILogger.cpp + system/CArchiveLoaderZip.cpp + system/CArchiveLoaderTar.cpp + system/CAPKResourcesArchive.cpp + system/ISystem.cpp + system/IFileArchive.cpp + system/CColoredStdoutLoggerWin32.cpp + system/CStdoutLoggerAndroid.cpp + system/CFileViewVirtualAllocatorWin32.cpp + system/CFileViewVirtualAllocatorPOSIX.cpp + system/CFileViewAPKAllocator.cpp + system/CFileWin32.cpp + system/CFilePOSIX.cpp + system/CSystemWin32.cpp + system/CSystemAndroid.cpp + system/ISystemPOSIX.cpp + system/CSystemLinux.cpp ) set(NBL_UI_SOURCES - ${NBL_ROOT_PATH}/src/nbl/ui/CWindowWin32.cpp - ${NBL_ROOT_PATH}/src/nbl/ui/CWindowManagerWin32.cpp - ${NBL_ROOT_PATH}/src/nbl/ui/CWindowManagerAndroid.cpp - ${NBL_ROOT_PATH}/src/nbl/ui/CGraphicalApplicationAndroid.cpp + ui/CWindowWin32.cpp + ui/CWindowManagerWin32.cpp + ui/CWindowManagerAndroid.cpp + ui/CGraphicalApplicationAndroid.cpp ) set(NBL_ASSET_SOURCES # Assets - ${NBL_ROOT_PATH}/src/nbl/asset/IAsset.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/IRenderpass.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/IAssetManager.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/ICPUDescriptorSet.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/ICPUImage.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/ICPUPolygonGeometry.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/IAssetWriter.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/IAssetLoader.cpp + asset/IAsset.cpp + asset/IRenderpass.cpp + asset/IAssetManager.cpp + asset/ICPUDescriptorSet.cpp + asset/ICPUImage.cpp + asset/ICPUPolygonGeometry.cpp + asset/interchange/IAssetWriter.cpp + asset/interchange/IAssetLoader.cpp # Shaders - ${NBL_ROOT_PATH}/src/nbl/asset/utils/ISPIRVOptimizer.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/utils/ISPIRVEntryPointTrimmer.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/utils/IShaderCompiler.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/utils/CGLSLCompiler.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/utils/CHLSLCompiler.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/utils/CCompilerSet.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/utils/CSPIRVIntrospector.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/CGLSLLoader.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/CHLSLLoader.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/CSPVLoader.cpp + asset/utils/ISPIRVOptimizer.cpp + asset/utils/ISPIRVEntryPointTrimmer.cpp + asset/utils/IShaderCompiler.cpp + asset/utils/CGLSLCompiler.cpp + asset/utils/CHLSLCompiler.cpp + asset/utils/CWaveStringResolver.cpp + asset/utils/CCompilerSet.cpp + asset/utils/CSPIRVIntrospector.cpp + asset/interchange/CGLSLLoader.cpp + asset/interchange/CHLSLLoader.cpp + asset/interchange/CSPVLoader.cpp # Pipeline loaders - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/CGraphicsPipelineLoaderMTL.cpp + asset/interchange/CGraphicsPipelineLoaderMTL.cpp # Meshes - ${NBL_ROOT_PATH}/src/nbl/asset/utils/CForsythVertexCacheOptimizer.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/utils/CSmoothNormalGenerator.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/utils/CGeometryCreator.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/utils/CPolygonGeometryManipulator.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/utils/COverdrawPolygonGeometryOptimizer.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/utils/CSmoothNormalGenerator.cpp + asset/utils/CForsythVertexCacheOptimizer.cpp + asset/utils/CSmoothNormalGenerator.cpp + asset/utils/CGeometryCreator.cpp + asset/utils/CPolygonGeometryManipulator.cpp + asset/utils/COverdrawPolygonGeometryOptimizer.cpp + asset/utils/CSmoothNormalGenerator.cpp # Mesh loaders - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/COBJMeshFileLoader.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/CPLYMeshFileLoader.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/CSTLMeshFileLoader.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/CBufferLoaderBIN.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/CGLTFLoader.cpp + asset/interchange/COBJMeshFileLoader.cpp + asset/interchange/CPLYMeshFileLoader.cpp + asset/interchange/CSTLMeshFileLoader.cpp + asset/interchange/CBufferLoaderBIN.cpp + asset/interchange/CGLTFLoader.cpp # Mesh writers - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/CPLYMeshWriter.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/CSTLMeshWriter.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/CGLTFWriter.cpp + asset/interchange/CPLYMeshWriter.cpp + asset/interchange/CSTLMeshWriter.cpp + asset/interchange/CGLTFWriter.cpp # Images - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/IImageAssetHandlerBase.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/filters/CBasicImageFilterCommon.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/filters/kernels/CConvolutionWeightFunction.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/utils/CDerivativeMapCreator.cpp + asset/interchange/IImageAssetHandlerBase.cpp + asset/filters/CBasicImageFilterCommon.cpp + asset/filters/kernels/CConvolutionWeightFunction.cpp + asset/utils/CDerivativeMapCreator.cpp # Image loaders - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/IImageLoader.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/CImageLoaderJPG.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/CImageLoaderPNG.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/CImageLoaderTGA.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/CImageLoaderOpenEXR.cpp # TODO: Nahim - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/CGLILoader.cpp + asset/interchange/IImageLoader.cpp + asset/interchange/CImageLoaderJPG.cpp + asset/interchange/CImageLoaderPNG.cpp + asset/interchange/CImageLoaderTGA.cpp + asset/interchange/CImageLoaderOpenEXR.cpp # TODO: Nahim + asset/interchange/CGLILoader.cpp # Image writers - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/IImageWriter.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/CImageWriterJPG.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/CImageWriterPNG.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/CImageWriterTGA.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/CImageWriterOpenEXR.cpp # TODO: Nahim - ${NBL_ROOT_PATH}/src/nbl/asset/interchange/CGLIWriter.cpp + asset/interchange/IImageWriter.cpp + asset/interchange/CImageWriterJPG.cpp + asset/interchange/CImageWriterPNG.cpp + asset/interchange/CImageWriterTGA.cpp + asset/interchange/CImageWriterOpenEXR.cpp # TODO: Nahim + asset/interchange/CGLIWriter.cpp # Material compiler - ${NBL_ROOT_PATH}/src/nbl/asset/material_compiler/CMaterialCompilerGLSLBackendCommon.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/material_compiler/CMaterialCompilerGLSLRasterBackend.cpp + asset/material_compiler/CMaterialCompilerGLSLBackendCommon.cpp + asset/material_compiler/CMaterialCompilerGLSLRasterBackend.cpp ) set(NBL_VIDEO_SOURCES # Utilities - ${NBL_ROOT_PATH}/src/nbl/video/utilities/ImageRegionIterator.cpp - ${NBL_ROOT_PATH}/src/nbl/video/utilities/ICommandPoolCache.cpp - ${NBL_ROOT_PATH}/src/nbl/video/utilities/IPropertyPool.cpp - ${NBL_ROOT_PATH}/src/nbl/video/utilities/IUtilities.cpp - ${NBL_ROOT_PATH}/src/nbl/video/utilities/CPropertyPoolHandler.cpp - ${NBL_ROOT_PATH}/src/nbl/video/utilities/CScanner.cpp - ${NBL_ROOT_PATH}/src/nbl/video/utilities/CComputeBlit.cpp - ${NBL_ROOT_PATH}/src/nbl/video/utilities/CAssetConverter.cpp + video/utilities/ImageRegionIterator.cpp + video/utilities/ICommandPoolCache.cpp + video/utilities/IPropertyPool.cpp + video/utilities/IUtilities.cpp + video/utilities/CPropertyPoolHandler.cpp + video/utilities/CScanner.cpp + video/utilities/CComputeBlit.cpp + video/utilities/CAssetConverter.cpp # Interfaces - ${NBL_ROOT_PATH}/src/nbl/video/IAPIConnection.cpp - ${NBL_ROOT_PATH}/src/nbl/video/IPhysicalDevice.cpp - ${NBL_ROOT_PATH}/src/nbl/video/IDescriptorPool.cpp - ${NBL_ROOT_PATH}/src/nbl/video/ILogicalDevice.cpp - ${NBL_ROOT_PATH}/src/nbl/video/IGPUAccelerationStructure.cpp - ${NBL_ROOT_PATH}/src/nbl/video/IGPUCommandBuffer.cpp - ${NBL_ROOT_PATH}/src/nbl/video/IQueue.cpp - ${NBL_ROOT_PATH}/src/nbl/video/IGPUDescriptorSet.cpp - ${NBL_ROOT_PATH}/src/nbl/video/IDeviceMemoryAllocation.cpp - ${NBL_ROOT_PATH}/src/nbl/video/IDeviceMemoryBacked.cpp - ${NBL_ROOT_PATH}/src/nbl/video/ISemaphore.cpp - ${NBL_ROOT_PATH}/src/nbl/video/ISwapchain.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CJITIncludeLoader.cpp + video/IAPIConnection.cpp + video/IPhysicalDevice.cpp + video/IDescriptorPool.cpp + video/ILogicalDevice.cpp + video/IGPUAccelerationStructure.cpp + video/IGPUCommandBuffer.cpp + video/IQueue.cpp + video/IGPUDescriptorSet.cpp + video/IDeviceMemoryAllocation.cpp + video/IDeviceMemoryBacked.cpp + video/ISemaphore.cpp + video/ISwapchain.cpp + video/CJITIncludeLoader.cpp # Vulkan - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanDeviceMemoryBacked.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanSwapchain.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanImage.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanQueue.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanSemaphore.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanFramebuffer.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanRenderpass.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanImageView.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanCommandBuffer.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanCommandPool.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanBuffer.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanDescriptorSetLayout.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanPipelineLayout.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanPipelineCache.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanComputePipeline.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanDescriptorPool.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanDescriptorSet.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanMemoryAllocation.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanBufferView.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanLogicalDevice.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanDeferredOperation.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanAccelerationStructure.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanQueryPool.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanSampler.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanConnection.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanPhysicalDevice.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanGraphicsPipeline.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanRayTracingPipeline.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CVulkanEvent.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CSurfaceVulkan.cpp + video/CVulkanDeviceMemoryBacked.cpp + video/CVulkanSwapchain.cpp + video/CVulkanImage.cpp + video/CVulkanQueue.cpp + video/CVulkanSemaphore.cpp + video/CVulkanFramebuffer.cpp + video/CVulkanRenderpass.cpp + video/CVulkanImageView.cpp + video/CVulkanCommandBuffer.cpp + video/CVulkanCommandPool.cpp + video/CVulkanBuffer.cpp + video/CVulkanDescriptorSetLayout.cpp + video/CVulkanPipelineLayout.cpp + video/CVulkanPipelineCache.cpp + video/CVulkanComputePipeline.cpp + video/CVulkanDescriptorPool.cpp + video/CVulkanDescriptorSet.cpp + video/CVulkanMemoryAllocation.cpp + video/CVulkanBufferView.cpp + video/CVulkanLogicalDevice.cpp + video/CVulkanDeferredOperation.cpp + video/CVulkanAccelerationStructure.cpp + video/CVulkanQueryPool.cpp + video/CVulkanSampler.cpp + video/CVulkanConnection.cpp + video/CVulkanPhysicalDevice.cpp + video/CVulkanGraphicsPipeline.cpp + video/CVulkanRayTracingPipeline.cpp + video/CVulkanEvent.cpp + video/CSurfaceVulkan.cpp # CUDA - ${NBL_ROOT_PATH}/src/nbl/video/CCUDAHandler.cpp - ${NBL_ROOT_PATH}/src/nbl/video/CCUDADevice.cpp + video/CCUDAHandler.cpp + video/CCUDADevice.cpp ) set(NBL_SCENE_SOURCES - ${NBL_ROOT_PATH}/src/nbl/scene/ITransformTree.cpp + scene/ITransformTree.cpp ) set(NBL_META_SOURCES - ${NBL_ROOT_PATH}/src/nbl/gtml.cpp + gtml.cpp ) set(NABLA_SRCS_COMMON @@ -342,6 +343,16 @@ endif() nbl_adjust_flags(TARGET Nabla MAP_RELEASE Release MAP_RELWITHDEBINFO RelWithDebInfo MAP_DEBUG Debug) nbl_adjust_definitions() +option(NBL_WAVE_STRING_RESOLVER_TU_DEBUG_OPTIMISATION "Enable to optimise CWaveStringResolver.cpp in Debug configuration, uses RWDI compile options for the TU" ON) +if(NBL_WAVE_STRING_RESOLVER_TU_DEBUG_OPTIMISATION) + set_source_files_properties(asset/utils/CWaveStringResolver.cpp PROPERTIES + # just enabling inlining and optimisations will help a lot + COMPILE_OPTIONS "$<$:${NBL_CXX_RELWITHDEBINFO_COMPILE_OPTIONS}>" + # trade is you cannot mix with PCH + set this property per config (it seems), different compile options would lead to corrruptions and undefined behaviours + SKIP_PRECOMPILE_HEADERS ON + ) +endif() + if(NBL_EXPLICIT_MODULE_LOAD_LOG) target_compile_definitions(Nabla PUBLIC NBL_EXPLICIT_MODULE_LOAD_LOG) endif() diff --git a/src/nbl/asset/utils/CHLSLCompiler.cpp b/src/nbl/asset/utils/CHLSLCompiler.cpp index f99d81d01f..fdfabbacad 100644 --- a/src/nbl/asset/utils/CHLSLCompiler.cpp +++ b/src/nbl/asset/utils/CHLSLCompiler.cpp @@ -342,9 +342,12 @@ static DxcCompilationResult dxcCompile(const CHLSLCompiler* compiler, nbl::asset return result; } - #include "nbl/asset/utils/waveContext.h" +namespace nbl::wave +{ + extern nbl::core::string resolveString(std::string& code, const IShaderCompiler::SPreprocessorOptions& preprocessOptions, bool withCaching, std::function post); +} std::string CHLSLCompiler::preprocessShader(std::string&& code, IShader::E_SHADER_STAGE& stage, const SPreprocessorOptions& preprocessOptions, std::vector& dxc_compile_flags_override, std::vector* dependencies) const { @@ -361,37 +364,22 @@ std::string CHLSLCompiler::preprocessShader(std::string&& code, IShader::E_SHADE } } - nbl::wave::context context(code.begin(),code.end(),preprocessOptions.sourceIdentifier.data(),{preprocessOptions}); - // If dependencies were passed, we assume we want caching - context.set_caching(bool(dependencies)); - context.add_macro_definition("__HLSL_VERSION"); - - // instead of defining extraDefines as "NBL_GLSL_LIMIT_MAX_IMAGE_DIMENSION_1D 32768", - // now define them as "NBL_GLSL_LIMIT_MAX_IMAGE_DIMENSION_1D=32768" - // to match boost wave syntax - // https://www.boost.org/doc/libs/1_82_0/libs/wave/doc/class_reference_context.html#:~:text=Maintain%20defined%20macros-,add_macro_definition,-bool%20add_macro_definition - for (const auto& define : preprocessOptions.extraDefines) - context.add_macro_definition(define.identifier.data()+core::string("=")+define.definition.data()); - // preprocess - core::string resolvedString; - try - { - std::stringstream stream = std::stringstream(); - for (auto i=context.begin(); i!=context.end(); i++) - stream << i->get_value(); - resolvedString = stream.str(); - } - catch (boost::wave::preprocess_exception& e) - { - preprocessOptions.logger.log("%s exception caught. %s [%s:%d:%d]",system::ILogger::ELL_ERROR,e.what(),e.description(),e.file_name(),e.line_no(),e.column_no()); - return {}; - } - catch (...) - { - preprocessOptions.logger.log("Unknown exception caught!",system::ILogger::ELL_ERROR); - return {}; - } + core::string resolvedString = nbl::wave::resolveString(code, preprocessOptions, bool(dependencies) /* if dependencies were passed, we assume we want caching*/, + [&dxc_compile_flags_override, &stage, &dependencies](nbl::wave::context& context) -> void + { + if (context.get_hooks().m_dxc_compile_flags_override.size() != 0) + dxc_compile_flags_override = context.get_hooks().m_dxc_compile_flags_override; + + // pragma overrides what we passed in + if (context.get_hooks().m_pragmaStage != IShader::E_SHADER_STAGE::ESS_UNKNOWN) + stage = context.get_hooks().m_pragmaStage; + + if (dependencies) { + *dependencies = std::move(context.get_dependencies()); + } + } + ); // for debugging cause MSVC doesn't like to show more than 21k LoC in TextVisualizer if constexpr (true) @@ -406,17 +394,6 @@ std::string CHLSLCompiler::preprocessShader(std::string&& code, IShader::E_SHADE } } - if (context.get_hooks().m_dxc_compile_flags_override.size() != 0) - dxc_compile_flags_override = context.get_hooks().m_dxc_compile_flags_override; - - // pragma overrides what we passed in - if(context.get_hooks().m_pragmaStage != IShader::E_SHADER_STAGE::ESS_UNKNOWN) - stage = context.get_hooks().m_pragmaStage; - - if (dependencies) { - *dependencies = std::move(context.get_dependencies()); - } - return resolvedString; } @@ -437,6 +414,7 @@ core::smart_refctd_ptr CHLSLCompiler::compileToSPIRV_impl(const std::st } std::vector dxc_compile_flags = {}; IShader::E_SHADER_STAGE stage = options.stage; + auto newCode = preprocessShader(std::string(code), stage, hlslOptions.preprocessorOptions, dxc_compile_flags, dependencies); if (newCode.empty()) return nullptr; diff --git a/src/nbl/asset/utils/CWaveStringResolver.cpp b/src/nbl/asset/utils/CWaveStringResolver.cpp new file mode 100644 index 0000000000..457a2ef5a0 --- /dev/null +++ b/src/nbl/asset/utils/CWaveStringResolver.cpp @@ -0,0 +1,57 @@ +// Copyright (C) 2018-2025 - DevSH Graphics Programming Sp. z O.O. +// This file is part of the "Nabla Engine". +// For conditions of distribution and use, see copyright notice in nabla.h + +//! wave token preprocessing with isolated translation unit optimization +/* + the source has separate optimization flags because of how boost spirit (header only dep) the wave relies on is slow in Debug builds, ABI related + options remain and there is no mismatch, we force agressive inlining and optimizations mostly regardless build configuration by default +*/ + +#include "nbl/asset/utils/IShaderCompiler.h" + +using namespace nbl; +using namespace nbl::asset; + +#include "nbl/asset/utils/waveContext.h" + +namespace nbl::wave +{ + std::string resolveString(std::string& code, const nbl::asset::IShaderCompiler::SPreprocessorOptions& preprocessOptions, bool withCaching, std::function post) + { + nbl::wave::context context(code.begin(), code.end(), preprocessOptions.sourceIdentifier.data(), { preprocessOptions }); + context.set_caching(withCaching); + context.add_macro_definition("__HLSL_VERSION"); + + // instead of defining extraDefines as "NBL_GLSL_LIMIT_MAX_IMAGE_DIMENSION_1D 32768", + // now define them as "NBL_GLSL_LIMIT_MAX_IMAGE_DIMENSION_1D=32768" + // to match boost wave syntax + // https://www.boost.org/doc/libs/1_82_0/libs/wave/doc/class_reference_context.html#:~:text=Maintain%20defined%20macros-,add_macro_definition,-bool%20add_macro_definition + for (const auto& define : preprocessOptions.extraDefines) + context.add_macro_definition(define.identifier.data() + core::string("=") + define.definition.data()); + + // preprocess + core::string resolvedString; + try + { + auto stream = std::stringstream(); + for (auto i= context.begin(); i!= context.end(); i++) + stream << i->get_value(); + resolvedString = stream.str(); + } + catch (boost::wave::preprocess_exception& e) + { + preprocessOptions.logger.log("%s exception caught. %s [%s:%d:%d]",system::ILogger::ELL_ERROR,e.what(),e.description(),e.file_name(),e.line_no(),e.column_no()); + return {}; + } + catch (...) + { + preprocessOptions.logger.log("Unknown exception caught!",system::ILogger::ELL_ERROR); + return {}; + } + + post(context); + + return resolvedString; + } +} \ No newline at end of file diff --git a/src/nbl/asset/utils/waveContext.h b/src/nbl/asset/utils/waveContext.h index a374391576..f6c0014e39 100644 --- a/src/nbl/asset/utils/waveContext.h +++ b/src/nbl/asset/utils/waveContext.h @@ -5,17 +5,11 @@ #define _NBL_ASSET_WAVE_CONTEXT_H_INCLUDED_ //! This file is not supposed to be included in user-accesible header files -#define BOOST_WAVE_ENABLE_COMMANDLINE_MACROS 1 -#define BOOST_WAVE_SUPPORT_PRAGMA_ONCE 0 -#define BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES 1 -#define BOOST_WAVE_SERIALIZATION 0 -#define BOOST_WAVE_SUPPORT_INCLUDE_NEXT 0 #include #include #include -#include "nbl/core/declarations.h" - +#include "nbl/asset/utils/IShaderCompiler.h" namespace nbl::wave { @@ -48,8 +42,8 @@ struct load_to_string final struct preprocessing_hooks final : public boost::wave::context_policies::default_preprocessing_hooks { - preprocessing_hooks(const IShaderCompiler::SPreprocessorOptions& _preprocessOptions) - : m_includeFinder(_preprocessOptions.includeFinder), m_logger(_preprocessOptions.logger), m_pragmaStage(IShader::E_SHADER_STAGE::ESS_UNKNOWN), m_dxc_compile_flags_override() + preprocessing_hooks(const nbl::asset::IShaderCompiler::SPreprocessorOptions& _preprocessOptions) + : m_includeFinder(_preprocessOptions.includeFinder), m_logger(_preprocessOptions.logger), m_pragmaStage(nbl::asset::IShader::E_SHADER_STAGE::ESS_UNKNOWN), m_dxc_compile_flags_override() { hash_token_occurences = 0; } @@ -156,9 +150,9 @@ struct preprocessing_hooks final : public boost::wave::context_policies::default } - const IShaderCompiler::CIncludeFinder* m_includeFinder; + const asset::IShaderCompiler::CIncludeFinder* m_includeFinder; system::logger_opt_ptr m_logger; - IShader::E_SHADER_STAGE m_pragmaStage; + asset::IShader::E_SHADER_STAGE m_pragmaStage; int hash_token_occurences; std::vector m_dxc_compile_flags_override; diff --git a/tools/nsc/main.cpp b/tools/nsc/main.cpp index f659b1adb4..c4ce43b326 100644 --- a/tools/nsc/main.cpp +++ b/tools/nsc/main.cpp @@ -225,12 +225,17 @@ class ShaderCompiler final : public system::IApplicationFramework m_logger->log("Error. Loaded shader file content is not HLSL.", ILogger::ELL_ERROR); return false; } + + auto start = std::chrono::high_resolution_clock::now(); auto compilation_result = compile_shader(shader.get(), shaderStage, file_to_compile); + auto end = std::chrono::high_resolution_clock::now(); // writie compiled shader to file as bytes if (compilation_result) { m_logger->log("Shader compilation successful.", ILogger::ELL_INFO); + const auto took = std::to_string(std::chrono::duration_cast(end - start).count()); + m_logger->log("Took %s ms.", ILogger::ELL_PERFORMANCE, took.c_str()); { const auto location = std::filesystem::path(output_filepath); const auto parentDirectory = location.parent_path(); From 439177e0d68407094c9f5eb5b1cfa8f57d05d46e Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Mon, 30 Jun 2025 11:10:45 +0200 Subject: [PATCH 07/13] save plan & thoughts in comments --- src/nbl/asset/utils/CWaveStringResolver.cpp | 27 +++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/nbl/asset/utils/CWaveStringResolver.cpp b/src/nbl/asset/utils/CWaveStringResolver.cpp index 457a2ef5a0..864be22ef0 100644 --- a/src/nbl/asset/utils/CWaveStringResolver.cpp +++ b/src/nbl/asset/utils/CWaveStringResolver.cpp @@ -8,6 +8,33 @@ options remain and there is no mismatch, we force agressive inlining and optimizations mostly regardless build configuration by default */ +/* + Arek leaving thoughts, TODO: + + in NBL_WAVE_STRING_RESOLVER_TU_DEBUG_OPTIMISATION mode enabled -> here in this TU do + + #define _ITERATOR_DEBUG_LEVEL 0 + #define _HAS_ITERATOR_DEBUGGING 0 + + and allow Nabla to mismatch debug iterator *on purpose* by + + #define _ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH + + in Debug/RWDI + + then make resolveString full C API with raw in/out pointers and bytes out pointer, + with mismtach we must be very careful about memory ownership as STL stuff will have + different struct layouts and its easy to make a crash, we will have extra memcpy and + deallocation but as a trade each config will have almost the same preprocessing perf + which matters for our NSC integration + + then we can think to make use of existing shader cache and maybe consider HLSL PCH + which NSC would inject into each input + + NOTE: this approach allows to do all in single Nabla module, no extra proxy/fake shared DLL needed! + NOTE: yep I know I have currently a callback for which context size will differ accross TUs afterwards but will think about it +*/ + #include "nbl/asset/utils/IShaderCompiler.h" using namespace nbl; From 09ec4b4c4d3543f7b2d482a0d8cf3209f95ce603 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Thu, 3 Jul 2025 20:39:01 +0200 Subject: [PATCH 08/13] rename NBL_REGISTER_SPIRV_SHADERS to NBL_REGISTER_BUILD_MOUNT_POINT, make it more general purpose, update examples_tests submodule --- cmake/common.cmake | 42 ++++++++++++++++++++++++++---------------- examples_tests | 2 +- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/cmake/common.cmake b/cmake/common.cmake index 2ec9e8cfc4..ccc24076f7 100755 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -1228,35 +1228,39 @@ function(NBL_ADJUST_FOLDERS NS) endforeach() endfunction() -function(NBL_REGISTER_SPIRV_SHADERS) - cmake_parse_arguments(IMPL "" "DISCARD;LINK_TO;MOUNT_POINT_DEFINE" "PERMUTE;REQUIRED;ARCHIVE;INPUTS" ${ARGN}) - - if(NOT IMPL_MOUNT_POINT_DEFINE) - message(FATAL_ERROR "MOUNT_POINT_DEFINE argument missing!") - endif() +function(NBL_REGISTER_BUILD_MOUNT_POINT) + cmake_parse_arguments(IMPL "" "DISCARD;LINK_TO" "PERMUTE;REQUIRED;ARCHIVE;SHADERS;BUILTINS" ${ARGN}) if(NOT IMPL_ARCHIVE) message(FATAL_ERROR "ARCHIVE arguments missing!") endif() - cmake_parse_arguments(IMPL "" "TARGET;INPUT_DIRECTORY;NAMESPACE;PREFIX" "" ${IMPL_ARCHIVE}) + cmake_parse_arguments(IMPL "" "TARGET;INPUT_DIRECTORY;OUTPUT_DIRECTORY;NAMESPACE;PREFIX;MOUNT_POINT_DEFINE" "" ${IMPL_ARCHIVE}) if(NOT IMPL_TARGET) message(FATAL_ERROR "Missing TARGET argument in ARCHIVE specification!") endif() if(NOT IMPL_INPUT_DIRECTORY) - message(FATAL_ERROR "Missing INPUT_DIRECTORY argument in ARCHIVE specification!") + set(IMPL_INPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") + endif() + + if(NOT IMPL_OUTPUT_DIRECTORY) + set(IMPL_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") endif() if(NOT IMPL_NAMESPACE) message(FATAL_ERROR "Missing NAMESPACE argument in ARCHIVE specification!") endif() + if(NOT IMPL_MOUNT_POINT_DEFINE) + message(FATAL_ERROR "MOUNT_POINT_DEFINE argument missing!") + endif() + set(_BUNDLE_ARCHIVE_ABSOLUTE_PATH_ ${IMPL_PREFIX}) - get_filename_component(_BUNDLE_SEARCH_DIRECTORY_ "${CMAKE_CURRENT_BINARY_DIR}/builtin/spirv/shaders/mount-point" ABSOLUTE) - get_filename_component(_OUTPUT_DIRECTORY_SOURCE_ "${CMAKE_CURRENT_BINARY_DIR}/builtin/spirv/archive/src" ABSOLUTE) - get_filename_component(_OUTPUT_DIRECTORY_HEADER_ "${CMAKE_CURRENT_BINARY_DIR}/builtin/spirv/archive/include" ABSOLUTE) + get_filename_component(_BUNDLE_SEARCH_DIRECTORY_ "${IMPL_OUTPUT_DIRECTORY}" ABSOLUTE) + get_filename_component(_OUTPUT_DIRECTORY_SOURCE_ "${IMPL_OUTPUT_DIRECTORY}/archive/src" ABSOLUTE) + get_filename_component(_OUTPUT_DIRECTORY_HEADER_ "${IMPL_OUTPUT_DIRECTORY}/archive/include" ABSOLUTE) set(_BUILTIN_RESOURCES_NAMESPACE_ ${IMPL_NAMESPACE}) set(_LINK_MODE_ STATIC) @@ -1346,23 +1350,23 @@ glue device permutation caps config with input # create compile rules for given input with permuted config set(i 0) - list(LENGTH IMPL_INPUTS LEN) + list(LENGTH IMPL_SHADERS LEN) while(i LESS LEN) - list(GET IMPL_INPUTS ${i} TOKEN) + list(GET IMPL_SHADERS ${i} TOKEN) if(TOKEN STREQUAL "KEY") math(EXPR i "${i} + 1") - list(GET IMPL_INPUTS ${i} FILEPATH) + list(GET IMPL_SHADERS ${i} FILEPATH) set(COMPILE_OPTIONS "") math(EXPR i "${i} + 1") - list(GET IMPL_INPUTS ${i} NEXT) + list(GET IMPL_SHADERS ${i} NEXT) if(NOT NEXT STREQUAL "COMPILE_OPTIONS") message(FATAL_ERROR "Expected COMPILE_OPTIONS after KEY ${FILEPATH}") endif() math(EXPR i "${i} + 1") while(i LESS LEN) - list(GET IMPL_INPUTS ${i} ARG) + list(GET IMPL_SHADERS ${i} ARG) if(ARG STREQUAL "KEY") break() endif() @@ -1457,6 +1461,12 @@ glue device permutation caps config with input endforeach() if(NBL_EMBED_BUILTIN_RESOURCES) + if(IMPL_BUILTINS) + foreach(IT ${IMPL_BUILTINS}) + LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED ${IT}) + endforeach() + endif() + ADD_CUSTOM_BUILTIN_RESOURCES(${IMPL_TARGET} NBL_RESOURCES_TO_EMBED "${_BUNDLE_SEARCH_DIRECTORY_}" "${_BUNDLE_ARCHIVE_ABSOLUTE_PATH_}" "${_BUILTIN_RESOURCES_NAMESPACE_}" "${_OUTPUT_DIRECTORY_HEADER_}" "${_OUTPUT_DIRECTORY_SOURCE_}" "${_LINK_MODE_}") else() add_library(${IMPL_TARGET} INTERFACE) diff --git a/examples_tests b/examples_tests index 9eb0615c71..60bdf1bb1e 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 9eb0615c71330e3b09e3cb8bc50b7b7e2fb6f3a6 +Subproject commit 60bdf1bb1e37465fac44c8f865e63189f497cfb1 From b8c2ca19e91d9ac0fbee7a362fe3465db61883ff Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Thu, 3 Jul 2025 21:12:56 +0200 Subject: [PATCH 09/13] handle DEPENDS in NBL_REGISTER_BUILD_MOUNT_POINT, update examples_tests --- cmake/common.cmake | 44 +++++++++++++++++++++++++++++--------------- examples_tests | 2 +- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/cmake/common.cmake b/cmake/common.cmake index ccc24076f7..1194154d77 100755 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -1267,12 +1267,6 @@ function(NBL_REGISTER_BUILD_MOUNT_POINT) get_filename_component(BUILTIN_ARCHIVE_INPUT_ABS_ENTRY "${IMPL_INPUT_DIRECTORY}" ABSOLUTE) set(BUILTIN_KEY_ENTRY_ABS "${BUILTIN_ARCHIVE_INPUT_ABS_ENTRY}/${_BUNDLE_ARCHIVE_ABSOLUTE_PATH_}") - - # REMOVE IT AND ADD "DEPENDS" to INPUTS - # file(GLOB_RECURSE _DEPENDS_ON_ CONFIGURE_DEPENDS "${BUILTIN_KEY_ENTRY_ABS}/*.hlsl") - # list(FILTER _DEPENDS_ON_ EXCLUDE REGEX /preprocessed.hlsl) - # and maybe extra DEPENDS shared for all inputs - #################### set(SPIRV_OUTPUT_ARCHIVE_KEY_ABS_ENTRY_DIR "${_BUNDLE_SEARCH_DIRECTORY_}/${_BUNDLE_ARCHIVE_ABSOLUTE_PATH_}") @@ -1357,6 +1351,7 @@ glue device permutation caps config with input math(EXPR i "${i} + 1") list(GET IMPL_SHADERS ${i} FILEPATH) set(COMPILE_OPTIONS "") + set(DEPENDS_ON "") math(EXPR i "${i} + 1") list(GET IMPL_SHADERS ${i} NEXT) @@ -1367,31 +1362,46 @@ glue device permutation caps config with input while(i LESS LEN) list(GET IMPL_SHADERS ${i} ARG) - if(ARG STREQUAL "KEY") + if(ARG STREQUAL "KEY" OR ARG STREQUAL "DEPENDS") break() endif() list(APPEND COMPILE_OPTIONS "${ARG}") math(EXPR i "${i} + 1") endwhile() + if(i LESS LEN) + list(GET IMPL_SHADERS ${i} NEXT_TOKEN) + if(NEXT_TOKEN STREQUAL "DEPENDS") + math(EXPR i "${i} + 1") + while(i LESS LEN) + list(GET IMPL_SHADERS ${i} ARG) + if(ARG STREQUAL "KEY") + break() + endif() + list(APPEND DEPENDS_ON "${ARG}") + math(EXPR i "${i} + 1") + endwhile() + endif() + endif() + set(IMPL_KEY ${FILEPATH}) set(TARGET_KEY "${IMPL_KEY}${POSTFIX_ACCESS_KEY}${KEY_EXTENSION}") if(IMPL_DISCARD AND "${POSTFIX_ACCESS_KEY}" MATCHES "${IMPL_DISCARD}") if(NBL_LOG_VERBOSE) - message(STATUS "[Nabla Builtin SPIRV]: Discarded \"${TARGET_KEY}\" key for ${IMPL_TARGET}") + message(STATUS "[Nabla Builtin]: Discarded \"${TARGET_KEY}\" key for ${IMPL_TARGET} target") endif() continue() endif() if(NBL_LOG_VERBOSE) - message(STATUS "[Nabla Builtin SPIRV]: Registered \"${TARGET_KEY}\" key ${IMPL_TARGET}") + message(STATUS "[Nabla Builtin]: Registered \"${TARGET_KEY}\" key for ${IMPL_TARGET} target") endif() set(TARGET_INPUT "${BUILTIN_KEY_ENTRY_ABS}/${IMPL_KEY}") list(APPEND REQUESTED_INPUTS "${TARGET_INPUT}") - set(TAGET_OUTPUT "${SPIRV_OUTPUT_ARCHIVE_KEY_ABS_ENTRY_DIR}/${TARGET_KEY}") - list(APPEND SPIRV_OUTPUTS "${TAGET_OUTPUT}") + set(TARGET_OUTPUT "${SPIRV_OUTPUT_ARCHIVE_KEY_ABS_ENTRY_DIR}/${TARGET_KEY}") + list(APPEND SPIRV_OUTPUTS "${TARGET_OUTPUT}") # doing as workaround for (**), dynamic define include could be better because then I don't have to generate intermediate files with glue at configure time set(INT_INPUT "${SPIRV_OUTPUT_ARCHIVE_KEY_ABS_ENTRY_DIR}/.int/${TARGET_KEY}") @@ -1437,16 +1447,16 @@ glue device permutation caps config with input set(NBL_NSC_COMPILE_COMMAND "$" - -Fc "${TAGET_OUTPUT}" + -Fc "${TARGET_OUTPUT}" ${COMPILE_OPTIONS} ${REQUIRED_OPTIONS} # "-DNBL_DYMANIC_INCLUDE=<${TARGET_INPUT}>" # (**)! "${INT_INPUT}" ) - add_custom_command(OUTPUT "${TAGET_OUTPUT}" + add_custom_command(OUTPUT "${TARGET_OUTPUT}" COMMAND ${NBL_NSC_COMPILE_COMMAND} - DEPENDS ${_DEPENDS_ON_} ${INT_INPUT} - COMMENT "Creating ${TAGET_OUTPUT}" + DEPENDS ${DEPENDS_ON} ${INT_INPUT} + COMMENT "Creating ${TARGET_OUTPUT}" VERBATIM COMMAND_EXPAND_LISTS ) @@ -1463,6 +1473,10 @@ glue device permutation caps config with input if(NBL_EMBED_BUILTIN_RESOURCES) if(IMPL_BUILTINS) foreach(IT ${IMPL_BUILTINS}) + if(NBL_LOG_VERBOSE) + message(STATUS "[Nabla Builtin]: Registered \"${IT}\" key for ${IMPL_TARGET} target") + endif() + LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED ${IT}) endforeach() endif() diff --git a/examples_tests b/examples_tests index 60bdf1bb1e..767e6c4e46 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 60bdf1bb1e37465fac44c8f865e63189f497cfb1 +Subproject commit 767e6c4e46e1e5c5ab4ec827f94f8886f705eb33 From bed4f09be5a72b2d033b3875578ece6bb0ba6fca Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Thu, 3 Jul 2025 21:58:48 +0200 Subject: [PATCH 10/13] move targetSpirvVersion from SCompilerOptions to SPreprocessorOptions, define `__SPIRV_MAJOR_VERSION__` and `__SPIRV_MINOR_VERSION__`, update examples_tests submodules --- examples_tests | 2 +- include/nbl/asset/utils/IShaderCompiler.h | 18 +++++++++++++----- src/nbl/asset/utils/CGLSLCompiler.cpp | 2 +- src/nbl/asset/utils/CHLSLCompiler.cpp | 6 +++--- src/nbl/asset/utils/CWaveStringResolver.cpp | 8 ++++++-- src/nbl/video/ILogicalDevice.cpp | 2 +- 6 files changed, 25 insertions(+), 13 deletions(-) diff --git a/examples_tests b/examples_tests index 767e6c4e46..c573951ec3 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 767e6c4e46e1e5c5ab4ec827f94f8886f705eb33 +Subproject commit c573951ec38a3aa187b6ac8724cff1c9d293631c diff --git a/include/nbl/asset/utils/IShaderCompiler.h b/include/nbl/asset/utils/IShaderCompiler.h index d4b8e50119..30d37f36c7 100644 --- a/include/nbl/asset/utils/IShaderCompiler.h +++ b/include/nbl/asset/utils/IShaderCompiler.h @@ -118,6 +118,17 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted std::string_view definition; }; + // + using E_SPIRV_VERSION = nbl::hlsl::SpirvVersion; + + static inline constexpr uint32_t getSpirvMajor(E_SPIRV_VERSION version) { + return (version >> 16u) & 0xFFu; + } + + static inline constexpr uint32_t getSpirvMinor(E_SPIRV_VERSION version) { + return (version >> 8u) & 0xFFu; + } + // struct SPreprocessorOptions { @@ -125,11 +136,9 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted system::logger_opt_ptr logger = nullptr; const CIncludeFinder* includeFinder = nullptr; std::span extraDefines = {}; + E_SPIRV_VERSION targetSpirvVersion = E_SPIRV_VERSION::ESV_1_6; }; - // - using E_SPIRV_VERSION = nbl::hlsl::SpirvVersion; - // https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/SPIR-V.rst#debugging enum class E_DEBUG_INFO_FLAGS : uint8_t { @@ -169,7 +178,6 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted virtual IShader::E_CONTENT_TYPE getCodeContentType() const { return IShader::E_CONTENT_TYPE::ECT_UNKNOWN; }; IShader::E_SHADER_STAGE stage = IShader::E_SHADER_STAGE::ESS_ALL_OR_LIBRARY; - E_SPIRV_VERSION targetSpirvVersion = E_SPIRV_VERSION::ESV_1_6; const ISPIRVOptimizer* spirvOptimizer = nullptr; core::bitflag debugInfoFlags = core::bitflag(E_DEBUG_INFO_FLAGS::EDIF_SOURCE_BIT) | E_DEBUG_INFO_FLAGS::EDIF_TOOL_BIT; SPreprocessorOptions preprocessorOptions = {}; @@ -301,7 +309,7 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted // Only SEntry should instantiate this struct SCompilerArgs(const SCompilerOptions& options) - : stage(options.stage), targetSpirvVersion(options.targetSpirvVersion), debugInfoFlags(options.debugInfoFlags), preprocessorArgs(options.preprocessorOptions) + : stage(options.stage), targetSpirvVersion(options.preprocessorOptions.targetSpirvVersion), debugInfoFlags(options.debugInfoFlags), preprocessorArgs(options.preprocessorOptions) { if (options.spirvOptimizer) { for (auto pass : options.spirvOptimizer->getPasses()) diff --git a/src/nbl/asset/utils/CGLSLCompiler.cpp b/src/nbl/asset/utils/CGLSLCompiler.cpp index 723bad2a7b..a593a11597 100644 --- a/src/nbl/asset/utils/CGLSLCompiler.cpp +++ b/src/nbl/asset/utils/CGLSLCompiler.cpp @@ -266,7 +266,7 @@ core::smart_refctd_ptr CGLSLCompiler::compileToSPIRV_impl(const std::st shaderc::Compiler comp; shaderc::CompileOptions shadercOptions; //default options - shadercOptions.SetTargetSpirv(static_cast(glslOptions.targetSpirvVersion)); + shadercOptions.SetTargetSpirv(static_cast(glslOptions.preprocessorOptions.targetSpirvVersion)); const shaderc_shader_kind stage = glslOptions.stage == IShader::E_SHADER_STAGE::ESS_UNKNOWN ? shaderc_glsl_infer_from_source : ESStoShadercEnum(glslOptions.stage); if (glslOptions.debugInfoFlags.value != IShaderCompiler::E_DEBUG_INFO_FLAGS::EDIF_NONE) shadercOptions.SetGenerateDebugInfo(); diff --git a/src/nbl/asset/utils/CHLSLCompiler.cpp b/src/nbl/asset/utils/CHLSLCompiler.cpp index fdfabbacad..4420a4d319 100644 --- a/src/nbl/asset/utils/CHLSLCompiler.cpp +++ b/src/nbl/asset/utils/CHLSLCompiler.cpp @@ -346,7 +346,7 @@ static DxcCompilationResult dxcCompile(const CHLSLCompiler* compiler, nbl::asset namespace nbl::wave { - extern nbl::core::string resolveString(std::string& code, const IShaderCompiler::SPreprocessorOptions& preprocessOptions, bool withCaching, std::function post); + extern nbl::core::string preprocess(std::string& code, const IShaderCompiler::SPreprocessorOptions& preprocessOptions, bool withCaching, std::function post); } std::string CHLSLCompiler::preprocessShader(std::string&& code, IShader::E_SHADER_STAGE& stage, const SPreprocessorOptions& preprocessOptions, std::vector& dxc_compile_flags_override, std::vector* dependencies) const @@ -365,7 +365,7 @@ std::string CHLSLCompiler::preprocessShader(std::string&& code, IShader::E_SHADE } // preprocess - core::string resolvedString = nbl::wave::resolveString(code, preprocessOptions, bool(dependencies) /* if dependencies were passed, we assume we want caching*/, + core::string resolvedString = nbl::wave::preprocess(code, preprocessOptions, bool(dependencies) /* if dependencies were passed, we assume we want caching*/, [&dxc_compile_flags_override, &stage, &dependencies](nbl::wave::context& context) -> void { if (context.get_hooks().m_dxc_compile_flags_override.size() != 0) @@ -435,7 +435,7 @@ core::smart_refctd_ptr CHLSLCompiler::compileToSPIRV_impl(const std::st for (size_t i = 0; i < required.size(); i++) arguments.push_back(required[i]); // - switch (options.targetSpirvVersion) + switch (options.preprocessorOptions.targetSpirvVersion) { case hlsl::SpirvVersion::ESV_1_4: arguments.push_back(L"-fspv-target-env=vulkan1.1spirv1.4"); diff --git a/src/nbl/asset/utils/CWaveStringResolver.cpp b/src/nbl/asset/utils/CWaveStringResolver.cpp index 864be22ef0..77207f84ca 100644 --- a/src/nbl/asset/utils/CWaveStringResolver.cpp +++ b/src/nbl/asset/utils/CWaveStringResolver.cpp @@ -22,7 +22,7 @@ in Debug/RWDI - then make resolveString full C API with raw in/out pointers and bytes out pointer, + then make preprocess full C API with raw in/out pointers and bytes out pointer, with mismtach we must be very careful about memory ownership as STL stuff will have different struct layouts and its easy to make a crash, we will have extra memcpy and deallocation but as a trade each config will have almost the same preprocessing perf @@ -33,6 +33,8 @@ NOTE: this approach allows to do all in single Nabla module, no extra proxy/fake shared DLL needed! NOTE: yep I know I have currently a callback for which context size will differ accross TUs afterwards but will think about it + + or ignore it and take care of NSC special target creating global HLSL PCH injected into each registered input */ #include "nbl/asset/utils/IShaderCompiler.h" @@ -44,11 +46,13 @@ using namespace nbl::asset; namespace nbl::wave { - std::string resolveString(std::string& code, const nbl::asset::IShaderCompiler::SPreprocessorOptions& preprocessOptions, bool withCaching, std::function post) + std::string preprocess(std::string& code, const nbl::asset::IShaderCompiler::SPreprocessorOptions& preprocessOptions, bool withCaching, std::function post) { nbl::wave::context context(code.begin(), code.end(), preprocessOptions.sourceIdentifier.data(), { preprocessOptions }); context.set_caching(withCaching); context.add_macro_definition("__HLSL_VERSION"); + context.add_macro_definition("__SPIRV_MAJOR_VERSION__=" + std::to_string(IShaderCompiler::getSpirvMajor(preprocessOptions.targetSpirvVersion))); + context.add_macro_definition("__SPIRV_MINOR_VERSION__=" + std::to_string(IShaderCompiler::getSpirvMinor(preprocessOptions.targetSpirvVersion))); // instead of defining extraDefines as "NBL_GLSL_LIMIT_MAX_IMAGE_DIMENSION_1D 32768", // now define them as "NBL_GLSL_LIMIT_MAX_IMAGE_DIMENSION_1D=32768" diff --git a/src/nbl/video/ILogicalDevice.cpp b/src/nbl/video/ILogicalDevice.cpp index 983daed190..a21e00e303 100644 --- a/src/nbl/video/ILogicalDevice.cpp +++ b/src/nbl/video/ILogicalDevice.cpp @@ -364,7 +364,7 @@ core::smart_refctd_ptr ILogicalDevice::compileShader(const SShad asset::IShaderCompiler::E_DEBUG_INFO_FLAGS::EDIF_SOURCE_BIT | asset::IShaderCompiler::E_DEBUG_INFO_FLAGS::EDIF_TOOL_BIT; commonCompileOptions.spirvOptimizer = creationParams.optimizer; - commonCompileOptions.targetSpirvVersion = m_physicalDevice->getLimits().spirvVersion; + commonCompileOptions.preprocessorOptions.targetSpirvVersion = m_physicalDevice->getLimits().spirvVersion; commonCompileOptions.readCache = creationParams.readCache; commonCompileOptions.writeCache = creationParams.writeCache; From 6dec863ee6eff1a3efc3c7ee5855dc9100ba754a Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sun, 6 Jul 2025 20:28:18 +0200 Subject: [PATCH 11/13] refactor SPIRV tool, split into 2 functions, have meta lists, separate incremental updates for NSC rules and single step for registering archive --- cmake/common.cmake | 450 ++++++++++++++++++++++----------------------- examples_tests | 2 +- 2 files changed, 221 insertions(+), 231 deletions(-) diff --git a/cmake/common.cmake b/cmake/common.cmake index 1194154d77..f265078b04 100755 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -1207,12 +1207,11 @@ macro(NBL_WAIT_FOR SLEEP_DURATION) execute_process(COMMAND ${CMAKE_COMMAND} -E sleep ${SLEEP_DURATION}) endmacro() -# helper macro for calling docker, takes args as a list of strings macro(NBL_DOCKER) execute_process(COMMAND ${DOCKER_EXECUTABLE} ${ARGN} RESULT_VARIABLE DOCKER_EXIT_CODE OUTPUT_VARIABLE DOCKER_OUTPUT_VAR - ) + ) endmacro() function(NBL_ADJUST_FOLDERS NS) @@ -1228,56 +1227,40 @@ function(NBL_ADJUST_FOLDERS NS) endforeach() endfunction() -function(NBL_REGISTER_BUILD_MOUNT_POINT) - cmake_parse_arguments(IMPL "" "DISCARD;LINK_TO" "PERMUTE;REQUIRED;ARCHIVE;SHADERS;BUILTINS" ${ARGN}) - - if(NOT IMPL_ARCHIVE) - message(FATAL_ERROR "ARCHIVE arguments missing!") - endif() - - cmake_parse_arguments(IMPL "" "TARGET;INPUT_DIRECTORY;OUTPUT_DIRECTORY;NAMESPACE;PREFIX;MOUNT_POINT_DEFINE" "" ${IMPL_ARCHIVE}) - - if(NOT IMPL_TARGET) - message(FATAL_ERROR "Missing TARGET argument in ARCHIVE specification!") - endif() - - if(NOT IMPL_INPUT_DIRECTORY) - set(IMPL_INPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") - endif() - - if(NOT IMPL_OUTPUT_DIRECTORY) - set(IMPL_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") - endif() - - if(NOT IMPL_NAMESPACE) - message(FATAL_ERROR "Missing NAMESPACE argument in ARCHIVE specification!") - endif() - - if(NOT IMPL_MOUNT_POINT_DEFINE) - message(FATAL_ERROR "MOUNT_POINT_DEFINE argument missing!") - endif() - - set(_BUNDLE_ARCHIVE_ABSOLUTE_PATH_ ${IMPL_PREFIX}) - get_filename_component(_BUNDLE_SEARCH_DIRECTORY_ "${IMPL_OUTPUT_DIRECTORY}" ABSOLUTE) - get_filename_component(_OUTPUT_DIRECTORY_SOURCE_ "${IMPL_OUTPUT_DIRECTORY}/archive/src" ABSOLUTE) - get_filename_component(_OUTPUT_DIRECTORY_HEADER_ "${IMPL_OUTPUT_DIRECTORY}/archive/include" ABSOLUTE) +function(NBL_PARSE_REQUIRED PREFIX) + set(VARIADIC ${ARGV}) + list(POP_FRONT VARIADIC VARIADIC) + foreach(ARG ${VARIADIC}) + set(V ${PREFIX}_${ARG}) + if(NOT ${V}) + message(FATAL_ERROR "\"${ARG}\" argument missing!") + endif() + endforeach() +endfunction() - set(_BUILTIN_RESOURCES_NAMESPACE_ ${IMPL_NAMESPACE}) - set(_LINK_MODE_ STATIC) +define_property(SOURCE PROPERTY NBL_SPIRV_REGISTERED_INPUT + BRIEF_DOCS "Absolute path to input shader which will be glued with device permutation config caps auto-gen file using #include directive, used as part of NSC compile rule to produce SPIRV output" +) - get_filename_component(BUILTIN_ARCHIVE_INPUT_ABS_ENTRY "${IMPL_INPUT_DIRECTORY}" ABSOLUTE) - set(BUILTIN_KEY_ENTRY_ABS "${BUILTIN_ARCHIVE_INPUT_ABS_ENTRY}/${_BUNDLE_ARCHIVE_ABSOLUTE_PATH_}") +define_property(SOURCE PROPERTY NBL_SPIRV_PERMUTATION_CONFIG + BRIEF_DOCS "Absolute path to intermediate config file, used as part of NSC compile rule to produce SPIRV output" + FULL_DOCS "The file is auto-generated at configuration time, contains DeviceConfigCaps struct with permuted device caps after which #include directive glues it with an input shader" +) - set(SPIRV_OUTPUT_ARCHIVE_KEY_ABS_ENTRY_DIR "${_BUNDLE_SEARCH_DIRECTORY_}/${_BUNDLE_ARCHIVE_ABSOLUTE_PATH_}") +define_property(TARGET PROPERTY NBL_SPIRV_OUTPUTS + BRIEF_DOCS "Absolute paths to SPIRV outputs, part of NSC compile rules" +) - set(DEVICE_CONFIG_ENTRY_DIR "${_BUNDLE_SEARCH_DIRECTORY_}/PermutationCaps") - set(DEVICE_CONFIG_TEMPLATE_PATH "${DEVICE_CONFIG_ENTRY_DIR}/DeviceConfig.hlsl") - file(REMOVE_RECURSE "${DEVICE_CONFIG_ENTRY_DIR}/") +# NBL_SPIRV_OUTPUT = NBL_SPIRV_BINARY_DIR/NBL_SPIRV_ACCESS_KEY +define_property(SOURCE PROPERTY NBL_SPIRV_BINARY_DIR) +define_property(SOURCE PROPERTY NBL_SPIRV_ACCESS_KEY) - set(DEVICE_CONFIG_VIEW +function(NBL_CREATE_NSC_COMPILE_RULES) + set(COMMENT "this code has been autogenerated with Nabla CMake NBL_CREATE_HLSL_COMPILE_RULES utility") + set(DEVICE_CONFIG_VIEW [=[ -// -> this code has been autogenerated! +// -> @COMMENT@! #ifndef _PERMUTATION_CAPS_AUTO_GEN_GLOBALS_INCLUDED_ #define _PERMUTATION_CAPS_AUTO_GEN_GLOBALS_INCLUDED_ #ifdef __HLSL_VERSION @@ -1286,230 +1269,237 @@ struct DeviceConfigCaps { @CAPS_EVAL@ }; + +#include "@TARGET_INPUT@" + #endif // __HLSL_VERSION #endif // _PERMUTATION_CAPS_AUTO_GEN_GLOBALS_INCLUDED_ -// <- this code has been autogenerated! - -/* -note: (**) -we have a bug and I cannot use -D to create -define with dxc options, it gets ignored, so -temporary I will create .int input files to -glue device permutation caps config with input - -#ifndef NBL_DYMANIC_INCLUDE -#error "NBL_DYMANIC_INCLUDE must be defined!" -#endif // NBL_DYMANIC_INCLUDE - -// proxy HLSL input with #define -#include NBL_DYMANIC_INCLUDE -*/ -]=] -) - set(KEY_EXTENSION .spv) +// <- @COMMENT@! + +]=]) + + # would get added by NSC anyway and spam in output + set(REQUIRED_OPTIONS + -HV 202x + -Wno-c++14-extensions + -Wno-gnu-static-float-init + -Wno-c++1z-extensions + -Wno-c++11-extensions + -fvk-use-scalar-layout + -enable-16bit-types + -Zpr + -spirv + -fspv-target-env=vulkan1.3 + ) - if(IMPL_PERMUTE) - list(LENGTH IMPL_PERMUTE KEYS_LENGTH) - math(EXPR TOTAL_INDEX_RANGE "(1 << ${KEYS_LENGTH}) - 1") - else() - set(TOTAL_INDEX_RANGE 0) + if(NOT NBL_EMBED_BUILTIN_RESOURCES) + list(APPEND REQUIRED_OPTIONS + -I "${NBL_ROOT_PATH}/include" + -I "${NBL_ROOT_PATH}/3rdparty/dxc/dxc/external/SPIRV-Headers/include" + -I "${NBL_ROOT_PATH}/3rdparty/boost/superproject/libs/preprocessor/include" + -I "${NBL_ROOT_PATH_BINARY}/src/nbl/device/include" + ) endif() - foreach(INDEX RANGE 0 ${TOTAL_INDEX_RANGE}) - set(BIT_INDEX 0) - unset(CAPS_EVAL) - unset(POSTFIX_ACCESS_KEY) - - foreach(KEY IN LISTS IMPL_PERMUTE) - math(EXPR BIT "((${INDEX} >> ${BIT_INDEX}) & 1)") - if(BIT EQUAL 1) - set(STATE "true") - else() - set(STATE "false") - endif() - string(APPEND POSTFIX_ACCESS_KEY "_${KEY}=${STATE}") - string(APPEND CAPS_EVAL "NBL_CONSTEXPR_STATIC_INLINE bool ${KEY} = ${STATE}; // got permuted\n") - math(EXPR BIT_INDEX "${BIT_INDEX} + 1") - endforeach() - - foreach(KEY IN LISTS IMPL_REQUIRED) - string(APPEND CAPS_EVAL "NBL_CONSTEXPR_STATIC_INLINE bool ${KEY} = true; // always required\n") - endforeach() - - # generate permuted config - set(PERMUTED_DEVICE_CONFIG "${DEVICE_CONFIG_TEMPLATE_PATH}${POSTFIX_ACCESS_KEY}") - list(APPEND DEVICE_CONFIG_FILES "${PERMUTED_DEVICE_CONFIG}") - string(CONFIGURE "${DEVICE_CONFIG_VIEW}" CONFIG_CONTENT @ONLY) - file(WRITE "${PERMUTED_DEVICE_CONFIG}" "${CONFIG_CONTENT}") - - # create compile rules for given input with permuted config - set(i 0) - list(LENGTH IMPL_SHADERS LEN) - while(i LESS LEN) - list(GET IMPL_SHADERS ${i} TOKEN) - if(TOKEN STREQUAL "KEY") - math(EXPR i "${i} + 1") - list(GET IMPL_SHADERS ${i} FILEPATH) - set(COMPILE_OPTIONS "") - set(DEPENDS_ON "") - math(EXPR i "${i} + 1") - - list(GET IMPL_SHADERS ${i} NEXT) - if(NOT NEXT STREQUAL "COMPILE_OPTIONS") - message(FATAL_ERROR "Expected COMPILE_OPTIONS after KEY ${FILEPATH}") - endif() - math(EXPR i "${i} + 1") - - while(i LESS LEN) - list(GET IMPL_SHADERS ${i} ARG) - if(ARG STREQUAL "KEY" OR ARG STREQUAL "DEPENDS") - break() - endif() - list(APPEND COMPILE_OPTIONS "${ARG}") - math(EXPR i "${i} + 1") - endwhile() - - if(i LESS LEN) - list(GET IMPL_SHADERS ${i} NEXT_TOKEN) - if(NEXT_TOKEN STREQUAL "DEPENDS") - math(EXPR i "${i} + 1") - while(i LESS LEN) - list(GET IMPL_SHADERS ${i} ARG) - if(ARG STREQUAL "KEY") - break() - endif() - list(APPEND DEPENDS_ON "${ARG}") - math(EXPR i "${i} + 1") - endwhile() - endif() - endif() + set(REQUIRED_SINGLE_ARGS TARGET BINARY_DIR OUTPUT_VAR INPUTS) + cmake_parse_arguments(IMPL "" "${REQUIRED_SINGLE_ARGS}" "COMMON_OPTIONS" ${ARGV}) + NBL_PARSE_REQUIRED(IMPL ${REQUIRED_SINGLE_ARGS}) - set(IMPL_KEY ${FILEPATH}) - set(TARGET_KEY "${IMPL_KEY}${POSTFIX_ACCESS_KEY}${KEY_EXTENSION}") + if(NOT TARGET ${IMPL_TARGET}) + add_library(${IMPL_TARGET} INTERFACE) + endif() - if(IMPL_DISCARD AND "${POSTFIX_ACCESS_KEY}" MATCHES "${IMPL_DISCARD}") - if(NBL_LOG_VERBOSE) - message(STATUS "[Nabla Builtin]: Discarded \"${TARGET_KEY}\" key for ${IMPL_TARGET} target") - endif() - continue() - endif() + string(JSON JSON_LENGTH LENGTH "${IMPL_INPUTS}") + math(EXPR LAST_INDEX "${JSON_LENGTH} - 1") - if(NBL_LOG_VERBOSE) - message(STATUS "[Nabla Builtin]: Registered \"${TARGET_KEY}\" key for ${IMPL_TARGET} target") - endif() + set(ALL_OUTPUT_KEYS "") - set(TARGET_INPUT "${BUILTIN_KEY_ENTRY_ABS}/${IMPL_KEY}") - list(APPEND REQUESTED_INPUTS "${TARGET_INPUT}") - set(TARGET_OUTPUT "${SPIRV_OUTPUT_ARCHIVE_KEY_ABS_ENTRY_DIR}/${TARGET_KEY}") - list(APPEND SPIRV_OUTPUTS "${TARGET_OUTPUT}") + foreach(INDEX RANGE ${LAST_INDEX}) + string(JSON INPUT GET "${IMPL_INPUTS}" ${INDEX} INPUT) + string(JSON COMPILE_OPTIONS_LENGTH LENGTH "${IMPL_INPUTS}" ${INDEX} COMPILE_OPTIONS) - # doing as workaround for (**), dynamic define include could be better because then I don't have to generate intermediate files with glue at configure time - set(INT_INPUT "${SPIRV_OUTPUT_ARCHIVE_KEY_ABS_ENTRY_DIR}/.int/${TARGET_KEY}") - list(APPEND INT_FILES "${INT_INPUT}") - set(INT_INPUT_VIEW -[=[ + set(COMPILE_OPTIONS "") + math(EXPR LAST_CO "${COMPILE_OPTIONS_LENGTH} - 1") + foreach(COMP_IDX RANGE 0 ${LAST_CO}) + string(JSON COMP_ITEM GET "${IMPL_INPUTS}" ${INDEX} COMPILE_OPTIONS ${COMP_IDX}) + list(APPEND COMPILE_OPTIONS "${COMP_ITEM}") + endforeach() -@INPUT_CONFIG_CONTENT@ + set(DEPENDS_ON "") + string(JSON HAS_DEPENDS TYPE "${IMPL_INPUTS}" ${INDEX} DEPENDS) + if(HAS_DEPENDS STREQUAL "ARRAY") + string(JSON DEPENDS_LENGTH LENGTH "${IMPL_INPUTS}" ${INDEX} DEPENDS) + if(NOT DEPENDS_LENGTH EQUAL 0) + math(EXPR LAST_DEP "${DEPENDS_LENGTH} - 1") + foreach(DEP_IDX RANGE 0 ${LAST_DEP}) + string(JSON DEP_ITEM GET "${IMPL_INPUTS}" ${INDEX} DEPENDS ${DEP_IDX}) + list(APPEND DEPENDS_ON "${DEP_ITEM}") + endforeach() + endif() + endif() -#include "@PERMUTED_DEVICE_CONFIG@" -#include "@TARGET_INPUT@" + get_filename_component(INPUT_NOEXT "${INPUT}" NAME_WLE) + get_filename_component(INPUT_DIR "${INPUT}" DIRECTORY) + set(BASE_KEY "${INPUT_DIR}/${INPUT_NOEXT}.spv") + + set(HAS_CAPS FALSE) + set(CAPS_LENGTH 0) + string(JSON CAPS_TYPE TYPE "${IMPL_INPUTS}" ${INDEX} CAPS) + if(CAPS_TYPE STREQUAL "ARRAY") + string(JSON CAPS_LENGTH LENGTH "${IMPL_INPUTS}" ${INDEX} CAPS) + if(NOT CAPS_LENGTH EQUAL 0) + set(HAS_CAPS TRUE) + endif() + endif() -]=] - ) + set(CAP_NAMES "") + set(CAP_TYPES "") + if(HAS_CAPS) + math(EXPR LAST_CAP "${CAPS_LENGTH} - 1") + foreach(CAP_IDX RANGE 0 ${LAST_CAP}) + string(JSON CAP_NAME GET "${IMPL_INPUTS}" ${INDEX} CAPS ${CAP_IDX} name) + string(JSON CAP_TYPE GET "${IMPL_INPUTS}" ${INDEX} CAPS ${CAP_IDX} type) + string(JSON CAP_VALUES_LENGTH LENGTH "${IMPL_INPUTS}" ${INDEX} CAPS ${CAP_IDX} values) + + set(VALUES "") + math(EXPR LAST_VAL "${CAP_VALUES_LENGTH} - 1") + foreach(VAL_IDX RANGE 0 ${LAST_VAL}) + string(JSON VALUE GET "${IMPL_INPUTS}" ${INDEX} CAPS ${CAP_IDX} values ${VAL_IDX}) + list(APPEND VALUES "${VALUE}") + endforeach() + + set(CAP_VALUES_${CAP_IDX} "${VALUES}") + list(APPEND CAP_NAMES "${CAP_NAME}") + list(APPEND CAP_TYPES "${CAP_TYPE}") + endforeach() + endif() - string(CONFIGURE "${INT_INPUT_VIEW}" INT_CONTENT @ONLY) - file(WRITE "${INT_INPUT}" "${INT_CONTENT}") + list(LENGTH CAP_NAMES NUM_CAPS) + set(TARGET_INPUT "${CMAKE_CURRENT_SOURCE_DIR}/${INPUT}") - set(REQUIRED_INCLUDES - -I "${NBL_ROOT_PATH}/include" - -I "${NBL_ROOT_PATH}/3rdparty/dxc/dxc/external/SPIRV-Headers/include" - -I "${NBL_ROOT_PATH}/3rdparty/boost/superproject/libs/preprocessor/include" - -I "${NBL_ROOT_PATH_BINARY}/src/nbl/device/include" - ) + function(GENERATE_KEYS PREFIX CAP_INDEX CAPS_EVAL_PART) + if(NUM_CAPS EQUAL 0 OR CAP_INDEX EQUAL ${NUM_CAPS}) + set(FINAL_KEY "${BASE_KEY}${PREFIX}") - # would get added by NSC anyway and spam in output - set(REQUIRED_OPTIONS - -HV 202x - -Wno-c++14-extensions - -Wno-gnu-static-float-init - -Wno-c++1z-extensions - -Wno-c++11-extensions - -fvk-use-scalar-layout - -enable-16bit-types - -Zpr - -spirv - -fspv-target-env=vulkan1.3 - ) + set(TARGET_OUTPUT "${IMPL_BINARY_DIR}/${FINAL_KEY}") + set(CONFIG_FILE "${TARGET_OUTPUT}.config") + set(CAPS_EVAL "${CAPS_EVAL_PART}") - if(NOT NBL_EMBED_BUILTIN_RESOURCES) - list(APPEND REQUIRED_OPTIONS ${REQUIRED_INCLUDES}) - endif() + string(CONFIGURE "${DEVICE_CONFIG_VIEW}" CONFIG_CONTENT @ONLY) + file(WRITE "${CONFIG_FILE}" "${CONFIG_CONTENT}") set(NBL_NSC_COMPILE_COMMAND "$" -Fc "${TARGET_OUTPUT}" - ${COMPILE_OPTIONS} ${REQUIRED_OPTIONS} - # "-DNBL_DYMANIC_INCLUDE=<${TARGET_INPUT}>" # (**)! - "${INT_INPUT}" + ${COMPILE_OPTIONS} ${REQUIRED_OPTIONS} ${IMPL_COMMON_OPTIONS} + "${CONFIG_FILE}" ) add_custom_command(OUTPUT "${TARGET_OUTPUT}" COMMAND ${NBL_NSC_COMPILE_COMMAND} - DEPENDS ${DEPENDS_ON} ${INT_INPUT} - COMMENT "Creating ${TARGET_OUTPUT}" + DEPENDS ${DEPENDS_ON} + COMMENT "Creating \"${TARGET_OUTPUT}\"" VERBATIM COMMAND_EXPAND_LISTS ) - if(NBL_EMBED_BUILTIN_RESOURCES) - LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED ${TARGET_KEY}) - endif() - else() - math(EXPR i "${i} + 1") + set(HEADER_ONLY_LIKE "${CONFIG_FILE}" "${TARGET_INPUT}" "${TARGET_OUTPUT}") + target_sources(${IMPL_TARGET} PRIVATE ${HEADER_ONLY_LIKE}) + + set_source_files_properties(${HEADER_ONLY_LIKE} PROPERTIES + HEADER_FILE_ONLY ON + VS_TOOL_OVERRIDE None + ) + + set_source_files_properties("${TARGET_OUTPUT}" PROPERTIES + NBL_SPIRV_REGISTERED_INPUT "${TARGET_INPUT}" + NBL_SPIRV_PERMUTATION_CONFIG "${CONFIG_FILE}" + NBL_SPIRV_BINARY_DIR "${IMPL_BINARY_DIR}" + NBL_SPIRV_ACCESS_KEY "${FINAL_KEY}" + ) + + set_property(TARGET ${IMPL_TARGET} APPEND PROPERTY NBL_SPIRV_OUTPUTS "${TARGET_OUTPUT}") + + return() endif() - endwhile() - endforeach() - if(NBL_EMBED_BUILTIN_RESOURCES) - if(IMPL_BUILTINS) - foreach(IT ${IMPL_BUILTINS}) - if(NBL_LOG_VERBOSE) - message(STATUS "[Nabla Builtin]: Registered \"${IT}\" key for ${IMPL_TARGET} target") - endif() + list(GET CAP_NAMES ${CAP_INDEX} CURRENT_CAP) + list(GET CAP_TYPES ${CAP_INDEX} CURRENT_TYPE) + set(VAR_NAME "CAP_VALUES_${CAP_INDEX}") + set(VALUES "${${VAR_NAME}}") - LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED ${IT}) + foreach(V IN LISTS VALUES) + set(NEW_PREFIX "${PREFIX}.${CURRENT_CAP}=${V}") + set(NEW_EVAL "${CAPS_EVAL_PART}NBL_CONSTEXPR_STATIC_INLINE ${CURRENT_TYPE} ${CURRENT_CAP} = (${CURRENT_TYPE}) ${V}; // got permuted\n") + math(EXPR NEXT_INDEX "${CAP_INDEX} + 1") + GENERATE_KEYS("${NEW_PREFIX}" "${NEXT_INDEX}" "${NEW_EVAL}") endforeach() + endfunction() + + GENERATE_KEYS("" 0 "") + endforeach() + + get_target_property(SPIRVs ${IMPL_TARGET} NBL_SPIRV_OUTPUTS) + foreach(SPIRV ${SPIRVs}) + get_source_file_property(CONFIG ${SPIRV} NBL_SPIRV_PERMUTATION_CONFIG) + get_source_file_property(INPUT ${SPIRV} NBL_SPIRV_REGISTERED_INPUT) + get_source_file_property(ACCESS_KEY ${SPIRV} NBL_SPIRV_ACCESS_KEY) + + list(APPEND CONFIGS ${CONFIG}) + list(APPEND INPUTS ${INPUT}) + list(APPEND KEYS ${ACCESS_KEY}) + + if(NBL_LOG_VERBOSE) + get_source_file_property(BINARY_DIR ${SPIRV} NBL_SPIRV_BINARY_DIR) + message(STATUS "[${IMPL_TARGET}'s SPIRV]: ${SPIRV}") + message(STATUS "-- BINARY_DIR: ${BINARY_DIR}") + message(STATUS "-- ACCESS_KEY: ${ACCESS_KEY}") + message(STATUS "-- CONFIG: ${CONFIG}") + message(STATUS "-- INPUT: ${INPUT}") endif() + endforeach() - ADD_CUSTOM_BUILTIN_RESOURCES(${IMPL_TARGET} NBL_RESOURCES_TO_EMBED "${_BUNDLE_SEARCH_DIRECTORY_}" "${_BUNDLE_ARCHIVE_ABSOLUTE_PATH_}" "${_BUILTIN_RESOURCES_NAMESPACE_}" "${_OUTPUT_DIRECTORY_HEADER_}" "${_OUTPUT_DIRECTORY_SOURCE_}" "${_LINK_MODE_}") - else() - add_library(${IMPL_TARGET} INTERFACE) - endif() + set(RTE "NSC Rules") + set(IN "${RTE}/In") + set(OUT "${RTE}/Out") - target_compile_definitions(${IMPL_TARGET} INTERFACE ${IMPL_MOUNT_POINT_DEFINE}="${_BUNDLE_SEARCH_DIRECTORY_}") + source_group("${IN}" FILES ${CONFIGS} ${INPUTS}) + source_group("${OUT}" FILES ${SPIRVs}) - if(IMPL_LINK_TO) - if(NBL_EMBED_BUILTIN_RESOURCES) - LINK_BUILTIN_RESOURCES_TO_TARGET(${IMPL_LINK_TO} ${IMPL_TARGET}) - else() - target_link_libraries(${IMPL_LINK_TO} INTERFACE ${IMPL_TARGET}) - endif() - endif() + set(${IMPL_OUTPUT_VAR} ${KEYS} PARENT_SCOPE) +endfunction() - set(HEADER_ONLY ${INT_FILES} ${DEVICE_CONFIG_FILES} ${REQUESTED_INPUTS} ${SPIRV_OUTPUTS}) - target_sources(${IMPL_TARGET} PRIVATE ${HEADER_ONLY}) +function(NBL_CREATE_RESOURCE_ARCHIVE) + set(REQUIRED_SINGLE_ARGS TARGET BIND NAMESPACE MOUNT_POINT_DEFINE) + cmake_parse_arguments(IMPL "" "${REQUIRED_SINGLE_ARGS}" "BUILTINS" ${ARGV}) + NBL_PARSE_REQUIRED(IMPL ${REQUIRED_SINGLE_ARGS}) - set_source_files_properties(${HEADER_ONLY} PROPERTIES - HEADER_FILE_ONLY ON - VS_TOOL_OVERRIDE None - ) + set(IMPL_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${IMPL_TARGET}") - set(RTE "Resources to embed") - set(IN "${RTE}/In") - set(OUT "${RTE}/Out") + set(_BUNDLE_ARCHIVE_ABSOLUTE_PATH_ "") + get_filename_component(_BUNDLE_SEARCH_DIRECTORY_ "${IMPL_BIND}" ABSOLUTE) + get_filename_component(_OUTPUT_DIRECTORY_SOURCE_ "${IMPL_OUTPUT_DIRECTORY}/archive/src" ABSOLUTE) + get_filename_component(_OUTPUT_DIRECTORY_HEADER_ "${IMPL_OUTPUT_DIRECTORY}/archive/include" ABSOLUTE) + + set(_BUILTIN_RESOURCES_NAMESPACE_ ${IMPL_NAMESPACE}) + set(_LINK_MODE_ STATIC) - source_group("${IN}/Intermediate" FILES ${INT_FILES}) - source_group("${IN}/Device Configs" FILES ${DEVICE_CONFIG_FILES}) - source_group("${IN}" FILES ${REQUESTED_INPUTS}) - source_group("${OUT}" FILES ${SPIRV_OUTPUTS}) + get_filename_component(BUILTIN_ARCHIVE_INPUT_ABS_ENTRY "${IMPL_INPUT_DIRECTORY}" ABSOLUTE) + set(BUILTIN_KEY_ENTRY_ABS "${BUILTIN_ARCHIVE_INPUT_ABS_ENTRY}/${_BUNDLE_ARCHIVE_ABSOLUTE_PATH_}") + + if(NBL_EMBED_BUILTIN_RESOURCES) + foreach(IT ${IMPL_BUILTINS}) + if(NBL_LOG_VERBOSE) + message(STATUS "[${IMPL_TARGET}'s Builtins]: Registered \"${IT}\" key") + endif() + + LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED ${IT}) + endforeach() + + ADD_CUSTOM_BUILTIN_RESOURCES(${IMPL_TARGET} NBL_RESOURCES_TO_EMBED "${_BUNDLE_SEARCH_DIRECTORY_}" "${_BUNDLE_ARCHIVE_ABSOLUTE_PATH_}" "${_BUILTIN_RESOURCES_NAMESPACE_}" "${_OUTPUT_DIRECTORY_HEADER_}" "${_OUTPUT_DIRECTORY_SOURCE_}" "${_LINK_MODE_}") + else() + add_library(${IMPL_TARGET} INTERFACE) + endif() + + target_compile_definitions(${IMPL_TARGET} INTERFACE ${IMPL_MOUNT_POINT_DEFINE}="${_BUNDLE_SEARCH_DIRECTORY_}") endfunction() \ No newline at end of file diff --git a/examples_tests b/examples_tests index c573951ec3..89ab539f1f 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit c573951ec38a3aa187b6ac8724cff1c9d293631c +Subproject commit 89ab539f1fe0d98d50b42f1a3f190cc66ec90073 From 172d9b31033d5fef3a44b04194fe7912b407a17d Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Mon, 7 Jul 2025 11:01:14 +0200 Subject: [PATCH 12/13] update SPIRV tool, add KEY json field and update examples_tests submodule --- cmake/common.cmake | 11 ++++++----- examples_tests | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cmake/common.cmake b/cmake/common.cmake index f265078b04..9d33cf6fc1 100755 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -1316,6 +1316,7 @@ struct DeviceConfigCaps foreach(INDEX RANGE ${LAST_INDEX}) string(JSON INPUT GET "${IMPL_INPUTS}" ${INDEX} INPUT) + string(JSON BASE_KEY GET "${IMPL_INPUTS}" ${INDEX} KEY) string(JSON COMPILE_OPTIONS_LENGTH LENGTH "${IMPL_INPUTS}" ${INDEX} COMPILE_OPTIONS) set(COMPILE_OPTIONS "") @@ -1338,10 +1339,6 @@ struct DeviceConfigCaps endif() endif() - get_filename_component(INPUT_NOEXT "${INPUT}" NAME_WLE) - get_filename_component(INPUT_DIR "${INPUT}" DIRECTORY) - set(BASE_KEY "${INPUT_DIR}/${INPUT_NOEXT}.spv") - set(HAS_CAPS FALSE) set(CAPS_LENGTH 0) string(JSON CAPS_TYPE TYPE "${IMPL_INPUTS}" ${INDEX} CAPS) @@ -1375,7 +1372,11 @@ struct DeviceConfigCaps endif() list(LENGTH CAP_NAMES NUM_CAPS) - set(TARGET_INPUT "${CMAKE_CURRENT_SOURCE_DIR}/${INPUT}") + + set(TARGET_INPUT "${INPUT}") + if(NOT IS_ABSOLUTE "${TARGET_INPUT}") + set(TARGET_INPUT "${CMAKE_CURRENT_SOURCE_DIR}/${TARGET_INPUT}") + endif() function(GENERATE_KEYS PREFIX CAP_INDEX CAPS_EVAL_PART) if(NUM_CAPS EQUAL 0 OR CAP_INDEX EQUAL ${NUM_CAPS}) diff --git a/examples_tests b/examples_tests index 89ab539f1f..e074ad32c2 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 89ab539f1fe0d98d50b42f1a3f190cc66ec90073 +Subproject commit e074ad32c23569bf5baa0cf8af4c65de2ef92c17 From 768b7cf2a46013263f56f5e2c21c99834cd7756b Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Thu, 10 Jul 2025 03:14:15 +0200 Subject: [PATCH 13/13] more properties, validation, logs and args for NBL_CREATE_NSC_COMPILE_RULES, update examples_tests --- cmake/common.cmake | 186 +++++++++++++++++++++++++++++++++++++++------ examples_tests | 2 +- 2 files changed, 162 insertions(+), 26 deletions(-) diff --git a/cmake/common.cmake b/cmake/common.cmake index 9d33cf6fc1..122f0b169b 100755 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -1238,6 +1238,8 @@ function(NBL_PARSE_REQUIRED PREFIX) endforeach() endfunction() +# TODO: could create them in the function as _ properties + define_property(SOURCE PROPERTY NBL_SPIRV_REGISTERED_INPUT BRIEF_DOCS "Absolute path to input shader which will be glued with device permutation config caps auto-gen file using #include directive, used as part of NSC compile rule to produce SPIRV output" ) @@ -1247,13 +1249,30 @@ define_property(SOURCE PROPERTY NBL_SPIRV_PERMUTATION_CONFIG FULL_DOCS "The file is auto-generated at configuration time, contains DeviceConfigCaps struct with permuted device caps after which #include directive glues it with an input shader" ) +define_property(SOURCE PROPERTY NBL_SPIRV_BINARY_DIR + BRIEF_DOCS "a = NBL_SPIRV_BINARY_DIR/NBL_SPIRV_ACCESS_KEY" +) +define_property(SOURCE PROPERTY NBL_SPIRV_ACCESS_KEY + BRIEF_DOCS "a = NBL_SPIRV_BINARY_DIR/NBL_SPIRV_ACCESS_KEY" +) + +define_property(TARGET PROPERTY NBL_CANONICAL_IDENTIFIERS + BRIEF_DOCS "List of identifiers composed as NBL_SPIRV_BINARY_DIR/KEY" + FULL_DOCS "For a given NBL_SPIRV_BINARY_DIR we define a set of canonical KEYs, each unique given which at runtime one can get SPIRV key to access by the canonical key which may contain special permutation part in character of (.=)(.=)(...)" +) + define_property(TARGET PROPERTY NBL_SPIRV_OUTPUTS - BRIEF_DOCS "Absolute paths to SPIRV outputs, part of NSC compile rules" + BRIEF_DOCS "Absolute paths to all s which are part of NSC compile rules" ) -# NBL_SPIRV_OUTPUT = NBL_SPIRV_BINARY_DIR/NBL_SPIRV_ACCESS_KEY -define_property(SOURCE PROPERTY NBL_SPIRV_BINARY_DIR) -define_property(SOURCE PROPERTY NBL_SPIRV_ACCESS_KEY) +define_property(TARGET PROPERTY NBL_HEADER_PATH + BRIEF_DOCS "Relative path for auto-gen include file with key getters" +) +define_property(TARGET PROPERTY NBL_HEADER_GENERATED_RULE) + +define_property(TARGET PROPERTY NBL_HEADER_CONTENT + BRIEF_DOCS "Contains NBL_HEADER_PATH's content" +) function(NBL_CREATE_NSC_COMPILE_RULES) set(COMMENT "this code has been autogenerated with Nabla CMake NBL_CREATE_HLSL_COMPILE_RULES utility") @@ -1301,7 +1320,7 @@ struct DeviceConfigCaps ) endif() - set(REQUIRED_SINGLE_ARGS TARGET BINARY_DIR OUTPUT_VAR INPUTS) + set(REQUIRED_SINGLE_ARGS TARGET BINARY_DIR OUTPUT_VAR INPUTS INCLUDE NAMESPACE) cmake_parse_arguments(IMPL "" "${REQUIRED_SINGLE_ARGS}" "COMMON_OPTIONS" ${ARGV}) NBL_PARSE_REQUIRED(IMPL ${REQUIRED_SINGLE_ARGS}) @@ -1309,6 +1328,59 @@ struct DeviceConfigCaps add_library(${IMPL_TARGET} INTERFACE) endif() + if(IS_ABSOLUTE "${IMPL_INCLUDE}") + message(FATAL_ERROR "INCLUDE argument must be relative path") + endif() + + set_target_properties(${IMPL_TARGET} PROPERTIES NBL_HEADER_PATH "${IMPL_INCLUDE}") + + get_target_property(HEADER_RULE_GENERATED ${IMPL_TARGET} NBL_HEADER_GENERATED_RULE) + if(NOT HEADER_RULE_GENERATED) + set(INCLUDE_DIR "$/${IMPL_TARGET}/.cmake/include") + set(INCLUDE_FILE "${INCLUDE_DIR}/$") + set(INCLUDE_CONTENT $) + + file(GENERATE OUTPUT ${INCLUDE_FILE} + CONTENT ${INCLUDE_CONTENT} + TARGET ${IMPL_TARGET} + ) + + target_include_directories(${IMPL_TARGET} INTERFACE ${INCLUDE_DIR}) + set_target_properties(${IMPL_TARGET} PROPERTIES NBL_HEADER_GENERATED_RULE ON) + + set(HEADER_ITEM_VIEW [=[ +#include "nabla.h" + +]=]) + set_property(TARGET ${IMPL_TARGET} APPEND_STRING PROPERTY NBL_HEADER_CONTENT "${HEADER_ITEM_VIEW}") + endif() + + string(MAKE_C_IDENTIFIER "${IMPL_TARGET}_${IMPL_NAMESPACE}" NS_IMPL_KEYS_PROPERTY) + get_property(NS_IMPL_KEYS_PROPERTY_DEFINED + TARGET ${IMPL_TARGET} + PROPERTY "${NS_IMPL_KEYS_PROPERTY}" + DEFINED + ) + if(NOT NS_IMPL_KEYS_PROPERTY_DEFINED) + set(HEADER_ITEM_VIEW [=[ +namespace @IMPL_NAMESPACE@ { + template + inline const nbl::core::string get_spirv_key(const nbl::video::SPhysicalDeviceLimits& limits, const nbl::video::SPhysicalDeviceFeatures& features); + + template + inline const nbl::core::string get_spirv_key(const nbl::video::ILogicalDevice* device) + { + return get_spirv_key(device->getPhysicalDevice()->getLimits(), device->getEnabledFeatures()); + } +} + +]=]) + string(CONFIGURE "${HEADER_ITEM_VIEW}" HEADER_ITEM_EVAL @ONLY) + set_property(TARGET ${IMPL_TARGET} APPEND_STRING PROPERTY NBL_HEADER_CONTENT "${HEADER_ITEM_EVAL}") + define_property(TARGET PROPERTY "${NS_IMPL_KEYS_PROPERTY}") + endif() + + string(JSON JSON_LENGTH LENGTH "${IMPL_INPUTS}") math(EXPR LAST_INDEX "${JSON_LENGTH} - 1") @@ -1349,6 +1421,14 @@ struct DeviceConfigCaps endif() endif() + function(ERROR_WHILE_PARSING_ITEM) + string(JSON ITEM GET "${IMPL_INPUTS}" ${INDEX}) + message(FATAL_ERROR + "While parsing ${IMPL_TARGET}'s NSC compile rule\n${ITEM}\n" + ${ARGV} + ) + endfunction() + set(CAP_NAMES "") set(CAP_TYPES "") if(HAS_CAPS) @@ -1356,14 +1436,40 @@ struct DeviceConfigCaps foreach(CAP_IDX RANGE 0 ${LAST_CAP}) string(JSON CAP_NAME GET "${IMPL_INPUTS}" ${INDEX} CAPS ${CAP_IDX} name) string(JSON CAP_TYPE GET "${IMPL_INPUTS}" ${INDEX} CAPS ${CAP_IDX} type) - string(JSON CAP_VALUES_LENGTH LENGTH "${IMPL_INPUTS}" ${INDEX} CAPS ${CAP_IDX} values) - set(VALUES "") - math(EXPR LAST_VAL "${CAP_VALUES_LENGTH} - 1") - foreach(VAL_IDX RANGE 0 ${LAST_VAL}) - string(JSON VALUE GET "${IMPL_INPUTS}" ${INDEX} CAPS ${CAP_IDX} values ${VAL_IDX}) - list(APPEND VALUES "${VALUE}") - endforeach() + if(NOT CAP_TYPE MATCHES "^(bool|uint16_t|uint32_t|uint64_t)$") + ERROR_WHILE_PARSING_ITEM( + "Invalid CAP type \"${CAP_TYPE}\" for ${CAP_NAME}\n" + "Allowed types are: bool, uint16_t, uint32_t, uint64_t" + ) + endif() + + string(JSON CAP_VALUES_LENGTH LENGTH "${IMPL_INPUTS}" ${INDEX} CAPS ${CAP_IDX} values) + + set(VALUES "") + math(EXPR LAST_VAL "${CAP_VALUES_LENGTH} - 1") + foreach(VAL_IDX RANGE 0 ${LAST_VAL}) + string(JSON VALUE GET "${IMPL_INPUTS}" ${INDEX} CAPS ${CAP_IDX} values ${VAL_IDX}) + string(JSON VAL_TYPE TYPE "${IMPL_INPUTS}" ${INDEX} CAPS ${CAP_IDX} values ${VAL_IDX}) + + if(NOT VAL_TYPE STREQUAL "NUMBER") + ERROR_WHILE_PARSING_ITEM( + "Invalid CAP value \"${VALUE}\" for CAP \"${CAP_NAME}\" of type ${CAP_TYPE}\n" + "Use numbers for uint*_t and 0/1 for bools." + ) + endif() + + if(CAP_TYPE STREQUAL "bool") + if(NOT VALUE MATCHES "^[01]$") + ERROR_WHILE_PARSING_ITEM( + "Invalid bool value \"${VALUE}\" for ${CAP_NAME}\n" + "Boolean CAPs can only have values 0 or 1." + ) + endif() + endif() + + list(APPEND VALUES "${VALUE}") + endforeach() set(CAP_VALUES_${CAP_IDX} "${VALUES}") list(APPEND CAP_NAMES "${CAP_NAME}") @@ -1378,9 +1484,47 @@ struct DeviceConfigCaps set(TARGET_INPUT "${CMAKE_CURRENT_SOURCE_DIR}/${TARGET_INPUT}") endif() + get_target_property(CANONICAL_IDENTIFIERS ${IMPL_TARGET} NBL_CANONICAL_IDENTIFIERS) + + set(NEW_CANONICAL_IDENTIFIER "${IMPL_BINARY_DIR}/${BASE_KEY}") + if(CANONICAL_IDENTIFIERS) + list(FIND CANONICAL_IDENTIFIERS "${NEW_CANONICAL_IDENTIFIER}" FOUND) + + if(NOT FOUND STREQUAL -1) + string(JSON ITEM GET "${IMPL_INPUTS}" ${INDEX}) + message(FATAL_ERROR "While parsing ${IMPL_TARGET}'s NSC compile rule\n${ITEM}\nwith binary directory \"${IMPL_BINARY_DIR}\",\ncanonical key \"${BASE_KEY}\" already defined!") + endif() + endif() + + set_property(TARGET ${IMPL_TARGET} APPEND PROPERTY NBL_CANONICAL_IDENTIFIERS "${NEW_CANONICAL_IDENTIFIER}") + + set(HEADER_ITEM_VIEW [=[ +namespace @IMPL_NAMESPACE@ { + template<> + inline const nbl::core::string get_spirv_key + (const nbl::video::SPhysicalDeviceLimits& limits, const nbl::video::SPhysicalDeviceFeatures& features) + { + nbl::core::string retval = "@BASE_KEY@"; +@RETVAL_EVAL@ + retval += ".spv"; + return retval; + } +} + +]=]) + unset(RETVAL_EVAL) + foreach(CAP ${CAP_NAMES}) + string(CONFIGURE [=[ + retval += ".@CAP@_" + std::to_string(limits.@CAP@); +]=] RETVALUE_VIEW @ONLY) + string(APPEND RETVAL_EVAL "${RETVALUE_VIEW}") + endforeach(CAP) + string(CONFIGURE "${HEADER_ITEM_VIEW}" HEADER_ITEM_EVAL @ONLY) + set_property(TARGET ${IMPL_TARGET} APPEND_STRING PROPERTY NBL_HEADER_CONTENT "${HEADER_ITEM_EVAL}") + function(GENERATE_KEYS PREFIX CAP_INDEX CAPS_EVAL_PART) if(NUM_CAPS EQUAL 0 OR CAP_INDEX EQUAL ${NUM_CAPS}) - set(FINAL_KEY "${BASE_KEY}${PREFIX}") + set(FINAL_KEY "${BASE_KEY}${PREFIX}.spv") # always add ext even if its already there to make sure asset loader always is able to load as IShader set(TARGET_OUTPUT "${IMPL_BINARY_DIR}/${FINAL_KEY}") set(CONFIG_FILE "${TARGET_OUTPUT}.config") @@ -1420,7 +1564,6 @@ struct DeviceConfigCaps ) set_property(TARGET ${IMPL_TARGET} APPEND PROPERTY NBL_SPIRV_OUTPUTS "${TARGET_OUTPUT}") - return() endif() @@ -1430,7 +1573,7 @@ struct DeviceConfigCaps set(VALUES "${${VAR_NAME}}") foreach(V IN LISTS VALUES) - set(NEW_PREFIX "${PREFIX}.${CURRENT_CAP}=${V}") + set(NEW_PREFIX "${PREFIX}.${CURRENT_CAP}_${V}") set(NEW_EVAL "${CAPS_EVAL_PART}NBL_CONSTEXPR_STATIC_INLINE ${CURRENT_TYPE} ${CURRENT_CAP} = (${CURRENT_TYPE}) ${V}; // got permuted\n") math(EXPR NEXT_INDEX "${CAP_INDEX} + 1") GENERATE_KEYS("${NEW_PREFIX}" "${NEXT_INDEX}" "${NEW_EVAL}") @@ -1440,6 +1583,7 @@ struct DeviceConfigCaps GENERATE_KEYS("" 0 "") endforeach() + unset(KEYS) get_target_property(SPIRVs ${IMPL_TARGET} NBL_SPIRV_OUTPUTS) foreach(SPIRV ${SPIRVs}) get_source_file_property(CONFIG ${SPIRV} NBL_SPIRV_PERMUTATION_CONFIG) @@ -1449,15 +1593,6 @@ struct DeviceConfigCaps list(APPEND CONFIGS ${CONFIG}) list(APPEND INPUTS ${INPUT}) list(APPEND KEYS ${ACCESS_KEY}) - - if(NBL_LOG_VERBOSE) - get_source_file_property(BINARY_DIR ${SPIRV} NBL_SPIRV_BINARY_DIR) - message(STATUS "[${IMPL_TARGET}'s SPIRV]: ${SPIRV}") - message(STATUS "-- BINARY_DIR: ${BINARY_DIR}") - message(STATUS "-- ACCESS_KEY: ${ACCESS_KEY}") - message(STATUS "-- CONFIG: ${CONFIG}") - message(STATUS "-- INPUT: ${INPUT}") - endif() endforeach() set(RTE "NSC Rules") @@ -1499,8 +1634,9 @@ function(NBL_CREATE_RESOURCE_ARCHIVE) ADD_CUSTOM_BUILTIN_RESOURCES(${IMPL_TARGET} NBL_RESOURCES_TO_EMBED "${_BUNDLE_SEARCH_DIRECTORY_}" "${_BUNDLE_ARCHIVE_ABSOLUTE_PATH_}" "${_BUILTIN_RESOURCES_NAMESPACE_}" "${_OUTPUT_DIRECTORY_HEADER_}" "${_OUTPUT_DIRECTORY_SOURCE_}" "${_LINK_MODE_}") else() - add_library(${IMPL_TARGET} INTERFACE) + add_library(${IMPL_TARGET} INTERFACE) # (***) endif() + # TODO (***): actually I better have this in meta target created by NBL_CREATE_NSC_COMPILE_RULES, then I kill its INTERFACE when builtins are off target_compile_definitions(${IMPL_TARGET} INTERFACE ${IMPL_MOUNT_POINT_DEFINE}="${_BUNDLE_SEARCH_DIRECTORY_}") endfunction() \ No newline at end of file diff --git a/examples_tests b/examples_tests index e074ad32c2..a6271a4ca0 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit e074ad32c23569bf5baa0cf8af4c65de2ef92c17 +Subproject commit a6271a4ca05eb0fe8bb7316f5bd857e64fdc3734