From 61540d64d42c0bf0d546a326698004e58c9f94c2 Mon Sep 17 00:00:00 2001 From: Przemog1 Date: Thu, 11 Dec 2025 17:07:59 +0100 Subject: [PATCH 1/9] Modified `LoadableImage` and `ResolveAccessorBase` concepts --- .../concepts/accessors/loadable_image.hlsl | 6 +-- include/nbl/builtin/hlsl/rwmc/resolve.hlsl | 47 +++++++++---------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/include/nbl/builtin/hlsl/concepts/accessors/loadable_image.hlsl b/include/nbl/builtin/hlsl/concepts/accessors/loadable_image.hlsl index 8c7251214d..924ee240d0 100644 --- a/include/nbl/builtin/hlsl/concepts/accessors/loadable_image.hlsl +++ b/include/nbl/builtin/hlsl/concepts/accessors/loadable_image.hlsl @@ -25,8 +25,8 @@ namespace accessors // declare concept #define NBL_CONCEPT_NAME LoadableImage -#define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(typename)(int32_t) -#define NBL_CONCEPT_TPLT_PRM_NAMES (U)(T)(Dims) +#define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(typename)(int32_t)(int32_t) +#define NBL_CONCEPT_TPLT_PRM_NAMES (U)(T)(Dims)(Components) // not the greatest syntax but works #define NBL_CONCEPT_PARAM_0 (a,U) #define NBL_CONCEPT_PARAM_1 (uv,vector) @@ -38,7 +38,7 @@ NBL_CONCEPT_BEGIN(3) #define uv NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 #define layer NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_2 NBL_CONCEPT_END( - ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(uv,layer)), ::nbl::hlsl::is_same_v, vector)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(uv,layer)), ::nbl::hlsl::is_same_v, vector)) ); #undef layer #undef uv diff --git a/include/nbl/builtin/hlsl/rwmc/resolve.hlsl b/include/nbl/builtin/hlsl/rwmc/resolve.hlsl index d8f777d277..64cec7dfe3 100644 --- a/include/nbl/builtin/hlsl/rwmc/resolve.hlsl +++ b/include/nbl/builtin/hlsl/rwmc/resolve.hlsl @@ -16,21 +16,21 @@ namespace rwmc { // declare concept #define NBL_CONCEPT_NAME ResolveAccessorBase -#define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(typename)(int32_t) -#define NBL_CONCEPT_TPLT_PRM_NAMES (T)(VectorScalarType)(Dims) +#define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(typename)(int32_t)(int32_t) +#define NBL_CONCEPT_TPLT_PRM_NAMES (T)(VectorScalarType)(Dims)(Components) // not the greatest syntax but works #define NBL_CONCEPT_PARAM_0 (a,T) -#define NBL_CONCEPT_PARAM_1 (scalar,VectorScalarType) +#define NBL_CONCEPT_PARAM_1 (vec,vector) // start concept - NBL_CONCEPT_BEGIN(2) +NBL_CONCEPT_BEGIN(2) // need to be defined AFTER the concept begins #define a NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 -#define scalar NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 +#define vec NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 NBL_CONCEPT_END( - ((NBL_CONCEPT_REQ_EXPR)((a.calcLuma(vector(scalar, scalar, scalar))))) + ((NBL_CONCEPT_REQ_EXPR)((a.calcLuma(vec)))) ); #undef a -#undef scalar +#undef vec #include /* ResolveAccessor is required to: @@ -38,14 +38,15 @@ NBL_CONCEPT_END( * - implement function called `calcLuma` which calculates luma from a 3 component pixel value */ -template -NBL_BOOL_CONCEPT ResolveAccessor = ResolveAccessorBase && concepts::accessors::LoadableImage; +template +NBL_BOOL_CONCEPT ResolveAccessor = ResolveAccessorBase && concepts::accessors::LoadableImage; template struct ResolveAccessorAdaptor { using output_scalar_type = OutputScalar; - using output_type = vector; + NBL_CONSTEXPR int32_t Components = 3; + using output_type = vector; NBL_CONSTEXPR int32_t image_dimension = 2; RWTexture2DArray cascade; @@ -63,13 +64,13 @@ struct ResolveAccessorAdaptor int16_t2 cascadeImageDimension = int16_t2(imgWidth, imgHeight); if (any(uv < int16_t2(0, 0)) || any(uv > cascadeImageDimension)) - return vector(0, 0, 0, 0); + return promote(0); return cascade.Load(int32_t3(uv, int32_t(layer))); } }; -template && ResolveAccessor) +template && ResolveAccessor) struct Resolver { using output_type = OutputColorTypeVec; @@ -92,12 +93,10 @@ struct Resolver output_type operator()(NBL_REF_ARG(CascadeAccessor) acc, const int16_t2 coord) { - using scalar_t = typename vector_traits::scalar_type; - scalar_t reciprocalBaseI = 1.f; CascadeSample curr = __sampleCascade(acc, coord, 0u, reciprocalBaseI); - output_type accumulation = output_type(0.0f, 0.0f, 0.0f); + output_type accumulation = promote(0.0f); scalar_t Emin = params.initialEmin; scalar_t prevNormalizedCenterLuma, prevNormalizedNeighbourhoodAverageLuma; @@ -162,15 +161,15 @@ struct Resolver CascadeSample __sampleCascade(NBL_REF_ARG(CascadeAccessor) acc, int16_t2 coord, uint16_t cascadeIndex, scalar_t reciprocalBaseI) { output_type neighbourhood[9]; - neighbourhood[0] = acc.template get(coord + int16_t2(-1, -1), cascadeIndex).xyz; - neighbourhood[1] = acc.template get(coord + int16_t2(0, -1), cascadeIndex).xyz; - neighbourhood[2] = acc.template get(coord + int16_t2(1, -1), cascadeIndex).xyz; - neighbourhood[3] = acc.template get(coord + int16_t2(-1, 0), cascadeIndex).xyz; - neighbourhood[4] = acc.template get(coord + int16_t2(0, 0), cascadeIndex).xyz; - neighbourhood[5] = acc.template get(coord + int16_t2(1, 0), cascadeIndex).xyz; - neighbourhood[6] = acc.template get(coord + int16_t2(-1, 1), cascadeIndex).xyz; - neighbourhood[7] = acc.template get(coord + int16_t2(0, 1), cascadeIndex).xyz; - neighbourhood[8] = acc.template get(coord + int16_t2(1, 1), cascadeIndex).xyz; + neighbourhood[0] = acc.template get(coord + int16_t2(-1, -1), cascadeIndex); + neighbourhood[1] = acc.template get(coord + int16_t2(0, -1), cascadeIndex); + neighbourhood[2] = acc.template get(coord + int16_t2(1, -1), cascadeIndex); + neighbourhood[3] = acc.template get(coord + int16_t2(-1, 0), cascadeIndex); + neighbourhood[4] = acc.template get(coord + int16_t2(0, 0), cascadeIndex); + neighbourhood[5] = acc.template get(coord + int16_t2(1, 0), cascadeIndex); + neighbourhood[6] = acc.template get(coord + int16_t2(-1, 1), cascadeIndex); + neighbourhood[7] = acc.template get(coord + int16_t2(0, 1), cascadeIndex); + neighbourhood[8] = acc.template get(coord + int16_t2(1, 1), cascadeIndex); // numerical robustness float32_t3 excl_hood_sum = ((neighbourhood[0] + neighbourhood[1]) + (neighbourhood[2] + neighbourhood[3])) + From 6953879dade4967e4ca0afd2451cc18b13214d87 Mon Sep 17 00:00:00 2001 From: Przemog1 Date: Mon, 22 Dec 2025 13:14:17 +0100 Subject: [PATCH 2/9] Small RWMC fixes --- .../nbl/builtin/hlsl/concepts/accessors/storable_image.hlsl | 6 +++--- include/nbl/builtin/hlsl/rwmc/resolve.hlsl | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/nbl/builtin/hlsl/concepts/accessors/storable_image.hlsl b/include/nbl/builtin/hlsl/concepts/accessors/storable_image.hlsl index 7eda9b9303..900352d993 100644 --- a/include/nbl/builtin/hlsl/concepts/accessors/storable_image.hlsl +++ b/include/nbl/builtin/hlsl/concepts/accessors/storable_image.hlsl @@ -18,13 +18,13 @@ namespace accessors { // declare concept #define NBL_CONCEPT_NAME StorableImage -#define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(typename)(int32_t) -#define NBL_CONCEPT_TPLT_PRM_NAMES (U)(T)(Dims) +#define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(typename)(int32_t)(int32_t) +#define NBL_CONCEPT_TPLT_PRM_NAMES (U)(T)(Dims)(Components) // not the greatest syntax but works #define NBL_CONCEPT_PARAM_0 (a,U) #define NBL_CONCEPT_PARAM_1 (uv,vector) #define NBL_CONCEPT_PARAM_2 (layer,uint16_t) -#define NBL_CONCEPT_PARAM_3 (data,vector) +#define NBL_CONCEPT_PARAM_3 (data,vector) // start concept NBL_CONCEPT_BEGIN(4) // need to be defined AFTER the cocnept begins diff --git a/include/nbl/builtin/hlsl/rwmc/resolve.hlsl b/include/nbl/builtin/hlsl/rwmc/resolve.hlsl index 64cec7dfe3..34d7c95960 100644 --- a/include/nbl/builtin/hlsl/rwmc/resolve.hlsl +++ b/include/nbl/builtin/hlsl/rwmc/resolve.hlsl @@ -27,7 +27,7 @@ NBL_CONCEPT_BEGIN(2) #define a NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 #define vec NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 NBL_CONCEPT_END( - ((NBL_CONCEPT_REQ_EXPR)((a.calcLuma(vec)))) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.calcLuma(vec)), ::nbl::hlsl::is_same_v, VectorScalarType)) ); #undef a #undef vec From addde12192a474a8a27bad7f58d48c3ba1f3a9d5 Mon Sep 17 00:00:00 2001 From: Przemog1 Date: Mon, 16 Feb 2026 05:10:24 +0100 Subject: [PATCH 3/9] RWMC fixes --- examples_tests | 2 +- .../concepts/accessors/loadable_image.hlsl | 6 +- .../builtin/hlsl/rwmc/CascadeAccumulator.hlsl | 80 +++++++++---------- .../builtin/hlsl/rwmc/ResolveParameters.hlsl | 34 ++++---- .../hlsl/rwmc/SplattingParameters.hlsl | 10 ++- include/nbl/builtin/hlsl/rwmc/resolve.hlsl | 32 ++++---- 6 files changed, 85 insertions(+), 79 deletions(-) diff --git a/examples_tests b/examples_tests index dd7de7a89c..4246192d21 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit dd7de7a89cfa5a59970dde4d4744ecf746d77a4a +Subproject commit 4246192d213c0c42a508257bd219c1fca0cb238f diff --git a/include/nbl/builtin/hlsl/concepts/accessors/loadable_image.hlsl b/include/nbl/builtin/hlsl/concepts/accessors/loadable_image.hlsl index 924ee240d0..f7b5122c81 100644 --- a/include/nbl/builtin/hlsl/concepts/accessors/loadable_image.hlsl +++ b/include/nbl/builtin/hlsl/concepts/accessors/loadable_image.hlsl @@ -47,8 +47,8 @@ NBL_CONCEPT_END( // declare concept #define NBL_CONCEPT_NAME MipmappedLoadableImage -#define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(typename)(int32_t) -#define NBL_CONCEPT_TPLT_PRM_NAMES (U)(T)(Dims) +#define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(typename)(int32_t)(int32_t) +#define NBL_CONCEPT_TPLT_PRM_NAMES (U)(T)(Dims)(Components) // not the greatest syntax but works #define NBL_CONCEPT_PARAM_0 (a,U) #define NBL_CONCEPT_PARAM_1 (uv,vector) @@ -62,7 +62,7 @@ NBL_CONCEPT_BEGIN(4) #define layer NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_2 #define level NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_3 NBL_CONCEPT_END( - ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(uv,layer,level)) , ::nbl::hlsl::is_same_v, vector)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(uv,layer,level)) , ::nbl::hlsl::is_same_v, vector)) ); #undef level #undef layer diff --git a/include/nbl/builtin/hlsl/rwmc/CascadeAccumulator.hlsl b/include/nbl/builtin/hlsl/rwmc/CascadeAccumulator.hlsl index 593e267a26..cdbb8271d2 100644 --- a/include/nbl/builtin/hlsl/rwmc/CascadeAccumulator.hlsl +++ b/include/nbl/builtin/hlsl/rwmc/CascadeAccumulator.hlsl @@ -14,36 +14,38 @@ namespace rwmc { template) -struct CascadeAccumulator +struct DefaultCascades { - struct CascadeEntry - { - uint32_t cascadeSampleCounter[CascadeCount]; - CascadeLayerType data[CascadeCount]; + using layer_type = CascadeLayerType; - void addSampleIntoCascadeEntry(CascadeLayerType _sample, uint32_t lowerCascadeIndex, float lowerCascadeLevelWeight, float higherCascadeLevelWeight, uint32_t sampleCount) - { - const float reciprocalSampleCount = 1.0f / float(sampleCount); + uint32_t cascadeSampleCounter[CascadeCount]; + CascadeLayerType data[CascadeCount]; - uint32_t lowerCascadeSampleCount = cascadeSampleCounter[lowerCascadeIndex]; - data[lowerCascadeIndex] += (_sample * lowerCascadeLevelWeight - (sampleCount - lowerCascadeSampleCount) * data[lowerCascadeIndex]) * reciprocalSampleCount; - cascadeSampleCounter[lowerCascadeIndex] = sampleCount; + void addSampleIntoCascadeEntry(CascadeLayerType _sample, uint16_t lowerCascadeIndex, SplattingParameters::scalar_t lowerCascadeLevelWeight, SplattingParameters::scalar_t higherCascadeLevelWeight, uint32_t sampleCount) + { + const float reciprocalSampleCount = 1.0f / float(sampleCount); - uint32_t higherCascadeIndex = lowerCascadeIndex + 1u; - if (higherCascadeIndex < CascadeCount) - { - uint32_t higherCascadeSampleCount = cascadeSampleCounter[higherCascadeIndex]; - data[higherCascadeIndex] += (_sample * higherCascadeLevelWeight - (sampleCount - higherCascadeSampleCount) * data[higherCascadeIndex]) * reciprocalSampleCount; - cascadeSampleCounter[higherCascadeIndex] = sampleCount; - } + uint32_t lowerCascadeSampleCount = cascadeSampleCounter[lowerCascadeIndex]; + data[lowerCascadeIndex] += (_sample * lowerCascadeLevelWeight - (sampleCount - lowerCascadeSampleCount) * data[lowerCascadeIndex]) * reciprocalSampleCount; + cascadeSampleCounter[lowerCascadeIndex] = sampleCount; + + uint16_t higherCascadeIndex = lowerCascadeIndex + 1u; + if (higherCascadeIndex < CascadeCount) + { + uint32_t higherCascadeSampleCount = cascadeSampleCounter[higherCascadeIndex]; + data[higherCascadeIndex] += (_sample * higherCascadeLevelWeight - (sampleCount - higherCascadeSampleCount) * data[higherCascadeIndex]) * reciprocalSampleCount; + cascadeSampleCounter[higherCascadeIndex] = sampleCount; } - }; + } +}; - using cascade_layer_scalar_type = typename vector_traits::scalar_type; - using this_t = CascadeAccumulator; - using input_sample_type = CascadeLayerType; - using output_storage_type = CascadeEntry; - using initialization_data = SplattingParameters; +template +struct CascadeAccumulator +{ + using input_sample_type = typename CascadesType::layer_type; + using cascade_layer_scalar_type = typename vector_traits::scalar_type; + using this_t = CascadeAccumulator; + using output_storage_type = CascadesType; output_storage_type accumulation; SplattingParameters splattingParameters; @@ -53,39 +55,35 @@ struct CascadeAccumulator this_t retval; for (int i = 0; i < CascadeCount; ++i) { - retval.accumulation.data[i] = promote(0.0f); + retval.accumulation.data[i] = promote(0.0f); retval.accumulation.cascadeSampleCounter[i] = 0u; } retval.splattingParameters = settings; return retval; } - - cascade_layer_scalar_type getLuma(NBL_CONST_REF_ARG(CascadeLayerType) col) - { - return hlsl::dot(hlsl::transpose(colorspace::scRGBtoXYZ)[1], col); - } // most of this code is stolen from https://cg.ivd.kit.edu/publications/2018/rwmc/tool/split.cpp void addSample(uint32_t sampleCount, input_sample_type _sample) { const float32_t2 unpackedParams = hlsl::unpackHalf2x16(splattingParameters.packedLog2); - const cascade_layer_scalar_type log2Start = unpackedParams[0]; - const cascade_layer_scalar_type log2Base = unpackedParams[1]; - const cascade_layer_scalar_type luma = getLuma(_sample); - const cascade_layer_scalar_type log2Luma = log2(luma); - const cascade_layer_scalar_type cascade = log2Luma * 1.f / log2Base - log2Start / log2Base; - const cascade_layer_scalar_type clampedCascade = clamp(cascade, 0, CascadeCount - 1); + const SplattingParameters::scalar_t log2Start = unpackedParams[0]; + const SplattingParameters::scalar_t rcpLog2Base = unpackedParams[1]; + const SplattingParameters::scalar_t luma = splattingParameters.getLuma(_sample); + const SplattingParameters::scalar_t log2Luma = log2(luma); + const SplattingParameters::scalar_t cascade = log2Luma * rcpLog2Base - log2Start * rcpLog2Base; + const SplattingParameters::scalar_t lastCascade = CascadeCount - 1; + const SplattingParameters::scalar_t clampedCascade = clamp(cascade, 0, lastCascade); // c<=0 -> 0, c>=Count-1 -> Count-1 - uint32_t lowerCascadeIndex = floor(cascade); + uint16_t lowerCascadeIndex = floor(cascade); // 0 whenever clamped or `cascade` is integer (when `clampedCascade` is integer) - cascade_layer_scalar_type higherCascadeWeight = clampedCascade - floor(clampedCascade); + SplattingParameters::scalar_t higherCascadeWeight = clampedCascade - floor(clampedCascade); // never 0 thanks to magic of `1-fract(x)` - cascade_layer_scalar_type lowerCascadeWeight = cascade_layer_scalar_type(1) - higherCascadeWeight; + SplattingParameters::scalar_t lowerCascadeWeight = SplattingParameters::scalar_t(1) - higherCascadeWeight; // handle super bright sample case - if (cascade > CascadeCount - 1) - lowerCascadeWeight = exp2(log2Start + log2Base * (CascadeCount - 1) - log2Luma); + if (cascade > lastCascade) + lowerCascadeWeight = exp2(log2Start + (1.0f/rcpLog2Base) * (lastCascade) - log2Luma); accumulation.addSampleIntoCascadeEntry(_sample, lowerCascadeIndex, lowerCascadeWeight, higherCascadeWeight, sampleCount); } diff --git a/include/nbl/builtin/hlsl/rwmc/ResolveParameters.hlsl b/include/nbl/builtin/hlsl/rwmc/ResolveParameters.hlsl index 7509eac493..17e3f8d720 100644 --- a/include/nbl/builtin/hlsl/rwmc/ResolveParameters.hlsl +++ b/include/nbl/builtin/hlsl/rwmc/ResolveParameters.hlsl @@ -12,7 +12,22 @@ namespace rwmc struct ResolveParameters { - uint32_t lastCascadeIndex; + static ResolveParameters create(float base, uint32_t sampleCount, float minReliableLuma, float kappa) + { + ResolveParameters retval; + retval.initialEmin = minReliableLuma; + retval.reciprocalBase = 1.f / base; + const float N = float(sampleCount); + retval.reciprocalN = 1.f / N; + retval.reciprocalKappa = 1.f / kappa; + // if not interested in exact expected value estimation (kappa!=1.f), can usually accept a bit more variance relative to the image brightness we already have + // allow up to ~ more energy in one sample to lessen bias in some cases + retval.colorReliabilityFactor = base + (1.f - base) * retval.reciprocalKappa; + retval.NOverKappa = N * retval.reciprocalKappa; + + return retval; + } + float initialEmin; // a minimum image brightness that we always consider reliable float reciprocalBase; float reciprocalN; @@ -21,23 +36,6 @@ struct ResolveParameters float NOverKappa; }; -ResolveParameters computeResolveParameters(float base, uint32_t sampleCount, float minReliableLuma, float kappa, uint32_t cascadeSize) -{ - ResolveParameters retval; - retval.lastCascadeIndex = cascadeSize - 1u; - retval.initialEmin = minReliableLuma; - retval.reciprocalBase = 1.f / base; - const float N = float(sampleCount); - retval.reciprocalN = 1.f / N; - retval.reciprocalKappa = 1.f / kappa; - // if not interested in exact expected value estimation (kappa!=1.f), can usually accept a bit more variance relative to the image brightness we already have - // allow up to ~ more energy in one sample to lessen bias in some cases - retval.colorReliabilityFactor = base + (1.f - base) * retval.reciprocalKappa; - retval.NOverKappa = N * retval.reciprocalKappa; - - return retval; -} - } } } diff --git a/include/nbl/builtin/hlsl/rwmc/SplattingParameters.hlsl b/include/nbl/builtin/hlsl/rwmc/SplattingParameters.hlsl index c549d83be6..74b062a2de 100644 --- a/include/nbl/builtin/hlsl/rwmc/SplattingParameters.hlsl +++ b/include/nbl/builtin/hlsl/rwmc/SplattingParameters.hlsl @@ -12,10 +12,18 @@ namespace rwmc struct SplattingParameters { + using scalar_t = float32_t; + // float16_t log2Start; 0 - // float16_t log2Base; 1 + // float16_t rcpLog2Base; 1 // pack as Half2x16 int32_t packedLog2; + + template + scalar_t getLuma(NBL_CONST_REF_ARG(CascadeLayerType) col) + { + return hlsl::dot(hlsl::transpose(colorspace::scRGBtoXYZ)[1], col); + } }; } diff --git a/include/nbl/builtin/hlsl/rwmc/resolve.hlsl b/include/nbl/builtin/hlsl/rwmc/resolve.hlsl index 34d7c95960..a3b4236dca 100644 --- a/include/nbl/builtin/hlsl/rwmc/resolve.hlsl +++ b/include/nbl/builtin/hlsl/rwmc/resolve.hlsl @@ -16,8 +16,8 @@ namespace rwmc { // declare concept #define NBL_CONCEPT_NAME ResolveAccessorBase -#define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(typename)(int32_t)(int32_t) -#define NBL_CONCEPT_TPLT_PRM_NAMES (T)(VectorScalarType)(Dims)(Components) +#define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(typename)(int32_t) +#define NBL_CONCEPT_TPLT_PRM_NAMES (T)(VectorScalarType)(Components) // not the greatest syntax but works #define NBL_CONCEPT_PARAM_0 (a,T) #define NBL_CONCEPT_PARAM_1 (vec,vector) @@ -28,6 +28,7 @@ NBL_CONCEPT_BEGIN(2) #define vec NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 NBL_CONCEPT_END( ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.calcLuma(vec)), ::nbl::hlsl::is_same_v, VectorScalarType)) + ((NBL_CONCEPT_REQ_TYPE)(T::output_t)) ); #undef a #undef vec @@ -39,14 +40,14 @@ NBL_CONCEPT_END( */ template -NBL_BOOL_CONCEPT ResolveAccessor = ResolveAccessorBase && concepts::accessors::LoadableImage; +NBL_BOOL_CONCEPT ResolveAccessor = ResolveAccessorBase && concepts::accessors::LoadableImage; template struct ResolveAccessorAdaptor { - using output_scalar_type = OutputScalar; + using output_scalar_t = OutputScalar; NBL_CONSTEXPR int32_t Components = 3; - using output_type = vector; + using output_t = vector; NBL_CONSTEXPR int32_t image_dimension = 2; RWTexture2DArray cascade; @@ -57,24 +58,24 @@ struct ResolveAccessorAdaptor } template - output_type get(vector uv, uint16_t layer) + output_t get(vector uv, uint16_t layer) { uint32_t imgWidth, imgHeight, layers; cascade.GetDimensions(imgWidth, imgHeight, layers); int16_t2 cascadeImageDimension = int16_t2(imgWidth, imgHeight); if (any(uv < int16_t2(0, 0)) || any(uv > cascadeImageDimension)) - return promote(0); + return promote(0); return cascade.Load(int32_t3(uv, int32_t(layer))); } }; -template && ResolveAccessor) +template) struct Resolver { - using output_type = OutputColorTypeVec; - using scalar_t = typename vector_traits::scalar_type; + using output_t = typename CascadeAccessor::output_t; + using scalar_t = typename vector_traits::scalar_type; struct CascadeSample { @@ -91,19 +92,20 @@ struct Resolver return retval; } - output_type operator()(NBL_REF_ARG(CascadeAccessor) acc, const int16_t2 coord) + output_t operator()(NBL_REF_ARG(CascadeAccessor) acc, const int16_t2 coord) { scalar_t reciprocalBaseI = 1.f; CascadeSample curr = __sampleCascade(acc, coord, 0u, reciprocalBaseI); - output_type accumulation = promote(0.0f); + output_t accumulation = promote(0.0f); scalar_t Emin = params.initialEmin; scalar_t prevNormalizedCenterLuma, prevNormalizedNeighbourhoodAverageLuma; - for (int16_t i = 0u; i <= params.lastCascadeIndex; i++) + NBL_UNROLL + for (int16_t i = 0u; i <= CascadeCount - 1; i++) { const bool notFirstCascade = i != 0; - const bool notLastCascade = i != params.lastCascadeIndex; + const bool notLastCascade = i != (CascadeCount - 1); CascadeSample next; if (notLastCascade) @@ -160,7 +162,7 @@ struct Resolver CascadeSample __sampleCascade(NBL_REF_ARG(CascadeAccessor) acc, int16_t2 coord, uint16_t cascadeIndex, scalar_t reciprocalBaseI) { - output_type neighbourhood[9]; + output_t neighbourhood[9]; neighbourhood[0] = acc.template get(coord + int16_t2(-1, -1), cascadeIndex); neighbourhood[1] = acc.template get(coord + int16_t2(0, -1), cascadeIndex); neighbourhood[2] = acc.template get(coord + int16_t2(1, -1), cascadeIndex); From 3a90b0cd2877a14c0b14c2ce3e17ae3d28d8f15a Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Mon, 16 Feb 2026 16:05:39 +0100 Subject: [PATCH 4/9] Finalize RWMC review fixes --- examples_tests | 2 +- .../builtin/hlsl/rwmc/CascadeAccumulator.hlsl | 55 ++-- .../builtin/hlsl/rwmc/ResolveParameters.hlsl | 39 ++- .../hlsl/rwmc/SplattingParameters.hlsl | 54 ++-- include/nbl/builtin/hlsl/rwmc/resolve.hlsl | 258 +++++++++--------- 5 files changed, 225 insertions(+), 183 deletions(-) diff --git a/examples_tests b/examples_tests index 4246192d21..130e049899 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 4246192d213c0c42a508257bd219c1fca0cb238f +Subproject commit 130e049899be16b50a5d27d7c67310a24d953530 diff --git a/include/nbl/builtin/hlsl/rwmc/CascadeAccumulator.hlsl b/include/nbl/builtin/hlsl/rwmc/CascadeAccumulator.hlsl index cdbb8271d2..e4bc9aa4fa 100644 --- a/include/nbl/builtin/hlsl/rwmc/CascadeAccumulator.hlsl +++ b/include/nbl/builtin/hlsl/rwmc/CascadeAccumulator.hlsl @@ -13,28 +13,36 @@ namespace hlsl namespace rwmc { -template) +template && concepts::UnsignedIntegralScalar) struct DefaultCascades { using layer_type = CascadeLayerType; + using sample_count_type = SampleCountType; + NBL_CONSTEXPR uint32_t cascade_count = CascadeCount; - uint32_t cascadeSampleCounter[CascadeCount]; - CascadeLayerType data[CascadeCount]; + sample_count_type cascadeSampleCounter[cascade_count]; + CascadeLayerType data[cascade_count]; + + void clear(uint32_t cascadeIx) + { + cascadeSampleCounter[cascadeIx] = sample_count_type(0u); + data[cascadeIx] = promote(0.0f); + } void addSampleIntoCascadeEntry(CascadeLayerType _sample, uint16_t lowerCascadeIndex, SplattingParameters::scalar_t lowerCascadeLevelWeight, SplattingParameters::scalar_t higherCascadeLevelWeight, uint32_t sampleCount) { - const float reciprocalSampleCount = 1.0f / float(sampleCount); + const SplattingParameters::scalar_t reciprocalSampleCount = SplattingParameters::scalar_t(1.0f) / SplattingParameters::scalar_t(sampleCount); - uint32_t lowerCascadeSampleCount = cascadeSampleCounter[lowerCascadeIndex]; + sample_count_type lowerCascadeSampleCount = cascadeSampleCounter[lowerCascadeIndex]; data[lowerCascadeIndex] += (_sample * lowerCascadeLevelWeight - (sampleCount - lowerCascadeSampleCount) * data[lowerCascadeIndex]) * reciprocalSampleCount; - cascadeSampleCounter[lowerCascadeIndex] = sampleCount; + cascadeSampleCounter[lowerCascadeIndex] = sample_count_type(sampleCount); - uint16_t higherCascadeIndex = lowerCascadeIndex + 1u; - if (higherCascadeIndex < CascadeCount) + uint16_t higherCascadeIndex = lowerCascadeIndex + uint16_t(1u); + if (higherCascadeIndex < cascade_count) { - uint32_t higherCascadeSampleCount = cascadeSampleCounter[higherCascadeIndex]; + sample_count_type higherCascadeSampleCount = cascadeSampleCounter[higherCascadeIndex]; data[higherCascadeIndex] += (_sample * higherCascadeLevelWeight - (sampleCount - higherCascadeSampleCount) * data[higherCascadeIndex]) * reciprocalSampleCount; - cascadeSampleCounter[higherCascadeIndex] = sampleCount; + cascadeSampleCounter[higherCascadeIndex] = sample_count_type(sampleCount); } } }; @@ -43,9 +51,9 @@ template struct CascadeAccumulator { using input_sample_type = typename CascadesType::layer_type; - using cascade_layer_scalar_type = typename vector_traits::scalar_type; using this_t = CascadeAccumulator; using output_storage_type = CascadesType; + NBL_CONSTEXPR uint32_t cascade_count = output_storage_type::cascade_count; output_storage_type accumulation; SplattingParameters splattingParameters; @@ -53,11 +61,8 @@ struct CascadeAccumulator static this_t create(NBL_CONST_REF_ARG(SplattingParameters) settings) { this_t retval; - for (int i = 0; i < CascadeCount; ++i) - { - retval.accumulation.data[i] = promote(0.0f); - retval.accumulation.cascadeSampleCounter[i] = 0u; - } + for (uint32_t i = 0u; i < cascade_count; ++i) + retval.accumulation.clear(i); retval.splattingParameters = settings; return retval; @@ -66,16 +71,16 @@ struct CascadeAccumulator // most of this code is stolen from https://cg.ivd.kit.edu/publications/2018/rwmc/tool/split.cpp void addSample(uint32_t sampleCount, input_sample_type _sample) { - const float32_t2 unpackedParams = hlsl::unpackHalf2x16(splattingParameters.packedLog2); - const SplattingParameters::scalar_t log2Start = unpackedParams[0]; - const SplattingParameters::scalar_t rcpLog2Base = unpackedParams[1]; - const SplattingParameters::scalar_t luma = splattingParameters.getLuma(_sample); + const SplattingParameters::scalar_t baseRootOfStart = splattingParameters.baseRootOfStart(); + const SplattingParameters::scalar_t rcpLog2Base = splattingParameters.rcpLog2Base(); + const SplattingParameters::scalar_t luma = splattingParameters.calcLuma(_sample); const SplattingParameters::scalar_t log2Luma = log2(luma); - const SplattingParameters::scalar_t cascade = log2Luma * rcpLog2Base - log2Start * rcpLog2Base; - const SplattingParameters::scalar_t lastCascade = CascadeCount - 1; + const SplattingParameters::scalar_t log2BaseRootOfStart = log2(baseRootOfStart); + const SplattingParameters::scalar_t cascade = log2Luma * rcpLog2Base - log2BaseRootOfStart; + const SplattingParameters::scalar_t lastCascade = cascade_count - 1u; const SplattingParameters::scalar_t clampedCascade = clamp(cascade, 0, lastCascade); // c<=0 -> 0, c>=Count-1 -> Count-1 - uint16_t lowerCascadeIndex = floor(cascade); + uint16_t lowerCascadeIndex = uint16_t(floor(clampedCascade)); // 0 whenever clamped or `cascade` is integer (when `clampedCascade` is integer) SplattingParameters::scalar_t higherCascadeWeight = clampedCascade - floor(clampedCascade); // never 0 thanks to magic of `1-fract(x)` @@ -83,7 +88,7 @@ struct CascadeAccumulator // handle super bright sample case if (cascade > lastCascade) - lowerCascadeWeight = exp2(log2Start + (1.0f/rcpLog2Base) * (lastCascade) - log2Luma); + lowerCascadeWeight = exp2((log2BaseRootOfStart + lastCascade) / rcpLog2Base - log2Luma); accumulation.addSampleIntoCascadeEntry(_sample, lowerCascadeIndex, lowerCascadeWeight, higherCascadeWeight, sampleCount); } @@ -95,4 +100,4 @@ struct CascadeAccumulator } } -#endif \ No newline at end of file +#endif diff --git a/include/nbl/builtin/hlsl/rwmc/ResolveParameters.hlsl b/include/nbl/builtin/hlsl/rwmc/ResolveParameters.hlsl index 17e3f8d720..c9a79d1149 100644 --- a/include/nbl/builtin/hlsl/rwmc/ResolveParameters.hlsl +++ b/include/nbl/builtin/hlsl/rwmc/ResolveParameters.hlsl @@ -1,7 +1,8 @@ #ifndef _NBL_BUILTIN_HLSL_RWMC_RESOLVE_PARAMETERS_HLSL_INCLUDED_ -#define _NBL_BUILTIN_HLSL_RWMC_RESOLVE_PARAMETERS_HLSL_INCLUDED_ - -#include "nbl/builtin/hlsl/cpp_compat.hlsl" +#define _NBL_BUILTIN_HLSL_RWMC_RESOLVE_PARAMETERS_HLSL_INCLUDED_ + +#include "nbl/builtin/hlsl/cpp_compat.hlsl" +#include namespace nbl { @@ -10,11 +11,13 @@ namespace hlsl namespace rwmc { -struct ResolveParameters -{ - static ResolveParameters create(float base, uint32_t sampleCount, float minReliableLuma, float kappa) - { - ResolveParameters retval; +struct ResolveParameters +{ + using scalar_t = float32_t; + + static ResolveParameters create(float base, uint32_t sampleCount, float minReliableLuma, float kappa) + { + ResolveParameters retval; retval.initialEmin = minReliableLuma; retval.reciprocalBase = 1.f / base; const float N = float(sampleCount); @@ -25,12 +28,18 @@ struct ResolveParameters retval.colorReliabilityFactor = base + (1.f - base) * retval.reciprocalKappa; retval.NOverKappa = N * retval.reciprocalKappa; - return retval; - } - - float initialEmin; // a minimum image brightness that we always consider reliable - float reciprocalBase; - float reciprocalN; + return retval; + } + + template + scalar_t calcLuma(NBL_CONST_REF_ARG(SampleType) col) + { + return hlsl::dot(hlsl::transpose(colorspace::scRGBtoXYZ)[1], col); + } + + float initialEmin; // a minimum image brightness that we always consider reliable + float reciprocalBase; + float reciprocalN; float reciprocalKappa; float colorReliabilityFactor; float NOverKappa; @@ -40,4 +49,4 @@ struct ResolveParameters } } -#endif \ No newline at end of file +#endif diff --git a/include/nbl/builtin/hlsl/rwmc/SplattingParameters.hlsl b/include/nbl/builtin/hlsl/rwmc/SplattingParameters.hlsl index 74b062a2de..a7c95e9e27 100644 --- a/include/nbl/builtin/hlsl/rwmc/SplattingParameters.hlsl +++ b/include/nbl/builtin/hlsl/rwmc/SplattingParameters.hlsl @@ -1,7 +1,8 @@ #ifndef _NBL_BUILTIN_HLSL_RWMC_SPLATTING_PARAMETERS_HLSL_INCLUDED_ -#define _NBL_BUILTIN_HLSL_RWMC_SPLATTING_PARAMETERS_HLSL_INCLUDED_ - -#include "nbl/builtin/hlsl/cpp_compat.hlsl" +#define _NBL_BUILTIN_HLSL_RWMC_SPLATTING_PARAMETERS_HLSL_INCLUDED_ + +#include "nbl/builtin/hlsl/cpp_compat.hlsl" +#include namespace nbl { @@ -10,24 +11,39 @@ namespace hlsl namespace rwmc { -struct SplattingParameters -{ - using scalar_t = float32_t; - - // float16_t log2Start; 0 - // float16_t rcpLog2Base; 1 - // pack as Half2x16 - int32_t packedLog2; - - template - scalar_t getLuma(NBL_CONST_REF_ARG(CascadeLayerType) col) - { - return hlsl::dot(hlsl::transpose(colorspace::scRGBtoXYZ)[1], col); - } -}; +struct SplattingParameters +{ + using scalar_t = float32_t; + + // float16_t baseRootOfStart; 0 + // float16_t rcpLog2Base; 1 + // pack as Half2x16 + int32_t packedLog2; + + float32_t2 unpackedLog2Parameters() + { + return hlsl::unpackHalf2x16(packedLog2); + } + + scalar_t baseRootOfStart() + { + return unpackedLog2Parameters()[0]; + } + + scalar_t rcpLog2Base() + { + return unpackedLog2Parameters()[1]; + } + + template + scalar_t calcLuma(NBL_CONST_REF_ARG(CascadeLayerType) col) + { + return hlsl::dot(hlsl::transpose(colorspace::scRGBtoXYZ)[1], col); + } +}; } } } -#endif \ No newline at end of file +#endif diff --git a/include/nbl/builtin/hlsl/rwmc/resolve.hlsl b/include/nbl/builtin/hlsl/rwmc/resolve.hlsl index a3b4236dca..ac65c2ed03 100644 --- a/include/nbl/builtin/hlsl/rwmc/resolve.hlsl +++ b/include/nbl/builtin/hlsl/rwmc/resolve.hlsl @@ -1,93 +1,105 @@ -#ifndef _NBL_BUILTIN_HLSL_RWMC_RESOLVE_HLSL_INCLUDED_ -#define _NBL_BUILTIN_HLSL_RWMC_RESOLVE_HLSL_INCLUDED_ - -#include "nbl/builtin/hlsl/cpp_compat.hlsl" -#include -#include -#include -#include -#include +#ifndef _NBL_BUILTIN_HLSL_RWMC_RESOLVE_HLSL_INCLUDED_ +#define _NBL_BUILTIN_HLSL_RWMC_RESOLVE_HLSL_INCLUDED_ + +#include "nbl/builtin/hlsl/cpp_compat.hlsl" +#include +#include +#include namespace nbl { namespace hlsl { -namespace rwmc -{ - // declare concept -#define NBL_CONCEPT_NAME ResolveAccessorBase -#define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(typename)(int32_t) -#define NBL_CONCEPT_TPLT_PRM_NAMES (T)(VectorScalarType)(Components) -// not the greatest syntax but works -#define NBL_CONCEPT_PARAM_0 (a,T) -#define NBL_CONCEPT_PARAM_1 (vec,vector) -// start concept -NBL_CONCEPT_BEGIN(2) -// need to be defined AFTER the concept begins -#define a NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 -#define vec NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 -NBL_CONCEPT_END( - ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.calcLuma(vec)), ::nbl::hlsl::is_same_v, VectorScalarType)) - ((NBL_CONCEPT_REQ_TYPE)(T::output_t)) -); -#undef a -#undef vec -#include - -/* ResolveAccessor is required to: -* - satisfy `LoadableImage` concept requirements -* - implement function called `calcLuma` which calculates luma from a 3 component pixel value -*/ - -template -NBL_BOOL_CONCEPT ResolveAccessor = ResolveAccessorBase && concepts::accessors::LoadableImage; - -template -struct ResolveAccessorAdaptor -{ - using output_scalar_t = OutputScalar; - NBL_CONSTEXPR int32_t Components = 3; +namespace rwmc +{ +// declare concept +#define NBL_CONCEPT_NAME ResolveLumaParamsBase +#define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(typename) +#define NBL_CONCEPT_TPLT_PRM_NAMES (T)(SampleType) +#define NBL_CONCEPT_PARAM_0 (a,T) +#define NBL_CONCEPT_PARAM_1 (sample,SampleType) +NBL_CONCEPT_BEGIN(2) +#define a NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 +#define sample NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 +NBL_CONCEPT_END( + ((NBL_CONCEPT_REQ_TYPE)(T::scalar_t)) + ((NBL_CONCEPT_REQ_TYPE_ALIAS_CONCEPT)(concepts::FloatingPointScalar, T::scalar_t)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template calcLuma(sample)), ::nbl::hlsl::is_same_v, typename T::scalar_t)) +); +#undef sample +#undef a +#include + +template +NBL_BOOL_CONCEPT ResolveLumaParams = ResolveLumaParamsBase; + +// declare concept +#define NBL_CONCEPT_NAME ResolveAccessorBase +#define NBL_CONCEPT_TPLT_PRM_KINDS (typename) +#define NBL_CONCEPT_TPLT_PRM_NAMES (T) +#define NBL_CONCEPT_PARAM_0 (a,T) +#define NBL_CONCEPT_PARAM_1 (uv,vector) +#define NBL_CONCEPT_PARAM_2 (layer,uint16_t) +NBL_CONCEPT_BEGIN(3) +#define a NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 +#define uv NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 +#define layer NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_2 +NBL_CONCEPT_END( + ((NBL_CONCEPT_REQ_TYPE)(T::output_t)) + ((NBL_CONCEPT_REQ_TYPE)(T::output_scalar_t)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(uv,layer)), ::nbl::hlsl::is_same_v, typename T::output_t)) +); +#undef layer +#undef uv +#undef a +#include + +template +NBL_BOOL_CONCEPT ResolveAccessor = ResolveAccessorBase && concepts::accessors::LoadableImage; + +template +struct ResolveAccessorAdaptor +{ + using output_scalar_t = OutputScalar; + NBL_CONSTEXPR int32_t Components = 3; using output_t = vector; NBL_CONSTEXPR int32_t image_dimension = 2; - - RWTexture2DArray cascade; - - float32_t calcLuma(NBL_REF_ARG(float32_t3) col) - { - return hlsl::dot(colorspace::scRGB::ToXYZ()[1], col); - } - - template - output_t get(vector uv, uint16_t layer) - { + + RWTexture2DArray cascade; + + template + output_t get(vector uv, uint16_t layer) + { uint32_t imgWidth, imgHeight, layers; - cascade.GetDimensions(imgWidth, imgHeight, layers); - int16_t2 cascadeImageDimension = int16_t2(imgWidth, imgHeight); - - if (any(uv < int16_t2(0, 0)) || any(uv > cascadeImageDimension)) - return promote(0); + cascade.GetDimensions(imgWidth, imgHeight, layers); + int16_t2 cascadeImageDimension = int16_t2(imgWidth, imgHeight); + + if (any(uv < int16_t2(0, 0)) || any(uv >= cascadeImageDimension)) + return promote(0); return cascade.Load(int32_t3(uv, int32_t(layer))); } }; -template) -struct Resolver -{ - using output_t = typename CascadeAccessor::output_t; - using scalar_t = typename vector_traits::scalar_type; - - struct CascadeSample - { - float32_t3 centerValue; - float normalizedCenterLuma; - float normalizedNeighbourhoodAverageLuma; - }; - - static Resolver create(NBL_REF_ARG(ResolveParameters) resolveParameters) - { - Resolver retval; - retval.params = resolveParameters; +template && ResolveLumaParams) +struct Resolver +{ + using output_t = typename CascadeAccessor::output_t; + using output_scalar_t = typename vector_traits::scalar_type; + using scalar_t = typename ResolveParamsType::scalar_t; + NBL_CONSTEXPR static uint16_t last_cascade = CascadeCount - 1u; + + struct CascadeSample + { + output_t centerValue; + float normalizedCenterLuma; + float normalizedNeighbourhoodAverageLuma; + }; + + static Resolver create(NBL_REF_ARG(ResolveParamsType) resolveParameters) + { + Resolver retval; + retval.params = resolveParameters; return retval; } @@ -97,18 +109,18 @@ struct Resolver scalar_t reciprocalBaseI = 1.f; CascadeSample curr = __sampleCascade(acc, coord, 0u, reciprocalBaseI); - output_t accumulation = promote(0.0f); - scalar_t Emin = params.initialEmin; - - scalar_t prevNormalizedCenterLuma, prevNormalizedNeighbourhoodAverageLuma; - NBL_UNROLL - for (int16_t i = 0u; i <= CascadeCount - 1; i++) - { - const bool notFirstCascade = i != 0; - const bool notLastCascade = i != (CascadeCount - 1); - - CascadeSample next; - if (notLastCascade) + output_t accumulation = promote(0.0f); + scalar_t Emin = params.initialEmin; + + scalar_t prevNormalizedCenterLuma, prevNormalizedNeighbourhoodAverageLuma; + NBL_UNROLL + for (uint16_t i = 0u; i <= last_cascade; i++) + { + const bool notFirstCascade = i != 0; + const bool notLastCascade = i != last_cascade; + + CascadeSample next; + if (notLastCascade) { reciprocalBaseI *= params.reciprocalBase; next = __sampleCascade(acc, coord, int16_t(i + 1), reciprocalBaseI); @@ -132,11 +144,11 @@ struct Resolver globalReliability += next.normalizedNeighbourhoodAverageLuma; } // check if above minimum sampling threshold (avg 9 sample occurences in 3x3 neighbourhood), then use per-pixel reliability (NOTE: tertiary op is in reverse) - reliability = globalReliability < params.reciprocalN ? globalReliability : localReliability; - { - const scalar_t accumLuma = acc.calcLuma(accumulation); - if (accumLuma > Emin) - Emin = accumLuma; + reliability = globalReliability < params.reciprocalN ? globalReliability : localReliability; + { + const scalar_t accumLuma = params.template calcLuma(accumulation); + if (accumLuma > Emin) + Emin = accumLuma; const scalar_t colorReliability = Emin * reciprocalBaseI * params.colorReliabilityFactor; @@ -153,40 +165,40 @@ struct Resolver curr = next; } - return accumulation; - } - - ResolveParameters params; + return accumulation; + } + + ResolveParamsType params; // pseudo private stuff: - CascadeSample __sampleCascade(NBL_REF_ARG(CascadeAccessor) acc, int16_t2 coord, uint16_t cascadeIndex, scalar_t reciprocalBaseI) - { - output_t neighbourhood[9]; - neighbourhood[0] = acc.template get(coord + int16_t2(-1, -1), cascadeIndex); - neighbourhood[1] = acc.template get(coord + int16_t2(0, -1), cascadeIndex); - neighbourhood[2] = acc.template get(coord + int16_t2(1, -1), cascadeIndex); - neighbourhood[3] = acc.template get(coord + int16_t2(-1, 0), cascadeIndex); - neighbourhood[4] = acc.template get(coord + int16_t2(0, 0), cascadeIndex); - neighbourhood[5] = acc.template get(coord + int16_t2(1, 0), cascadeIndex); - neighbourhood[6] = acc.template get(coord + int16_t2(-1, 1), cascadeIndex); - neighbourhood[7] = acc.template get(coord + int16_t2(0, 1), cascadeIndex); - neighbourhood[8] = acc.template get(coord + int16_t2(1, 1), cascadeIndex); - - // numerical robustness - float32_t3 excl_hood_sum = ((neighbourhood[0] + neighbourhood[1]) + (neighbourhood[2] + neighbourhood[3])) + - ((neighbourhood[5] + neighbourhood[6]) + (neighbourhood[7] + neighbourhood[8])); - - CascadeSample retval; - retval.centerValue = neighbourhood[4]; - retval.normalizedNeighbourhoodAverageLuma = retval.normalizedCenterLuma = acc.calcLuma(neighbourhood[4]) * reciprocalBaseI; - retval.normalizedNeighbourhoodAverageLuma = (acc.calcLuma(excl_hood_sum) * reciprocalBaseI + retval.normalizedNeighbourhoodAverageLuma) / 9.f; - return retval; - } -}; + CascadeSample __sampleCascade(NBL_REF_ARG(CascadeAccessor) acc, int16_t2 coord, uint16_t cascadeIndex, scalar_t reciprocalBaseI) + { + output_t neighbourhood[9]; + neighbourhood[0] = acc.template get(coord + int16_t2(-1, -1), cascadeIndex); + neighbourhood[1] = acc.template get(coord + int16_t2(0, -1), cascadeIndex); + neighbourhood[2] = acc.template get(coord + int16_t2(1, -1), cascadeIndex); + neighbourhood[3] = acc.template get(coord + int16_t2(-1, 0), cascadeIndex); + neighbourhood[4] = acc.template get(coord + int16_t2(0, 0), cascadeIndex); + neighbourhood[5] = acc.template get(coord + int16_t2(1, 0), cascadeIndex); + neighbourhood[6] = acc.template get(coord + int16_t2(-1, 1), cascadeIndex); + neighbourhood[7] = acc.template get(coord + int16_t2(0, 1), cascadeIndex); + neighbourhood[8] = acc.template get(coord + int16_t2(1, 1), cascadeIndex); + + // numerical robustness + output_t excl_hood_sum = ((neighbourhood[0] + neighbourhood[1]) + (neighbourhood[2] + neighbourhood[3])) + + ((neighbourhood[5] + neighbourhood[6]) + (neighbourhood[7] + neighbourhood[8])); + + CascadeSample retval; + retval.centerValue = neighbourhood[4]; + retval.normalizedNeighbourhoodAverageLuma = retval.normalizedCenterLuma = params.template calcLuma(neighbourhood[4]) * reciprocalBaseI; + retval.normalizedNeighbourhoodAverageLuma = (params.template calcLuma(excl_hood_sum) * reciprocalBaseI + retval.normalizedNeighbourhoodAverageLuma) / 9.f; + return retval; + } +}; } } } -#endif \ No newline at end of file +#endif From 187ced659281777cd98d5b3d449b7ab1aea47990 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Mon, 16 Feb 2026 16:42:32 +0100 Subject: [PATCH 5/9] Restrict Resolver template parameters to review scope --- include/nbl/builtin/hlsl/rwmc/resolve.hlsl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/nbl/builtin/hlsl/rwmc/resolve.hlsl b/include/nbl/builtin/hlsl/rwmc/resolve.hlsl index ac65c2ed03..84b0d44580 100644 --- a/include/nbl/builtin/hlsl/rwmc/resolve.hlsl +++ b/include/nbl/builtin/hlsl/rwmc/resolve.hlsl @@ -81,12 +81,12 @@ struct ResolveAccessorAdaptor } }; -template && ResolveLumaParams) +template && ResolveLumaParams) struct Resolver { using output_t = typename CascadeAccessor::output_t; using output_scalar_t = typename vector_traits::scalar_type; - using scalar_t = typename ResolveParamsType::scalar_t; + using scalar_t = typename ResolveParameters::scalar_t; NBL_CONSTEXPR static uint16_t last_cascade = CascadeCount - 1u; struct CascadeSample @@ -96,7 +96,7 @@ struct Resolver float normalizedNeighbourhoodAverageLuma; }; - static Resolver create(NBL_REF_ARG(ResolveParamsType) resolveParameters) + static Resolver create(NBL_REF_ARG(ResolveParameters) resolveParameters) { Resolver retval; retval.params = resolveParameters; @@ -168,7 +168,7 @@ struct Resolver return accumulation; } - ResolveParamsType params; + ResolveParameters params; // pseudo private stuff: From 70b90d66b329069d5f60cc15bb424da795ef7b50 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 17 Feb 2026 17:15:25 +0100 Subject: [PATCH 6/9] Finalize RWMC review fixes --- examples_tests | 2 +- .../accessors/anisotropically_sampled.hlsl | 2 +- .../concepts/accessors/loadable_image.hlsl | 2 +- .../hlsl/concepts/accessors/mip_mapped.hlsl | 2 +- .../builtin/hlsl/rwmc/CascadeAccumulator.hlsl | 46 ++--- .../builtin/hlsl/rwmc/ResolveParameters.hlsl | 54 +++--- .../hlsl/rwmc/SplattingParameters.hlsl | 24 ++- include/nbl/builtin/hlsl/rwmc/resolve.hlsl | 165 +++++++++--------- 8 files changed, 154 insertions(+), 143 deletions(-) diff --git a/examples_tests b/examples_tests index 130e049899..40ba7631e3 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 130e049899be16b50a5d27d7c67310a24d953530 +Subproject commit 40ba7631e305bbc5f10dfd07c96040e87b9ca4c8 diff --git a/include/nbl/builtin/hlsl/concepts/accessors/anisotropically_sampled.hlsl b/include/nbl/builtin/hlsl/concepts/accessors/anisotropically_sampled.hlsl index e6019d056c..b6b0716143 100644 --- a/include/nbl/builtin/hlsl/concepts/accessors/anisotropically_sampled.hlsl +++ b/include/nbl/builtin/hlsl/concepts/accessors/anisotropically_sampled.hlsl @@ -47,4 +47,4 @@ NBL_CONCEPT_END( } } } -#endif \ No newline at end of file +#endif diff --git a/include/nbl/builtin/hlsl/concepts/accessors/loadable_image.hlsl b/include/nbl/builtin/hlsl/concepts/accessors/loadable_image.hlsl index f7b5122c81..16fdf41c47 100644 --- a/include/nbl/builtin/hlsl/concepts/accessors/loadable_image.hlsl +++ b/include/nbl/builtin/hlsl/concepts/accessors/loadable_image.hlsl @@ -73,4 +73,4 @@ NBL_CONCEPT_END( } } } -#endif \ No newline at end of file +#endif diff --git a/include/nbl/builtin/hlsl/concepts/accessors/mip_mapped.hlsl b/include/nbl/builtin/hlsl/concepts/accessors/mip_mapped.hlsl index c49e66617b..81fb6e8502 100644 --- a/include/nbl/builtin/hlsl/concepts/accessors/mip_mapped.hlsl +++ b/include/nbl/builtin/hlsl/concepts/accessors/mip_mapped.hlsl @@ -44,4 +44,4 @@ NBL_CONCEPT_END( } } } -#endif \ No newline at end of file +#endif diff --git a/include/nbl/builtin/hlsl/rwmc/CascadeAccumulator.hlsl b/include/nbl/builtin/hlsl/rwmc/CascadeAccumulator.hlsl index e4bc9aa4fa..4be0fdab13 100644 --- a/include/nbl/builtin/hlsl/rwmc/CascadeAccumulator.hlsl +++ b/include/nbl/builtin/hlsl/rwmc/CascadeAccumulator.hlsl @@ -3,7 +3,6 @@ #include #include #include -#include #include namespace nbl @@ -13,15 +12,15 @@ namespace hlsl namespace rwmc { -template && concepts::UnsignedIntegralScalar) +template && concepts::UnsignedIntegralScalar) struct DefaultCascades { using layer_type = CascadeLayerType; using sample_count_type = SampleCountType; - NBL_CONSTEXPR uint32_t cascade_count = CascadeCount; + NBL_CONSTEXPR_STATIC_INLINE uint32_t CascadeCount = CascadeCountValue; - sample_count_type cascadeSampleCounter[cascade_count]; - CascadeLayerType data[cascade_count]; + sample_count_type cascadeSampleCounter[CascadeCount]; + CascadeLayerType data[CascadeCount]; void clear(uint32_t cascadeIx) { @@ -38,7 +37,7 @@ struct DefaultCascades cascadeSampleCounter[lowerCascadeIndex] = sample_count_type(sampleCount); uint16_t higherCascadeIndex = lowerCascadeIndex + uint16_t(1u); - if (higherCascadeIndex < cascade_count) + if (higherCascadeIndex < CascadeCount) { sample_count_type higherCascadeSampleCount = cascadeSampleCounter[higherCascadeIndex]; data[higherCascadeIndex] += (_sample * higherCascadeLevelWeight - (sampleCount - higherCascadeSampleCount) * data[higherCascadeIndex]) * reciprocalSampleCount; @@ -50,20 +49,24 @@ struct DefaultCascades template struct CascadeAccumulator { + using scalar_t = typename SplattingParameters::scalar_t; using input_sample_type = typename CascadesType::layer_type; using this_t = CascadeAccumulator; - using output_storage_type = CascadesType; - NBL_CONSTEXPR uint32_t cascade_count = output_storage_type::cascade_count; - output_storage_type accumulation; + using cascades_type = CascadesType; + NBL_CONSTEXPR_STATIC_INLINE uint32_t CascadeCount = cascades_type::CascadeCount; + NBL_CONSTEXPR_STATIC_INLINE scalar_t LastCascade = scalar_t(CascadeCount - 1u); + cascades_type accumulation; SplattingParameters splattingParameters; + SplattingParameters::SPrecomputed splattingParametersPrecomputed; static this_t create(NBL_CONST_REF_ARG(SplattingParameters) settings) { this_t retval; - for (uint32_t i = 0u; i < cascade_count; ++i) + for (uint32_t i = 0u; i < CascadeCount; ++i) retval.accumulation.clear(i); retval.splattingParameters = settings; + retval.splattingParametersPrecomputed = settings.template precompute(); return retval; } @@ -71,24 +74,21 @@ struct CascadeAccumulator // most of this code is stolen from https://cg.ivd.kit.edu/publications/2018/rwmc/tool/split.cpp void addSample(uint32_t sampleCount, input_sample_type _sample) { - const SplattingParameters::scalar_t baseRootOfStart = splattingParameters.baseRootOfStart(); - const SplattingParameters::scalar_t rcpLog2Base = splattingParameters.rcpLog2Base(); - const SplattingParameters::scalar_t luma = splattingParameters.calcLuma(_sample); - const SplattingParameters::scalar_t log2Luma = log2(luma); - const SplattingParameters::scalar_t log2BaseRootOfStart = log2(baseRootOfStart); - const SplattingParameters::scalar_t cascade = log2Luma * rcpLog2Base - log2BaseRootOfStart; - const SplattingParameters::scalar_t lastCascade = cascade_count - 1u; - const SplattingParameters::scalar_t clampedCascade = clamp(cascade, 0, lastCascade); + const scalar_t luma = splattingParameters.calcLuma(_sample); + const scalar_t log2Luma = log2(luma); + const scalar_t cascade = log2Luma * splattingParametersPrecomputed.RcpLog2Base - splattingParametersPrecomputed.Log2BaseRootOfStart; + const scalar_t clampedCascade = clamp(cascade, scalar_t(0), LastCascade); + const scalar_t clampedCascadeFloor = floor(clampedCascade); // c<=0 -> 0, c>=Count-1 -> Count-1 - uint16_t lowerCascadeIndex = uint16_t(floor(clampedCascade)); + uint16_t lowerCascadeIndex = uint16_t(clampedCascadeFloor); // 0 whenever clamped or `cascade` is integer (when `clampedCascade` is integer) - SplattingParameters::scalar_t higherCascadeWeight = clampedCascade - floor(clampedCascade); + scalar_t higherCascadeWeight = clampedCascade - clampedCascadeFloor; // never 0 thanks to magic of `1-fract(x)` - SplattingParameters::scalar_t lowerCascadeWeight = SplattingParameters::scalar_t(1) - higherCascadeWeight; + scalar_t lowerCascadeWeight = scalar_t(1) - higherCascadeWeight; // handle super bright sample case - if (cascade > lastCascade) - lowerCascadeWeight = exp2((log2BaseRootOfStart + lastCascade) / rcpLog2Base - log2Luma); + if (cascade > LastCascade) + lowerCascadeWeight = exp2(splattingParametersPrecomputed.BrightSampleLumaBias - log2Luma); accumulation.addSampleIntoCascadeEntry(_sample, lowerCascadeIndex, lowerCascadeWeight, higherCascadeWeight, sampleCount); } diff --git a/include/nbl/builtin/hlsl/rwmc/ResolveParameters.hlsl b/include/nbl/builtin/hlsl/rwmc/ResolveParameters.hlsl index c9a79d1149..8a16cdc2f5 100644 --- a/include/nbl/builtin/hlsl/rwmc/ResolveParameters.hlsl +++ b/include/nbl/builtin/hlsl/rwmc/ResolveParameters.hlsl @@ -2,7 +2,7 @@ #define _NBL_BUILTIN_HLSL_RWMC_RESOLVE_PARAMETERS_HLSL_INCLUDED_ #include "nbl/builtin/hlsl/cpp_compat.hlsl" -#include +#include namespace nbl { @@ -11,42 +11,42 @@ namespace hlsl namespace rwmc { -struct ResolveParameters +struct SResolveParameters { using scalar_t = float32_t; - static ResolveParameters create(float base, uint32_t sampleCount, float minReliableLuma, float kappa) + static SResolveParameters create(scalar_t base, uint32_t sampleCount, scalar_t minReliableLuma, scalar_t kappa) { - ResolveParameters retval; - retval.initialEmin = minReliableLuma; - retval.reciprocalBase = 1.f / base; - const float N = float(sampleCount); - retval.reciprocalN = 1.f / N; - retval.reciprocalKappa = 1.f / kappa; - // if not interested in exact expected value estimation (kappa!=1.f), can usually accept a bit more variance relative to the image brightness we already have - // allow up to ~ more energy in one sample to lessen bias in some cases - retval.colorReliabilityFactor = base + (1.f - base) * retval.reciprocalKappa; - retval.NOverKappa = N * retval.reciprocalKappa; - + SResolveParameters retval; + retval.initialEmin = minReliableLuma; + retval.reciprocalBase = 1.f / base; + const scalar_t N = scalar_t(sampleCount); + retval.reciprocalN = 1.f / N; + retval.reciprocalKappa = 1.f / kappa; + // if not interested in exact expected value estimation (kappa!=1.f), can usually accept a bit more variance relative to the image brightness we already have + // allow up to ~ more energy in one sample to lessen bias in some cases + retval.colorReliabilityFactor = base + (1.f - base) * retval.reciprocalKappa; + retval.NOverKappa = N * retval.reciprocalKappa; + return retval; } - template + template scalar_t calcLuma(NBL_CONST_REF_ARG(SampleType) col) { - return hlsl::dot(hlsl::transpose(colorspace::scRGBtoXYZ)[1], col); + return hlsl::dot(hlsl::transpose(Colorspace::ToXYZ())[1], col); } - float initialEmin; // a minimum image brightness that we always consider reliable - float reciprocalBase; - float reciprocalN; - float reciprocalKappa; - float colorReliabilityFactor; - float NOverKappa; -}; - -} -} -} + scalar_t initialEmin; // a minimum image brightness that we always consider reliable + scalar_t reciprocalBase; + scalar_t reciprocalN; + scalar_t reciprocalKappa; + scalar_t colorReliabilityFactor; + scalar_t NOverKappa; +}; + +} +} +} #endif diff --git a/include/nbl/builtin/hlsl/rwmc/SplattingParameters.hlsl b/include/nbl/builtin/hlsl/rwmc/SplattingParameters.hlsl index a7c95e9e27..7cbd52f0a4 100644 --- a/include/nbl/builtin/hlsl/rwmc/SplattingParameters.hlsl +++ b/include/nbl/builtin/hlsl/rwmc/SplattingParameters.hlsl @@ -2,7 +2,7 @@ #define _NBL_BUILTIN_HLSL_RWMC_SPLATTING_PARAMETERS_HLSL_INCLUDED_ #include "nbl/builtin/hlsl/cpp_compat.hlsl" -#include +#include namespace nbl { @@ -14,6 +14,12 @@ namespace rwmc struct SplattingParameters { using scalar_t = float32_t; + struct SPrecomputed + { + scalar_t RcpLog2Base; + scalar_t Log2BaseRootOfStart; + scalar_t BrightSampleLumaBias; + }; // float16_t baseRootOfStart; 0 // float16_t rcpLog2Base; 1 @@ -35,10 +41,22 @@ struct SplattingParameters return unpackedLog2Parameters()[1]; } - template + template + SPrecomputed precompute() + { + const scalar_t LastCascade = scalar_t(CascadeCount - 1u); + const float32_t2 unpacked = unpackedLog2Parameters(); + SPrecomputed retval; + retval.RcpLog2Base = unpacked[1]; + retval.Log2BaseRootOfStart = log2(unpacked[0]); + retval.BrightSampleLumaBias = (retval.Log2BaseRootOfStart + LastCascade) / retval.RcpLog2Base; + return retval; + } + + template scalar_t calcLuma(NBL_CONST_REF_ARG(CascadeLayerType) col) { - return hlsl::dot(hlsl::transpose(colorspace::scRGBtoXYZ)[1], col); + return hlsl::dot(hlsl::transpose(Colorspace::ToXYZ())[1], col); } }; diff --git a/include/nbl/builtin/hlsl/rwmc/resolve.hlsl b/include/nbl/builtin/hlsl/rwmc/resolve.hlsl index 84b0d44580..2b2d090fb1 100644 --- a/include/nbl/builtin/hlsl/rwmc/resolve.hlsl +++ b/include/nbl/builtin/hlsl/rwmc/resolve.hlsl @@ -17,98 +17,84 @@ namespace rwmc #define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(typename) #define NBL_CONCEPT_TPLT_PRM_NAMES (T)(SampleType) #define NBL_CONCEPT_PARAM_0 (a,T) -#define NBL_CONCEPT_PARAM_1 (sample,SampleType) -NBL_CONCEPT_BEGIN(2) +NBL_CONCEPT_BEGIN(1) #define a NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 -#define sample NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 NBL_CONCEPT_END( ((NBL_CONCEPT_REQ_TYPE)(T::scalar_t)) - ((NBL_CONCEPT_REQ_TYPE_ALIAS_CONCEPT)(concepts::FloatingPointScalar, T::scalar_t)) - ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template calcLuma(sample)), ::nbl::hlsl::is_same_v, typename T::scalar_t)) + ((NBL_CONCEPT_REQ_TYPE_ALIAS_CONCEPT)(concepts::FloatingPointScalar, typename T::scalar_t)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)( + (a.template calcLuma(::nbl::hlsl::experimental::declval())), + ::nbl::hlsl::is_same_v, + typename T::scalar_t + )) ); -#undef sample #undef a #include template NBL_BOOL_CONCEPT ResolveLumaParams = ResolveLumaParamsBase; -// declare concept -#define NBL_CONCEPT_NAME ResolveAccessorBase -#define NBL_CONCEPT_TPLT_PRM_KINDS (typename) -#define NBL_CONCEPT_TPLT_PRM_NAMES (T) -#define NBL_CONCEPT_PARAM_0 (a,T) -#define NBL_CONCEPT_PARAM_1 (uv,vector) -#define NBL_CONCEPT_PARAM_2 (layer,uint16_t) -NBL_CONCEPT_BEGIN(3) -#define a NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 -#define uv NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 -#define layer NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_2 -NBL_CONCEPT_END( - ((NBL_CONCEPT_REQ_TYPE)(T::output_t)) - ((NBL_CONCEPT_REQ_TYPE)(T::output_scalar_t)) - ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(uv,layer)), ::nbl::hlsl::is_same_v, typename T::output_t)) -); -#undef layer -#undef uv -#undef a -#include - template -NBL_BOOL_CONCEPT ResolveAccessor = ResolveAccessorBase && concepts::accessors::LoadableImage; - -template -struct ResolveAccessorAdaptor +NBL_BOOL_CONCEPT ResolveAccessor = concepts::accessors::MipmappedLoadableImage; + +template) +struct SResolveAccessorAdaptor { using output_scalar_t = OutputScalar; - NBL_CONSTEXPR int32_t Components = 3; - using output_t = vector; - NBL_CONSTEXPR int32_t image_dimension = 2; + NBL_CONSTEXPR_STATIC_INLINE int32_t Components = 3; + using output_t = vector; + NBL_CONSTEXPR_STATIC_INLINE int32_t image_dimension = 2; - RWTexture2DArray cascade; + template + void get(vector uv, uint16_t layer, uint16_t level, NBL_REF_ARG(output_t) value) + { + typename AccessorType::output_t sampled; + accessor.template get(uv, layer, level, sampled); + value = sampled.xyz; + } template - output_t get(vector uv, uint16_t layer) + output_t get(vector uv, uint16_t layer, uint16_t level) { - uint32_t imgWidth, imgHeight, layers; - cascade.GetDimensions(imgWidth, imgHeight, layers); - int16_t2 cascadeImageDimension = int16_t2(imgWidth, imgHeight); + output_t value; + get(uv, layer, level, value); + return value; + } - if (any(uv < int16_t2(0, 0)) || any(uv >= cascadeImageDimension)) - return promote(0); - - return cascade.Load(int32_t3(uv, int32_t(layer))); - } -}; - -template && ResolveLumaParams) -struct Resolver + AccessorType accessor; +}; + +template && + ResolveLumaParams +) +struct SResolver { using output_t = typename CascadeAccessor::output_t; using output_scalar_t = typename vector_traits::scalar_type; - using scalar_t = typename ResolveParameters::scalar_t; - NBL_CONSTEXPR static uint16_t last_cascade = CascadeCount - 1u; + using scalar_t = typename SResolveParameters::scalar_t; + NBL_CONSTEXPR_STATIC_INLINE uint16_t last_cascade = uint16_t(CascadeCount - 1u); - struct CascadeSample + struct SCascadeSample { output_t centerValue; - float normalizedCenterLuma; - float normalizedNeighbourhoodAverageLuma; + scalar_t normalizedCenterLuma; + scalar_t normalizedNeighbourhoodAverageLuma; }; - static Resolver create(NBL_REF_ARG(ResolveParameters) resolveParameters) + static SResolver create(NBL_REF_ARG(SResolveParameters) resolveParameters) { - Resolver retval; + SResolver retval; retval.params = resolveParameters; - - return retval; + + return retval; } - output_t operator()(NBL_REF_ARG(CascadeAccessor) acc, const int16_t2 coord) - { - scalar_t reciprocalBaseI = 1.f; - CascadeSample curr = __sampleCascade(acc, coord, 0u, reciprocalBaseI); - + output_t operator()(NBL_REF_ARG(CascadeAccessor) acc, const int16_t2 coord) + { + scalar_t reciprocalBaseI = 1.f; + SCascadeSample curr = __sampleCascade(acc, coord, 0u, reciprocalBaseI); + output_t accumulation = promote(0.0f); scalar_t Emin = params.initialEmin; @@ -119,10 +105,10 @@ struct Resolver const bool notFirstCascade = i != 0; const bool notLastCascade = i != last_cascade; - CascadeSample next; + SCascadeSample next; if (notLastCascade) - { - reciprocalBaseI *= params.reciprocalBase; + { + reciprocalBaseI *= params.reciprocalBase; next = __sampleCascade(acc, coord, int16_t(i + 1), reciprocalBaseI); } @@ -168,31 +154,38 @@ struct Resolver return accumulation; } - ResolveParameters params; + SResolveParameters params; // pseudo private stuff: - CascadeSample __sampleCascade(NBL_REF_ARG(CascadeAccessor) acc, int16_t2 coord, uint16_t cascadeIndex, scalar_t reciprocalBaseI) + SCascadeSample __sampleCascade(NBL_REF_ARG(CascadeAccessor) acc, int16_t2 coord, uint16_t cascadeIndex, scalar_t reciprocalBaseI) { - output_t neighbourhood[9]; - neighbourhood[0] = acc.template get(coord + int16_t2(-1, -1), cascadeIndex); - neighbourhood[1] = acc.template get(coord + int16_t2(0, -1), cascadeIndex); - neighbourhood[2] = acc.template get(coord + int16_t2(1, -1), cascadeIndex); - neighbourhood[3] = acc.template get(coord + int16_t2(-1, 0), cascadeIndex); - neighbourhood[4] = acc.template get(coord + int16_t2(0, 0), cascadeIndex); - neighbourhood[5] = acc.template get(coord + int16_t2(1, 0), cascadeIndex); - neighbourhood[6] = acc.template get(coord + int16_t2(-1, 1), cascadeIndex); - neighbourhood[7] = acc.template get(coord + int16_t2(0, 1), cascadeIndex); - neighbourhood[8] = acc.template get(coord + int16_t2(1, 1), cascadeIndex); - - // numerical robustness - output_t excl_hood_sum = ((neighbourhood[0] + neighbourhood[1]) + (neighbourhood[2] + neighbourhood[3])) + - ((neighbourhood[5] + neighbourhood[6]) + (neighbourhood[7] + neighbourhood[8])); - - CascadeSample retval; - retval.centerValue = neighbourhood[4]; - retval.normalizedNeighbourhoodAverageLuma = retval.normalizedCenterLuma = params.template calcLuma(neighbourhood[4]) * reciprocalBaseI; - retval.normalizedNeighbourhoodAverageLuma = (params.template calcLuma(excl_hood_sum) * reciprocalBaseI + retval.normalizedNeighbourhoodAverageLuma) / 9.f; + output_t sampleValue; + scalar_t excl_hood_luma_sum = 0.f; + + acc.template get(coord + int16_t2(-1, -1), cascadeIndex, 0u, sampleValue); + excl_hood_luma_sum += params.template calcLuma(sampleValue); + acc.template get(coord + int16_t2(0, -1), cascadeIndex, 0u, sampleValue); + excl_hood_luma_sum += params.template calcLuma(sampleValue); + acc.template get(coord + int16_t2(1, -1), cascadeIndex, 0u, sampleValue); + excl_hood_luma_sum += params.template calcLuma(sampleValue); + acc.template get(coord + int16_t2(-1, 0), cascadeIndex, 0u, sampleValue); + excl_hood_luma_sum += params.template calcLuma(sampleValue); + + SCascadeSample retval; + acc.template get(coord + int16_t2(0, 0), cascadeIndex, 0u, retval.centerValue); + const scalar_t centerLuma = params.template calcLuma(retval.centerValue); + acc.template get(coord + int16_t2(1, 0), cascadeIndex, 0u, sampleValue); + excl_hood_luma_sum += params.template calcLuma(sampleValue); + acc.template get(coord + int16_t2(-1, 1), cascadeIndex, 0u, sampleValue); + excl_hood_luma_sum += params.template calcLuma(sampleValue); + acc.template get(coord + int16_t2(0, 1), cascadeIndex, 0u, sampleValue); + excl_hood_luma_sum += params.template calcLuma(sampleValue); + acc.template get(coord + int16_t2(1, 1), cascadeIndex, 0u, sampleValue); + excl_hood_luma_sum += params.template calcLuma(sampleValue); + + retval.normalizedCenterLuma = centerLuma * reciprocalBaseI; + retval.normalizedNeighbourhoodAverageLuma = (excl_hood_luma_sum + centerLuma) * reciprocalBaseI / 9.f; return retval; } }; From ea2e5251b54d989fcedf0ad2ddf8d0b2cc3c730e Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 17 Feb 2026 17:44:27 +0100 Subject: [PATCH 7/9] Fix accessor concepts for out-param get --- .../accessors/anisotropically_sampled.hlsl | 7 +++++-- .../concepts/accessors/loadable_image.hlsl | 20 ++++++++++++------- .../hlsl/concepts/accessors/mip_mapped.hlsl | 7 +++++-- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/include/nbl/builtin/hlsl/concepts/accessors/anisotropically_sampled.hlsl b/include/nbl/builtin/hlsl/concepts/accessors/anisotropically_sampled.hlsl index b6b0716143..64b919be6a 100644 --- a/include/nbl/builtin/hlsl/concepts/accessors/anisotropically_sampled.hlsl +++ b/include/nbl/builtin/hlsl/concepts/accessors/anisotropically_sampled.hlsl @@ -26,17 +26,20 @@ namespace accessors #define NBL_CONCEPT_PARAM_2 (layer,uint16_t) #define NBL_CONCEPT_PARAM_3 (dU,vector) #define NBL_CONCEPT_PARAM_4 (dV,vector) +#define NBL_CONCEPT_PARAM_5 (outVal,float32_t4) // start concept -NBL_CONCEPT_BEGIN(5) +NBL_CONCEPT_BEGIN(6) // need to be defined AFTER the cocnept begins #define a NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 #define uv NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 #define layer NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_2 #define dU NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_3 #define dV NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_4 +#define outVal NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_5 NBL_CONCEPT_END( - ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(uv,layer,dU,dV)) , ::nbl::hlsl::is_same_v, float32_t4>)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(uv,layer,dU,dV,outVal)) , ::nbl::hlsl::is_same_v, void)) ); +#undef outVal #undef dV #undef dU #undef layer diff --git a/include/nbl/builtin/hlsl/concepts/accessors/loadable_image.hlsl b/include/nbl/builtin/hlsl/concepts/accessors/loadable_image.hlsl index 16fdf41c47..4a910a23bd 100644 --- a/include/nbl/builtin/hlsl/concepts/accessors/loadable_image.hlsl +++ b/include/nbl/builtin/hlsl/concepts/accessors/loadable_image.hlsl @@ -18,9 +18,9 @@ namespace accessors { // concept `LoadableImage` translates to smth like this: -//template -//concept LoadableImage = requires(U a, vector uv, uint16_t layer) { -// ::nbl::hlsl::is_same_v().template get(uv,layer)), vector>; +//template +//concept LoadableImage = requires(U a, vector uv, uint16_t layer, vector outVal) { +// ::nbl::hlsl::is_same_v().template get(uv,layer,outVal)), void>; //}; // declare concept @@ -31,15 +31,18 @@ namespace accessors #define NBL_CONCEPT_PARAM_0 (a,U) #define NBL_CONCEPT_PARAM_1 (uv,vector) #define NBL_CONCEPT_PARAM_2 (layer,uint16_t) +#define NBL_CONCEPT_PARAM_3 (outVal,vector) // start concept -NBL_CONCEPT_BEGIN(3) +NBL_CONCEPT_BEGIN(4) // need to be defined AFTER the concept begins #define a NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 #define uv NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 #define layer NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_2 +#define outVal NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_3 NBL_CONCEPT_END( - ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(uv,layer)), ::nbl::hlsl::is_same_v, vector)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(uv,layer,outVal)), ::nbl::hlsl::is_same_v, void)) ); +#undef outVal #undef layer #undef uv #undef a @@ -54,16 +57,19 @@ NBL_CONCEPT_END( #define NBL_CONCEPT_PARAM_1 (uv,vector) #define NBL_CONCEPT_PARAM_2 (layer,uint16_t) #define NBL_CONCEPT_PARAM_3 (level,uint16_t) +#define NBL_CONCEPT_PARAM_4 (outVal,vector) // start concept -NBL_CONCEPT_BEGIN(4) +NBL_CONCEPT_BEGIN(5) // need to be defined AFTER the cocnept begins #define a NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 #define uv NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 #define layer NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_2 #define level NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_3 +#define outVal NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_4 NBL_CONCEPT_END( - ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(uv,layer,level)) , ::nbl::hlsl::is_same_v, vector)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(uv,layer,level,outVal)) , ::nbl::hlsl::is_same_v, void)) ); +#undef outVal #undef level #undef layer #undef uv diff --git a/include/nbl/builtin/hlsl/concepts/accessors/mip_mapped.hlsl b/include/nbl/builtin/hlsl/concepts/accessors/mip_mapped.hlsl index 81fb6e8502..be7f997925 100644 --- a/include/nbl/builtin/hlsl/concepts/accessors/mip_mapped.hlsl +++ b/include/nbl/builtin/hlsl/concepts/accessors/mip_mapped.hlsl @@ -25,16 +25,19 @@ namespace accessors #define NBL_CONCEPT_PARAM_1 (uv,vector) #define NBL_CONCEPT_PARAM_2 (layer,uint16_t) #define NBL_CONCEPT_PARAM_3 (level,float) +#define NBL_CONCEPT_PARAM_4 (outVal,float32_t4) // start concept -NBL_CONCEPT_BEGIN(4) +NBL_CONCEPT_BEGIN(5) // need to be defined AFTER the cocnept begins #define a NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 #define uv NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 #define layer NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_2 #define level NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_3 +#define outVal NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_4 NBL_CONCEPT_END( - ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(uv,layer,level)) , ::nbl::hlsl::is_same_v, float32_t4>)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(uv,layer,level,outVal)) , ::nbl::hlsl::is_same_v, void)) ); +#undef outVal #undef level #undef layer #undef uv From 9399ad3d82718d1feb5cc2d39f85f3fec0b846e2 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 17 Feb 2026 18:10:43 +0100 Subject: [PATCH 8/9] Address latest RWMC accessor and splatting review comments --- examples_tests | 2 +- .../accessors/anisotropically_sampled.hlsl | 8 +-- .../concepts/accessors/loadable_image.hlsl | 6 +- .../hlsl/concepts/accessors/mip_mapped.hlsl | 2 +- .../builtin/hlsl/rwmc/CascadeAccumulator.hlsl | 18 +++--- .../hlsl/rwmc/SplattingParameters.hlsl | 59 ++++++++----------- include/nbl/builtin/hlsl/rwmc/resolve.hlsl | 30 ++++------ 7 files changed, 52 insertions(+), 73 deletions(-) diff --git a/examples_tests b/examples_tests index 40ba7631e3..c531404a5e 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit 40ba7631e305bbc5f10dfd07c96040e87b9ca4c8 +Subproject commit c531404a5ed53bf0d46f208199520fbd814522bf diff --git a/include/nbl/builtin/hlsl/concepts/accessors/anisotropically_sampled.hlsl b/include/nbl/builtin/hlsl/concepts/accessors/anisotropically_sampled.hlsl index 64b919be6a..76f2c2219a 100644 --- a/include/nbl/builtin/hlsl/concepts/accessors/anisotropically_sampled.hlsl +++ b/include/nbl/builtin/hlsl/concepts/accessors/anisotropically_sampled.hlsl @@ -18,15 +18,15 @@ namespace accessors { // declare concept #define NBL_CONCEPT_NAME AnisotropicallySampled -#define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(int32_t) -#define NBL_CONCEPT_TPLT_PRM_NAMES (U)(Dims) +#define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(int32_t)(int32_t) +#define NBL_CONCEPT_TPLT_PRM_NAMES (U)(Dims)(Components) // not the greatest syntax but works #define NBL_CONCEPT_PARAM_0 (a,U) #define NBL_CONCEPT_PARAM_1 (uv,vector) #define NBL_CONCEPT_PARAM_2 (layer,uint16_t) #define NBL_CONCEPT_PARAM_3 (dU,vector) #define NBL_CONCEPT_PARAM_4 (dV,vector) -#define NBL_CONCEPT_PARAM_5 (outVal,float32_t4) +#define NBL_CONCEPT_PARAM_5 (outVal,vector) // start concept NBL_CONCEPT_BEGIN(6) // need to be defined AFTER the cocnept begins @@ -37,7 +37,7 @@ NBL_CONCEPT_BEGIN(6) #define dV NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_4 #define outVal NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_5 NBL_CONCEPT_END( - ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(uv,layer,dU,dV,outVal)) , ::nbl::hlsl::is_same_v, void)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(outVal,uv,layer,dU,dV)) , ::nbl::hlsl::is_same_v, void)) ); #undef outVal #undef dV diff --git a/include/nbl/builtin/hlsl/concepts/accessors/loadable_image.hlsl b/include/nbl/builtin/hlsl/concepts/accessors/loadable_image.hlsl index 4a910a23bd..fcc200ad95 100644 --- a/include/nbl/builtin/hlsl/concepts/accessors/loadable_image.hlsl +++ b/include/nbl/builtin/hlsl/concepts/accessors/loadable_image.hlsl @@ -20,7 +20,7 @@ namespace accessors // concept `LoadableImage` translates to smth like this: //template //concept LoadableImage = requires(U a, vector uv, uint16_t layer, vector outVal) { -// ::nbl::hlsl::is_same_v().template get(uv,layer,outVal)), void>; +// ::nbl::hlsl::is_same_v().template get(outVal,uv,layer)), void>; //}; // declare concept @@ -40,7 +40,7 @@ NBL_CONCEPT_BEGIN(4) #define layer NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_2 #define outVal NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_3 NBL_CONCEPT_END( - ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(uv,layer,outVal)), ::nbl::hlsl::is_same_v, void)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(outVal,uv,layer)), ::nbl::hlsl::is_same_v, void)) ); #undef outVal #undef layer @@ -67,7 +67,7 @@ NBL_CONCEPT_BEGIN(5) #define level NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_3 #define outVal NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_4 NBL_CONCEPT_END( - ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(uv,layer,level,outVal)) , ::nbl::hlsl::is_same_v, void)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(outVal,uv,layer,level)) , ::nbl::hlsl::is_same_v, void)) ); #undef outVal #undef level diff --git a/include/nbl/builtin/hlsl/concepts/accessors/mip_mapped.hlsl b/include/nbl/builtin/hlsl/concepts/accessors/mip_mapped.hlsl index be7f997925..e8b61d4029 100644 --- a/include/nbl/builtin/hlsl/concepts/accessors/mip_mapped.hlsl +++ b/include/nbl/builtin/hlsl/concepts/accessors/mip_mapped.hlsl @@ -35,7 +35,7 @@ NBL_CONCEPT_BEGIN(5) #define level NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_3 #define outVal NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_4 NBL_CONCEPT_END( - ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(uv,layer,level,outVal)) , ::nbl::hlsl::is_same_v, void)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(outVal,uv,layer,level)) , ::nbl::hlsl::is_same_v, void)) ); #undef outVal #undef level diff --git a/include/nbl/builtin/hlsl/rwmc/CascadeAccumulator.hlsl b/include/nbl/builtin/hlsl/rwmc/CascadeAccumulator.hlsl index 4be0fdab13..a52c9302d3 100644 --- a/include/nbl/builtin/hlsl/rwmc/CascadeAccumulator.hlsl +++ b/include/nbl/builtin/hlsl/rwmc/CascadeAccumulator.hlsl @@ -28,9 +28,9 @@ struct DefaultCascades data[cascadeIx] = promote(0.0f); } - void addSampleIntoCascadeEntry(CascadeLayerType _sample, uint16_t lowerCascadeIndex, SplattingParameters::scalar_t lowerCascadeLevelWeight, SplattingParameters::scalar_t higherCascadeLevelWeight, uint32_t sampleCount) + void addSampleIntoCascadeEntry(CascadeLayerType _sample, uint16_t lowerCascadeIndex, SSplattingParameters::scalar_t lowerCascadeLevelWeight, SSplattingParameters::scalar_t higherCascadeLevelWeight, uint32_t sampleCount) { - const SplattingParameters::scalar_t reciprocalSampleCount = SplattingParameters::scalar_t(1.0f) / SplattingParameters::scalar_t(sampleCount); + const SSplattingParameters::scalar_t reciprocalSampleCount = SSplattingParameters::scalar_t(1.0f) / SSplattingParameters::scalar_t(sampleCount); sample_count_type lowerCascadeSampleCount = cascadeSampleCounter[lowerCascadeIndex]; data[lowerCascadeIndex] += (_sample * lowerCascadeLevelWeight - (sampleCount - lowerCascadeSampleCount) * data[lowerCascadeIndex]) * reciprocalSampleCount; @@ -49,7 +49,7 @@ struct DefaultCascades template struct CascadeAccumulator { - using scalar_t = typename SplattingParameters::scalar_t; + using scalar_t = typename SSplattingParameters::scalar_t; using input_sample_type = typename CascadesType::layer_type; using this_t = CascadeAccumulator; using cascades_type = CascadesType; @@ -57,16 +57,14 @@ struct CascadeAccumulator NBL_CONSTEXPR_STATIC_INLINE scalar_t LastCascade = scalar_t(CascadeCount - 1u); cascades_type accumulation; - SplattingParameters splattingParameters; - SplattingParameters::SPrecomputed splattingParametersPrecomputed; + SSplattingParameters splattingParameters; - static this_t create(NBL_CONST_REF_ARG(SplattingParameters) settings) + static this_t create(NBL_CONST_REF_ARG(SPackedSplattingParameters) settings) { this_t retval; for (uint32_t i = 0u; i < CascadeCount; ++i) retval.accumulation.clear(i); - retval.splattingParameters = settings; - retval.splattingParametersPrecomputed = settings.template precompute(); + retval.splattingParameters = settings.unpack(); return retval; } @@ -76,7 +74,7 @@ struct CascadeAccumulator { const scalar_t luma = splattingParameters.calcLuma(_sample); const scalar_t log2Luma = log2(luma); - const scalar_t cascade = log2Luma * splattingParametersPrecomputed.RcpLog2Base - splattingParametersPrecomputed.Log2BaseRootOfStart; + const scalar_t cascade = log2Luma * splattingParameters.RcpLog2Base - splattingParameters.Log2BaseRootOfStart; const scalar_t clampedCascade = clamp(cascade, scalar_t(0), LastCascade); const scalar_t clampedCascadeFloor = floor(clampedCascade); // c<=0 -> 0, c>=Count-1 -> Count-1 @@ -88,7 +86,7 @@ struct CascadeAccumulator // handle super bright sample case if (cascade > LastCascade) - lowerCascadeWeight = exp2(splattingParametersPrecomputed.BrightSampleLumaBias - log2Luma); + lowerCascadeWeight = exp2(splattingParameters.BrightSampleLumaBias - log2Luma); accumulation.addSampleIntoCascadeEntry(_sample, lowerCascadeIndex, lowerCascadeWeight, higherCascadeWeight, sampleCount); } diff --git a/include/nbl/builtin/hlsl/rwmc/SplattingParameters.hlsl b/include/nbl/builtin/hlsl/rwmc/SplattingParameters.hlsl index 7cbd52f0a4..b89c4ebfbe 100644 --- a/include/nbl/builtin/hlsl/rwmc/SplattingParameters.hlsl +++ b/include/nbl/builtin/hlsl/rwmc/SplattingParameters.hlsl @@ -11,53 +11,42 @@ namespace hlsl namespace rwmc { -struct SplattingParameters +struct SSplattingParameters { using scalar_t = float32_t; - struct SPrecomputed + scalar_t RcpLog2Base; + scalar_t Log2BaseRootOfStart; + scalar_t BrightSampleLumaBias; + + template + scalar_t calcLuma(NBL_CONST_REF_ARG(CascadeLayerType) col) { - scalar_t RcpLog2Base; - scalar_t Log2BaseRootOfStart; - scalar_t BrightSampleLumaBias; - }; + return hlsl::dot(hlsl::transpose(Colorspace::ToXYZ())[1], col); + } +}; +struct SPackedSplattingParameters +{ // float16_t baseRootOfStart; 0 // float16_t rcpLog2Base; 1 // pack as Half2x16 - int32_t packedLog2; - - float32_t2 unpackedLog2Parameters() - { - return hlsl::unpackHalf2x16(packedLog2); - } - - scalar_t baseRootOfStart() - { - return unpackedLog2Parameters()[0]; - } + int32_t PackedLog2; - scalar_t rcpLog2Base() - { - return unpackedLog2Parameters()[1]; - } + // float16_t log2BaseRootOfStart; 2 + // float16_t brightSampleLumaBias; 3 + // pack as Half2x16 + int32_t PackedPrecomputed; - template - SPrecomputed precompute() + SSplattingParameters unpack() { - const scalar_t LastCascade = scalar_t(CascadeCount - 1u); - const float32_t2 unpacked = unpackedLog2Parameters(); - SPrecomputed retval; - retval.RcpLog2Base = unpacked[1]; - retval.Log2BaseRootOfStart = log2(unpacked[0]); - retval.BrightSampleLumaBias = (retval.Log2BaseRootOfStart + LastCascade) / retval.RcpLog2Base; + SSplattingParameters retval; + const float32_t2 unpackedLog2 = hlsl::unpackHalf2x16(PackedLog2); + const float32_t2 unpackedPrecomputed = hlsl::unpackHalf2x16(PackedPrecomputed); + retval.RcpLog2Base = unpackedLog2[1]; + retval.Log2BaseRootOfStart = unpackedPrecomputed[0]; + retval.BrightSampleLumaBias = unpackedPrecomputed[1]; return retval; } - - template - scalar_t calcLuma(NBL_CONST_REF_ARG(CascadeLayerType) col) - { - return hlsl::dot(hlsl::transpose(Colorspace::ToXYZ())[1], col); - } }; } diff --git a/include/nbl/builtin/hlsl/rwmc/resolve.hlsl b/include/nbl/builtin/hlsl/rwmc/resolve.hlsl index 2b2d090fb1..a30bd49e74 100644 --- a/include/nbl/builtin/hlsl/rwmc/resolve.hlsl +++ b/include/nbl/builtin/hlsl/rwmc/resolve.hlsl @@ -46,21 +46,13 @@ struct SResolveAccessorAdaptor NBL_CONSTEXPR_STATIC_INLINE int32_t image_dimension = 2; template - void get(vector uv, uint16_t layer, uint16_t level, NBL_REF_ARG(output_t) value) + void get(NBL_REF_ARG(output_t) value, vector uv, uint16_t layer, uint16_t level) { typename AccessorType::output_t sampled; - accessor.template get(uv, layer, level, sampled); + accessor.template get(sampled, uv, layer, level); value = sampled.xyz; } - template - output_t get(vector uv, uint16_t layer, uint16_t level) - { - output_t value; - get(uv, layer, level, value); - return value; - } - AccessorType accessor; }; @@ -163,25 +155,25 @@ struct SResolver output_t sampleValue; scalar_t excl_hood_luma_sum = 0.f; - acc.template get(coord + int16_t2(-1, -1), cascadeIndex, 0u, sampleValue); + acc.template get(sampleValue, coord + int16_t2(-1, -1), cascadeIndex, 0u); excl_hood_luma_sum += params.template calcLuma(sampleValue); - acc.template get(coord + int16_t2(0, -1), cascadeIndex, 0u, sampleValue); + acc.template get(sampleValue, coord + int16_t2(0, -1), cascadeIndex, 0u); excl_hood_luma_sum += params.template calcLuma(sampleValue); - acc.template get(coord + int16_t2(1, -1), cascadeIndex, 0u, sampleValue); + acc.template get(sampleValue, coord + int16_t2(1, -1), cascadeIndex, 0u); excl_hood_luma_sum += params.template calcLuma(sampleValue); - acc.template get(coord + int16_t2(-1, 0), cascadeIndex, 0u, sampleValue); + acc.template get(sampleValue, coord + int16_t2(-1, 0), cascadeIndex, 0u); excl_hood_luma_sum += params.template calcLuma(sampleValue); SCascadeSample retval; - acc.template get(coord + int16_t2(0, 0), cascadeIndex, 0u, retval.centerValue); + acc.template get(retval.centerValue, coord + int16_t2(0, 0), cascadeIndex, 0u); const scalar_t centerLuma = params.template calcLuma(retval.centerValue); - acc.template get(coord + int16_t2(1, 0), cascadeIndex, 0u, sampleValue); + acc.template get(sampleValue, coord + int16_t2(1, 0), cascadeIndex, 0u); excl_hood_luma_sum += params.template calcLuma(sampleValue); - acc.template get(coord + int16_t2(-1, 1), cascadeIndex, 0u, sampleValue); + acc.template get(sampleValue, coord + int16_t2(-1, 1), cascadeIndex, 0u); excl_hood_luma_sum += params.template calcLuma(sampleValue); - acc.template get(coord + int16_t2(0, 1), cascadeIndex, 0u, sampleValue); + acc.template get(sampleValue, coord + int16_t2(0, 1), cascadeIndex, 0u); excl_hood_luma_sum += params.template calcLuma(sampleValue); - acc.template get(coord + int16_t2(1, 1), cascadeIndex, 0u, sampleValue); + acc.template get(sampleValue, coord + int16_t2(1, 1), cascadeIndex, 0u); excl_hood_luma_sum += params.template calcLuma(sampleValue); retval.normalizedCenterLuma = centerLuma * reciprocalBaseI; From 1125f48d1af4ea3fcb0cc416b128ab3cb8f6beb7 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lachowicz Date: Tue, 17 Feb 2026 18:41:03 +0100 Subject: [PATCH 9/9] Improve packed splatting parameter naming --- examples_tests | 2 +- .../nbl/builtin/hlsl/rwmc/SplattingParameters.hlsl | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples_tests b/examples_tests index c531404a5e..af29d6546f 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit c531404a5ed53bf0d46f208199520fbd814522bf +Subproject commit af29d6546ff9f9e7beeea633f7e8de27fb879ba7 diff --git a/include/nbl/builtin/hlsl/rwmc/SplattingParameters.hlsl b/include/nbl/builtin/hlsl/rwmc/SplattingParameters.hlsl index b89c4ebfbe..0b804a1517 100644 --- a/include/nbl/builtin/hlsl/rwmc/SplattingParameters.hlsl +++ b/include/nbl/builtin/hlsl/rwmc/SplattingParameters.hlsl @@ -30,21 +30,21 @@ struct SPackedSplattingParameters // float16_t baseRootOfStart; 0 // float16_t rcpLog2Base; 1 // pack as Half2x16 - int32_t PackedLog2; + int32_t PackedBaseRootAndRcpLog2Base; // float16_t log2BaseRootOfStart; 2 // float16_t brightSampleLumaBias; 3 // pack as Half2x16 - int32_t PackedPrecomputed; + int32_t PackedLog2BaseRootAndBrightSampleLumaBias; SSplattingParameters unpack() { SSplattingParameters retval; - const float32_t2 unpackedLog2 = hlsl::unpackHalf2x16(PackedLog2); - const float32_t2 unpackedPrecomputed = hlsl::unpackHalf2x16(PackedPrecomputed); - retval.RcpLog2Base = unpackedLog2[1]; - retval.Log2BaseRootOfStart = unpackedPrecomputed[0]; - retval.BrightSampleLumaBias = unpackedPrecomputed[1]; + const float32_t2 unpackedBaseRootAndRcpLog2Base = hlsl::unpackHalf2x16(PackedBaseRootAndRcpLog2Base); + const float32_t2 unpackedLog2BaseRootAndBrightSampleLumaBias = hlsl::unpackHalf2x16(PackedLog2BaseRootAndBrightSampleLumaBias); + retval.RcpLog2Base = unpackedBaseRootAndRcpLog2Base[1]; + retval.Log2BaseRootOfStart = unpackedLog2BaseRootAndBrightSampleLumaBias[0]; + retval.BrightSampleLumaBias = unpackedLog2BaseRootAndBrightSampleLumaBias[1]; return retval; } };