From 624184fff3d2e25f483b0d8993f85a18df46fd10 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sun, 22 Mar 2026 19:25:07 +0100 Subject: [PATCH 01/60] Reduce Wave preprocess overhead and update DXC pointer --- 3rdparty/dxc/dxc | 2 +- include/nbl/asset/utils/IShaderCompiler.h | 17 +- .../hlsl/bxdf/reflection/beckmann.hlsl | 2 - .../nbl/builtin/hlsl/bxdf/reflection/ggx.hlsl | 2 - .../hlsl/bxdf/transmission/beckmann.hlsl | 4 +- .../builtin/hlsl/bxdf/transmission/ggx.hlsl | 3 - .../nbl/builtin/hlsl/emulated/float64_t.hlsl | 1 - .../nbl/builtin/hlsl/member_test_macros.hlsl | 7 +- .../builtin/hlsl/path_tracing/concepts.hlsl | 52 +++- .../hlsl/path_tracing/unidirectional.hlsl | 4 +- include/nbl/builtin/hlsl/tgmath.hlsl | 4 - include/nbl/video/CJITIncludeLoader.h | 2 +- src/nbl/asset/utils/CWaveStringResolver.cpp | 129 +++++---- src/nbl/asset/utils/IShaderCompiler.cpp | 108 ++++++-- src/nbl/asset/utils/includeResolutionCommon.h | 36 +++ src/nbl/asset/utils/waveContext.h | 253 ++++++++++++++++-- src/nbl/video/CJITIncludeLoader.cpp | 2 +- 17 files changed, 510 insertions(+), 118 deletions(-) create mode 100644 src/nbl/asset/utils/includeResolutionCommon.h diff --git a/3rdparty/dxc/dxc b/3rdparty/dxc/dxc index d76c7890b1..8466c63aaf 160000 --- a/3rdparty/dxc/dxc +++ b/3rdparty/dxc/dxc @@ -1 +1 @@ -Subproject commit d76c7890b19ce0b344ee0ce116dbc1c92220ccea +Subproject commit 8466c63aaf8f577948b5dfeb7f92b244c7bb9062 diff --git a/include/nbl/asset/utils/IShaderCompiler.h b/include/nbl/asset/utils/IShaderCompiler.h index f3cfe07132..c43890d161 100644 --- a/include/nbl/asset/utils/IShaderCompiler.h +++ b/include/nbl/asset/utils/IShaderCompiler.h @@ -17,6 +17,9 @@ #include "nbl/builtin/hlsl/enums.hlsl" #include +#include +#include +#include namespace nbl::asset { @@ -39,7 +42,7 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted explicit inline operator bool() const {return !absolutePath.empty();} }; - virtual found_t getInclude(const system::path& searchPath, const std::string& includeName) const = 0; + virtual found_t getInclude(const system::path& searchPath, const std::string& includeName, bool needHash = true) const = 0; }; class NBL_API2 IIncludeGenerator : public core::IReferenceCounted @@ -65,10 +68,13 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted public: CFileSystemIncludeLoader(core::smart_refctd_ptr&& system); - IIncludeLoader::found_t getInclude(const system::path& searchPath, const std::string& includeName) const override; + IIncludeLoader::found_t getInclude(const system::path& searchPath, const std::string& includeName, bool needHash = true) const override; protected: core::smart_refctd_ptr m_system; + mutable std::mutex m_cacheMutex; + mutable std::unordered_map m_cache; + mutable std::unordered_set m_missingCache; }; class NBL_API2 CIncludeFinder : public core::IReferenceCounted @@ -79,12 +85,12 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted // ! includes within <> // @param requestingSourceDir: the directory where the incude was requested // @param includeName: the string within <> of the include preprocessing directive - IIncludeLoader::found_t getIncludeStandard(const system::path& requestingSourceDir, const std::string& includeName) const; + IIncludeLoader::found_t getIncludeStandard(const system::path& requestingSourceDir, const std::string& includeName, bool needHash = true) const; // ! includes within "" // @param requestingSourceDir: the directory where the incude was requested // @param includeName: the string within "" of the include preprocessing directive - IIncludeLoader::found_t getIncludeRelative(const system::path& requestingSourceDir, const std::string& includeName) const; + IIncludeLoader::found_t getIncludeRelative(const system::path& requestingSourceDir, const std::string& includeName, bool needHash = true) const; inline core::smart_refctd_ptr getDefaultFileSystemLoader() const { return m_defaultFileSystemLoader; } @@ -93,7 +99,7 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted void addGenerator(const core::smart_refctd_ptr& generator); protected: - IIncludeLoader::found_t trySearchPaths(const std::string& includeName) const; + IIncludeLoader::found_t trySearchPaths(const std::string& includeName, bool needHash) const; IIncludeLoader::found_t tryIncludeGenerators(const std::string& includeName) const; @@ -137,6 +143,7 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted std::span extraDefines = {}; E_SPIRV_VERSION targetSpirvVersion = E_SPIRV_VERSION::ESV_1_6; bool depfile = false; + bool preserveComments = false; system::path depfilePath = {}; std::function onPartialOutputOnFailure = {}; }; diff --git a/include/nbl/builtin/hlsl/bxdf/reflection/beckmann.hlsl b/include/nbl/builtin/hlsl/bxdf/reflection/beckmann.hlsl index cb7743e02d..65db32f336 100644 --- a/include/nbl/builtin/hlsl/bxdf/reflection/beckmann.hlsl +++ b/include/nbl/builtin/hlsl/bxdf/reflection/beckmann.hlsl @@ -4,9 +4,7 @@ #ifndef _NBL_BUILTIN_HLSL_BXDF_REFLECTION_BECKMANN_INCLUDED_ #define _NBL_BUILTIN_HLSL_BXDF_REFLECTION_BECKMANN_INCLUDED_ -#include "nbl/builtin/hlsl/bxdf/common.hlsl" #include "nbl/builtin/hlsl/bxdf/bxdf_traits.hlsl" -#include "nbl/builtin/hlsl/sampling/cos_weighted_spheres.hlsl" #include "nbl/builtin/hlsl/bxdf/ndf/beckmann.hlsl" #include "nbl/builtin/hlsl/bxdf/base/cook_torrance_base.hlsl" diff --git a/include/nbl/builtin/hlsl/bxdf/reflection/ggx.hlsl b/include/nbl/builtin/hlsl/bxdf/reflection/ggx.hlsl index 0f49d0be43..a984a14b3f 100644 --- a/include/nbl/builtin/hlsl/bxdf/reflection/ggx.hlsl +++ b/include/nbl/builtin/hlsl/bxdf/reflection/ggx.hlsl @@ -4,9 +4,7 @@ #ifndef _NBL_BUILTIN_HLSL_BXDF_REFLECTION_GGX_INCLUDED_ #define _NBL_BUILTIN_HLSL_BXDF_REFLECTION_GGX_INCLUDED_ -#include "nbl/builtin/hlsl/bxdf/common.hlsl" #include "nbl/builtin/hlsl/bxdf/bxdf_traits.hlsl" -#include "nbl/builtin/hlsl/sampling/cos_weighted_spheres.hlsl" #include "nbl/builtin/hlsl/bxdf/ndf/ggx.hlsl" #include "nbl/builtin/hlsl/bxdf/base/cook_torrance_base.hlsl" diff --git a/include/nbl/builtin/hlsl/bxdf/transmission/beckmann.hlsl b/include/nbl/builtin/hlsl/bxdf/transmission/beckmann.hlsl index 8c61692c5c..b911968d16 100644 --- a/include/nbl/builtin/hlsl/bxdf/transmission/beckmann.hlsl +++ b/include/nbl/builtin/hlsl/bxdf/transmission/beckmann.hlsl @@ -4,10 +4,8 @@ #ifndef _NBL_BUILTIN_HLSL_BXDF_TRANSMISSION_BECKMANN_INCLUDED_ #define _NBL_BUILTIN_HLSL_BXDF_TRANSMISSION_BECKMANN_INCLUDED_ -#include "nbl/builtin/hlsl/bxdf/common.hlsl" #include "nbl/builtin/hlsl/bxdf/bxdf_traits.hlsl" -#include "nbl/builtin/hlsl/sampling/cos_weighted_spheres.hlsl" -#include "nbl/builtin/hlsl/bxdf/reflection.hlsl" +#include "nbl/builtin/hlsl/bxdf/ndf/beckmann.hlsl" #include "nbl/builtin/hlsl/bxdf/base/cook_torrance_base.hlsl" namespace nbl diff --git a/include/nbl/builtin/hlsl/bxdf/transmission/ggx.hlsl b/include/nbl/builtin/hlsl/bxdf/transmission/ggx.hlsl index cdd4483c7f..a095d5fdba 100644 --- a/include/nbl/builtin/hlsl/bxdf/transmission/ggx.hlsl +++ b/include/nbl/builtin/hlsl/bxdf/transmission/ggx.hlsl @@ -4,10 +4,7 @@ #ifndef _NBL_BUILTIN_HLSL_BXDF_TRANSMISSION_GGX_INCLUDED_ #define _NBL_BUILTIN_HLSL_BXDF_TRANSMISSION_GGX_INCLUDED_ -#include "nbl/builtin/hlsl/bxdf/common.hlsl" #include "nbl/builtin/hlsl/bxdf/bxdf_traits.hlsl" -#include "nbl/builtin/hlsl/sampling/cos_weighted_spheres.hlsl" -#include "nbl/builtin/hlsl/bxdf/reflection.hlsl" #include "nbl/builtin/hlsl/bxdf/base/cook_torrance_base.hlsl" namespace nbl diff --git a/include/nbl/builtin/hlsl/emulated/float64_t.hlsl b/include/nbl/builtin/hlsl/emulated/float64_t.hlsl index da32fab7b0..54c07ddb27 100644 --- a/include/nbl/builtin/hlsl/emulated/float64_t.hlsl +++ b/include/nbl/builtin/hlsl/emulated/float64_t.hlsl @@ -2,7 +2,6 @@ #define _NBL_BUILTIN_HLSL_EMULATED_FLOAT64_T_HLSL_INCLUDED_ #include -#include namespace nbl { diff --git a/include/nbl/builtin/hlsl/member_test_macros.hlsl b/include/nbl/builtin/hlsl/member_test_macros.hlsl index 7579fb0fa2..556c6a463e 100644 --- a/include/nbl/builtin/hlsl/member_test_macros.hlsl +++ b/include/nbl/builtin/hlsl/member_test_macros.hlsl @@ -5,7 +5,10 @@ #define _NBL_BUILTIN_HLSL_MEMBER_TEST_MACROS_INCLUDED_ #include -#include +#include +#include +#include +#include #ifdef __HLSL_VERSION @@ -123,4 +126,4 @@ GENERATE_METHOD_TESTER(set) #endif -#endif \ No newline at end of file +#endif diff --git a/include/nbl/builtin/hlsl/path_tracing/concepts.hlsl b/include/nbl/builtin/hlsl/path_tracing/concepts.hlsl index 25ca98772c..24a0e86455 100644 --- a/include/nbl/builtin/hlsl/path_tracing/concepts.hlsl +++ b/include/nbl/builtin/hlsl/path_tracing/concepts.hlsl @@ -5,7 +5,6 @@ #define _NBL_BUILTIN_HLSL_PATH_TRACING_CONCEPTS_INCLUDED_ #include -#include namespace nbl { @@ -15,6 +14,17 @@ namespace path_tracing { namespace concepts { +namespace impl +{ +template +struct DummyRayInteraction +{ + using vector3_type = Vector3; + + vector3_type getN() NBL_CONST_MEMBER_FUNC; + bool isMaterialBSDF() NBL_CONST_MEMBER_FUNC; +}; +} #define NBL_CONCEPT_NAME RandGenerator #define NBL_CONCEPT_TPLT_PRM_KINDS (typename) @@ -38,7 +48,7 @@ NBL_CONCEPT_END( #define NBL_CONCEPT_TPLT_PRM_NAMES (T) #define NBL_CONCEPT_PARAM_0 (ray, T) #define NBL_CONCEPT_PARAM_1 (v, typename T::vector3_type) -#define NBL_CONCEPT_PARAM_2 (interaction, bxdf::surface_interactions::SIsotropic, typename T::spectral_type>) +#define NBL_CONCEPT_PARAM_2 (interaction, impl::DummyRayInteraction) #define NBL_CONCEPT_PARAM_3 (scalar, typename T::scalar_type) #define NBL_CONCEPT_PARAM_4 (color, typename T::spectral_type) NBL_CONCEPT_BEGIN(5) @@ -52,7 +62,7 @@ NBL_CONCEPT_END( ((NBL_CONCEPT_REQ_TYPE)(T::vector3_type)) ((NBL_CONCEPT_REQ_TYPE)(T::spectral_type)) ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((ray.init(v/*origin*/, v/*direction*/)), ::nbl::hlsl::is_same_v, void)) - ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((ray.template setInteraction, typename T::spectral_type> >(interaction)), ::nbl::hlsl::is_same_v, void)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((ray.setInteraction(interaction)), ::nbl::hlsl::is_same_v, void)) ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((ray.initPayload()), ::nbl::hlsl::is_same_v, void)) ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((ray.shouldDoMIS()), ::nbl::hlsl::is_same_v, bool)) ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((ray.foundEmissiveMIS(scalar)), ::nbl::hlsl::is_same_v, typename T::scalar_type)) @@ -70,6 +80,21 @@ NBL_CONCEPT_END( #undef ray #include +#define NBL_CONCEPT_NAME RaySetInteraction +#define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(typename) +#define NBL_CONCEPT_TPLT_PRM_NAMES (RayT)(Interaction) +#define NBL_CONCEPT_PARAM_0 (ray, RayT) +#define NBL_CONCEPT_PARAM_1 (interaction, Interaction) +NBL_CONCEPT_BEGIN(2) +#define ray NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 +#define interaction NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 +NBL_CONCEPT_END( + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((ray.setInteraction(interaction)), ::nbl::hlsl::is_same_v, void)) +); +#undef interaction +#undef ray +#include + #define NBL_CONCEPT_NAME RayGenerator #define NBL_CONCEPT_TPLT_PRM_KINDS (typename) #define NBL_CONCEPT_TPLT_PRM_NAMES (T) @@ -124,6 +149,7 @@ NBL_CONCEPT_END( ((NBL_CONCEPT_REQ_TYPE)(T::scene_type)) ((NBL_CONCEPT_REQ_TYPE)(T::ray_type)) ((NBL_CONCEPT_REQ_TYPE)(T::object_handle_type)) + ((NBL_CONCEPT_REQ_TYPE)(T::anisotropic_interaction_type)) ((NBL_CONCEPT_REQ_TYPE)(T::closest_hit_type)) ((NBL_CONCEPT_REQ_TYPE_ALIAS_CONCEPT)(IntersectorClosestHit, typename T::closest_hit_type)) ((NBL_CONCEPT_REQ_TYPE_ALIAS_CONCEPT)(Ray, typename T::ray_type)) @@ -136,6 +162,26 @@ NBL_CONCEPT_END( #undef intersect #include +#define NBL_CONCEPT_NAME UnidirectionalInteractionContract +#define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(typename)(typename) +#define NBL_CONCEPT_TPLT_PRM_NAMES (RayT)(IntersectorT)(MaterialSystemT) +#define NBL_CONCEPT_PARAM_0 (ray, RayT) +#define NBL_CONCEPT_PARAM_1 (hit, typename IntersectorT::closest_hit_type) +#define NBL_CONCEPT_PARAM_2 (interaction, typename MaterialSystemT::anisotropic_interaction_type) +NBL_CONCEPT_BEGIN(3) +#define ray NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 +#define hit NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 +#define interaction NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_2 +NBL_CONCEPT_END( + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((hit.getInteraction()), ::nbl::hlsl::is_same_v, typename IntersectorT::anisotropic_interaction_type)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((hit.getInteraction()), ::nbl::hlsl::is_same_v, typename MaterialSystemT::anisotropic_interaction_type)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((ray.setInteraction(interaction)), ::nbl::hlsl::is_same_v, void)) +); +#undef interaction +#undef hit +#undef ray +#include + #define NBL_CONCEPT_NAME BxdfNode #define NBL_CONCEPT_TPLT_PRM_KINDS (typename) #define NBL_CONCEPT_TPLT_PRM_NAMES (T) diff --git a/include/nbl/builtin/hlsl/path_tracing/unidirectional.hlsl b/include/nbl/builtin/hlsl/path_tracing/unidirectional.hlsl index 43e4cb124e..505b366b0f 100644 --- a/include/nbl/builtin/hlsl/path_tracing/unidirectional.hlsl +++ b/include/nbl/builtin/hlsl/path_tracing/unidirectional.hlsl @@ -5,11 +5,8 @@ #define _NBL_BUILTIN_HLSL_PATH_TRACING_UNIDIRECTIONAL_INCLUDED_ #include -#include #include #include -#include -#include #include namespace nbl @@ -22,6 +19,7 @@ namespace path_tracing template && concepts::Ray && concepts::Intersector && concepts::MaterialSystem && + concepts::UnidirectionalInteractionContract && concepts::NextEventEstimator && concepts::Accumulator && concepts::Scene) struct Unidirectional diff --git a/include/nbl/builtin/hlsl/tgmath.hlsl b/include/nbl/builtin/hlsl/tgmath.hlsl index c569d34f85..40ad48c13c 100644 --- a/include/nbl/builtin/hlsl/tgmath.hlsl +++ b/include/nbl/builtin/hlsl/tgmath.hlsl @@ -7,12 +7,8 @@ #include #include #include -#include #include #include -#include -#include -#include #include // C++ headers diff --git a/include/nbl/video/CJITIncludeLoader.h b/include/nbl/video/CJITIncludeLoader.h index 3b341631f4..04be1ea60a 100644 --- a/include/nbl/video/CJITIncludeLoader.h +++ b/include/nbl/video/CJITIncludeLoader.h @@ -20,7 +20,7 @@ class NBL_API2 CJITIncludeLoader : public asset::IShaderCompiler::IIncludeLoader m_includes["nbl/builtin/hlsl/jit/device_capabilities.hlsl"] = collectDeviceCaps(limits,features); } - found_t getInclude(const system::path& searchPath, const std::string& includeName) const override; + found_t getInclude(const system::path& searchPath, const std::string& includeName, bool needHash = true) const override; protected: template diff --git a/src/nbl/asset/utils/CWaveStringResolver.cpp b/src/nbl/asset/utils/CWaveStringResolver.cpp index 8da0e828ec..744c103818 100644 --- a/src/nbl/asset/utils/CWaveStringResolver.cpp +++ b/src/nbl/asset/utils/CWaveStringResolver.cpp @@ -57,13 +57,11 @@ constexpr size_t kWaveFailureLogTokenPreviewMaxChars = 160ull; struct WaveRenderProgress { core::string output; - std::optional previousPosition = std::nullopt; + std::string previousFile; + int previousLine = 0; + bool hasPreviousToken = false; bool previousWasExplicitWhitespace = false; size_t emittedTokenCount = 0ull; - std::string lastTokenFile; - int lastTokenLine = 0; - int lastTokenColumn = 0; - std::string lastTokenValue; }; std::string getLineSnippet(std::string_view text, const int lineNo) @@ -218,11 +216,6 @@ std::string makeWaveFailureContext( stream << "\n emitted_output_bytes: " << renderProgress.output.size(); stream << "\n emitted_output_lines: " << countLogicalLines(renderProgress.output); stream << "\n emitted_token_count: " << renderProgress.emittedTokenCount; - if (!renderProgress.lastTokenFile.empty()) - stream << "\n last_emitted_token_location: " << nbl::wave::detail::escape_control_chars(renderProgress.lastTokenFile) << ':' << renderProgress.lastTokenLine << ':' << renderProgress.lastTokenColumn; - if (!renderProgress.lastTokenValue.empty()) - stream << "\n last_emitted_token_value: " << truncateEscapedPreview(nbl::wave::detail::escape_control_chars(renderProgress.lastTokenValue), kWaveFailureLogTokenPreviewMaxChars); - const auto snippet = getLineSnippet(code, lineNo); if (!snippet.empty() && fileName && preprocessOptions.sourceIdentifier == fileName) { @@ -248,64 +241,90 @@ bool isWhitespaceLikeToken(const TokenT& token) return id == T_NEWLINE || id == T_GENERATEDNEWLINE || id == T_CONTLINE || IS_CATEGORY(token, WhiteSpaceTokenType); } -template -std::string tokenValueToString(const TokenT& token) -{ - const auto& value = token.get_value(); - return std::string(value.data(), value.size()); -} - void renderPreprocessedOutput(nbl::wave::context& context, WaveRenderProgress& renderProgress) { using namespace boost::wave; util::insert_whitespace_detection whitespace(true); - - for (auto it = context.begin(); it != context.end(); ++it) + auto& perfStats = nbl::wave::detail::perf_stats(); + auto it = context.begin(); + const auto end = context.end(); + while (it != end) { + std::optional loopBodyTimer; + if (perfStats.enabled) + loopBodyTimer.emplace(perfStats.loopBodyTime); + const auto& token = *it; const auto id = token_id(token); - if (id == T_EOF || id == T_EOI) - continue; + if (id != T_EOF && id != T_EOI) + { + std::optional tokenTimer; + if (perfStats.enabled) + tokenTimer.emplace(perfStats.tokenHandlingTime); - const auto explicitWhitespace = isWhitespaceLikeToken(token); - const auto& position = token.get_position(); - const auto value = tokenValueToString(token); + const auto explicitWhitespace = isWhitespaceLikeToken(token); + const auto& position = token.get_position(); + const auto& value = token.get_value(); - if (renderProgress.previousPosition.has_value() && !explicitWhitespace) - { - const auto movedToNewLogicalLine = - position.get_file() != renderProgress.previousPosition->get_file() || - position.get_line() > renderProgress.previousPosition->get_line(); + const auto currentLine = position.get_line(); + const auto& currentFile = position.get_file(); - if (movedToNewLogicalLine) + if (renderProgress.hasPreviousToken && !explicitWhitespace) { - if (renderProgress.output.empty() || renderProgress.output.back() != '\n') + bool movedToNewLogicalLine = currentLine > renderProgress.previousLine; + if (!movedToNewLogicalLine) { - renderProgress.output.push_back('\n'); - whitespace.shift_tokens(T_NEWLINE); + movedToNewLogicalLine = + renderProgress.previousFile.size() != currentFile.size() || + !std::equal(currentFile.begin(), currentFile.end(), renderProgress.previousFile.begin()); } - } - else if (!renderProgress.previousWasExplicitWhitespace && whitespace.must_insert(id, value)) - { - if (renderProgress.output.empty() || (renderProgress.output.back() != ' ' && renderProgress.output.back() != '\n' && renderProgress.output.back() != '\r' && renderProgress.output.back() != '\t')) + + if (movedToNewLogicalLine) { - renderProgress.output.push_back(' '); - whitespace.shift_tokens(T_SPACE); + if (renderProgress.output.empty() || renderProgress.output.back() != '\n') + { + renderProgress.output.push_back('\n'); + whitespace.shift_tokens(T_NEWLINE); + } } + else if (!renderProgress.previousWasExplicitWhitespace && whitespace.must_insert(id, value)) + { + if (renderProgress.output.empty() || (renderProgress.output.back() != ' ' && renderProgress.output.back() != '\n' && renderProgress.output.back() != '\r' && renderProgress.output.back() != '\t')) + { + renderProgress.output.push_back(' '); + whitespace.shift_tokens(T_SPACE); + } + } + } + + renderProgress.output.append(value.data(), value.size()); + whitespace.shift_tokens(id); + if (!renderProgress.hasPreviousToken || + renderProgress.previousFile.size() != currentFile.size() || + !std::equal(currentFile.begin(), currentFile.end(), renderProgress.previousFile.begin())) + { + renderProgress.previousFile.assign(currentFile.c_str(), currentFile.size()); } + renderProgress.previousLine = currentLine; + renderProgress.hasPreviousToken = true; + renderProgress.previousWasExplicitWhitespace = explicitWhitespace; + ++renderProgress.emittedTokenCount; + + if (tokenTimer.has_value()) + tokenTimer.reset(); } - renderProgress.output += value; - whitespace.shift_tokens(id); - renderProgress.previousPosition = position; - renderProgress.previousWasExplicitWhitespace = explicitWhitespace; - const auto& file = position.get_file(); - renderProgress.lastTokenFile.assign(file.c_str(), file.size()); - renderProgress.lastTokenLine = position.get_line(); - renderProgress.lastTokenColumn = position.get_column(); - renderProgress.lastTokenValue = value; - ++renderProgress.emittedTokenCount; + if (loopBodyTimer.has_value()) + loopBodyTimer.reset(); + + if (perfStats.enabled) + { + nbl::wave::detail::ScopedPerfTimer iteratorAdvanceTimer(perfStats.iteratorAdvanceTime); + ++it; + } + else + ++it; } } @@ -331,6 +350,8 @@ std::string preprocessImpl( }; try { + const auto totalBegin = std::chrono::steady_clock::now(); + nbl::wave::detail::reset_perf_stats(); context.set_caching(withCaching); context.add_macro_definition("__HLSL_VERSION"); context.add_macro_definition("__SPIRV_MAJOR_VERSION__=" + std::to_string(IShaderCompiler::getSpirvMajor(preprocessOptions.targetSpirvVersion))); @@ -347,7 +368,14 @@ std::string preprocessImpl( activeMacroDefinition.clear(); phase = "expanding translation unit"; - renderPreprocessedOutput(context, renderProgress); + { + nbl::wave::detail::ScopedPerfTimer renderTimer(nbl::wave::detail::perf_stats().renderTime); + renderPreprocessedOutput(context, renderProgress); + } + auto& perfStats = nbl::wave::detail::perf_stats(); + perfStats.outputBytes = renderProgress.output.size(); + perfStats.emittedTokenCount = renderProgress.emittedTokenCount; + perfStats.totalPreprocessTime = std::chrono::steady_clock::now() - totalBegin; } catch (boost::wave::preprocess_exception& e) { @@ -384,6 +412,7 @@ std::string preprocessImpl( } post(context); + nbl::wave::detail::dump_perf_stats(); return std::move(renderProgress.output); } diff --git a/src/nbl/asset/utils/IShaderCompiler.cpp b/src/nbl/asset/utils/IShaderCompiler.cpp index 372e877e21..434a5bf416 100644 --- a/src/nbl/asset/utils/IShaderCompiler.cpp +++ b/src/nbl/asset/utils/IShaderCompiler.cpp @@ -2,6 +2,7 @@ // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h #include "nbl/asset/utils/IShaderCompiler.h" +#include "includeResolutionCommon.h" #include "nbl/asset/utils/shadercUtils.h" #include @@ -600,22 +601,53 @@ core::vector IShaderCompiler::IIncludeGenerator::parseArgumentsFrom IShaderCompiler::CFileSystemIncludeLoader::CFileSystemIncludeLoader(core::smart_refctd_ptr&& system) : m_system(std::move(system)) {} -auto IShaderCompiler::CFileSystemIncludeLoader::getInclude(const system::path& searchPath, const std::string& includeName) const -> found_t +auto IShaderCompiler::CFileSystemIncludeLoader::getInclude(const system::path& searchPath, const std::string& includeName, bool needHash) const -> found_t { - system::path path = searchPath / includeName; - if (std::filesystem::exists(path)) - path = std::filesystem::canonical(path); + system::path path = (searchPath / includeName).lexically_normal(); + + const auto cacheKey = path.generic_string(); + if (!cacheKey.empty()) + { + std::lock_guard lock(m_cacheMutex); + const auto found = m_cache.find(cacheKey); + if (found != m_cache.end()) + { + if (needHash && found->second.hash == core::blake3_hash_t{}) + { + core::blake3_hasher hasher; + hasher.update(reinterpret_cast(found->second.contents.data()), found->second.contents.size() * (sizeof(char) / sizeof(uint8_t))); + found->second.hash = static_cast(hasher); + } + return found->second; + } + if (m_missingCache.contains(cacheKey)) + return {}; + } core::smart_refctd_ptr f; { system::ISystem::future_t> future; m_system->createFile(future, path.c_str(), system::IFile::ECF_READ); if (!future.wait()) + { + if (!cacheKey.empty()) + { + std::lock_guard lock(m_cacheMutex); + m_missingCache.insert(cacheKey); + } return {}; + } future.acquire().move_into(f); } if (!f) + { + if (!cacheKey.empty()) + { + std::lock_guard lock(m_cacheMutex); + m_missingCache.insert(cacheKey); + } return {}; + } const size_t size = f->getSize(); std::string contents(size, '\0'); @@ -624,7 +656,22 @@ auto IShaderCompiler::CFileSystemIncludeLoader::getInclude(const system::path& s const bool success = bool(succ); assert(success); - return { f->getFileName(),std::move(contents) }; + found_t retVal = { f->getFileName(),std::move(contents) }; + if (needHash) + { + core::blake3_hasher hasher; + hasher.update(reinterpret_cast(retVal.contents.data()), retVal.contents.size() * (sizeof(char) / sizeof(uint8_t))); + retVal.hash = static_cast(hasher); + } + + if (!cacheKey.empty()) + { + std::lock_guard lock(m_cacheMutex); + m_missingCache.erase(cacheKey); + m_cache.insert_or_assign(cacheKey, retVal); + } + + return retVal; } namespace @@ -644,49 +691,68 @@ std::string normalizeIncludeLookupName(const std::string& includeName) return includeName.substr(1ull); } + } IShaderCompiler::CIncludeFinder::CIncludeFinder(core::smart_refctd_ptr&& system) : m_defaultFileSystemLoader(core::make_smart_refctd_ptr(std::move(system))) { - addSearchPath("", m_defaultFileSystemLoader); } // ! includes within <> // @param requestingSourceDir: the directory where the incude was requested // @param includeName: the string within <> of the include preprocessing directive // @param -auto IShaderCompiler::CIncludeFinder::getIncludeStandard(const system::path& requestingSourceDir, const std::string& includeName) const -> IIncludeLoader::found_t +auto IShaderCompiler::CIncludeFinder::getIncludeStandard(const system::path& requestingSourceDir, const std::string& includeName, bool needHash) const -> IIncludeLoader::found_t { const auto lookupName = normalizeIncludeLookupName(includeName); IShaderCompiler::IIncludeLoader::found_t retVal; if (auto contents = tryIncludeGenerators(lookupName)) retVal = std::move(contents); - else if (auto contents = trySearchPaths(lookupName)) + else if (auto contents = trySearchPaths(lookupName, needHash)) retVal = std::move(contents); - else retVal = m_defaultFileSystemLoader->getInclude(requestingSourceDir.string(), lookupName); + else retVal = m_defaultFileSystemLoader->getInclude(requestingSourceDir.string(), lookupName, needHash); - core::blake3_hasher hasher; - hasher.update(reinterpret_cast(retVal.contents.data()), retVal.contents.size() * (sizeof(char) / sizeof(uint8_t))); - retVal.hash = static_cast(hasher); + if (needHash && retVal && retVal.hash == core::blake3_hash_t{}) + { + core::blake3_hasher hasher; + hasher.update(reinterpret_cast(retVal.contents.data()), retVal.contents.size() * (sizeof(char) / sizeof(uint8_t))); + retVal.hash = static_cast(hasher); + } return retVal; } // ! includes within "" // @param requestingSourceDir: the directory where the incude was requested // @param includeName: the string within "" of the include preprocessing directive -auto IShaderCompiler::CIncludeFinder::getIncludeRelative(const system::path& requestingSourceDir, const std::string& includeName) const -> IIncludeLoader::found_t +auto IShaderCompiler::CIncludeFinder::getIncludeRelative(const system::path& requestingSourceDir, const std::string& includeName, bool needHash) const -> IIncludeLoader::found_t { const auto lookupName = normalizeIncludeLookupName(includeName); IShaderCompiler::IIncludeLoader::found_t retVal; - if (auto contents = m_defaultFileSystemLoader->getInclude(requestingSourceDir.string(), lookupName)) - retVal = std::move(contents); - else retVal = std::move(trySearchPaths(lookupName)); + if (asset::detail::isGloballyResolvedIncludeName(lookupName)) + { + if (auto contents = tryIncludeGenerators(lookupName)) + retVal = std::move(contents); + else if (auto contents = trySearchPaths(lookupName, needHash)) + retVal = std::move(contents); + else retVal = m_defaultFileSystemLoader->getInclude(requestingSourceDir.string(), lookupName, needHash); + } + else + { + if (auto contents = m_defaultFileSystemLoader->getInclude(requestingSourceDir.string(), lookupName, needHash)) + retVal = std::move(contents); + else if (auto contents = tryIncludeGenerators(lookupName)) + retVal = std::move(contents); + else retVal = std::move(trySearchPaths(lookupName, needHash)); + } - core::blake3_hasher hasher; - hasher.update(reinterpret_cast(retVal.contents.data()), retVal.contents.size() * (sizeof(char) / sizeof(uint8_t))); - retVal.hash = static_cast(hasher); + if (needHash && retVal && retVal.hash == core::blake3_hash_t{}) + { + core::blake3_hasher hasher; + hasher.update(reinterpret_cast(retVal.contents.data()), retVal.contents.size() * (sizeof(char) / sizeof(uint8_t))); + retVal.hash = static_cast(hasher); + } return retVal; } @@ -713,10 +779,10 @@ void IShaderCompiler::CIncludeFinder::addGenerator(const core::smart_refctd_ptr< m_generators.insert(found, generatorToAdd); } -auto IShaderCompiler::CIncludeFinder::trySearchPaths(const std::string& includeName) const -> IIncludeLoader::found_t +auto IShaderCompiler::CIncludeFinder::trySearchPaths(const std::string& includeName, bool needHash) const -> IIncludeLoader::found_t { for (const auto& itr : m_loaders) - if (auto contents = itr.loader->getInclude(itr.searchPath, includeName)) + if (auto contents = itr.loader->getInclude(itr.searchPath, includeName, needHash)) return contents; return {}; } diff --git a/src/nbl/asset/utils/includeResolutionCommon.h b/src/nbl/asset/utils/includeResolutionCommon.h new file mode 100644 index 0000000000..dfe9a28684 --- /dev/null +++ b/src/nbl/asset/utils/includeResolutionCommon.h @@ -0,0 +1,36 @@ +// Copyright (C) 2018-2026 - 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 +#ifndef _NBL_ASSET_INCLUDE_RESOLUTION_COMMON_H_INCLUDED_ +#define _NBL_ASSET_INCLUDE_RESOLUTION_COMMON_H_INCLUDED_ + +#include + +namespace nbl::asset::detail +{ +inline bool isGloballyResolvedIncludeName(std::string_view includeName) +{ + constexpr std::string_view globalPrefixes[] = { + "nbl/", + "nbl\\", + "boost/", + "boost\\", + "glm/", + "glm\\", + "spirv/", + "spirv\\", + "Imath/", + "Imath\\" + }; + + for (const auto prefix : globalPrefixes) + { + if (includeName.rfind(prefix, 0ull) == 0ull) + return true; + } + + return false; +} +} + +#endif diff --git a/src/nbl/asset/utils/waveContext.h b/src/nbl/asset/utils/waveContext.h index 36f9d4ea99..4b9a263add 100644 --- a/src/nbl/asset/utils/waveContext.h +++ b/src/nbl/asset/utils/waveContext.h @@ -8,10 +8,16 @@ #include #include #include +#include +#include +#include +#include #include +#include #include #include "nbl/asset/utils/IShaderCompiler.h" +#include "includeResolutionCommon.h" namespace nbl::wave { @@ -21,6 +27,153 @@ using namespace boost::wave::util; namespace detail { +struct PerfStats +{ + bool enabled = false; + bool includeDetailsEnabled = false; + uint64_t includeRequests = 0ull; + uint64_t includeLookupCount = 0ull; + uint64_t includeResolutionCacheSkips = 0ull; + uint64_t postLoadPragmaSkips = 0ull; + std::chrono::nanoseconds includeLookupTime = std::chrono::nanoseconds::zero(); + std::chrono::nanoseconds tokenHandlingTime = std::chrono::nanoseconds::zero(); + std::chrono::nanoseconds iteratorAdvanceTime = std::chrono::nanoseconds::zero(); + std::chrono::nanoseconds loopBodyTime = std::chrono::nanoseconds::zero(); + std::chrono::nanoseconds renderTime = std::chrono::nanoseconds::zero(); + std::chrono::nanoseconds totalPreprocessTime = std::chrono::nanoseconds::zero(); + size_t outputBytes = 0ull; + uint64_t emittedTokenCount = 0ull; + std::unordered_map requestedIncludeSpellingCounts; + std::unordered_map resolvedIncludePathCounts; +}; + +inline PerfStats& perf_stats() +{ + static PerfStats stats = []() + { + PerfStats value; + value.enabled = std::getenv("NBL_WAVE_PROFILE") != nullptr; + value.includeDetailsEnabled = std::getenv("NBL_WAVE_PROFILE_INCLUDES") != nullptr; + return value; + }(); + return stats; +} + +inline void reset_perf_stats() +{ + auto& stats = perf_stats(); + const bool enabled = stats.enabled; + const bool includeDetailsEnabled = stats.includeDetailsEnabled; + stats = {}; + stats.enabled = enabled; + stats.includeDetailsEnabled = includeDetailsEnabled; +} + +class ScopedPerfTimer +{ + public: + explicit ScopedPerfTimer(std::chrono::nanoseconds& target) : m_target(target), m_begin(std::chrono::steady_clock::now()) {} + ~ScopedPerfTimer() + { + m_target += std::chrono::steady_clock::now() - m_begin; + } + + private: + std::chrono::nanoseconds& m_target; + std::chrono::steady_clock::time_point m_begin; +}; + +inline void dump_perf_stats() +{ + const auto& stats = perf_stats(); + if (!stats.enabled) + return; + + const auto to_ms = [](const std::chrono::nanoseconds value) -> double + { + return std::chrono::duration(value).count(); + }; + + std::fprintf( + stderr, + "[wave-profile] total_ms=%.3f include_lookup_ms=%.3f token_handling_ms=%.3f iterator_advance_ms=%.3f loop_body_ms=%.3f render_ms=%.3f include_requests=%llu include_lookups=%llu resolution_cache_skips=%llu postload_pragma_skips=%llu emitted_tokens=%llu output_bytes=%zu\n", + to_ms(stats.totalPreprocessTime), + to_ms(stats.includeLookupTime), + to_ms(stats.tokenHandlingTime), + to_ms(stats.iteratorAdvanceTime), + to_ms(stats.loopBodyTime), + to_ms(stats.renderTime), + static_cast(stats.includeRequests), + static_cast(stats.includeLookupCount), + static_cast(stats.includeResolutionCacheSkips), + static_cast(stats.postLoadPragmaSkips), + static_cast(stats.emittedTokenCount), + stats.outputBytes + ); + + if (!stats.includeDetailsEnabled) + return; + + auto dumpTopCounts = [](const char* const label, const std::unordered_map& counts) + { + if (counts.empty()) + return; + + std::vector> entries; + entries.reserve(counts.size()); + for (const auto& [name, count] : counts) + entries.emplace_back(name, count); + + std::sort(entries.begin(), entries.end(), [](const auto& lhs, const auto& rhs) + { + if (lhs.second != rhs.second) + return lhs.second > rhs.second; + return lhs.first < rhs.first; + }); + + constexpr size_t kMaxEntries = 24ull; + const auto limit = std::min(entries.size(), kMaxEntries); + for (size_t i = 0ull; i < limit; ++i) + { + const auto& entry = entries[i]; + std::fprintf(stderr, "[wave-profile] %s[%zu]=%llu %s\n", label, i, static_cast(entry.second), entry.first.c_str()); + } + }; + + dumpTopCounts("requested_include", stats.requestedIncludeSpellingCounts); + dumpTopCounts("resolved_include", stats.resolvedIncludePathCounts); +} + +struct LanguageFlagConfig +{ + bool preserveComments = false; + bool enableCpp20 = true; + bool preferPpNumbers = true; + bool emitLineDirectives = true; + bool includeGuardDetection = true; + bool emitPragmaDirectives = true; +}; + +inline boost::wave::language_support make_language_flags(const LanguageFlagConfig& config) +{ + auto flags = boost::wave::language_support(); + if (config.enableCpp20) + flags = boost::wave::language_support(flags | support_cpp20); // C++20 lexer mode. https://github.com/Devsh-Graphics-Programming/wave/blob/e02cda69e4d070fd9b16a39282d6b5c717cb3da4/include/boost/wave/language_support.hpp#L56-L59 + if (config.preferPpNumbers) + flags = boost::wave::language_support(flags | support_option_prefer_pp_numbers); // Prefer pp-number lexing before retokenization. https://github.com/Devsh-Graphics-Programming/wave/blob/e02cda69e4d070fd9b16a39282d6b5c717cb3da4/include/boost/wave/language_support.hpp#L71 + if (config.preserveComments) + flags = boost::wave::language_support(flags | support_option_preserve_comments); // Keep comments in the token stream. https://github.com/Devsh-Graphics-Programming/wave/blob/e02cda69e4d070fd9b16a39282d6b5c717cb3da4/include/boost/wave/language_support.hpp#L67 + if (config.emitLineDirectives) + flags = boost::wave::language_support(flags | support_option_emit_line_directives); // Emit #line directives in the output. https://github.com/Devsh-Graphics-Programming/wave/blob/e02cda69e4d070fd9b16a39282d6b5c717cb3da4/include/boost/wave/language_support.hpp#L72 + if (config.includeGuardDetection) + flags = boost::wave::language_support(flags | support_option_include_guard_detection); // Let Wave short-circuit classic include guards. https://github.com/Devsh-Graphics-Programming/wave/blob/e02cda69e4d070fd9b16a39282d6b5c717cb3da4/libs/wave/include/boost/wave/language_support.hpp#L239 + if (config.emitPragmaDirectives) + flags = boost::wave::language_support(flags | support_option_emit_pragma_directives); // Keep pragma directives in the output. https://github.com/Devsh-Graphics-Programming/wave/blob/e02cda69e4d070fd9b16a39282d6b5c717cb3da4/include/boost/wave/language_support.hpp#L74 + // support_option_emit_contnewlines // Emit escaped line continuations. https://github.com/Devsh-Graphics-Programming/wave/blob/e02cda69e4d070fd9b16a39282d6b5c717cb3da4/include/boost/wave/language_support.hpp#L65 + // support_option_insert_whitespace // Let Wave inject separator whitespace. https://github.com/Devsh-Graphics-Programming/wave/blob/e02cda69e4d070fd9b16a39282d6b5c717cb3da4/include/boost/wave/language_support.hpp#L66 + return flags; +} + inline std::string escape_control_chars(std::string_view text) { static constexpr char hex[] = "0123456789ABCDEF"; @@ -81,7 +234,7 @@ struct load_to_string final template static void init_iterators(IterContextT& iter_ctx, PositionT const& act_pos, boost::wave::language_support language) { - iter_ctx.instring = iter_ctx.ctx.get_located_include_content(); + iter_ctx.instring = iter_ctx.ctx.take_located_include_content(); if (!iter_ctx.instring.empty() && iter_ctx.instring.back() != '\n' && iter_ctx.instring.back() != '\r') iter_ctx.instring.push_back('\n'); @@ -99,7 +252,7 @@ struct load_to_string final struct preprocessing_hooks final : public boost::wave::context_policies::default_preprocessing_hooks { 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() + : m_includeFinder(_preprocessOptions.includeFinder), m_logger(_preprocessOptions.logger), m_preserveComments(_preprocessOptions.preserveComments), m_pragmaStage(nbl::asset::IShader::E_SHADER_STAGE::ESS_UNKNOWN), m_dxc_compile_flags_override() { hash_token_occurences = 0; } @@ -205,9 +358,9 @@ struct preprocessing_hooks final : public boost::wave::context_policies::default return false; } - const asset::IShaderCompiler::CIncludeFinder* m_includeFinder; system::logger_opt_ptr m_logger; + bool m_preserveComments; asset::IShader::E_SHADER_STAGE m_pragmaStage; int hash_token_occurences; std::vector m_dxc_compile_flags_override; @@ -250,15 +403,7 @@ class context : private boost::noncopyable , current_filename(fname) , current_relative_filename(fname) , macros(*this_()) - , language(language_support( - support_cpp20 // C++20 lexer mode. https://github.com/Devsh-Graphics-Programming/wave/blob/e02cda69e4d070fd9b16a39282d6b5c717cb3da4/include/boost/wave/language_support.hpp#L56-L59 - | support_option_prefer_pp_numbers // Prefer pp-number lexing before retokenization. https://github.com/Devsh-Graphics-Programming/wave/blob/e02cda69e4d070fd9b16a39282d6b5c717cb3da4/include/boost/wave/language_support.hpp#L71 - | support_option_preserve_comments // Keep comments in the token stream. https://github.com/Devsh-Graphics-Programming/wave/blob/e02cda69e4d070fd9b16a39282d6b5c717cb3da4/include/boost/wave/language_support.hpp#L67 - | support_option_emit_line_directives // Emit #line directives in the output. https://github.com/Devsh-Graphics-Programming/wave/blob/e02cda69e4d070fd9b16a39282d6b5c717cb3da4/include/boost/wave/language_support.hpp#L72 - | support_option_emit_pragma_directives // Keep pragma directives in the output. https://github.com/Devsh-Graphics-Programming/wave/blob/e02cda69e4d070fd9b16a39282d6b5c717cb3da4/include/boost/wave/language_support.hpp#L74 -// | support_option_emit_contnewlines // Emit escaped line continuations. https://github.com/Devsh-Graphics-Programming/wave/blob/e02cda69e4d070fd9b16a39282d6b5c717cb3da4/include/boost/wave/language_support.hpp#L65 -// | support_option_insert_whitespace // Let Wave inject separator whitespace. https://github.com/Devsh-Graphics-Programming/wave/blob/e02cda69e4d070fd9b16a39282d6b5c717cb3da4/include/boost/wave/language_support.hpp#L66 - )) + , language(detail::make_language_flags(detail::LanguageFlagConfig{.preserveComments = hooks_.m_preserveComments})) , hooks(hooks_) { macros.init_predefined_macros(fname); @@ -414,6 +559,10 @@ class context : private boost::noncopyable { return located_include_content; } + core::string take_located_include_content() + { + return std::move(located_include_content); + } // Nabla Additions End #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) @@ -512,6 +661,19 @@ class context : private boost::noncopyable { return pragma_once_headers.contains(filename_); } + bool has_cached_include_resolution(std::string_view includeName, bool is_system, std::string& absolutePath) const + { + const auto found = include_resolution_cache.find(make_include_resolution_key(includeName, is_system)); + if (found == include_resolution_cache.end()) + return false; + + absolutePath = found->second; + return true; + } + void cache_include_resolution(std::string_view includeName, bool is_system, const std::string& absolutePath) + { + include_resolution_cache.insert_or_assign(make_include_resolution_key(includeName, is_system), absolutePath); + } bool add_pragma_once_header(std::string const& filename_, std::string const& guard_name) { get_hooks().detected_include_guard(derived(), filename_, guard_name); @@ -558,6 +720,7 @@ class context : private boost::noncopyable #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 std::unordered_set pragma_once_headers; #endif + std::unordered_map include_resolution_cache; // Cache Additions bool cachingRequested = false; std::vector dependencies = {}; @@ -568,6 +731,25 @@ class context : private boost::noncopyable macromap_type macros; // map of defined macros const boost::wave::language_support language; // supported language/extensions preprocessing_hooks hooks; // hook policy instance + + std::string make_include_resolution_key(std::string_view includeName, bool is_system) const + { + std::string key; + const bool globallyResolved = is_system || asset::detail::isGloballyResolvedIncludeName(includeName); + if (!globallyResolved) + { + const auto currentDirString = current_dir.generic_string(); + key.reserve(currentDirString.size() + includeName.size() + 3ull); + key.append(currentDirString); + key.push_back('\n'); + } + else + key.reserve(includeName.size() + 2ull); + key.push_back(globallyResolved ? 'G' : 'R'); + key.push_back('\n'); + key.append(includeName.data(), includeName.size()); + return key; + } }; } @@ -588,19 +770,49 @@ template<> inline bool boost::wave::impl::pp_iterator_functorgetDefaultFileSystemLoader()->getInclude(nbl::system::path{}, cachedAbsolutePath, needHash); + standardInclude = is_system; + } + } - if (includeFinder) + if (!result && includeFinder) { + nbl::wave::detail::ScopedPerfTimer lookupTimer(perfStats.includeLookupTime); + if (perfStats.enabled) + ++perfStats.includeLookupCount; if (is_system) { - result = includeFinder->getIncludeStandard(ctx.get_current_directory(), file_path); + result = includeFinder->getIncludeStandard(ctx.get_current_directory(), file_path, needHash); standardInclude = true; } else { - result = includeFinder->getIncludeRelative(ctx.get_current_directory(), file_path); + result = includeFinder->getIncludeRelative(ctx.get_current_directory(), file_path, needHash); standardInclude = false; } } - else { + else if (!result) { const auto escapedPath = nbl::wave::detail::escape_control_chars(file_path); ctx.get_hooks().m_logger.log("Pre-processor error: Include finder not assigned, preprocessor will not include file %s", nbl::system::ILogger::ELL_ERROR, escapedPath.c_str()); return false; @@ -618,9 +830,18 @@ template<> inline bool boost::wave::impl::pp_iterator_functor found_t +auto CJITIncludeLoader::getInclude(const system::path& searchPath, const std::string& includeName, bool) const -> found_t { assert(searchPath=="nbl/builtin/hlsl/jit"); From 555684d18626008154be5ca524ab9b239444b781 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sun, 22 Mar 2026 23:22:44 +0100 Subject: [PATCH 02/60] Advance DXC to latest unroll-devshFixes --- 3rdparty/dxc/dxc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty/dxc/dxc b/3rdparty/dxc/dxc index 8466c63aaf..118cade274 160000 --- a/3rdparty/dxc/dxc +++ b/3rdparty/dxc/dxc @@ -1 +1 @@ -Subproject commit 8466c63aaf8f577948b5dfeb7f92b244c7bb9062 +Subproject commit 118cade2746a156d17fb219a7e16e2d9d433742e From 03ad12b4cc651719220442592e1aacff6530cc80 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Mon, 23 Mar 2026 05:43:58 +0100 Subject: [PATCH 03/60] Restore default include search path for builtin HLSL --- src/nbl/asset/utils/IShaderCompiler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nbl/asset/utils/IShaderCompiler.cpp b/src/nbl/asset/utils/IShaderCompiler.cpp index 434a5bf416..8ef764e4a6 100644 --- a/src/nbl/asset/utils/IShaderCompiler.cpp +++ b/src/nbl/asset/utils/IShaderCompiler.cpp @@ -697,6 +697,7 @@ std::string normalizeIncludeLookupName(const std::string& includeName) IShaderCompiler::CIncludeFinder::CIncludeFinder(core::smart_refctd_ptr&& system) : m_defaultFileSystemLoader(core::make_smart_refctd_ptr(std::move(system))) { + addSearchPath("", m_defaultFileSystemLoader); } // ! includes within <> From ac0289dda98b1046000873b0b3ffedb06356be53 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Mon, 23 Mar 2026 10:42:38 +0100 Subject: [PATCH 04/60] Advance DXC to latest unroll-devshFixes --- 3rdparty/dxc/dxc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty/dxc/dxc b/3rdparty/dxc/dxc index 118cade274..07f06e9d48 160000 --- a/3rdparty/dxc/dxc +++ b/3rdparty/dxc/dxc @@ -1 +1 @@ -Subproject commit 118cade2746a156d17fb219a7e16e2d9d433742e +Subproject commit 07f06e9d48807ef8e7cabc41ae6acdeb26c68c09 From 8e3c301685a29e7dde322048ac0199c35df1dc4c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 23 Mar 2026 11:45:40 +0100 Subject: [PATCH 05/60] Promote NSC channel ac0289dda98b1046000873b0b3ffedb06356be53 (#1028) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- tools/nsc/manifests/nsc-windows-x64-release.tag | 2 +- .../exe/tools/nsc/bin/build-info.json.dvc | 4 ++-- .../nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc | 2 +- .../runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc | 4 ++-- .../nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/nsc/manifests/nsc-windows-x64-release.tag b/tools/nsc/manifests/nsc-windows-x64-release.tag index cd8d651439..0e2bf783fa 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release.tag +++ b/tools/nsc/manifests/nsc-windows-x64-release.tag @@ -1 +1 @@ -nsc-windows-x64-release-66da590b3f06b586f69bdb522bad2f2eebf11b6f +nsc-windows-x64-release-ac0289dda98b1046000873b0b3ffedb06356be53 diff --git a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc index 2e26e723f6..aa682377ac 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc @@ -1,5 +1,5 @@ outs: -- md5: 3422c063e9f0078b4efae5aa374e12c6 - size: 1286 +- md5: 0313edc75aedd79a1ec94ab90feb5881 + size: 1326 hash: md5 path: build-info.json diff --git a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc index 976c2e55fb..38b1766b5a 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc @@ -1,5 +1,5 @@ outs: -- md5: e8859f963019b7c7dd0fd815e625e4ee +- md5: 159813ebd3546457ad48e3a310b3f693 size: 256512 hash: md5 path: nsc.exe diff --git a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc index 3b22d29bd8..b1f8ff3713 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc @@ -1,5 +1,5 @@ outs: -- md5: bcdd137482f6fd4a3b55da0884978d58 - size: 21367296 +- md5: ec2f20db14ac9272795ba5ad970423b8 + size: 21578752 hash: md5 path: dxcompiler.dll diff --git a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc index 5ad31c5b16..c74a077ab8 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc @@ -1,5 +1,5 @@ outs: -- md5: 5707af6c5ca1d82db41e877d075af6b2 - size: 29018624 +- md5: 219186a91cf612f2ab0f9dd22278206f + size: 29173760 hash: md5 path: Nabla.dll From fe4a5280abd281a6b309fa04c06141359fb8035c Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Mon, 23 Mar 2026 12:49:03 +0100 Subject: [PATCH 06/60] Update examples_tests to local unroll --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 8f045a1c27..adf0db4f96 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 8f045a1c27a198f8542456378f865032765378b8 +Subproject commit adf0db4f96e56330b58100adceff172e2f640da6 From f195565cdf9ca828194d5156230663f5c76769e7 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Mon, 23 Mar 2026 16:03:36 +0100 Subject: [PATCH 07/60] Update EX31 examples pointer --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index adf0db4f96..13f092092d 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit adf0db4f96e56330b58100adceff172e2f640da6 +Subproject commit 13f092092d31101b1cf82cbf4442f8666cdfc1ff From 697cfcfdd27c6264ecc1b833dd78f7abcccf1877 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Mon, 23 Mar 2026 17:26:51 +0100 Subject: [PATCH 08/60] Wire path tracer pipeline cache --- examples_tests | 2 +- include/nbl/ext/FullScreenTriangle/FullScreenTriangle.h | 3 ++- src/nbl/ext/FullScreenTriangle/CFullScreenTriangle.cpp | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/examples_tests b/examples_tests index 13f092092d..6fec0e4035 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 13f092092d31101b1cf82cbf4442f8666cdfc1ff +Subproject commit 6fec0e40352023965da651a364df3a0c229a3152 diff --git a/include/nbl/ext/FullScreenTriangle/FullScreenTriangle.h b/include/nbl/ext/FullScreenTriangle/FullScreenTriangle.h index 597ebdbd4e..39013417dc 100644 --- a/include/nbl/ext/FullScreenTriangle/FullScreenTriangle.h +++ b/include/nbl/ext/FullScreenTriangle/FullScreenTriangle.h @@ -24,7 +24,8 @@ struct ProtoPipeline final const video::IGPURenderpass* renderpass, const uint32_t subpassIx=0, asset::SBlendParams blendParams = {}, - const hlsl::SurfaceTransform::FLAG_BITS swapchainTransform=hlsl::SurfaceTransform::FLAG_BITS::IDENTITY_BIT + const hlsl::SurfaceTransform::FLAG_BITS swapchainTransform=hlsl::SurfaceTransform::FLAG_BITS::IDENTITY_BIT, + video::IGPUPipelineCache* pipelineCache = nullptr ); core::smart_refctd_ptr m_vxShader; diff --git a/src/nbl/ext/FullScreenTriangle/CFullScreenTriangle.cpp b/src/nbl/ext/FullScreenTriangle/CFullScreenTriangle.cpp index fd5411c2ab..58b1f2ea84 100644 --- a/src/nbl/ext/FullScreenTriangle/CFullScreenTriangle.cpp +++ b/src/nbl/ext/FullScreenTriangle/CFullScreenTriangle.cpp @@ -84,7 +84,8 @@ smart_refctd_ptr ProtoPipeline::createPipeline( const IGPURenderpass* renderpass, const uint32_t subpassIx, SBlendParams blendParams, - const hlsl::SurfaceTransform::FLAG_BITS swapchainTransform) + const hlsl::SurfaceTransform::FLAG_BITS swapchainTransform, + IGPUPipelineCache* pipelineCache) { if (!renderpass || !bool(*this) || hlsl::bitCount(swapchainTransform) != 1) return nullptr; @@ -116,7 +117,7 @@ smart_refctd_ptr ProtoPipeline::createPipeline( }; params[0].renderpass = renderpass; - if (!device->createGraphicsPipelines(nullptr, params, &m_retval)) + if (!device->createGraphicsPipelines(pipelineCache, params, &m_retval)) return nullptr; } return m_retval; From fad9d56e4773b073463fd9b969c3cece03d1b827 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Mon, 23 Mar 2026 17:33:12 +0100 Subject: [PATCH 09/60] Update path tracer examples pointer --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 6fec0e4035..25d3f00972 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 6fec0e40352023965da651a364df3a0c229a3152 +Subproject commit 25d3f00972e786e4641a06a1abe2a65f952743d6 From a0b65da93ee84c6e3931b61af61dd06a7b1f27eb Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Mon, 23 Mar 2026 22:03:00 +0100 Subject: [PATCH 10/60] Add SPIR-V trimmer fast path --- .../nbl/asset/utils/ISPIRVEntryPointTrimmer.h | 2 +- .../asset/utils/ISPIRVEntryPointTrimmer.cpp | 116 +++++++++++------- 2 files changed, 72 insertions(+), 46 deletions(-) diff --git a/include/nbl/asset/utils/ISPIRVEntryPointTrimmer.h b/include/nbl/asset/utils/ISPIRVEntryPointTrimmer.h index a2e24dabab..1a1f6b857c 100644 --- a/include/nbl/asset/utils/ISPIRVEntryPointTrimmer.h +++ b/include/nbl/asset/utils/ISPIRVEntryPointTrimmer.h @@ -10,7 +10,7 @@ namespace nbl::asset { -class ISPIRVEntryPointTrimmer final : public core::IReferenceCounted +class NBL_API2 ISPIRVEntryPointTrimmer final : public core::IReferenceCounted { public: ISPIRVEntryPointTrimmer(); diff --git a/src/nbl/asset/utils/ISPIRVEntryPointTrimmer.cpp b/src/nbl/asset/utils/ISPIRVEntryPointTrimmer.cpp index 6695c78e96..3ee3f18e35 100644 --- a/src/nbl/asset/utils/ISPIRVEntryPointTrimmer.cpp +++ b/src/nbl/asset/utils/ISPIRVEntryPointTrimmer.cpp @@ -31,27 +31,6 @@ ISPIRVEntryPointTrimmer::ISPIRVEntryPointTrimmer() m_optimizer = core::make_smart_refctd_ptr(std::span(optimizationPasses)); } -// This is for debugging temporarily. will be reworked after finish testing -static void printCapabilities(const uint32_t* spirv, uint32_t spirvDwordCount,nbl::system::logger_opt_ptr logger) -{ - spvtools::SpirvTools core(SPIRV_VERSION); - std::string disassembly; - core.Disassemble(spirv, spirvDwordCount, &disassembly, SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); - std::stringstream ss(disassembly); - std::string to; - const auto stringsToFind = std::array{ "OpCapability", "= OpFunction","OpFunctionEnd", "OpSpecConstant", "=OpType"}; - while(std::getline(ss, to, '\n')){ - if (to.size() > 1 && to.back() == ',') continue; - for (const auto& stringToFind: stringsToFind) - { - if (to.find(stringToFind) != std::string::npos) - { - logger.log("%s", nbl::system::ILogger::ELL_DEBUG, to.c_str()); - } - } - } -} - static bool validate(const uint32_t* binary, uint32_t binarySize, nbl::system::logger_opt_ptr logger) { auto msgConsumer = [&logger](spv_message_level_t level, const char* src, const spv_position_t& pos, const char* msg) @@ -98,18 +77,6 @@ ISPIRVEntryPointTrimmer::Result ISPIRVEntryPointTrimmer::trim(const ICPUBuffer* }; } - auto foundEntryPoint = 0; - - const bool isInputSpirvValid = validate(spirv, spirvDwordCount, logger); - if (!isInputSpirvValid) - { - logger.log("SPIR-V is not valid", system::ILogger::ELL_ERROR); - return Result{ - nullptr, - false - }; - } - auto getHlslShaderStage = [](spv::ExecutionModel executionModel) -> hlsl::ShaderStage { switch (executionModel) @@ -149,6 +116,77 @@ ISPIRVEntryPointTrimmer::Result ISPIRVEntryPointTrimmer::trim(const ICPUBuffer* return { length, opcode }; }; + { + auto probeOffset = HEADER_SIZE; + auto totalEntryPoints = 0u; + auto matchingEntryPoints = 0u; + auto validFastPath = (spirvDwordCount >= HEADER_SIZE); + + while (validFastPath && probeOffset < spirvDwordCount) + { + const auto instruction = spirv[probeOffset]; + const auto [length, opcode] = parse_instruction(instruction); + if (length == 0u || (probeOffset + length) > spirvDwordCount) + { + validFastPath = false; + break; + } + if (opcode == spv::OpEntryPoint) + break; + probeOffset += length; + } + + while (validFastPath && probeOffset < spirvDwordCount) + { + const auto curOffset = probeOffset; + const auto instruction = spirv[curOffset]; + const auto [length, opcode] = parse_instruction(instruction); + if (length == 0u || (probeOffset + length) > spirvDwordCount) + { + validFastPath = false; + break; + } + if (opcode != spv::OpEntryPoint) + break; + probeOffset += length; + ++totalEntryPoints; + + const auto curExecutionModel = static_cast(spirv[curOffset + 1]); + const auto curEntryPointName = std::string_view(reinterpret_cast(spirv + curOffset + 3)); + const auto entryPoint = EntryPoint{ + .name = curEntryPointName, + .stage = getHlslShaderStage(curExecutionModel), + }; + if (entryPoint.stage == hlsl::ESS_UNKNOWN) + { + validFastPath = false; + break; + } + if (entryPoints.contains(entryPoint)) + ++matchingEntryPoints; + } + + if (validFastPath && totalEntryPoints == entryPoints.size() && matchingEntryPoints == entryPoints.size()) + { + return { + .spirv = nullptr, + .isSuccess = true, + }; + } + } + + auto foundEntryPoint = 0; + + const bool isInputSpirvValid = validate(spirv, spirvDwordCount, logger); + if (!isInputSpirvValid) + { + logger.log("SPIR-V is not valid", system::ILogger::ELL_ERROR); + return Result{ + nullptr, + false + }; + } + // Keep in mind about this layout while reading all the code below: https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#LogicalLayout // skip until entry point @@ -244,18 +282,6 @@ ISPIRVEntryPointTrimmer::Result ISPIRVEntryPointTrimmer::trim(const ICPUBuffer* auto trimmedSpirv = m_optimizer->optimize(minimizedSpirv.data(), minimizedSpirv.size(), logger); -#ifdef _NBL_DEBUG - logger.log("Before stripping capabilities:", nbl::system::ILogger::ELL_DEBUG); - printCapabilities(spirv, spirvDwordCount, logger); - logger.log("\n", nbl::system::ILogger::ELL_DEBUG); - - const auto* trimmedSpirvBuffer = static_cast(trimmedSpirv->getPointer()); - const auto trimmedSpirvDwordCount = trimmedSpirv->getSize() / 4; - logger.log("After stripping capabilities:", nbl::system::ILogger::ELL_DEBUG); - printCapabilities(trimmedSpirvBuffer, trimmedSpirvDwordCount, logger); - logger.log("\n", nbl::system::ILogger::ELL_DEBUG); -#endif - return { .spirv = std::move(trimmedSpirv), .isSuccess = true, From 9515bdda3296bab56af2b34773b385959dceb251 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Mon, 23 Mar 2026 22:03:10 +0100 Subject: [PATCH 11/60] Update path tracer examples pointer --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 25d3f00972..3b9b2f32ca 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 25d3f00972e786e4641a06a1abe2a65f952743d6 +Subproject commit 3b9b2f32cab4be51007e3b5874a5be2089396bf1 From 939de4f02438064c6a8b01b1e86572de5cee6adc Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 24 Mar 2026 06:20:17 +0100 Subject: [PATCH 12/60] Update path tracer examples pointer --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 3b9b2f32ca..f966e190b1 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 3b9b2f32cab4be51007e3b5874a5be2089396bf1 +Subproject commit f966e190b1b0a7c54a28f5a36035c206ba568e99 From dd5180b0a97c1fdab819a885f8e2c40973bb2e33 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 24 Mar 2026 07:23:13 +0100 Subject: [PATCH 13/60] Update path tracer examples pointer --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index f966e190b1..6b5ff686fb 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit f966e190b1b0a7c54a28f5a36035c206ba568e99 +Subproject commit 6b5ff686fbb5d2f2c5aecf988398e407f4814e60 From 8d3e66d2e79865c594824a1c8c1778d919a6e790 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 24 Mar 2026 07:30:57 +0100 Subject: [PATCH 14/60] Trim manifest whitespace and update examples pointer --- examples_tests | 2 +- .../exe/tools/nsc/bin/build-info.json.dvc | 4 ++-- .../nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc | 2 +- .../runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc | 4 ++-- .../nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples_tests b/examples_tests index 6b5ff686fb..200cb4a670 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 6b5ff686fbb5d2f2c5aecf988398e407f4814e60 +Subproject commit 200cb4a670b69667d03ce7f58427016e3a7054c3 diff --git a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc index aa682377ac..0b3eb66f37 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc @@ -1,5 +1,5 @@ outs: -- md5: 0313edc75aedd79a1ec94ab90feb5881 - size: 1326 +- md5: 0313edc75aedd79a1ec94ab90feb5881 + size: 1326 hash: md5 path: build-info.json diff --git a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc index 38b1766b5a..11c5dee4da 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc @@ -1,5 +1,5 @@ outs: -- md5: 159813ebd3546457ad48e3a310b3f693 +- md5: 159813ebd3546457ad48e3a310b3f693 size: 256512 hash: md5 path: nsc.exe diff --git a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc index b1f8ff3713..0edd7b4136 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc @@ -1,5 +1,5 @@ outs: -- md5: ec2f20db14ac9272795ba5ad970423b8 - size: 21578752 +- md5: ec2f20db14ac9272795ba5ad970423b8 + size: 21578752 hash: md5 path: dxcompiler.dll diff --git a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc index c74a077ab8..aa5654f0ec 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc @@ -1,5 +1,5 @@ outs: -- md5: 219186a91cf612f2ab0f9dd22278206f - size: 29173760 +- md5: 219186a91cf612f2ab0f9dd22278206f + size: 29173760 hash: md5 path: Nabla.dll From cba61133a3bf969e49e1e9009ba8e721877089f7 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 24 Mar 2026 08:52:19 +0100 Subject: [PATCH 15/60] Clean up shader review leftovers --- .../builtin/hlsl/path_tracing/concepts.hlsl | 15 ---------- src/nbl/asset/utils/CWaveStringResolver.cpp | 29 ------------------- src/nbl/asset/utils/waveContext.h | 7 ++++- 3 files changed, 6 insertions(+), 45 deletions(-) diff --git a/include/nbl/builtin/hlsl/path_tracing/concepts.hlsl b/include/nbl/builtin/hlsl/path_tracing/concepts.hlsl index 24a0e86455..140a800c81 100644 --- a/include/nbl/builtin/hlsl/path_tracing/concepts.hlsl +++ b/include/nbl/builtin/hlsl/path_tracing/concepts.hlsl @@ -80,21 +80,6 @@ NBL_CONCEPT_END( #undef ray #include -#define NBL_CONCEPT_NAME RaySetInteraction -#define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(typename) -#define NBL_CONCEPT_TPLT_PRM_NAMES (RayT)(Interaction) -#define NBL_CONCEPT_PARAM_0 (ray, RayT) -#define NBL_CONCEPT_PARAM_1 (interaction, Interaction) -NBL_CONCEPT_BEGIN(2) -#define ray NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 -#define interaction NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 -NBL_CONCEPT_END( - ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((ray.setInteraction(interaction)), ::nbl::hlsl::is_same_v, void)) -); -#undef interaction -#undef ray -#include - #define NBL_CONCEPT_NAME RayGenerator #define NBL_CONCEPT_TPLT_PRM_KINDS (typename) #define NBL_CONCEPT_TPLT_PRM_NAMES (T) diff --git a/src/nbl/asset/utils/CWaveStringResolver.cpp b/src/nbl/asset/utils/CWaveStringResolver.cpp index 744c103818..29ddf4ce55 100644 --- a/src/nbl/asset/utils/CWaveStringResolver.cpp +++ b/src/nbl/asset/utils/CWaveStringResolver.cpp @@ -8,35 +8,6 @@ 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 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 - 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 - - or ignore it and take care of NSC special target creating global HLSL PCH injected into each registered input -*/ - #include "nabla.h" #include #include diff --git a/src/nbl/asset/utils/waveContext.h b/src/nbl/asset/utils/waveContext.h index 4b9a263add..147d6d53e0 100644 --- a/src/nbl/asset/utils/waveContext.h +++ b/src/nbl/asset/utils/waveContext.h @@ -403,7 +403,12 @@ class context : private boost::noncopyable , current_filename(fname) , current_relative_filename(fname) , macros(*this_()) - , language(detail::make_language_flags(detail::LanguageFlagConfig{.preserveComments = hooks_.m_preserveComments})) + , language([&hooks_] + { + auto config = detail::LanguageFlagConfig{}; + config.preserveComments = hooks_.m_preserveComments; + return detail::make_language_flags(config); + }()) , hooks(hooks_) { macros.init_predefined_macros(fname); From 476a5bfb3012b5814675784a9e34fbf09602690d Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 24 Mar 2026 08:55:07 +0100 Subject: [PATCH 16/60] Update path tracer examples pointer --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 200cb4a670..b78500cba0 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 200cb4a670b69667d03ce7f58427016e3a7054c3 +Subproject commit b78500cba07327e9d3f6219be6a42c8b7c44ee35 From d986945228c2a50fb88390aa2fdfbbd0da054ffe Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 24 Mar 2026 10:25:24 +0100 Subject: [PATCH 17/60] Cache validated SPIR-V hashes --- examples_tests | 2 +- .../nbl/asset/utils/ISPIRVEntryPointTrimmer.h | 5 ++ .../asset/utils/ISPIRVEntryPointTrimmer.cpp | 62 ++++++++++++++++--- 3 files changed, 58 insertions(+), 11 deletions(-) diff --git a/examples_tests b/examples_tests index b78500cba0..1a64e825a8 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit b78500cba07327e9d3f6219be6a42c8b7c44ee35 +Subproject commit 1a64e825a85eb4fe44176caa61bbb8743683107c diff --git a/include/nbl/asset/utils/ISPIRVEntryPointTrimmer.h b/include/nbl/asset/utils/ISPIRVEntryPointTrimmer.h index 1a1f6b857c..1ccde512a6 100644 --- a/include/nbl/asset/utils/ISPIRVEntryPointTrimmer.h +++ b/include/nbl/asset/utils/ISPIRVEntryPointTrimmer.h @@ -7,6 +7,8 @@ #include "nbl/system/ILogger.h" +#include + namespace nbl::asset { @@ -46,6 +48,7 @@ class NBL_API2 ISPIRVEntryPointTrimmer final : public core::IReferenceCounted }; Result trim(const ICPUBuffer* spirvBuffer, const core::set& entryPoints, system::logger_opt_ptr logger = nullptr) const; + bool ensureValidated(const ICPUBuffer* spirvBuffer, system::logger_opt_ptr logger = nullptr) const; inline core::smart_refctd_ptr trim(const IShader* shader, const core::set& entryPoints, system::logger_opt_ptr logger = nullptr) const { @@ -72,6 +75,8 @@ class NBL_API2 ISPIRVEntryPointTrimmer final : public core::IReferenceCounted private: core::smart_refctd_ptr m_optimizer; + mutable std::mutex m_validationCacheMutex; + mutable core::unordered_set m_validatedSpirvHashes; }; } diff --git a/src/nbl/asset/utils/ISPIRVEntryPointTrimmer.cpp b/src/nbl/asset/utils/ISPIRVEntryPointTrimmer.cpp index 3ee3f18e35..c6503e3481 100644 --- a/src/nbl/asset/utils/ISPIRVEntryPointTrimmer.cpp +++ b/src/nbl/asset/utils/ISPIRVEntryPointTrimmer.cpp @@ -8,7 +8,9 @@ using namespace nbl::asset; -static constexpr spv_target_env SPIRV_VERSION = spv_target_env::SPV_ENV_UNIVERSAL_1_6; +// Why are we validating Universal instead of a Vulkan environment? +// Trimming works on generic SPIR-V before the Vulkan backend chooses its environment. +static constexpr spv_target_env SPIRV_VALIDATION_ENV = spv_target_env::SPV_ENV_UNIVERSAL_1_6; ISPIRVEntryPointTrimmer::ISPIRVEntryPointTrimmer() { @@ -55,7 +57,7 @@ static bool validate(const uint32_t* binary, uint32_t binarySize, nbl::system::l logger.log(location, lvl, msg); }; - spvtools::SpirvTools core(SPIRV_VERSION); + spvtools::SpirvTools core(SPIRV_VALIDATION_ENV); core.SetMessageConsumer(msgConsumer); spvtools::ValidatorOptions validatorOptions; // Nabla use Scalar block layout, we skip this validation to work around this and to save time @@ -63,6 +65,31 @@ static bool validate(const uint32_t* binary, uint32_t binarySize, nbl::system::l return core.Validate(binary, binarySize, validatorOptions); } +bool ISPIRVEntryPointTrimmer::ensureValidated(const ICPUBuffer* spirvBuffer, system::logger_opt_ptr logger) const +{ + auto contentHash = spirvBuffer->getContentHash(); + if (contentHash == ICPUBuffer::INVALID_HASH) + contentHash = spirvBuffer->computeContentHash(); + + { + std::lock_guard lock(m_validationCacheMutex); + if (m_validatedSpirvHashes.contains(contentHash)) + return true; + } + + const auto* spirv = static_cast(spirvBuffer->getPointer()); + const auto spirvDwordCount = spirvBuffer->getSize() / 4u; + if (!validate(spirv, spirvDwordCount, logger)) + return false; + + { + std::lock_guard lock(m_validationCacheMutex); + m_validatedSpirvHashes.insert(contentHash); + } + + return true; +} + ISPIRVEntryPointTrimmer::Result ISPIRVEntryPointTrimmer::trim(const ICPUBuffer* spirvBuffer, const core::set& entryPoints, system::logger_opt_ptr logger) const { const auto* spirv = static_cast(spirvBuffer->getPointer()); @@ -175,18 +202,17 @@ ISPIRVEntryPointTrimmer::Result ISPIRVEntryPointTrimmer::trim(const ICPUBuffer* } } - auto foundEntryPoint = 0; - - const bool isInputSpirvValid = validate(spirv, spirvDwordCount, logger); - if (!isInputSpirvValid) + if (!ensureValidated(spirvBuffer, logger)) { logger.log("SPIR-V is not valid", system::ILogger::ELL_ERROR); return Result{ - nullptr, - false + .spirv = nullptr, + .isSuccess = false, }; } + auto foundEntryPoint = 0; + // Keep in mind about this layout while reading all the code below: https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#LogicalLayout // skip until entry point @@ -278,9 +304,25 @@ ISPIRVEntryPointTrimmer::Result ISPIRVEntryPointTrimmer::trim(const ICPUBuffer* minimizedSpirv.insert(minimizedSpirv.end(), spirv + offset, spirv + spirvDwordCount); - assert(validate(minimizedSpirv.data(), minimizedSpirv.size(), logger)); - auto trimmedSpirv = m_optimizer->optimize(minimizedSpirv.data(), minimizedSpirv.size(), logger); + if (!trimmedSpirv) + { + logger.log("Failed to optimize trimmed SPIR-V", system::ILogger::ELL_ERROR); + return { + .spirv = nullptr, + .isSuccess = false, + }; + } + + trimmedSpirv->setContentHash(trimmedSpirv->computeContentHash()); + if (!ensureValidated(trimmedSpirv.get(), logger)) + { + logger.log("Trimmed SPIR-V is not valid", system::ILogger::ELL_ERROR); + return { + .spirv = nullptr, + .isSuccess = false, + }; + } return { .spirv = std::move(trimmedSpirv), From 5ecde9af1a2bc50462dcf4b8bf0cc1b8d1745d6d Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 24 Mar 2026 11:28:31 +0100 Subject: [PATCH 18/60] Update path tracer examples pointer --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 1a64e825a8..db1e1cf679 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 1a64e825a85eb4fe44176caa61bbb8743683107c +Subproject commit db1e1cf679d4d74423d4cfc7edf9134e06f39239 From 1ede3de70723eccdd22d58f98e404e63d0bdc105 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 24 Mar 2026 12:33:55 +0100 Subject: [PATCH 19/60] Tighten final shader cleanup --- examples_tests | 2 +- src/nbl/asset/utils/ISPIRVEntryPointTrimmer.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples_tests b/examples_tests index db1e1cf679..20587db819 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit db1e1cf679d4d74423d4cfc7edf9134e06f39239 +Subproject commit 20587db819f8ab19554f2872c7a44149c99f9fa4 diff --git a/src/nbl/asset/utils/ISPIRVEntryPointTrimmer.cpp b/src/nbl/asset/utils/ISPIRVEntryPointTrimmer.cpp index c6503e3481..8ec28f5222 100644 --- a/src/nbl/asset/utils/ISPIRVEntryPointTrimmer.cpp +++ b/src/nbl/asset/utils/ISPIRVEntryPointTrimmer.cpp @@ -78,7 +78,7 @@ bool ISPIRVEntryPointTrimmer::ensureValidated(const ICPUBuffer* spirvBuffer, sys } const auto* spirv = static_cast(spirvBuffer->getPointer()); - const auto spirvDwordCount = spirvBuffer->getSize() / 4u; + const auto spirvDwordCount = spirvBuffer->getSize() / sizeof(uint32_t); if (!validate(spirv, spirvDwordCount, logger)) return false; @@ -93,7 +93,7 @@ bool ISPIRVEntryPointTrimmer::ensureValidated(const ICPUBuffer* spirvBuffer, sys ISPIRVEntryPointTrimmer::Result ISPIRVEntryPointTrimmer::trim(const ICPUBuffer* spirvBuffer, const core::set& entryPoints, system::logger_opt_ptr logger) const { const auto* spirv = static_cast(spirvBuffer->getPointer()); - const auto spirvDwordCount = spirvBuffer->getSize() / 4; + const auto spirvDwordCount = spirvBuffer->getSize() / sizeof(uint32_t); if (entryPoints.empty()) { From 758f7c8a43d481ce1a99fb005eaafc4b0457a509 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 24 Mar 2026 12:42:40 +0100 Subject: [PATCH 20/60] Update path tracer examples pointer --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 20587db819..63a0cb9351 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 20587db819f8ab19554f2872c7a44149c99f9fa4 +Subproject commit 63a0cb935125bbe7005d9ece342f4df479914ebb From 8745660c8aaffdbeee465896bc2ea9f6ba3cea47 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 24 Mar 2026 17:23:26 +0100 Subject: [PATCH 21/60] Update path tracer examples pointer --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 63a0cb9351..4a68db651f 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 63a0cb935125bbe7005d9ece342f4df479914ebb +Subproject commit 4a68db651f95cb1f9785ada468d4a515d3f9a8f0 From 94a501fc1dfd86c6855b9ee11eb0d6fc4963cee3 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 24 Mar 2026 17:47:41 +0100 Subject: [PATCH 22/60] Mark generated NSC headers correctly --- cmake/common.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/common.cmake b/cmake/common.cmake index e70994dcdb..041904471c 100755 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -1308,6 +1308,7 @@ struct DeviceConfigCaps target_sources(${IMPL_TARGET} PUBLIC ${INCLUDE_FILE}) set_source_files_properties(${INCLUDE_FILE} PROPERTIES + GENERATED ON HEADER_FILE_ONLY ON VS_TOOL_OVERRIDE None ) From b1f28c08c794dbba93ff1afdef04bb6f2d540e28 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 24 Mar 2026 18:32:43 +0100 Subject: [PATCH 23/60] Update path tracer examples pointer --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 4a68db651f..704ef5fa6c 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 4a68db651f95cb1f9785ada468d4a515d3f9a8f0 +Subproject commit 704ef5fa6cd5e2e749b5001c2d586c280fa00311 From 4b444b6b0c4db0b907692540260972ff8ddf93f3 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 24 Mar 2026 19:44:14 +0100 Subject: [PATCH 24/60] Revert "Mark generated NSC headers correctly" This reverts commit 94a501fc1dfd86c6855b9ee11eb0d6fc4963cee3. --- cmake/common.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/common.cmake b/cmake/common.cmake index 041904471c..e70994dcdb 100755 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -1308,7 +1308,6 @@ struct DeviceConfigCaps target_sources(${IMPL_TARGET} PUBLIC ${INCLUDE_FILE}) set_source_files_properties(${INCLUDE_FILE} PROPERTIES - GENERATED ON HEADER_FILE_ONLY ON VS_TOOL_OVERRIDE None ) From f4b0aedbdce7919bf3bfcb10f21659f4ba507185 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 24 Mar 2026 19:44:25 +0100 Subject: [PATCH 25/60] Update path tracer examples pointer --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 704ef5fa6c..3fd1ae6640 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 704ef5fa6cd5e2e749b5001c2d586c280fa00311 +Subproject commit 3fd1ae6640f0fcd06371afadf9b345ac56077b27 From 01794c57ee30d267a91cd25e82e9cbab9edd70f5 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 24 Mar 2026 21:15:59 +0100 Subject: [PATCH 26/60] Update path tracer examples pointer --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 3fd1ae6640..bfaa4a2b57 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 3fd1ae6640f0fcd06371afadf9b345ac56077b27 +Subproject commit bfaa4a2b57ce3207bc5ea384194137c030ee4420 From 4a0c2e24ec86361e3a357f78ca5a1160166a3f57 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 24 Mar 2026 22:11:47 +0100 Subject: [PATCH 27/60] Update path tracer examples pointer --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index bfaa4a2b57..615ae45d25 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit bfaa4a2b57ce3207bc5ea384194137c030ee4420 +Subproject commit 615ae45d25d7b2aea584659e3f96255692fe7347 From 02f04db2b265cdd8cf0626af61b52b83f5f00c74 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 24 Mar 2026 23:23:29 +0100 Subject: [PATCH 28/60] Update path tracer examples pointer --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 615ae45d25..caaf16ce78 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 615ae45d25d7b2aea584659e3f96255692fe7347 +Subproject commit caaf16ce78086ae5854b5e78da9d06ab758106c5 From 3ae2b26254edc09c1e1ef95fb1d7e05e06875bc1 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 25 Mar 2026 00:59:15 +0100 Subject: [PATCH 29/60] Update path tracer examples pointer --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index caaf16ce78..079b6e4664 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit caaf16ce78086ae5854b5e78da9d06ab758106c5 +Subproject commit 079b6e4664459785e9913a72b37245976d601373 From fcae99102a97e50b0a865677dc6d91d77af13a3c Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 25 Mar 2026 01:27:20 +0100 Subject: [PATCH 30/60] Update path tracer examples pointer --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 079b6e4664..fc1ae322fd 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 079b6e4664459785e9913a72b37245976d601373 +Subproject commit fc1ae322fd43b867ff183ec58d24c328f48f5581 From c8af81b2f261f9e653f04545dd4792b0730af00f Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 25 Mar 2026 01:58:32 +0100 Subject: [PATCH 31/60] Update path tracer examples pointer --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index fc1ae322fd..8424767aad 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit fc1ae322fd43b867ff183ec58d24c328f48f5581 +Subproject commit 8424767aad75c5d6fd4ffa15a79a983ce3f53734 From 3541a9d24d57132609f0291f4cef89cf08827007 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 25 Mar 2026 05:26:17 +0100 Subject: [PATCH 32/60] Update path tracer examples pointer --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 8424767aad..018757b8f7 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 8424767aad75c5d6fd4ffa15a79a983ce3f53734 +Subproject commit 018757b8f7031922b181e3aaae4453d7ec02863e From 87237712ffb45b08ee3af3dc79c9d40468aef14d Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 25 Mar 2026 06:14:22 +0100 Subject: [PATCH 33/60] Validate SPIR-V once per blob --- examples_tests | 2 +- .../nbl/asset/utils/ISPIRVEntryPointTrimmer.h | 1 + .../asset/utils/ISPIRVEntryPointTrimmer.cpp | 34 +++++++++++++------ 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/examples_tests b/examples_tests index 018757b8f7..a3ef3600f3 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 018757b8f7031922b181e3aaae4453d7ec02863e +Subproject commit a3ef3600f3afa7ad2caefb1ab7b36a997ea9e1af diff --git a/include/nbl/asset/utils/ISPIRVEntryPointTrimmer.h b/include/nbl/asset/utils/ISPIRVEntryPointTrimmer.h index 1ccde512a6..fceea0aac3 100644 --- a/include/nbl/asset/utils/ISPIRVEntryPointTrimmer.h +++ b/include/nbl/asset/utils/ISPIRVEntryPointTrimmer.h @@ -49,6 +49,7 @@ class NBL_API2 ISPIRVEntryPointTrimmer final : public core::IReferenceCounted Result trim(const ICPUBuffer* spirvBuffer, const core::set& entryPoints, system::logger_opt_ptr logger = nullptr) const; bool ensureValidated(const ICPUBuffer* spirvBuffer, system::logger_opt_ptr logger = nullptr) const; + void markValidated(const ICPUBuffer* spirvBuffer) const; inline core::smart_refctd_ptr trim(const IShader* shader, const core::set& entryPoints, system::logger_opt_ptr logger = nullptr) const { diff --git a/src/nbl/asset/utils/ISPIRVEntryPointTrimmer.cpp b/src/nbl/asset/utils/ISPIRVEntryPointTrimmer.cpp index 8ec28f5222..8c3b72e08b 100644 --- a/src/nbl/asset/utils/ISPIRVEntryPointTrimmer.cpp +++ b/src/nbl/asset/utils/ISPIRVEntryPointTrimmer.cpp @@ -65,11 +65,17 @@ static bool validate(const uint32_t* binary, uint32_t binarySize, nbl::system::l return core.Validate(binary, binarySize, validatorOptions); } -bool ISPIRVEntryPointTrimmer::ensureValidated(const ICPUBuffer* spirvBuffer, system::logger_opt_ptr logger) const +static nbl::core::blake3_hash_t getContentHash(const ICPUBuffer* spirvBuffer) { auto contentHash = spirvBuffer->getContentHash(); if (contentHash == ICPUBuffer::INVALID_HASH) contentHash = spirvBuffer->computeContentHash(); + return contentHash; +} + +bool ISPIRVEntryPointTrimmer::ensureValidated(const ICPUBuffer* spirvBuffer, system::logger_opt_ptr logger) const +{ + const auto contentHash = getContentHash(spirvBuffer); { std::lock_guard lock(m_validationCacheMutex); @@ -84,12 +90,18 @@ bool ISPIRVEntryPointTrimmer::ensureValidated(const ICPUBuffer* spirvBuffer, sys { std::lock_guard lock(m_validationCacheMutex); - m_validatedSpirvHashes.insert(contentHash); + m_validatedSpirvHashes.emplace(contentHash); } return true; } +void ISPIRVEntryPointTrimmer::markValidated(const ICPUBuffer* spirvBuffer) const +{ + std::lock_guard lock(m_validationCacheMutex); + m_validatedSpirvHashes.emplace(getContentHash(spirvBuffer)); +} + ISPIRVEntryPointTrimmer::Result ISPIRVEntryPointTrimmer::trim(const ICPUBuffer* spirvBuffer, const core::set& entryPoints, system::logger_opt_ptr logger) const { const auto* spirv = static_cast(spirvBuffer->getPointer()); @@ -143,6 +155,15 @@ ISPIRVEntryPointTrimmer::Result ISPIRVEntryPointTrimmer::trim(const ICPUBuffer* return { length, opcode }; }; + if (!ensureValidated(spirvBuffer, logger)) + { + logger.log("SPIR-V is not valid", system::ILogger::ELL_ERROR); + return Result{ + .spirv = nullptr, + .isSuccess = false, + }; + } + { auto probeOffset = HEADER_SIZE; auto totalEntryPoints = 0u; @@ -202,15 +223,6 @@ ISPIRVEntryPointTrimmer::Result ISPIRVEntryPointTrimmer::trim(const ICPUBuffer* } } - if (!ensureValidated(spirvBuffer, logger)) - { - logger.log("SPIR-V is not valid", system::ILogger::ELL_ERROR); - return Result{ - .spirv = nullptr, - .isSuccess = false, - }; - } - auto foundEntryPoint = 0; // Keep in mind about this layout while reading all the code below: https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#LogicalLayout From 52ae40bf4bdebdd66da32c5d27598dd8344ecaab Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 25 Mar 2026 06:50:54 +0100 Subject: [PATCH 34/60] Update EX31 examples pointer --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index a3ef3600f3..339cb3efa1 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit a3ef3600f3afa7ad2caefb1ab7b36a997ea9e1af +Subproject commit 339cb3efa11aa5f5454fdf6f3fc0fb89fa9a28c5 From 6476500519b4378fec94a61e452e4d287ce2c20d Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 25 Mar 2026 07:17:03 +0100 Subject: [PATCH 35/60] Update EX31 examples pointer --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 339cb3efa1..04863f9cdd 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 339cb3efa11aa5f5454fdf6f3fc0fb89fa9a28c5 +Subproject commit 04863f9cddcdbcdaea990d8086c2e5200a673b66 From f5f036e488db23b6fdb2fb71e7c198f37447ee37 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 25 Mar 2026 09:09:13 +0100 Subject: [PATCH 36/60] Update EX31 examples pointer --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 04863f9cdd..7b6c1540b1 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 04863f9cddcdbcdaea990d8086c2e5200a673b66 +Subproject commit 7b6c1540b1bac6af168b32419a0102369455961d From e545d3787abe18c8dd31d46865bafb42dca8b13b Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Wed, 25 Mar 2026 11:46:18 +0100 Subject: [PATCH 37/60] Update EX31 examples pointer --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 7b6c1540b1..520e26fb52 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 7b6c1540b1bac6af168b32419a0102369455961d +Subproject commit 520e26fb5225072a8cdc9d47b9c8077c0065f8c2 From 5aa95f1014efdda4398c95a819b293b1b260de8b Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Thu, 26 Mar 2026 05:59:13 +0100 Subject: [PATCH 38/60] Address shader compiler review feedback locally --- include/nbl/asset/utils/IShaderCompiler.h | 6 -- src/nbl/asset/utils/IShaderCompiler.cpp | 60 +------------------ src/nbl/asset/utils/includeResolutionCommon.h | 36 ----------- src/nbl/asset/utils/waveContext.h | 27 ++++++++- 4 files changed, 28 insertions(+), 101 deletions(-) delete mode 100644 src/nbl/asset/utils/includeResolutionCommon.h diff --git a/include/nbl/asset/utils/IShaderCompiler.h b/include/nbl/asset/utils/IShaderCompiler.h index c43890d161..9952197e22 100644 --- a/include/nbl/asset/utils/IShaderCompiler.h +++ b/include/nbl/asset/utils/IShaderCompiler.h @@ -17,9 +17,6 @@ #include "nbl/builtin/hlsl/enums.hlsl" #include -#include -#include -#include namespace nbl::asset { @@ -72,9 +69,6 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted protected: core::smart_refctd_ptr m_system; - mutable std::mutex m_cacheMutex; - mutable std::unordered_map m_cache; - mutable std::unordered_set m_missingCache; }; class NBL_API2 CIncludeFinder : public core::IReferenceCounted diff --git a/src/nbl/asset/utils/IShaderCompiler.cpp b/src/nbl/asset/utils/IShaderCompiler.cpp index 8ef764e4a6..470bb4a4c6 100644 --- a/src/nbl/asset/utils/IShaderCompiler.cpp +++ b/src/nbl/asset/utils/IShaderCompiler.cpp @@ -2,7 +2,6 @@ // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h #include "nbl/asset/utils/IShaderCompiler.h" -#include "includeResolutionCommon.h" #include "nbl/asset/utils/shadercUtils.h" #include @@ -605,49 +604,16 @@ auto IShaderCompiler::CFileSystemIncludeLoader::getInclude(const system::path& s { system::path path = (searchPath / includeName).lexically_normal(); - const auto cacheKey = path.generic_string(); - if (!cacheKey.empty()) - { - std::lock_guard lock(m_cacheMutex); - const auto found = m_cache.find(cacheKey); - if (found != m_cache.end()) - { - if (needHash && found->second.hash == core::blake3_hash_t{}) - { - core::blake3_hasher hasher; - hasher.update(reinterpret_cast(found->second.contents.data()), found->second.contents.size() * (sizeof(char) / sizeof(uint8_t))); - found->second.hash = static_cast(hasher); - } - return found->second; - } - if (m_missingCache.contains(cacheKey)) - return {}; - } - core::smart_refctd_ptr f; { system::ISystem::future_t> future; m_system->createFile(future, path.c_str(), system::IFile::ECF_READ); if (!future.wait()) - { - if (!cacheKey.empty()) - { - std::lock_guard lock(m_cacheMutex); - m_missingCache.insert(cacheKey); - } return {}; - } future.acquire().move_into(f); } if (!f) - { - if (!cacheKey.empty()) - { - std::lock_guard lock(m_cacheMutex); - m_missingCache.insert(cacheKey); - } return {}; - } const size_t size = f->getSize(); std::string contents(size, '\0'); @@ -664,13 +630,6 @@ auto IShaderCompiler::CFileSystemIncludeLoader::getInclude(const system::path& s retVal.hash = static_cast(hasher); } - if (!cacheKey.empty()) - { - std::lock_guard lock(m_cacheMutex); - m_missingCache.erase(cacheKey); - m_cache.insert_or_assign(cacheKey, retVal); - } - return retVal; } @@ -731,22 +690,9 @@ auto IShaderCompiler::CIncludeFinder::getIncludeRelative(const system::path& req { const auto lookupName = normalizeIncludeLookupName(includeName); IShaderCompiler::IIncludeLoader::found_t retVal; - if (asset::detail::isGloballyResolvedIncludeName(lookupName)) - { - if (auto contents = tryIncludeGenerators(lookupName)) - retVal = std::move(contents); - else if (auto contents = trySearchPaths(lookupName, needHash)) - retVal = std::move(contents); - else retVal = m_defaultFileSystemLoader->getInclude(requestingSourceDir.string(), lookupName, needHash); - } - else - { - if (auto contents = m_defaultFileSystemLoader->getInclude(requestingSourceDir.string(), lookupName, needHash)) - retVal = std::move(contents); - else if (auto contents = tryIncludeGenerators(lookupName)) - retVal = std::move(contents); - else retVal = std::move(trySearchPaths(lookupName, needHash)); - } + if (auto contents = m_defaultFileSystemLoader->getInclude(requestingSourceDir.string(), lookupName, needHash)) + retVal = std::move(contents); + else retVal = std::move(trySearchPaths(lookupName, needHash)); if (needHash && retVal && retVal.hash == core::blake3_hash_t{}) { diff --git a/src/nbl/asset/utils/includeResolutionCommon.h b/src/nbl/asset/utils/includeResolutionCommon.h deleted file mode 100644 index dfe9a28684..0000000000 --- a/src/nbl/asset/utils/includeResolutionCommon.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (C) 2018-2026 - 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 -#ifndef _NBL_ASSET_INCLUDE_RESOLUTION_COMMON_H_INCLUDED_ -#define _NBL_ASSET_INCLUDE_RESOLUTION_COMMON_H_INCLUDED_ - -#include - -namespace nbl::asset::detail -{ -inline bool isGloballyResolvedIncludeName(std::string_view includeName) -{ - constexpr std::string_view globalPrefixes[] = { - "nbl/", - "nbl\\", - "boost/", - "boost\\", - "glm/", - "glm\\", - "spirv/", - "spirv\\", - "Imath/", - "Imath\\" - }; - - for (const auto prefix : globalPrefixes) - { - if (includeName.rfind(prefix, 0ull) == 0ull) - return true; - } - - return false; -} -} - -#endif diff --git a/src/nbl/asset/utils/waveContext.h b/src/nbl/asset/utils/waveContext.h index 147d6d53e0..e105f8d386 100644 --- a/src/nbl/asset/utils/waveContext.h +++ b/src/nbl/asset/utils/waveContext.h @@ -17,7 +17,6 @@ #include #include "nbl/asset/utils/IShaderCompiler.h" -#include "includeResolutionCommon.h" namespace nbl::wave { @@ -27,6 +26,30 @@ using namespace boost::wave::util; namespace detail { +inline bool is_globally_resolved_include_name(std::string_view includeName) +{ + constexpr std::string_view globalPrefixes[] = { + "nbl/", + "nbl\\", + "boost/", + "boost\\", + "glm/", + "glm\\", + "spirv/", + "spirv\\", + "Imath/", + "Imath\\" + }; + + for (const auto prefix : globalPrefixes) + { + if (includeName.rfind(prefix, 0ull) == 0ull) + return true; + } + + return false; +} + struct PerfStats { bool enabled = false; @@ -740,7 +763,7 @@ class context : private boost::noncopyable std::string make_include_resolution_key(std::string_view includeName, bool is_system) const { std::string key; - const bool globallyResolved = is_system || asset::detail::isGloballyResolvedIncludeName(includeName); + const bool globallyResolved = is_system || detail::is_globally_resolved_include_name(includeName); if (!globallyResolved) { const auto currentDirString = current_dir.generic_string(); From 40e1e1e46f98307f0ac7d20d48ddaa03e1838fe6 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Thu, 26 Mar 2026 06:03:25 +0100 Subject: [PATCH 39/60] Checkpoint local EX31 review state --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 520e26fb52..7e0e7f98ab 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 520e26fb5225072a8cdc9d47b9c8077c0065f8c2 +Subproject commit 7e0e7f98ab9a14b831de54423b81fcca8443cc0e From daf1fe39a433a469a210ea30b6a7a20abf57583d Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Thu, 26 Mar 2026 06:24:48 +0100 Subject: [PATCH 40/60] Add include session cache plumbing --- include/nbl/asset/utils/IShaderCompiler.h | 29 ++++++- src/nbl/asset/utils/CGLSLCompiler.cpp | 22 ++++-- src/nbl/asset/utils/CHLSLCompiler.cpp | 19 +++-- src/nbl/asset/utils/IShaderCompiler.cpp | 92 ++++++++++++++++++++++- src/nbl/asset/utils/waveContext.h | 7 +- 5 files changed, 147 insertions(+), 22 deletions(-) diff --git a/include/nbl/asset/utils/IShaderCompiler.h b/include/nbl/asset/utils/IShaderCompiler.h index 9952197e22..ac7c13213d 100644 --- a/include/nbl/asset/utils/IShaderCompiler.h +++ b/include/nbl/asset/utils/IShaderCompiler.h @@ -17,6 +17,8 @@ #include "nbl/builtin/hlsl/enums.hlsl" #include +#include +#include namespace nbl::asset { @@ -74,17 +76,39 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted class NBL_API2 CIncludeFinder : public core::IReferenceCounted { public: + struct SSessionCache + { + enum class E_LOOKUP_RESULT : uint8_t + { + Miss, + Missing, + Found + }; + + explicit SSessionCache(const bool threadSafe = false) : threadSafe(threadSafe) {} + + void clear(); + E_LOOKUP_RESULT lookup(const std::string& key, IIncludeLoader::found_t& result) const; + void store(const std::string& key, IIncludeLoader::found_t result); + + bool threadSafe = false; + + mutable std::mutex mutex; + core::unordered_map found; + core::unordered_set missing; + }; + CIncludeFinder(core::smart_refctd_ptr&& system); // ! includes within <> // @param requestingSourceDir: the directory where the incude was requested // @param includeName: the string within <> of the include preprocessing directive - IIncludeLoader::found_t getIncludeStandard(const system::path& requestingSourceDir, const std::string& includeName, bool needHash = true) const; + IIncludeLoader::found_t getIncludeStandard(const system::path& requestingSourceDir, const std::string& includeName, bool needHash = true, SSessionCache* sessionCache = nullptr) const; // ! includes within "" // @param requestingSourceDir: the directory where the incude was requested // @param includeName: the string within "" of the include preprocessing directive - IIncludeLoader::found_t getIncludeRelative(const system::path& requestingSourceDir, const std::string& includeName, bool needHash = true) const; + IIncludeLoader::found_t getIncludeRelative(const system::path& requestingSourceDir, const std::string& includeName, bool needHash = true, SSessionCache* sessionCache = nullptr) const; inline core::smart_refctd_ptr getDefaultFileSystemLoader() const { return m_defaultFileSystemLoader; } @@ -134,6 +158,7 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted std::string_view sourceIdentifier = ""; system::logger_opt_ptr logger = nullptr; const CIncludeFinder* includeFinder = nullptr; + mutable CIncludeFinder::SSessionCache* includeSessionCache = nullptr; std::span extraDefines = {}; E_SPIRV_VERSION targetSpirvVersion = E_SPIRV_VERSION::ESV_1_6; bool depfile = false; diff --git a/src/nbl/asset/utils/CGLSLCompiler.cpp b/src/nbl/asset/utils/CGLSLCompiler.cpp index a593a11597..d250250280 100644 --- a/src/nbl/asset/utils/CGLSLCompiler.cpp +++ b/src/nbl/asset/utils/CGLSLCompiler.cpp @@ -44,11 +44,12 @@ namespace nbl::asset::impl class Includer : public shaderc::CompileOptions::IncluderInterface { const IShaderCompiler::CIncludeFinder* m_defaultIncludeFinder; + IShaderCompiler::CIncludeFinder::SSessionCache* m_includeSessionCache; const system::ISystem* m_system; const uint32_t m_maxInclCnt; public: - Includer(const IShaderCompiler::CIncludeFinder* _inclFinder, const system::ISystem* _fs, uint32_t _maxInclCnt) : m_defaultIncludeFinder(_inclFinder), m_system(_fs), m_maxInclCnt{ _maxInclCnt } {} + Includer(const IShaderCompiler::CIncludeFinder* _inclFinder, IShaderCompiler::CIncludeFinder::SSessionCache* _includeSessionCache, const system::ISystem* _fs, uint32_t _maxInclCnt) : m_defaultIncludeFinder(_inclFinder), m_includeSessionCache(_includeSessionCache), m_system(_fs), m_maxInclCnt{ _maxInclCnt } {} //_requesting_source in top level #include's is what shaderc::Compiler's compiling functions get as `input_file_name` parameter //so in order for properly working relative #include's (""-type) `input_file_name` has to be path to file from which the GLSL source really come from @@ -81,11 +82,11 @@ namespace nbl::asset::impl IShaderCompiler::IIncludeLoader::found_t result; if (_type == shaderc_include_type_relative) { - result = m_defaultIncludeFinder->getIncludeRelative(relDir, _requested_source); + result = m_defaultIncludeFinder->getIncludeRelative(relDir, _requested_source, true, m_includeSessionCache); } else //shaderc_include_type_standard { - result = m_defaultIncludeFinder->getIncludeStandard(relDir, _requested_source); + result = m_defaultIncludeFinder->getIncludeStandard(relDir, _requested_source, true, m_includeSessionCache); } if (!result) @@ -136,10 +137,15 @@ CGLSLCompiler::CGLSLCompiler(core::smart_refctd_ptr&& system) std::string CGLSLCompiler::preprocessShader(std::string&& code, IShader::E_SHADER_STAGE& stage, const SPreprocessorOptions& preprocessOptions, std::vector* dependencies) const { + auto effectiveOptions = preprocessOptions; + IShaderCompiler::CIncludeFinder::SSessionCache localIncludeSessionCache; + if (effectiveOptions.includeFinder && !effectiveOptions.includeSessionCache) + effectiveOptions.includeSessionCache = &localIncludeSessionCache; + if (!preprocessOptions.extraDefines.empty()) { std::ostringstream insertion; - for (const auto& define : preprocessOptions.extraDefines) + for (const auto& define : effectiveOptions.extraDefines) insertion << "#define " << define.identifier << " " << define.definition << "\n"; insertIntoStart(code,std::move(insertion)); } @@ -149,15 +155,15 @@ std::string CGLSLCompiler::preprocessShader(std::string&& code, IShader::E_SHADE shaderc::CompileOptions options; options.SetTargetSpirv(shaderc_spirv_version_1_6); - if (preprocessOptions.includeFinder != nullptr) + if (effectiveOptions.includeFinder != nullptr) { - options.SetIncluder(std::make_unique(preprocessOptions.includeFinder, m_system.get(), /*maxSelfInclusionCount*/5));//custom #include handler + options.SetIncluder(std::make_unique(effectiveOptions.includeFinder, effectiveOptions.includeSessionCache, m_system.get(), /*maxSelfInclusionCount*/5));//custom #include handler } const shaderc_shader_kind scstage = stage == IShader::E_SHADER_STAGE::ESS_UNKNOWN ? shaderc_glsl_infer_from_source : ESStoShadercEnum(stage); - auto res = comp.PreprocessGlsl(code, scstage, preprocessOptions.sourceIdentifier.data(), options); + auto res = comp.PreprocessGlsl(code, scstage, effectiveOptions.sourceIdentifier.data(), options); if (res.GetCompilationStatus() != shaderc_compilation_status_success) { - preprocessOptions.logger.log("%s\n", system::ILogger::ELL_ERROR, res.GetErrorMessage().c_str()); + effectiveOptions.logger.log("%s\n", system::ILogger::ELL_ERROR, res.GetErrorMessage().c_str()); return nullptr; } diff --git a/src/nbl/asset/utils/CHLSLCompiler.cpp b/src/nbl/asset/utils/CHLSLCompiler.cpp index a3d1b3acf9..ffb3ab88c3 100644 --- a/src/nbl/asset/utils/CHLSLCompiler.cpp +++ b/src/nbl/asset/utils/CHLSLCompiler.cpp @@ -454,12 +454,17 @@ static std::string preprocessShaderImpl( std::vector* dependencies, system::ISystem* system) { - const bool depfileEnabled = preprocessOptions.depfile; + auto effectiveOptions = preprocessOptions; + IShaderCompiler::CIncludeFinder::SSessionCache localIncludeSessionCache; + if (effectiveOptions.includeFinder && !effectiveOptions.includeSessionCache) + effectiveOptions.includeSessionCache = &localIncludeSessionCache; + + const bool depfileEnabled = effectiveOptions.depfile; if (depfileEnabled) { - if (preprocessOptions.depfilePath.empty()) + if (effectiveOptions.depfilePath.empty()) { - preprocessOptions.logger.log("Depfile path is empty.", system::ILogger::ELL_ERROR); + effectiveOptions.logger.log("Depfile path is empty.", system::ILogger::ELL_ERROR); return {}; } } @@ -473,7 +478,7 @@ static std::string preprocessShaderImpl( ensureTrailingNewline(code); // preprocess - core::string resolvedString = nbl::wave::preprocess(code, preprocessOptions, bool(dependenciesOut), + core::string resolvedString = nbl::wave::preprocess(code, effectiveOptions, bool(dependenciesOut), [&dxc_compile_flags_override, &stage, &dependenciesOut](nbl::wave::context& context) -> void { if (context.get_hooks().m_dxc_compile_flags_override.size() != 0) @@ -494,13 +499,13 @@ static std::string preprocessShaderImpl( if (depfileEnabled) { IShaderCompiler::DepfileWriteParams params = {}; - const std::string depfilePathString = preprocessOptions.depfilePath.generic_string(); + const std::string depfilePathString = effectiveOptions.depfilePath.generic_string(); params.depfilePath = depfilePathString; - params.sourceIdentifier = preprocessOptions.sourceIdentifier; + params.sourceIdentifier = effectiveOptions.sourceIdentifier; if (!params.sourceIdentifier.empty()) params.workingDirectory = std::filesystem::path(std::string(params.sourceIdentifier)).parent_path(); params.system = system; - if (!IShaderCompiler::writeDepfile(params, *dependenciesOut, preprocessOptions.includeFinder, preprocessOptions.logger)) + if (!IShaderCompiler::writeDepfile(params, *dependenciesOut, effectiveOptions.includeFinder, effectiveOptions.logger)) return {}; } diff --git a/src/nbl/asset/utils/IShaderCompiler.cpp b/src/nbl/asset/utils/IShaderCompiler.cpp index 470bb4a4c6..14654c530b 100644 --- a/src/nbl/asset/utils/IShaderCompiler.cpp +++ b/src/nbl/asset/utils/IShaderCompiler.cpp @@ -651,6 +651,68 @@ std::string normalizeIncludeLookupName(const std::string& includeName) return includeName.substr(1ull); } +template +auto withSessionCacheLock(IShaderCompiler::CIncludeFinder::SSessionCache* cache, Func&& func) -> decltype(func()) +{ + if (cache && cache->threadSafe) + { + std::lock_guard lock(cache->mutex); + return func(); + } + return func(); +} + +std::string makeIncludeSessionCacheKey(const system::path& requestingSourceDir, std::string_view includeName, const bool needHash, const char mode) +{ + const auto requestingDir = requestingSourceDir.generic_string(); + std::string key; + key.reserve(requestingDir.size() + includeName.size() + 4ull); + key.push_back(mode); + key.push_back('\n'); + key.push_back(needHash ? 'H' : 'N'); + key.push_back('\n'); + key.append(requestingDir); + key.push_back('\n'); + key.append(includeName.data(), includeName.size()); + return key; +} + +} + +void IShaderCompiler::CIncludeFinder::SSessionCache::clear() +{ + withSessionCacheLock(this, [&]() + { + found.clear(); + missing.clear(); + }); +} + +auto IShaderCompiler::CIncludeFinder::SSessionCache::lookup(const std::string& key, IIncludeLoader::found_t& result) const -> E_LOOKUP_RESULT +{ + return withSessionCacheLock(const_cast(this), [&]() -> E_LOOKUP_RESULT + { + if (const auto foundIt = found.find(key); foundIt != found.end()) + { + result = foundIt->second; + return E_LOOKUP_RESULT::Found; + } + if (missing.contains(key)) + return E_LOOKUP_RESULT::Missing; + return E_LOOKUP_RESULT::Miss; + }); +} + +void IShaderCompiler::CIncludeFinder::SSessionCache::store(const std::string& key, IIncludeLoader::found_t result) +{ + withSessionCacheLock(this, [&]() + { + missing.erase(key); + if (result) + found.insert_or_assign(key, std::move(result)); + else + missing.insert(key); + }); } IShaderCompiler::CIncludeFinder::CIncludeFinder(core::smart_refctd_ptr&& system) @@ -663,10 +725,21 @@ IShaderCompiler::CIncludeFinder::CIncludeFinder(core::smart_refctd_ptr of the include preprocessing directive // @param -auto IShaderCompiler::CIncludeFinder::getIncludeStandard(const system::path& requestingSourceDir, const std::string& includeName, bool needHash) const -> IIncludeLoader::found_t +auto IShaderCompiler::CIncludeFinder::getIncludeStandard(const system::path& requestingSourceDir, const std::string& includeName, bool needHash, SSessionCache* sessionCache) const -> IIncludeLoader::found_t { const auto lookupName = normalizeIncludeLookupName(includeName); + const auto cacheKey = makeIncludeSessionCacheKey(requestingSourceDir, lookupName, needHash, 'S'); IShaderCompiler::IIncludeLoader::found_t retVal; + switch (sessionCache ? sessionCache->lookup(cacheKey, retVal) : SSessionCache::E_LOOKUP_RESULT::Miss) + { + case SSessionCache::E_LOOKUP_RESULT::Found: + return retVal; + case SSessionCache::E_LOOKUP_RESULT::Missing: + return {}; + case SSessionCache::E_LOOKUP_RESULT::Miss: + break; + } + if (auto contents = tryIncludeGenerators(lookupName)) retVal = std::move(contents); else if (auto contents = trySearchPaths(lookupName, needHash)) @@ -680,16 +753,29 @@ auto IShaderCompiler::CIncludeFinder::getIncludeStandard(const system::path& req hasher.update(reinterpret_cast(retVal.contents.data()), retVal.contents.size() * (sizeof(char) / sizeof(uint8_t))); retVal.hash = static_cast(hasher); } + if (sessionCache) + sessionCache->store(cacheKey, retVal); return retVal; } // ! includes within "" // @param requestingSourceDir: the directory where the incude was requested // @param includeName: the string within "" of the include preprocessing directive -auto IShaderCompiler::CIncludeFinder::getIncludeRelative(const system::path& requestingSourceDir, const std::string& includeName, bool needHash) const -> IIncludeLoader::found_t +auto IShaderCompiler::CIncludeFinder::getIncludeRelative(const system::path& requestingSourceDir, const std::string& includeName, bool needHash, SSessionCache* sessionCache) const -> IIncludeLoader::found_t { const auto lookupName = normalizeIncludeLookupName(includeName); + const auto cacheKey = makeIncludeSessionCacheKey(requestingSourceDir, lookupName, needHash, 'R'); IShaderCompiler::IIncludeLoader::found_t retVal; + switch (sessionCache ? sessionCache->lookup(cacheKey, retVal) : SSessionCache::E_LOOKUP_RESULT::Miss) + { + case SSessionCache::E_LOOKUP_RESULT::Found: + return retVal; + case SSessionCache::E_LOOKUP_RESULT::Missing: + return {}; + case SSessionCache::E_LOOKUP_RESULT::Miss: + break; + } + if (auto contents = m_defaultFileSystemLoader->getInclude(requestingSourceDir.string(), lookupName, needHash)) retVal = std::move(contents); else retVal = std::move(trySearchPaths(lookupName, needHash)); @@ -700,6 +786,8 @@ auto IShaderCompiler::CIncludeFinder::getIncludeRelative(const system::path& req hasher.update(reinterpret_cast(retVal.contents.data()), retVal.contents.size() * (sizeof(char) / sizeof(uint8_t))); retVal.hash = static_cast(hasher); } + if (sessionCache) + sessionCache->store(cacheKey, retVal); return retVal; } diff --git a/src/nbl/asset/utils/waveContext.h b/src/nbl/asset/utils/waveContext.h index e105f8d386..8d3fbf8bc0 100644 --- a/src/nbl/asset/utils/waveContext.h +++ b/src/nbl/asset/utils/waveContext.h @@ -275,7 +275,7 @@ struct load_to_string final struct preprocessing_hooks final : public boost::wave::context_policies::default_preprocessing_hooks { preprocessing_hooks(const nbl::asset::IShaderCompiler::SPreprocessorOptions& _preprocessOptions) - : m_includeFinder(_preprocessOptions.includeFinder), m_logger(_preprocessOptions.logger), m_preserveComments(_preprocessOptions.preserveComments), m_pragmaStage(nbl::asset::IShader::E_SHADER_STAGE::ESS_UNKNOWN), m_dxc_compile_flags_override() + : m_includeFinder(_preprocessOptions.includeFinder), m_includeSessionCache(_preprocessOptions.includeSessionCache), m_logger(_preprocessOptions.logger), m_preserveComments(_preprocessOptions.preserveComments), m_pragmaStage(nbl::asset::IShader::E_SHADER_STAGE::ESS_UNKNOWN), m_dxc_compile_flags_override() { hash_token_occurences = 0; } @@ -382,6 +382,7 @@ struct preprocessing_hooks final : public boost::wave::context_policies::default } const asset::IShaderCompiler::CIncludeFinder* m_includeFinder; + asset::IShaderCompiler::CIncludeFinder::SSessionCache* m_includeSessionCache; system::logger_opt_ptr m_logger; bool m_preserveComments; asset::IShader::E_SHADER_STAGE m_pragmaStage; @@ -832,11 +833,11 @@ template<> inline bool boost::wave::impl::pp_iterator_functorgetIncludeStandard(ctx.get_current_directory(), file_path, needHash); + result = includeFinder->getIncludeStandard(ctx.get_current_directory(), file_path, needHash, ctx.get_hooks().m_includeSessionCache); standardInclude = true; } else { - result = includeFinder->getIncludeRelative(ctx.get_current_directory(), file_path, needHash); + result = includeFinder->getIncludeRelative(ctx.get_current_directory(), file_path, needHash, ctx.get_hooks().m_includeSessionCache); standardInclude = false; } } From 9912390d32d6bbabbe5aa63d78ff3ccd21c66399 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Thu, 26 Mar 2026 06:27:25 +0100 Subject: [PATCH 41/60] Update EX31 examples pointer locally --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 7e0e7f98ab..7c0858bd32 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 7e0e7f98ab9a14b831de54423b81fcca8443cc0e +Subproject commit 7c0858bd320a9c2ce0627ca49c79c845a7069ff9 From a75f581b6195667f322ee05c4f90a2615e6533e5 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Thu, 26 Mar 2026 07:55:15 +0100 Subject: [PATCH 42/60] Update EX31 examples pointer locally --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index 7c0858bd32..6b0563698f 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 7c0858bd320a9c2ce0627ca49c79c845a7069ff9 +Subproject commit 6b0563698fa581eea8d1f54cf35e09f0df070cbd From 4aa78fd250d731c0a5423e202313597b4b46a1d1 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Thu, 26 Mar 2026 10:35:47 +0100 Subject: [PATCH 43/60] Classify toolchain include roots --- cmake/common.cmake | 11 +- examples_tests | 2 +- include/nbl/asset/utils/IShaderCompiler.h | 48 ++++++++- include/nbl/system/ISystem.h | 1 + src/nbl/asset/utils/IShaderCompiler.cpp | 125 +++++++++++++++++----- src/nbl/asset/utils/waveContext.h | 32 +----- src/nbl/system/ISystem.cpp | 9 ++ src/nbl/video/ILogicalDevice.cpp | 4 +- tools/nsc/main.cpp | 35 ++++-- 9 files changed, 196 insertions(+), 71 deletions(-) diff --git a/cmake/common.cmake b/cmake/common.cmake index e70994dcdb..ed06c32437 100755 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -1259,10 +1259,10 @@ struct DeviceConfigCaps if(NOT NBL_EMBED_BUILTIN_RESOURCES) list(APPEND REQUIRED_OPTIONS -no-nbl-builtins - -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" + -isystem "${NBL_ROOT_PATH}/include" + -isystem "${NBL_ROOT_PATH}/3rdparty/dxc/dxc/external/SPIRV-Headers/include" + -isystem "${NBL_ROOT_PATH}/3rdparty/boost/superproject/libs/preprocessor/include" + -isystem "${NBL_ROOT_PATH_BINARY}/src/nbl/device/include" ) endif() @@ -1307,7 +1307,8 @@ struct DeviceConfigCaps ) target_sources(${IMPL_TARGET} PUBLIC ${INCLUDE_FILE}) - set_source_files_properties(${INCLUDE_FILE} PROPERTIES + set_source_files_properties(${INCLUDE_FILE} PROPERTIES + GENERATED TRUE HEADER_FILE_ONLY ON VS_TOOL_OVERRIDE None ) diff --git a/examples_tests b/examples_tests index 6b0563698f..d50719c8ba 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 6b0563698fa581eea8d1f54cf35e09f0df070cbd +Subproject commit d50719c8baf51a39e3aeb7108388631558b172f9 diff --git a/include/nbl/asset/utils/IShaderCompiler.h b/include/nbl/asset/utils/IShaderCompiler.h index ac7c13213d..4197ad468f 100644 --- a/include/nbl/asset/utils/IShaderCompiler.h +++ b/include/nbl/asset/utils/IShaderCompiler.h @@ -28,6 +28,25 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted public: IShaderCompiler(core::smart_refctd_ptr&& system); + enum class IncludeRootOrigin : uint8_t + { + User, + Builtin, + Generated + }; + + enum class HeaderClass : uint8_t + { + User, + System + }; + + struct IncludeClassification + { + IncludeRootOrigin origin = IncludeRootOrigin::User; + HeaderClass headerClass = HeaderClass::User; + }; + class NBL_API2 IIncludeLoader : public core::IReferenceCounted { public: @@ -36,6 +55,7 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted system::path absolutePath = {}; std::string contents = {}; core::blake3_hash_t hash = {}; // TODO: we're not yet using IFile::getPrecomputedHash(), so for builtins we can maybe use that in the future + IncludeClassification classification = {}; // Could be used in the future for early rejection of cache hit //nbl::system::IFileBase::time_point_t lastWriteTime = {}; @@ -78,7 +98,7 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted public: struct SSessionCache { - enum class E_LOOKUP_RESULT : uint8_t + enum class LookupResult : uint8_t { Miss, Missing, @@ -88,7 +108,7 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted explicit SSessionCache(const bool threadSafe = false) : threadSafe(threadSafe) {} void clear(); - E_LOOKUP_RESULT lookup(const std::string& key, IIncludeLoader::found_t& result) const; + LookupResult lookup(const std::string& key, IIncludeLoader::found_t& result) const; void store(const std::string& key, IIncludeLoader::found_t result); bool threadSafe = false; @@ -112,23 +132,41 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted inline core::smart_refctd_ptr getDefaultFileSystemLoader() const { return m_defaultFileSystemLoader; } - void addSearchPath(const std::string& searchPath, const core::smart_refctd_ptr& loader); + void addSearchPath(const std::string& searchPath, const core::smart_refctd_ptr& loader, IncludeClassification classification = {}); + + void addGenerator(const core::smart_refctd_ptr& generator, IncludeClassification classification = {IncludeRootOrigin::Generated,HeaderClass::System}); - void addGenerator(const core::smart_refctd_ptr& generator); + bool isKnownGlobalInclude(std::string_view includeName) const; + IIncludeLoader::found_t classifyFound(IIncludeLoader::found_t found) const; protected: IIncludeLoader::found_t trySearchPaths(const std::string& includeName, bool needHash) const; IIncludeLoader::found_t tryIncludeGenerators(const std::string& includeName) const; + void registerHeaderRoot(std::string rootPath, IncludeClassification classification); struct LoaderSearchPath { core::smart_refctd_ptr loader = nullptr; std::string searchPath = {}; + IncludeClassification classification = {}; + }; + + struct GeneratorEntry + { + core::smart_refctd_ptr generator = nullptr; + IncludeClassification classification = {IncludeRootOrigin::Generated,HeaderClass::System}; + }; + + struct HeaderRoot + { + std::string path = {}; + IncludeClassification classification = {}; }; std::vector m_loaders; - std::vector> m_generators; + std::vector m_generators; + std::vector m_headerRoots; core::smart_refctd_ptr m_defaultFileSystemLoader; }; diff --git a/include/nbl/system/ISystem.h b/include/nbl/system/ISystem.h index 4af5b150ea..36c19f1961 100644 --- a/include/nbl/system/ISystem.h +++ b/include/nbl/system/ISystem.h @@ -144,6 +144,7 @@ class NBL_API2 ISystem : public core::IReferenceCounted void unmountBuiltins(); bool areBuiltinsMounted() const; size_t getMountedBuiltinArchiveCount() const; + core::vector getBuiltinMountAliases() const; inline size_t getMountedArchiveCount() const { return m_cachedArchiveFiles.getSize(); } // diff --git a/src/nbl/asset/utils/IShaderCompiler.cpp b/src/nbl/asset/utils/IShaderCompiler.cpp index 14654c530b..f6e951a33c 100644 --- a/src/nbl/asset/utils/IShaderCompiler.cpp +++ b/src/nbl/asset/utils/IShaderCompiler.cpp @@ -651,6 +651,23 @@ std::string normalizeIncludeLookupName(const std::string& includeName) return includeName.substr(1ull); } +std::string normalizeClassifiedRootPath(std::string value) +{ + std::replace(value.begin(), value.end(), '\\', '/'); + while (value.size() > 1ull && value.back() == '/') + value.pop_back(); + if (value.size() > 2ull && value.front() == '/' && value[1ull] != '/') + value.erase(value.begin()); + return value; +} + +bool pathHasRegisteredRoot(std::string_view path, std::string_view root) +{ + if (root.empty() || path.size() < root.size() || path.substr(0ull, root.size()) != root) + return false; + return path.size() == root.size() || path[root.size()] == '/'; +} + template auto withSessionCacheLock(IShaderCompiler::CIncludeFinder::SSessionCache* cache, Func&& func) -> decltype(func()) { @@ -688,18 +705,18 @@ void IShaderCompiler::CIncludeFinder::SSessionCache::clear() }); } -auto IShaderCompiler::CIncludeFinder::SSessionCache::lookup(const std::string& key, IIncludeLoader::found_t& result) const -> E_LOOKUP_RESULT +auto IShaderCompiler::CIncludeFinder::SSessionCache::lookup(const std::string& key, IIncludeLoader::found_t& result) const -> LookupResult { - return withSessionCacheLock(const_cast(this), [&]() -> E_LOOKUP_RESULT + return withSessionCacheLock(const_cast(this), [&]() -> LookupResult { if (const auto foundIt = found.find(key); foundIt != found.end()) { result = foundIt->second; - return E_LOOKUP_RESULT::Found; + return LookupResult::Found; } if (missing.contains(key)) - return E_LOOKUP_RESULT::Missing; - return E_LOOKUP_RESULT::Miss; + return LookupResult::Missing; + return LookupResult::Miss; }); } @@ -716,9 +733,11 @@ void IShaderCompiler::CIncludeFinder::SSessionCache::store(const std::string& ke } IShaderCompiler::CIncludeFinder::CIncludeFinder(core::smart_refctd_ptr&& system) - : m_defaultFileSystemLoader(core::make_smart_refctd_ptr(std::move(system))) + : m_defaultFileSystemLoader(core::make_smart_refctd_ptr(core::smart_refctd_ptr(system))) { addSearchPath("", m_defaultFileSystemLoader); + for (const auto& builtinRoot : system->getBuiltinMountAliases()) + registerHeaderRoot(builtinRoot.generic_string(), {IncludeRootOrigin::Builtin,HeaderClass::System}); } // ! includes within <> @@ -730,13 +749,13 @@ auto IShaderCompiler::CIncludeFinder::getIncludeStandard(const system::path& req const auto lookupName = normalizeIncludeLookupName(includeName); const auto cacheKey = makeIncludeSessionCacheKey(requestingSourceDir, lookupName, needHash, 'S'); IShaderCompiler::IIncludeLoader::found_t retVal; - switch (sessionCache ? sessionCache->lookup(cacheKey, retVal) : SSessionCache::E_LOOKUP_RESULT::Miss) + switch (sessionCache ? sessionCache->lookup(cacheKey, retVal) : SSessionCache::LookupResult::Miss) { - case SSessionCache::E_LOOKUP_RESULT::Found: + case SSessionCache::LookupResult::Found: return retVal; - case SSessionCache::E_LOOKUP_RESULT::Missing: + case SSessionCache::LookupResult::Missing: return {}; - case SSessionCache::E_LOOKUP_RESULT::Miss: + case SSessionCache::LookupResult::Miss: break; } @@ -747,6 +766,8 @@ auto IShaderCompiler::CIncludeFinder::getIncludeStandard(const system::path& req else retVal = m_defaultFileSystemLoader->getInclude(requestingSourceDir.string(), lookupName, needHash); + retVal = classifyFound(std::move(retVal)); + if (needHash && retVal && retVal.hash == core::blake3_hash_t{}) { core::blake3_hasher hasher; @@ -766,13 +787,13 @@ auto IShaderCompiler::CIncludeFinder::getIncludeRelative(const system::path& req const auto lookupName = normalizeIncludeLookupName(includeName); const auto cacheKey = makeIncludeSessionCacheKey(requestingSourceDir, lookupName, needHash, 'R'); IShaderCompiler::IIncludeLoader::found_t retVal; - switch (sessionCache ? sessionCache->lookup(cacheKey, retVal) : SSessionCache::E_LOOKUP_RESULT::Miss) + switch (sessionCache ? sessionCache->lookup(cacheKey, retVal) : SSessionCache::LookupResult::Miss) { - case SSessionCache::E_LOOKUP_RESULT::Found: + case SSessionCache::LookupResult::Found: return retVal; - case SSessionCache::E_LOOKUP_RESULT::Missing: + case SSessionCache::LookupResult::Missing: return {}; - case SSessionCache::E_LOOKUP_RESULT::Miss: + case SSessionCache::LookupResult::Miss: break; } @@ -780,6 +801,8 @@ auto IShaderCompiler::CIncludeFinder::getIncludeRelative(const system::path& req retVal = std::move(contents); else retVal = std::move(trySearchPaths(lookupName, needHash)); + retVal = classifyFound(std::move(retVal)); + if (needHash && retVal && retVal.hash == core::blake3_hash_t{}) { core::blake3_hasher hasher; @@ -791,27 +814,32 @@ auto IShaderCompiler::CIncludeFinder::getIncludeRelative(const system::path& req return retVal; } -void IShaderCompiler::CIncludeFinder::addSearchPath(const std::string& searchPath, const core::smart_refctd_ptr& loader) +void IShaderCompiler::CIncludeFinder::addSearchPath(const std::string& searchPath, const core::smart_refctd_ptr& loader, IncludeClassification classification) { if (!loader) return; - m_loaders.emplace_back(LoaderSearchPath{ loader, searchPath }); + auto normalizedSearchPath = normalizeClassifiedRootPath(searchPath); + if (!normalizedSearchPath.empty()) + registerHeaderRoot(normalizedSearchPath, classification); + m_loaders.emplace_back(LoaderSearchPath{ loader, std::move(normalizedSearchPath), classification }); } -void IShaderCompiler::CIncludeFinder::addGenerator(const core::smart_refctd_ptr& generatorToAdd) +void IShaderCompiler::CIncludeFinder::addGenerator(const core::smart_refctd_ptr& generatorToAdd, IncludeClassification classification) { if (!generatorToAdd) return; + registerHeaderRoot(std::string(generatorToAdd->getPrefix()), classification); + // this will find the place of first generator with prefix <= generatorToAdd or end auto found = std::lower_bound(m_generators.begin(), m_generators.end(), generatorToAdd->getPrefix(), - [](const core::smart_refctd_ptr& generator, const std::string_view& value) + [](const GeneratorEntry& generator, const std::string_view& value) { - auto element = generator->getPrefix(); + auto element = generator.generator->getPrefix(); return element.compare(value) > 0; // first to return false is lower_bound -> first element that is <= value }); - m_generators.insert(found, generatorToAdd); + m_generators.insert(found, GeneratorEntry{ generatorToAdd, classification }); } auto IShaderCompiler::CIncludeFinder::trySearchPaths(const std::string& includeName, bool needHash) const -> IIncludeLoader::found_t @@ -848,23 +876,23 @@ auto IShaderCompiler::CIncludeFinder::tryIncludeGenerators(const std::string& in while (!path.empty() && path.root_name().empty() && end != m_generators.end()) { auto begin = std::lower_bound(end, m_generators.end(), path.string(), - [&standardizePrefix](const core::smart_refctd_ptr& generator, const std::string& value) + [&standardizePrefix](const GeneratorEntry& generator, const std::string& value) { - const auto element = standardizePrefix(generator->getPrefix()); + const auto element = standardizePrefix(generator.generator->getPrefix()); return element.compare(value) > 0; // first to return false is lower_bound -> first element that is <= value }); // search from new beginning to real end end = std::upper_bound(begin, m_generators.end(), path.string(), - [&standardizePrefix](const std::string& value, const core::smart_refctd_ptr& generator) + [&standardizePrefix](const std::string& value, const GeneratorEntry& generator) { - const auto element = standardizePrefix(generator->getPrefix()); + const auto element = standardizePrefix(generator.generator->getPrefix()); return value.compare(element) > 0; // first to return true is upper_bound -> first element that is < value }); for (auto generatorIt = begin; generatorIt != end; generatorIt++) { - if (auto contents = (*generatorIt)->getInclude(includeName)) + if (auto contents = generatorIt->generator->getInclude(includeName)) return contents; } @@ -874,6 +902,53 @@ auto IShaderCompiler::CIncludeFinder::tryIncludeGenerators(const std::string& in return {}; } +bool IShaderCompiler::CIncludeFinder::isKnownGlobalInclude(std::string_view includeName) const +{ + const auto normalizedIncludeName = normalizeClassifiedRootPath(std::string(includeName)); + return std::any_of(m_headerRoots.begin(), m_headerRoots.end(), [&](const HeaderRoot& root) + { + return root.classification.headerClass == HeaderClass::System && pathHasRegisteredRoot(normalizedIncludeName, root.path); + }); +} + +auto IShaderCompiler::CIncludeFinder::classifyFound(IIncludeLoader::found_t found) const -> IIncludeLoader::found_t +{ + if (!found) + return found; + + const auto normalizedPath = normalizeClassifiedRootPath(found.absolutePath.generic_string()); + size_t bestMatchLength = 0ull; + for (const auto& root : m_headerRoots) + { + if (root.path.size() <= bestMatchLength) + continue; + if (!pathHasRegisteredRoot(normalizedPath, root.path)) + continue; + found.classification = root.classification; + bestMatchLength = root.path.size(); + } + return found; +} + +void IShaderCompiler::CIncludeFinder::registerHeaderRoot(std::string rootPath, IncludeClassification classification) +{ + rootPath = normalizeClassifiedRootPath(std::move(rootPath)); + if (rootPath.empty()) + return; + + const auto found = std::find_if(m_headerRoots.begin(), m_headerRoots.end(), [&](const HeaderRoot& entry) + { + return entry.path == rootPath; + }); + if (found != m_headerRoots.end()) + { + found->classification = classification; + return; + } + + m_headerRoots.push_back({ std::move(rootPath),classification }); +} + core::smart_refctd_ptr IShaderCompiler::CCache::find(const SEntry& mainFile, const IShaderCompiler::CIncludeFinder* finder) const { const auto found = find_impl(mainFile, finder); diff --git a/src/nbl/asset/utils/waveContext.h b/src/nbl/asset/utils/waveContext.h index 8d3fbf8bc0..1e2297d73c 100644 --- a/src/nbl/asset/utils/waveContext.h +++ b/src/nbl/asset/utils/waveContext.h @@ -26,30 +26,6 @@ using namespace boost::wave::util; namespace detail { -inline bool is_globally_resolved_include_name(std::string_view includeName) -{ - constexpr std::string_view globalPrefixes[] = { - "nbl/", - "nbl\\", - "boost/", - "boost\\", - "glm/", - "glm\\", - "spirv/", - "spirv\\", - "Imath/", - "Imath\\" - }; - - for (const auto prefix : globalPrefixes) - { - if (includeName.rfind(prefix, 0ull) == 0ull) - return true; - } - - return false; -} - struct PerfStats { bool enabled = false; @@ -764,7 +740,7 @@ class context : private boost::noncopyable std::string make_include_resolution_key(std::string_view includeName, bool is_system) const { std::string key; - const bool globallyResolved = is_system || detail::is_globally_resolved_include_name(includeName); + const bool globallyResolved = is_system || (hooks.m_includeFinder && hooks.m_includeFinder->isKnownGlobalInclude(includeName)); if (!globallyResolved) { const auto currentDirString = current_dir.generic_string(); @@ -822,7 +798,7 @@ template<> inline bool boost::wave::impl::pp_iterator_functorgetDefaultFileSystemLoader()->getInclude(nbl::system::path{}, cachedAbsolutePath, needHash); + result = includeFinder->classifyFound(includeFinder->getDefaultFileSystemLoader()->getInclude(nbl::system::path{}, cachedAbsolutePath, needHash)); standardInclude = is_system; } } @@ -871,6 +847,8 @@ template<> inline bool boost::wave::impl::pp_iterator_functor inline bool boost::wave::impl::pp_iterator_functor new_iter_ctx( new iteration_context_type(ctx,result.absolutePath.string().c_str(),act_pos, boost::wave::enable_prefer_pp_numbers(ctx.get_language()), - is_system ? base_iteration_context_type::system_header : + systemHeader ? base_iteration_context_type::system_header : base_iteration_context_type::user_header)); // call the include policy trace function diff --git a/src/nbl/system/ISystem.cpp b/src/nbl/system/ISystem.cpp index bd07c7a81a..079a861bfd 100644 --- a/src/nbl/system/ISystem.cpp +++ b/src/nbl/system/ISystem.cpp @@ -341,6 +341,15 @@ size_t ISystem::getMountedBuiltinArchiveCount() const return retval; } +core::vector ISystem::getBuiltinMountAliases() const +{ + core::vector retval; + retval.reserve(m_builtinMounts.size()); + for (const auto& mount : m_builtinMounts) + retval.push_back(mount.pathAlias.empty() ? mount.archive->getDefaultAbsolutePath() : mount.pathAlias); + return retval; +} + void ISystem::mountBuiltin(core::smart_refctd_ptr&& archive, const system::path& pathAlias) { auto tracked = archive; diff --git a/src/nbl/video/ILogicalDevice.cpp b/src/nbl/video/ILogicalDevice.cpp index 7958efa5c0..8379d0bf0e 100644 --- a/src/nbl/video/ILogicalDevice.cpp +++ b/src/nbl/video/ILogicalDevice.cpp @@ -159,7 +159,7 @@ ILogicalDevice::ILogicalDevice(core::smart_refctd_ptr&& ap } if (auto hlslCompiler = m_compilerSet ? m_compilerSet->getShaderCompiler(asset::IShader::E_CONTENT_TYPE::ECT_HLSL) : nullptr) - hlslCompiler->getDefaultIncludeFinder()->addSearchPath("nbl/builtin/hlsl/jit", core::make_smart_refctd_ptr(m_physicalDevice->getLimits(), m_enabledFeatures)); + hlslCompiler->getDefaultIncludeFinder()->addSearchPath("nbl/builtin/hlsl/jit", core::make_smart_refctd_ptr(m_physicalDevice->getLimits(), m_enabledFeatures), {asset::IShaderCompiler::IncludeRootOrigin::Generated,asset::IShaderCompiler::HeaderClass::System}); } E_API_TYPE ILogicalDevice::getAPIType() const { return m_physicalDevice->getAPIType(); } @@ -1155,4 +1155,4 @@ bool ILogicalDevice::createRayTracingPipelines(IGPUPipelineCache* const pipeline } return retval; } -#include "nbl/undef_logging_macros.h" \ No newline at end of file +#include "nbl/undef_logging_macros.h" diff --git a/tools/nsc/main.cpp b/tools/nsc/main.cpp index 94180ba71c..ac2586f858 100644 --- a/tools/nsc/main.cpp +++ b/tools/nsc/main.cpp @@ -378,11 +378,25 @@ class ShaderCompiler final : public IApplicationFramework m_arguments.push_back("main"); } - for (size_t i = 0; i + 1 < m_arguments.size(); ++i) + std::vector normalizedArguments; + normalizedArguments.reserve(m_arguments.size()); + for (size_t i = 0; i < m_arguments.size(); ++i) { - if (m_arguments[i] == "-I") - m_include_search_paths.emplace_back(m_arguments[i + 1]); + const auto& argument = m_arguments[i]; + if ((argument == "-I" || argument == "-isystem") && i + 1 < m_arguments.size()) + { + const auto classification = IShaderCompiler::IncludeClassification{ + IShaderCompiler::IncludeRootOrigin::User, + argument == "-isystem" ? IShaderCompiler::HeaderClass::System : IShaderCompiler::HeaderClass::User + }; + m_include_search_paths.push_back({ m_arguments[i + 1],classification }); + ++i; + continue; + } + + normalizedArguments.emplace_back(argument); } + m_arguments = std::move(normalizedArguments); const char* const action = preprocessOnly ? "Preprocessing" : "Compiling"; const char* const outType = preprocessOnly ? "Preprocessed" : "Compiled"; @@ -470,6 +484,8 @@ class ShaderCompiler final : public IApplicationFramework for (const auto& a : args) { + if (split(a, "-isystem")) continue; + if (split(a, "-I")) continue; if (split(a, "-MF")) continue; if (split(a, "-Fo")) continue; if (split(a, "-Fc")) continue; @@ -544,8 +560,8 @@ class ShaderCompiler final : public IApplicationFramework auto includeFinder = make_smart_refctd_ptr(smart_refctd_ptr(m_system)); auto includeLoader = includeFinder->getDefaultFileSystemLoader(); - for (const auto& p : m_include_search_paths) - includeFinder->addSearchPath(p, includeLoader); + for (const auto& searchPath : m_include_search_paths) + includeFinder->addSearchPath(searchPath.path, includeLoader, searchPath.classification); // need this struct becuase fields of IShaderCompiler::SMacroDefinition are string views struct SMacroDefinitionBuffer @@ -678,7 +694,14 @@ class ShaderCompiler final : public IApplicationFramework smart_refctd_ptr m_system; smart_refctd_ptr m_logger; - std::vector m_arguments, m_include_search_paths; + struct SearchPathArgument + { + std::string path; + IShaderCompiler::IncludeClassification classification = {}; + }; + + std::vector m_arguments; + std::vector m_include_search_paths; smart_refctd_ptr m_assetMgr; }; From 15b80eb19cc97895f0a6f4c9cae21de04ae70a6c Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Thu, 26 Mar 2026 11:54:40 +0100 Subject: [PATCH 44/60] Split include session cache reads and writes --- include/nbl/asset/utils/IShaderCompiler.h | 18 +++++-- src/nbl/asset/utils/CGLSLCompiler.cpp | 23 +++++--- src/nbl/asset/utils/CHLSLCompiler.cpp | 12 ++++- src/nbl/asset/utils/CWaveStringResolver.cpp | 22 ++++++++ src/nbl/asset/utils/IShaderCompiler.cpp | 60 ++++++++++++++++++--- src/nbl/asset/utils/waveContext.h | 33 ++++++++++-- 6 files changed, 143 insertions(+), 25 deletions(-) diff --git a/include/nbl/asset/utils/IShaderCompiler.h b/include/nbl/asset/utils/IShaderCompiler.h index 4197ad468f..05116b8d52 100644 --- a/include/nbl/asset/utils/IShaderCompiler.h +++ b/include/nbl/asset/utils/IShaderCompiler.h @@ -98,6 +98,15 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted public: struct SSessionCache { + struct Stats + { + uint64_t lookupFound = 0ull; + uint64_t lookupMissing = 0ull; + uint64_t lookupMiss = 0ull; + uint64_t storeFound = 0ull; + uint64_t storeMissing = 0ull; + }; + enum class LookupResult : uint8_t { Miss, @@ -110,10 +119,12 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted void clear(); LookupResult lookup(const std::string& key, IIncludeLoader::found_t& result) const; void store(const std::string& key, IIncludeLoader::found_t result); + Stats snapshotStats() const; bool threadSafe = false; mutable std::mutex mutex; + mutable Stats stats; core::unordered_map found; core::unordered_set missing; }; @@ -123,12 +134,12 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted // ! includes within <> // @param requestingSourceDir: the directory where the incude was requested // @param includeName: the string within <> of the include preprocessing directive - IIncludeLoader::found_t getIncludeStandard(const system::path& requestingSourceDir, const std::string& includeName, bool needHash = true, SSessionCache* sessionCache = nullptr) const; + IIncludeLoader::found_t getIncludeStandard(const system::path& requestingSourceDir, const std::string& includeName, bool needHash = true, SSessionCache* readSessionCache = nullptr, SSessionCache* writeSessionCache = nullptr) const; // ! includes within "" // @param requestingSourceDir: the directory where the incude was requested // @param includeName: the string within "" of the include preprocessing directive - IIncludeLoader::found_t getIncludeRelative(const system::path& requestingSourceDir, const std::string& includeName, bool needHash = true, SSessionCache* sessionCache = nullptr) const; + IIncludeLoader::found_t getIncludeRelative(const system::path& requestingSourceDir, const std::string& includeName, bool needHash = true, SSessionCache* readSessionCache = nullptr, SSessionCache* writeSessionCache = nullptr) const; inline core::smart_refctd_ptr getDefaultFileSystemLoader() const { return m_defaultFileSystemLoader; } @@ -196,7 +207,8 @@ class NBL_API2 IShaderCompiler : public core::IReferenceCounted std::string_view sourceIdentifier = ""; system::logger_opt_ptr logger = nullptr; const CIncludeFinder* includeFinder = nullptr; - mutable CIncludeFinder::SSessionCache* includeSessionCache = nullptr; + CIncludeFinder::SSessionCache* readIncludeSessionCache = nullptr; + CIncludeFinder::SSessionCache* writeIncludeSessionCache = nullptr; std::span extraDefines = {}; E_SPIRV_VERSION targetSpirvVersion = E_SPIRV_VERSION::ESV_1_6; bool depfile = false; diff --git a/src/nbl/asset/utils/CGLSLCompiler.cpp b/src/nbl/asset/utils/CGLSLCompiler.cpp index d250250280..9b8bde5d0c 100644 --- a/src/nbl/asset/utils/CGLSLCompiler.cpp +++ b/src/nbl/asset/utils/CGLSLCompiler.cpp @@ -44,12 +44,13 @@ namespace nbl::asset::impl class Includer : public shaderc::CompileOptions::IncluderInterface { const IShaderCompiler::CIncludeFinder* m_defaultIncludeFinder; - IShaderCompiler::CIncludeFinder::SSessionCache* m_includeSessionCache; + IShaderCompiler::CIncludeFinder::SSessionCache* m_readIncludeSessionCache; + IShaderCompiler::CIncludeFinder::SSessionCache* m_writeIncludeSessionCache; const system::ISystem* m_system; const uint32_t m_maxInclCnt; public: - Includer(const IShaderCompiler::CIncludeFinder* _inclFinder, IShaderCompiler::CIncludeFinder::SSessionCache* _includeSessionCache, const system::ISystem* _fs, uint32_t _maxInclCnt) : m_defaultIncludeFinder(_inclFinder), m_includeSessionCache(_includeSessionCache), m_system(_fs), m_maxInclCnt{ _maxInclCnt } {} + Includer(const IShaderCompiler::CIncludeFinder* _inclFinder, IShaderCompiler::CIncludeFinder::SSessionCache* _readIncludeSessionCache, IShaderCompiler::CIncludeFinder::SSessionCache* _writeIncludeSessionCache, const system::ISystem* _fs, uint32_t _maxInclCnt) : m_defaultIncludeFinder(_inclFinder), m_readIncludeSessionCache(_readIncludeSessionCache), m_writeIncludeSessionCache(_writeIncludeSessionCache), m_system(_fs), m_maxInclCnt{ _maxInclCnt } {} //_requesting_source in top level #include's is what shaderc::Compiler's compiling functions get as `input_file_name` parameter //so in order for properly working relative #include's (""-type) `input_file_name` has to be path to file from which the GLSL source really come from @@ -82,11 +83,11 @@ namespace nbl::asset::impl IShaderCompiler::IIncludeLoader::found_t result; if (_type == shaderc_include_type_relative) { - result = m_defaultIncludeFinder->getIncludeRelative(relDir, _requested_source, true, m_includeSessionCache); + result = m_defaultIncludeFinder->getIncludeRelative(relDir, _requested_source, true, m_readIncludeSessionCache, m_writeIncludeSessionCache); } else //shaderc_include_type_standard { - result = m_defaultIncludeFinder->getIncludeStandard(relDir, _requested_source, true, m_includeSessionCache); + result = m_defaultIncludeFinder->getIncludeStandard(relDir, _requested_source, true, m_readIncludeSessionCache, m_writeIncludeSessionCache); } if (!result) @@ -139,8 +140,16 @@ std::string CGLSLCompiler::preprocessShader(std::string&& code, IShader::E_SHADE { auto effectiveOptions = preprocessOptions; IShaderCompiler::CIncludeFinder::SSessionCache localIncludeSessionCache; - if (effectiveOptions.includeFinder && !effectiveOptions.includeSessionCache) - effectiveOptions.includeSessionCache = &localIncludeSessionCache; + if (effectiveOptions.includeFinder) + { + if (!effectiveOptions.readIncludeSessionCache && !effectiveOptions.writeIncludeSessionCache) + { + effectiveOptions.readIncludeSessionCache = &localIncludeSessionCache; + effectiveOptions.writeIncludeSessionCache = &localIncludeSessionCache; + } + else if (!effectiveOptions.readIncludeSessionCache && effectiveOptions.writeIncludeSessionCache) + effectiveOptions.readIncludeSessionCache = effectiveOptions.writeIncludeSessionCache; + } if (!preprocessOptions.extraDefines.empty()) { @@ -157,7 +166,7 @@ std::string CGLSLCompiler::preprocessShader(std::string&& code, IShader::E_SHADE if (effectiveOptions.includeFinder != nullptr) { - options.SetIncluder(std::make_unique(effectiveOptions.includeFinder, effectiveOptions.includeSessionCache, m_system.get(), /*maxSelfInclusionCount*/5));//custom #include handler + options.SetIncluder(std::make_unique(effectiveOptions.includeFinder, effectiveOptions.readIncludeSessionCache, effectiveOptions.writeIncludeSessionCache, m_system.get(), /*maxSelfInclusionCount*/5));//custom #include handler } const shaderc_shader_kind scstage = stage == IShader::E_SHADER_STAGE::ESS_UNKNOWN ? shaderc_glsl_infer_from_source : ESStoShadercEnum(stage); auto res = comp.PreprocessGlsl(code, scstage, effectiveOptions.sourceIdentifier.data(), options); diff --git a/src/nbl/asset/utils/CHLSLCompiler.cpp b/src/nbl/asset/utils/CHLSLCompiler.cpp index ffb3ab88c3..6fec81c8cc 100644 --- a/src/nbl/asset/utils/CHLSLCompiler.cpp +++ b/src/nbl/asset/utils/CHLSLCompiler.cpp @@ -456,8 +456,16 @@ static std::string preprocessShaderImpl( { auto effectiveOptions = preprocessOptions; IShaderCompiler::CIncludeFinder::SSessionCache localIncludeSessionCache; - if (effectiveOptions.includeFinder && !effectiveOptions.includeSessionCache) - effectiveOptions.includeSessionCache = &localIncludeSessionCache; + if (effectiveOptions.includeFinder) + { + if (!effectiveOptions.readIncludeSessionCache && !effectiveOptions.writeIncludeSessionCache) + { + effectiveOptions.readIncludeSessionCache = &localIncludeSessionCache; + effectiveOptions.writeIncludeSessionCache = &localIncludeSessionCache; + } + else if (!effectiveOptions.readIncludeSessionCache && effectiveOptions.writeIncludeSessionCache) + effectiveOptions.readIncludeSessionCache = effectiveOptions.writeIncludeSessionCache; + } const bool depfileEnabled = effectiveOptions.depfile; if (depfileEnabled) diff --git a/src/nbl/asset/utils/CWaveStringResolver.cpp b/src/nbl/asset/utils/CWaveStringResolver.cpp index 29ddf4ce55..f8f3b8aa5c 100644 --- a/src/nbl/asset/utils/CWaveStringResolver.cpp +++ b/src/nbl/asset/utils/CWaveStringResolver.cpp @@ -25,6 +25,19 @@ constexpr size_t kWaveFailureLogOutputTailMaxChars = 4096ull; constexpr size_t kWaveFailureLogOutputTailMaxLines = 16ull; constexpr size_t kWaveFailureLogTokenPreviewMaxChars = 160ull; +auto subtractSessionCacheStats( + const IShaderCompiler::CIncludeFinder::SSessionCache::Stats& end, + const IShaderCompiler::CIncludeFinder::SSessionCache::Stats& begin) -> IShaderCompiler::CIncludeFinder::SSessionCache::Stats +{ + IShaderCompiler::CIncludeFinder::SSessionCache::Stats result; + result.lookupFound = end.lookupFound - begin.lookupFound; + result.lookupMissing = end.lookupMissing - begin.lookupMissing; + result.lookupMiss = end.lookupMiss - begin.lookupMiss; + result.storeFound = end.storeFound - begin.storeFound; + result.storeMissing = end.storeMissing - begin.storeMissing; + return result; +} + struct WaveRenderProgress { core::string output; @@ -305,6 +318,10 @@ std::string preprocessImpl( const bool withCaching, std::function post) { + const auto emptySessionCacheStats = IShaderCompiler::CIncludeFinder::SSessionCache::Stats{}; + const auto readSessionCacheStatsBegin = preprocessOptions.readIncludeSessionCache ? preprocessOptions.readIncludeSessionCache->snapshotStats() : emptySessionCacheStats; + const auto writeSessionCacheStatsBegin = preprocessOptions.writeIncludeSessionCache ? preprocessOptions.writeIncludeSessionCache->snapshotStats() : emptySessionCacheStats; + nbl::wave::context context(code.begin(), code.end(), preprocessOptions.sourceIdentifier.data(), { preprocessOptions }); WaveRenderProgress renderProgress; @@ -383,6 +400,11 @@ std::string preprocessImpl( } post(context); + const auto readSessionCacheStatsEnd = preprocessOptions.readIncludeSessionCache ? preprocessOptions.readIncludeSessionCache->snapshotStats() : emptySessionCacheStats; + const auto writeSessionCacheStatsEnd = preprocessOptions.writeIncludeSessionCache ? preprocessOptions.writeIncludeSessionCache->snapshotStats() : emptySessionCacheStats; + nbl::wave::detail::set_session_cache_perf_stats( + subtractSessionCacheStats(readSessionCacheStatsEnd, readSessionCacheStatsBegin), + subtractSessionCacheStats(writeSessionCacheStatsEnd, writeSessionCacheStatsBegin)); nbl::wave::detail::dump_perf_stats(); return std::move(renderProgress.output); diff --git a/src/nbl/asset/utils/IShaderCompiler.cpp b/src/nbl/asset/utils/IShaderCompiler.cpp index f6e951a33c..d180d83a5c 100644 --- a/src/nbl/asset/utils/IShaderCompiler.cpp +++ b/src/nbl/asset/utils/IShaderCompiler.cpp @@ -694,6 +694,33 @@ std::string makeIncludeSessionCacheKey(const system::path& requestingSourceDir, return key; } +auto lookupIncludeSessionCache(IShaderCompiler::CIncludeFinder::SSessionCache* readCache, IShaderCompiler::CIncludeFinder::SSessionCache* writeCache, const std::string& key, IShaderCompiler::IIncludeLoader::found_t& result) -> IShaderCompiler::CIncludeFinder::SSessionCache::LookupResult +{ + using LookupResult = IShaderCompiler::CIncludeFinder::SSessionCache::LookupResult; + const auto lookupResult = readCache ? readCache->lookup(key, result) : LookupResult::Miss; + if (readCache && writeCache && readCache != writeCache) + { + switch (lookupResult) + { + case LookupResult::Found: + writeCache->store(key, result); + break; + case LookupResult::Missing: + writeCache->store(key, {}); + break; + case LookupResult::Miss: + break; + } + } + return lookupResult; +} + +void writeIncludeSessionCache(IShaderCompiler::CIncludeFinder::SSessionCache* writeCache, const std::string& key, const IShaderCompiler::IIncludeLoader::found_t& result) +{ + if (writeCache) + writeCache->store(key, result); +} + } void IShaderCompiler::CIncludeFinder::SSessionCache::clear() @@ -711,11 +738,16 @@ auto IShaderCompiler::CIncludeFinder::SSessionCache::lookup(const std::string& k { if (const auto foundIt = found.find(key); foundIt != found.end()) { + ++stats.lookupFound; result = foundIt->second; return LookupResult::Found; } if (missing.contains(key)) + { + ++stats.lookupMissing; return LookupResult::Missing; + } + ++stats.lookupMiss; return LookupResult::Miss; }); } @@ -726,9 +758,23 @@ void IShaderCompiler::CIncludeFinder::SSessionCache::store(const std::string& ke { missing.erase(key); if (result) + { + ++stats.storeFound; found.insert_or_assign(key, std::move(result)); + } else + { + ++stats.storeMissing; missing.insert(key); + } + }); +} + +auto IShaderCompiler::CIncludeFinder::SSessionCache::snapshotStats() const -> Stats +{ + return withSessionCacheLock(const_cast(this), [&]() -> Stats + { + return stats; }); } @@ -744,12 +790,12 @@ IShaderCompiler::CIncludeFinder::CIncludeFinder(core::smart_refctd_ptr of the include preprocessing directive // @param -auto IShaderCompiler::CIncludeFinder::getIncludeStandard(const system::path& requestingSourceDir, const std::string& includeName, bool needHash, SSessionCache* sessionCache) const -> IIncludeLoader::found_t +auto IShaderCompiler::CIncludeFinder::getIncludeStandard(const system::path& requestingSourceDir, const std::string& includeName, bool needHash, SSessionCache* readSessionCache, SSessionCache* writeSessionCache) const -> IIncludeLoader::found_t { const auto lookupName = normalizeIncludeLookupName(includeName); const auto cacheKey = makeIncludeSessionCacheKey(requestingSourceDir, lookupName, needHash, 'S'); IShaderCompiler::IIncludeLoader::found_t retVal; - switch (sessionCache ? sessionCache->lookup(cacheKey, retVal) : SSessionCache::LookupResult::Miss) + switch (lookupIncludeSessionCache(readSessionCache, writeSessionCache, cacheKey, retVal)) { case SSessionCache::LookupResult::Found: return retVal; @@ -774,20 +820,19 @@ auto IShaderCompiler::CIncludeFinder::getIncludeStandard(const system::path& req hasher.update(reinterpret_cast(retVal.contents.data()), retVal.contents.size() * (sizeof(char) / sizeof(uint8_t))); retVal.hash = static_cast(hasher); } - if (sessionCache) - sessionCache->store(cacheKey, retVal); + writeIncludeSessionCache(writeSessionCache, cacheKey, retVal); return retVal; } // ! includes within "" // @param requestingSourceDir: the directory where the incude was requested // @param includeName: the string within "" of the include preprocessing directive -auto IShaderCompiler::CIncludeFinder::getIncludeRelative(const system::path& requestingSourceDir, const std::string& includeName, bool needHash, SSessionCache* sessionCache) const -> IIncludeLoader::found_t +auto IShaderCompiler::CIncludeFinder::getIncludeRelative(const system::path& requestingSourceDir, const std::string& includeName, bool needHash, SSessionCache* readSessionCache, SSessionCache* writeSessionCache) const -> IIncludeLoader::found_t { const auto lookupName = normalizeIncludeLookupName(includeName); const auto cacheKey = makeIncludeSessionCacheKey(requestingSourceDir, lookupName, needHash, 'R'); IShaderCompiler::IIncludeLoader::found_t retVal; - switch (sessionCache ? sessionCache->lookup(cacheKey, retVal) : SSessionCache::LookupResult::Miss) + switch (lookupIncludeSessionCache(readSessionCache, writeSessionCache, cacheKey, retVal)) { case SSessionCache::LookupResult::Found: return retVal; @@ -809,8 +854,7 @@ auto IShaderCompiler::CIncludeFinder::getIncludeRelative(const system::path& req hasher.update(reinterpret_cast(retVal.contents.data()), retVal.contents.size() * (sizeof(char) / sizeof(uint8_t))); retVal.hash = static_cast(hasher); } - if (sessionCache) - sessionCache->store(cacheKey, retVal); + writeIncludeSessionCache(writeSessionCache, cacheKey, retVal); return retVal; } diff --git a/src/nbl/asset/utils/waveContext.h b/src/nbl/asset/utils/waveContext.h index 1e2297d73c..4904846463 100644 --- a/src/nbl/asset/utils/waveContext.h +++ b/src/nbl/asset/utils/waveContext.h @@ -34,6 +34,11 @@ struct PerfStats uint64_t includeLookupCount = 0ull; uint64_t includeResolutionCacheSkips = 0ull; uint64_t postLoadPragmaSkips = 0ull; + uint64_t sessionLookupFound = 0ull; + uint64_t sessionLookupMissing = 0ull; + uint64_t sessionLookupMiss = 0ull; + uint64_t sessionStoreFound = 0ull; + uint64_t sessionStoreMissing = 0ull; std::chrono::nanoseconds includeLookupTime = std::chrono::nanoseconds::zero(); std::chrono::nanoseconds tokenHandlingTime = std::chrono::nanoseconds::zero(); std::chrono::nanoseconds iteratorAdvanceTime = std::chrono::nanoseconds::zero(); @@ -95,7 +100,7 @@ inline void dump_perf_stats() std::fprintf( stderr, - "[wave-profile] total_ms=%.3f include_lookup_ms=%.3f token_handling_ms=%.3f iterator_advance_ms=%.3f loop_body_ms=%.3f render_ms=%.3f include_requests=%llu include_lookups=%llu resolution_cache_skips=%llu postload_pragma_skips=%llu emitted_tokens=%llu output_bytes=%zu\n", + "[wave-profile] total_ms=%.3f include_lookup_ms=%.3f token_handling_ms=%.3f iterator_advance_ms=%.3f loop_body_ms=%.3f render_ms=%.3f include_requests=%llu include_lookups=%llu resolution_cache_skips=%llu postload_pragma_skips=%llu session_lookup_found=%llu session_lookup_missing=%llu session_lookup_miss=%llu session_store_found=%llu session_store_missing=%llu emitted_tokens=%llu output_bytes=%zu\n", to_ms(stats.totalPreprocessTime), to_ms(stats.includeLookupTime), to_ms(stats.tokenHandlingTime), @@ -106,6 +111,11 @@ inline void dump_perf_stats() static_cast(stats.includeLookupCount), static_cast(stats.includeResolutionCacheSkips), static_cast(stats.postLoadPragmaSkips), + static_cast(stats.sessionLookupFound), + static_cast(stats.sessionLookupMissing), + static_cast(stats.sessionLookupMiss), + static_cast(stats.sessionStoreFound), + static_cast(stats.sessionStoreMissing), static_cast(stats.emittedTokenCount), stats.outputBytes ); @@ -173,6 +183,18 @@ inline boost::wave::language_support make_language_flags(const LanguageFlagConfi return flags; } +inline void set_session_cache_perf_stats( + const asset::IShaderCompiler::CIncludeFinder::SSessionCache::Stats& readDelta, + const asset::IShaderCompiler::CIncludeFinder::SSessionCache::Stats& writeDelta) +{ + auto& stats = perf_stats(); + stats.sessionLookupFound = readDelta.lookupFound; + stats.sessionLookupMissing = readDelta.lookupMissing; + stats.sessionLookupMiss = readDelta.lookupMiss; + stats.sessionStoreFound = writeDelta.storeFound; + stats.sessionStoreMissing = writeDelta.storeMissing; +} + inline std::string escape_control_chars(std::string_view text) { static constexpr char hex[] = "0123456789ABCDEF"; @@ -251,7 +273,7 @@ struct load_to_string final struct preprocessing_hooks final : public boost::wave::context_policies::default_preprocessing_hooks { preprocessing_hooks(const nbl::asset::IShaderCompiler::SPreprocessorOptions& _preprocessOptions) - : m_includeFinder(_preprocessOptions.includeFinder), m_includeSessionCache(_preprocessOptions.includeSessionCache), m_logger(_preprocessOptions.logger), m_preserveComments(_preprocessOptions.preserveComments), m_pragmaStage(nbl::asset::IShader::E_SHADER_STAGE::ESS_UNKNOWN), m_dxc_compile_flags_override() + : m_includeFinder(_preprocessOptions.includeFinder), m_readIncludeSessionCache(_preprocessOptions.readIncludeSessionCache), m_writeIncludeSessionCache(_preprocessOptions.writeIncludeSessionCache), m_logger(_preprocessOptions.logger), m_preserveComments(_preprocessOptions.preserveComments), m_pragmaStage(nbl::asset::IShader::E_SHADER_STAGE::ESS_UNKNOWN), m_dxc_compile_flags_override() { hash_token_occurences = 0; } @@ -358,7 +380,8 @@ struct preprocessing_hooks final : public boost::wave::context_policies::default } const asset::IShaderCompiler::CIncludeFinder* m_includeFinder; - asset::IShaderCompiler::CIncludeFinder::SSessionCache* m_includeSessionCache; + asset::IShaderCompiler::CIncludeFinder::SSessionCache* m_readIncludeSessionCache; + asset::IShaderCompiler::CIncludeFinder::SSessionCache* m_writeIncludeSessionCache; system::logger_opt_ptr m_logger; bool m_preserveComments; asset::IShader::E_SHADER_STAGE m_pragmaStage; @@ -809,11 +832,11 @@ template<> inline bool boost::wave::impl::pp_iterator_functorgetIncludeStandard(ctx.get_current_directory(), file_path, needHash, ctx.get_hooks().m_includeSessionCache); + result = includeFinder->getIncludeStandard(ctx.get_current_directory(), file_path, needHash, ctx.get_hooks().m_readIncludeSessionCache, ctx.get_hooks().m_writeIncludeSessionCache); standardInclude = true; } else { - result = includeFinder->getIncludeRelative(ctx.get_current_directory(), file_path, needHash, ctx.get_hooks().m_includeSessionCache); + result = includeFinder->getIncludeRelative(ctx.get_current_directory(), file_path, needHash, ctx.get_hooks().m_readIncludeSessionCache, ctx.get_hooks().m_writeIncludeSessionCache); standardInclude = false; } } From cfaac9c36e0d169e44dc75d4a774703b3c94782d Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Thu, 26 Mar 2026 13:31:45 +0100 Subject: [PATCH 45/60] Stop exporting generated keys header as source --- cmake/common.cmake | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cmake/common.cmake b/cmake/common.cmake index ed06c32437..6c10a0a450 100755 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -1306,13 +1306,6 @@ struct DeviceConfigCaps TARGET ${IMPL_TARGET} ) - target_sources(${IMPL_TARGET} PUBLIC ${INCLUDE_FILE}) - set_source_files_properties(${INCLUDE_FILE} PROPERTIES - GENERATED TRUE - HEADER_FILE_ONLY ON - VS_TOOL_OVERRIDE None - ) - target_compile_definitions(${IMPL_TARGET} INTERFACE $) target_include_directories(${IMPL_TARGET} INTERFACE ${INCLUDE_DIR}) set_target_properties(${IMPL_TARGET} PROPERTIES NBL_HEADER_GENERATED_RULE ON) From 3cf364bbcc7b65f80e8440248c39404811ad2cd8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 26 Mar 2026 13:35:01 +0000 Subject: [PATCH 46/60] Promote NSC channel cfaac9c36e0d169e44dc75d4a774703b3c94782d --- tools/nsc/manifests/nsc-windows-x64-release.tag | 2 +- .../exe/tools/nsc/bin/build-info.json.dvc | 4 ++-- .../nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc | 4 ++-- .../runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc | 4 ++-- .../nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/nsc/manifests/nsc-windows-x64-release.tag b/tools/nsc/manifests/nsc-windows-x64-release.tag index 0e2bf783fa..931da9d18e 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release.tag +++ b/tools/nsc/manifests/nsc-windows-x64-release.tag @@ -1 +1 @@ -nsc-windows-x64-release-ac0289dda98b1046000873b0b3ffedb06356be53 +nsc-windows-x64-release-cfaac9c36e0d169e44dc75d4a774703b3c94782d diff --git a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc index 0b3eb66f37..6e3a943350 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc @@ -1,5 +1,5 @@ outs: -- md5: 0313edc75aedd79a1ec94ab90feb5881 - size: 1326 +- md5: bfe10e309bf3d13c7001d74e865ff3d4 + size: 1333 hash: md5 path: build-info.json diff --git a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc index 11c5dee4da..a4bc0abf25 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc @@ -1,5 +1,5 @@ outs: -- md5: 159813ebd3546457ad48e3a310b3f693 - size: 256512 +- md5: 909097754c60bc39a7a29096cb92f371 + size: 258048 hash: md5 path: nsc.exe diff --git a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc index 0edd7b4136..7bf59320af 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc @@ -1,5 +1,5 @@ outs: -- md5: ec2f20db14ac9272795ba5ad970423b8 - size: 21578752 +- md5: ca7a75916d7960805560852aac1ef9e8 + size: 21578752 hash: md5 path: dxcompiler.dll diff --git a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc index aa5654f0ec..57b548dd0e 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc @@ -1,5 +1,5 @@ outs: -- md5: 219186a91cf612f2ab0f9dd22278206f - size: 29173760 +- md5: f22f7f7b10f9bc3164e702c7ecccd472 + size: 29195264 hash: md5 path: Nabla.dll From 6dc6485fe26651b096c49ebebb58b2b443ab5439 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Thu, 26 Mar 2026 15:02:56 +0100 Subject: [PATCH 47/60] Update examples_tests after master merge --- examples_tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_tests b/examples_tests index d50719c8ba..2d663f5041 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit d50719c8baf51a39e3aeb7108388631558b172f9 +Subproject commit 2d663f5041b7570b43901e903afb7129332bae5a From 27a4d6f68b9e1757fbeb86181d179c27251f81c9 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Fri, 27 Mar 2026 19:30:58 +0100 Subject: [PATCH 48/60] Roll DXC to devshFixes --- 3rdparty/dxc/dxc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty/dxc/dxc b/3rdparty/dxc/dxc index 07f06e9d48..d76c7890b1 160000 --- a/3rdparty/dxc/dxc +++ b/3rdparty/dxc/dxc @@ -1 +1 @@ -Subproject commit 07f06e9d48807ef8e7cabc41ae6acdeb26c68c09 +Subproject commit d76c7890b19ce0b344ee0ce116dbc1c92220ccea From 77ad5e00114f1c178e6e8b294adb3139a6227cca Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 27 Mar 2026 19:38:13 +0000 Subject: [PATCH 49/60] Promote NSC channel 27a4d6f68b9e1757fbeb86181d179c27251f81c9 --- tools/nsc/manifests/nsc-windows-x64-release.tag | 2 +- .../exe/tools/nsc/bin/build-info.json.dvc | 4 ++-- .../nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc | 2 +- .../runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc | 4 ++-- .../nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/nsc/manifests/nsc-windows-x64-release.tag b/tools/nsc/manifests/nsc-windows-x64-release.tag index 931da9d18e..94e66c264a 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release.tag +++ b/tools/nsc/manifests/nsc-windows-x64-release.tag @@ -1 +1 @@ -nsc-windows-x64-release-cfaac9c36e0d169e44dc75d4a774703b3c94782d +nsc-windows-x64-release-27a4d6f68b9e1757fbeb86181d179c27251f81c9 diff --git a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc index 6e3a943350..bfd2a26c39 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc @@ -1,5 +1,5 @@ outs: -- md5: bfe10e309bf3d13c7001d74e865ff3d4 - size: 1333 +- md5: 3d428b7ea712df7f29476037f3a4cc79 + size: 1269 hash: md5 path: build-info.json diff --git a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc index a4bc0abf25..16abc634c4 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc @@ -1,5 +1,5 @@ outs: -- md5: 909097754c60bc39a7a29096cb92f371 +- md5: 610fe2e3519a71dd4c55116ceb08bec7 size: 258048 hash: md5 path: nsc.exe diff --git a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc index 7bf59320af..eddd5001c1 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc @@ -1,5 +1,5 @@ outs: -- md5: ca7a75916d7960805560852aac1ef9e8 - size: 21578752 +- md5: 33669fee00214d4b52d983a99c0a001d + size: 21367296 hash: md5 path: dxcompiler.dll diff --git a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc index 57b548dd0e..dbd68f38f3 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc @@ -1,5 +1,5 @@ outs: -- md5: f22f7f7b10f9bc3164e702c7ecccd472 - size: 29195264 +- md5: 10ade1f6844aa6e984d499f386700fb4 + size: 29079040 hash: md5 path: Nabla.dll From 77a6801c653d8a291b0432f2ff43fb503e0b4cd6 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sat, 28 Mar 2026 23:08:53 +0100 Subject: [PATCH 50/60] Update DXC pointer to unroll-devshFixes --- .gitmodules | 2 +- 3rdparty/dxc/dxc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 6ffcf79503..6ef5432f80 100644 --- a/.gitmodules +++ b/.gitmodules @@ -72,7 +72,7 @@ [submodule "3rdparty/dxc/dxc"] path = 3rdparty/dxc/dxc url = git@github.com:Devsh-Graphics-Programming/DirectXShaderCompiler.git - branch = devshFixes + branch = unroll-devshFixes [submodule "3rdparty/imgui"] path = 3rdparty/imgui url = git@github.com:Devsh-Graphics-Programming/imgui.git diff --git a/3rdparty/dxc/dxc b/3rdparty/dxc/dxc index d76c7890b1..891d1d7bd6 160000 --- a/3rdparty/dxc/dxc +++ b/3rdparty/dxc/dxc @@ -1 +1 @@ -Subproject commit d76c7890b19ce0b344ee0ce116dbc1c92220ccea +Subproject commit 891d1d7bd6fb20757a3af07f5a7a33ef59f7c15e From 589ca093e67eaf79cdfe090b8cb5068a96e20d2c Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sun, 29 Mar 2026 00:42:49 +0100 Subject: [PATCH 51/60] Update DXC pointer to unroll-devshFixes --- 3rdparty/dxc/dxc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty/dxc/dxc b/3rdparty/dxc/dxc index 891d1d7bd6..d7bbe85dc7 160000 --- a/3rdparty/dxc/dxc +++ b/3rdparty/dxc/dxc @@ -1 +1 @@ -Subproject commit 891d1d7bd6fb20757a3af07f5a7a33ef59f7c15e +Subproject commit d7bbe85dc7bd721df6b375fe3c3bce7c4028669e From 125efc459b5b899f36d2cf506c502da8469a0055 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 29 Mar 2026 00:48:06 +0000 Subject: [PATCH 52/60] Promote NSC channel 589ca093e67eaf79cdfe090b8cb5068a96e20d2c --- tools/nsc/manifests/nsc-windows-x64-release.tag | 2 +- .../exe/tools/nsc/bin/build-info.json.dvc | 4 ++-- .../nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc | 2 +- .../runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc | 4 ++-- .../nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/nsc/manifests/nsc-windows-x64-release.tag b/tools/nsc/manifests/nsc-windows-x64-release.tag index 94e66c264a..249119c019 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release.tag +++ b/tools/nsc/manifests/nsc-windows-x64-release.tag @@ -1 +1 @@ -nsc-windows-x64-release-27a4d6f68b9e1757fbeb86181d179c27251f81c9 +nsc-windows-x64-release-589ca093e67eaf79cdfe090b8cb5068a96e20d2c diff --git a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc index bfd2a26c39..8d55cd22c5 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc @@ -1,5 +1,5 @@ outs: -- md5: 3d428b7ea712df7f29476037f3a4cc79 - size: 1269 +- md5: aaec35978009baa370a601d3049dd31a + size: 1346 hash: md5 path: build-info.json diff --git a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc index 16abc634c4..0b7e25cfff 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc @@ -1,5 +1,5 @@ outs: -- md5: 610fe2e3519a71dd4c55116ceb08bec7 +- md5: 3fb0799e7a084ad7ed42e2c60f0012a5 size: 258048 hash: md5 path: nsc.exe diff --git a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc index eddd5001c1..74f9e6e3a5 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc @@ -1,5 +1,5 @@ outs: -- md5: 33669fee00214d4b52d983a99c0a001d - size: 21367296 +- md5: ee621de468e745312f6ed640451a5dd7 + size: 21583872 hash: md5 path: dxcompiler.dll diff --git a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc index dbd68f38f3..41cbffb148 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc @@ -1,5 +1,5 @@ outs: -- md5: 10ade1f6844aa6e984d499f386700fb4 - size: 29079040 +- md5: f5af7ccc7e12b62e032cd59188610184 + size: 29196288 hash: md5 path: Nabla.dll From 08e87a0e4cca7be01d020235525d28d161894307 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sun, 29 Mar 2026 03:59:10 +0200 Subject: [PATCH 53/60] Use O1experimental in debug and rwdi --- cmake/common.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/common.cmake b/cmake/common.cmake index 6c10a0a450..5bb10480da 100755 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -1231,9 +1231,9 @@ struct DeviceConfigCaps -Wshadow -Wconversion -Wno-local-type-template-args - $<$:-O0> + $<$:-O1experimental> $<$:-O3> - $<$:-O3> + $<$:-O1experimental> ) if(NSC_DEBUG_EDIF_FILE_BIT) From 6683a20d668f1207e822c2efedba901e4ae11028 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sun, 29 Mar 2026 05:05:25 +0200 Subject: [PATCH 54/60] Scope O1experimental to EX31 --- cmake/common.cmake | 4 ++-- examples_tests | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/common.cmake b/cmake/common.cmake index 5bb10480da..6c10a0a450 100755 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -1231,9 +1231,9 @@ struct DeviceConfigCaps -Wshadow -Wconversion -Wno-local-type-template-args - $<$:-O1experimental> + $<$:-O0> $<$:-O3> - $<$:-O1experimental> + $<$:-O3> ) if(NSC_DEBUG_EDIF_FILE_BIT) diff --git a/examples_tests b/examples_tests index 887100fd44..9c6dff419d 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 887100fd445775f21ba10faae0c91366de7e913b +Subproject commit 9c6dff419d881ebd1c174b3b8541e6a126f939cd From 0e04e4f1167dbf2d6862a9daf81cbe4e65154598 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 29 Mar 2026 05:09:31 +0000 Subject: [PATCH 55/60] Promote NSC channel 6683a20d668f1207e822c2efedba901e4ae11028 --- tools/nsc/manifests/nsc-windows-x64-release.tag | 2 +- .../exe/tools/nsc/bin/build-info.json.dvc | 4 ++-- .../nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc | 2 +- .../runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc | 2 +- .../nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/nsc/manifests/nsc-windows-x64-release.tag b/tools/nsc/manifests/nsc-windows-x64-release.tag index 249119c019..77e81c53ec 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release.tag +++ b/tools/nsc/manifests/nsc-windows-x64-release.tag @@ -1 +1 @@ -nsc-windows-x64-release-589ca093e67eaf79cdfe090b8cb5068a96e20d2c +nsc-windows-x64-release-6683a20d668f1207e822c2efedba901e4ae11028 diff --git a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc index 8d55cd22c5..b259e6fc25 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc @@ -1,5 +1,5 @@ outs: -- md5: aaec35978009baa370a601d3049dd31a - size: 1346 +- md5: 9e2c1537859c6f840f8cedcda575d845 + size: 1335 hash: md5 path: build-info.json diff --git a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc index 0b7e25cfff..d76605a700 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc @@ -1,5 +1,5 @@ outs: -- md5: 3fb0799e7a084ad7ed42e2c60f0012a5 +- md5: dac035a1aa111f8e6551ba08f7c7f7ea size: 258048 hash: md5 path: nsc.exe diff --git a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc index 74f9e6e3a5..a35ca7c654 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc @@ -1,5 +1,5 @@ outs: -- md5: ee621de468e745312f6ed640451a5dd7 +- md5: f71b14a52e199ad9b8a75aa74c3a2ffb size: 21583872 hash: md5 path: dxcompiler.dll diff --git a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc index 41cbffb148..689bf8b048 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc @@ -1,5 +1,5 @@ outs: -- md5: f5af7ccc7e12b62e032cd59188610184 +- md5: 846e2b97b36c84f5e2544f30bcb6e180 size: 29196288 hash: md5 path: Nabla.dll From 2617eb2e7f7ac4a82f147bcf252dee36c0b1e51f Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sun, 29 Mar 2026 07:39:50 +0200 Subject: [PATCH 56/60] Update DXC unroll-devshFixes pointer --- 3rdparty/dxc/dxc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty/dxc/dxc b/3rdparty/dxc/dxc index d7bbe85dc7..a4c67cfcfb 160000 --- a/3rdparty/dxc/dxc +++ b/3rdparty/dxc/dxc @@ -1 +1 @@ -Subproject commit d7bbe85dc7bd721df6b375fe3c3bce7c4028669e +Subproject commit a4c67cfcfbd0ab1a5537dd3d72f228539481e3a4 From 4b76234272ef138e721f5b71e6f8ab55e1377584 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sun, 29 Mar 2026 07:41:28 +0200 Subject: [PATCH 57/60] Refresh DXC unroll-devshFixes pointer --- 3rdparty/dxc/dxc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty/dxc/dxc b/3rdparty/dxc/dxc index a4c67cfcfb..07085e0bb3 160000 --- a/3rdparty/dxc/dxc +++ b/3rdparty/dxc/dxc @@ -1 +1 @@ -Subproject commit a4c67cfcfbd0ab1a5537dd3d72f228539481e3a4 +Subproject commit 07085e0bb3fc64e77f0e7abf80af86af17f6656e From 0d19dfaac0387590c8eee46c97d3090580449d75 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sun, 29 Mar 2026 10:10:56 +0200 Subject: [PATCH 58/60] Refresh DXC unroll-devshFixes pointer --- 3rdparty/dxc/dxc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty/dxc/dxc b/3rdparty/dxc/dxc index 07085e0bb3..2b1668e3cb 160000 --- a/3rdparty/dxc/dxc +++ b/3rdparty/dxc/dxc @@ -1 +1 @@ -Subproject commit 07085e0bb3fc64e77f0e7abf80af86af17f6656e +Subproject commit 2b1668e3cbc89129b4e7dfe582592f667e0e7de1 From 29bda527be490f8214e937ae33bbffd438cce6e6 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Sun, 29 Mar 2026 19:52:22 +0200 Subject: [PATCH 59/60] Enable O1experimental by default for NSC rules --- 3rdparty/dxc/dxc | 2 +- cmake/common.cmake | 22 +++++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/3rdparty/dxc/dxc b/3rdparty/dxc/dxc index 2b1668e3cb..4c5fbdc9c1 160000 --- a/3rdparty/dxc/dxc +++ b/3rdparty/dxc/dxc @@ -1 +1 @@ -Subproject commit 2b1668e3cbc89129b4e7dfe582592f667e0e7de1 +Subproject commit 4c5fbdc9c1b9e8c4daaed07a30b60c4f91d96e4a diff --git a/cmake/common.cmake b/cmake/common.cmake index 6c10a0a450..e10facab0c 100755 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -1191,6 +1191,7 @@ option(NSC_DEBUG_EDIF_LINE_BIT "Add \"-fspv-debug=line\" to NSC Debug CLI" OFF) option(NSC_DEBUG_EDIF_TOOL_BIT "Add \"-fspv-debug=tool\" to NSC Debug CLI" ON) option(NSC_DEBUG_EDIF_NON_SEMANTIC_BIT "Add \"-fspv-debug=vulkan-with-source\" to NSC Debug CLI" OFF) option(NSC_USE_DEPFILE "Generate depfiles for NSC custom commands" ON) +option(NBL_DISABLE_EXPERIMENTAL_OPTS "Disable -O1experimental for all NSC compile rules globally" OFF) function(NBL_CREATE_NSC_COMPILE_RULES) set(COMMENT "this code has been autogenerated with Nabla CMake NBL_CREATE_HLSL_COMPILE_RULES utility") @@ -1230,10 +1231,7 @@ struct DeviceConfigCaps -fspv-target-env=vulkan1.3 -Wshadow -Wconversion - -Wno-local-type-template-args - $<$:-O0> - $<$:-O3> - $<$:-O3> + -Wno-local-type-template-args ) if(NSC_DEBUG_EDIF_FILE_BIT) @@ -1268,9 +1266,23 @@ struct DeviceConfigCaps set(REQUIRED_SINGLE_ARGS TARGET BINARY_DIR OUTPUT_VAR INPUTS INCLUDE NAMESPACE MOUNT_POINT_DEFINE) set(OPTIONAL_SINGLE_ARGS GLOB_DIR) - cmake_parse_arguments(IMPL "DISCARD_DEFAULT_GLOB" "${REQUIRED_SINGLE_ARGS};${OPTIONAL_SINGLE_ARGS};LINK_TO" "COMMON_OPTIONS;DEPENDS" ${ARGV}) + cmake_parse_arguments(IMPL "DISCARD_DEFAULT_GLOB;DISABLE_EXPERIMENTAL_OPTS" "${REQUIRED_SINGLE_ARGS};${OPTIONAL_SINGLE_ARGS};LINK_TO" "COMMON_OPTIONS;DEPENDS" ${ARGV}) NBL_PARSE_REQUIRED(IMPL ${REQUIRED_SINGLE_ARGS}) + if(NBL_DISABLE_EXPERIMENTAL_OPTS OR IMPL_DISABLE_EXPERIMENTAL_OPTS) + list(APPEND REQUIRED_OPTIONS + $<$:-O0> + $<$:-O3> + $<$:-O3> + ) + else() + list(APPEND REQUIRED_OPTIONS + $<$:-O1experimental> + $<$:-O3> + $<$:-O1experimental> + ) + endif() + set(IMPL_HLSL_GLOB "") if(NOT IMPL_DISCARD_DEFAULT_GLOB) set(GLOB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}") From d39ba00a3170bf7add37316f9ae37fec66cb87a9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 29 Mar 2026 18:56:55 +0000 Subject: [PATCH 60/60] Promote NSC channel 29bda527be490f8214e937ae33bbffd438cce6e6 --- tools/nsc/manifests/nsc-windows-x64-release.tag | 2 +- .../exe/tools/nsc/bin/build-info.json.dvc | 4 ++-- .../nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc | 2 +- .../runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc | 4 ++-- .../nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/nsc/manifests/nsc-windows-x64-release.tag b/tools/nsc/manifests/nsc-windows-x64-release.tag index 77e81c53ec..2b2bd74fe3 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release.tag +++ b/tools/nsc/manifests/nsc-windows-x64-release.tag @@ -1 +1 @@ -nsc-windows-x64-release-6683a20d668f1207e822c2efedba901e4ae11028 +nsc-windows-x64-release-29bda527be490f8214e937ae33bbffd438cce6e6 diff --git a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc index b259e6fc25..8ca7a61538 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/build-info.json.dvc @@ -1,5 +1,5 @@ outs: -- md5: 9e2c1537859c6f840f8cedcda575d845 - size: 1335 +- md5: f739d206ca9055781c891f130c6ebc1b + size: 1311 hash: md5 path: build-info.json diff --git a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc index d76605a700..a00e876502 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/exe/tools/nsc/bin/nsc.exe.dvc @@ -1,5 +1,5 @@ outs: -- md5: dac035a1aa111f8e6551ba08f7c7f7ea +- md5: c4bb7179384f8fe59a5706751a2ef473 size: 258048 hash: md5 path: nsc.exe diff --git a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc index a35ca7c654..b4ba827093 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/3rdparty/dxc/dxcompiler.dll.dvc @@ -1,5 +1,5 @@ outs: -- md5: f71b14a52e199ad9b8a75aa74c3a2ffb - size: 21583872 +- md5: 862b11b94cb23c8bac2a20a215eb6597 + size: 21601280 hash: md5 path: dxcompiler.dll diff --git a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc index 689bf8b048..9fdd807d6a 100644 --- a/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc +++ b/tools/nsc/manifests/nsc-windows-x64-release/runtime/nbl/Nabla.dll.dvc @@ -1,5 +1,5 @@ outs: -- md5: 846e2b97b36c84f5e2544f30bcb6e180 - size: 29196288 +- md5: 5edb2790e9ceae424e3c0a04e3d84718 + size: 29212672 hash: md5 path: Nabla.dll