diff --git a/README.md b/README.md
index d21e897..8dabb09 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,12 @@ Spatially Hashed Radiance Cache is a technique aimed at improving signal quality
## Distribution
SHARC is distributed as a set of shader-only sources along with [integration guide][SharcIntegrationGuide].
-For usage of the SHARC library please check the samples in the [RTXGI v2.0 SDK][RTXGI].
+For usage of the SHARC library please check the samples in the [RTXGI v2.0 SDK][RTXGI2].
+
+See the [changelog][Changelog] in RTXGI v2.0 SDK for the latest SHARC changes.
+
[SharcIntegrationGuide]: ./docs/Integration.md
-[RTXGI]: https://github.com/NVIDIAGameWorks/RTXGI
+[RTXGI2]: https://github.com/NVIDIAGameWorks/RTXGI/tree/main
+[Changelog]: https://github.com/NVIDIAGameWorks/RTXGI/blob/main/CHANGELOG.md
+
diff --git a/docs/Integration.md b/docs/Integration.md
index b15b096..96a7c93 100644
--- a/docs/Integration.md
+++ b/docs/Integration.md
@@ -34,10 +34,11 @@ At Render-Time
`Hash grid` visualization itself doesn’t require any GPU resources to be used. The simplest debug visualization uses world space position derived from the primary ray hit intersection.
```C++
-GridParameters gridParameters;
+HashGridParameters gridParameters;
gridParameters.cameraPosition = g_Constants.cameraPosition;
gridParameters.logarithmBase = SHARC_GRID_LOGARITHM_BASE;
gridParameters.sceneScale = g_Constants.sharcSceneScale;
+gridParameters.levelBias = SHARC_GRID_LEVEL_BIAS;
float3 color = HashGridDebugColoredHash(positionWorld, gridParameters);
```
@@ -48,7 +49,7 @@ float3 color = HashGridDebugColoredHash(positionWorld, gridParameters);
Image 2. SHaRC hash grid vizualization
-Logarithm base controls levels of detail distribution and voxel size ratio change between neighboring levels, it doesn’t make voxel sizes bigger or smaller on average. To control voxel size use ```sceneScale``` parameter instead. HASH_GRID_LEVEL_BIAS should be used to control at which level near the camera the voxel level get's clamped to avoid getting detailed levels if it is not required.
+Logarithm base controls levels of detail distribution and voxel size ratio change between neighboring levels, it doesn’t make voxel sizes bigger or smaller on average. To control voxel size use ```sceneScale``` parameter instead. HashGridParameters::levelBias should be used to control at which level near the camera the voxel level get's clamped to avoid getting detailed levels if it is not required.
## Implementation Details
diff --git a/include/HashGridCommon.h b/include/HashGridCommon.h
index 2e2d432..9921c4d 100644
--- a/include/HashGridCommon.h
+++ b/include/HashGridCommon.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023-2024, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2023-2025, NVIDIA CORPORATION. All rights reserved.
*
* NVIDIA CORPORATION and its licensors retain all intellectual property
* and proprietary rights in and to this software, related documentation
@@ -8,6 +8,7 @@
* license agreement from NVIDIA CORPORATION is strictly prohibited.
*/
+// Constants
#define HASH_GRID_POSITION_BIT_NUM 17
#define HASH_GRID_POSITION_BIT_MASK ((1u << HASH_GRID_POSITION_BIT_NUM) - 1)
#define HASH_GRID_LEVEL_BIT_NUM 10
@@ -16,31 +17,46 @@
#define HASH_GRID_NORMAL_BIT_MASK ((1u << HASH_GRID_NORMAL_BIT_NUM) - 1)
#define HASH_GRID_HASH_MAP_BUCKET_SIZE 32
#define HASH_GRID_INVALID_HASH_KEY 0
-#define HASH_GRID_INVALID_CACHE_ENTRY 0xFFFFFFFF
-#define HASH_GRID_USE_NORMALS 1 // account for normal data in the hash key
+#define HASH_GRID_INVALID_CACHE_INDEX 0xFFFFFFFF
+
+// Tweakable parameters
+#ifndef HASH_GRID_USE_NORMALS
+#define HASH_GRID_USE_NORMALS 1 // account for the normal data in the hash key
+#endif
+
+#ifndef HASH_GRID_ALLOW_COMPACTION
#define HASH_GRID_ALLOW_COMPACTION (HASH_GRID_HASH_MAP_BUCKET_SIZE == 32)
-#define HASH_GRID_LEVEL_BIAS 2 // positive bias adds extra levels with content magnification (can be negative as well)
+#endif
+
+#ifndef HASH_GRID_POSITION_OFFSET
#define HASH_GRID_POSITION_OFFSET float3(0.0f, 0.0f, 0.0f)
+#endif
+
+#ifndef HASH_GRID_POSITION_BIAS
#define HASH_GRID_POSITION_BIAS 1e-4f // may require adjustment for extreme scene scales
+#endif
+
+#ifndef HASH_GRID_NORMAL_BIAS
#define HASH_GRID_NORMAL_BIAS 1e-3f
+#endif
-#define CacheEntry uint
-#define HashKey uint64_t
+#define HashGridIndex uint
+#define HashGridKey uint64_t
-struct GridParameters
+struct HashGridParameters
{
float3 cameraPosition;
- float3 cameraPositionPrev;
float logarithmBase;
float sceneScale;
+ float levelBias;
};
-float LogBase(float x, float base)
+float HashGridLogBase(float x, float base)
{
return log(x) / log(base);
}
-uint GetBaseSlot(uint slot, uint capacity)
+uint HashGridGetBaseSlot(uint slot, uint capacity)
{
#if HASH_GRID_ALLOW_COMPACTION
return (slot / HASH_GRID_HASH_MAP_BUCKET_SIZE) * HASH_GRID_HASH_MAP_BUCKET_SIZE;
@@ -50,7 +66,7 @@ uint GetBaseSlot(uint slot, uint capacity)
}
// http://burtleburtle.net/bob/hash/integer.html
-uint HashJenkins32(uint a)
+uint HashGridHashJenkins32(uint a)
{
a = (a + 0x7ed55d16) + (a << 12);
a = (a ^ 0xc761c23c) ^ (a >> 19);
@@ -61,50 +77,49 @@ uint HashJenkins32(uint a)
return a;
}
-uint Hash32(HashKey hashKey)
+uint HashGridHash32(HashGridKey hashKey)
{
- return HashJenkins32(uint((hashKey >> 0) & 0xffffffff))
- ^ HashJenkins32(uint((hashKey >> 32) & 0xffffffff));
+ return HashGridHashJenkins32(uint((hashKey >> 0) & 0xFFFFFFFF)) ^ HashGridHashJenkins32(uint((hashKey >> 32) & 0xFFFFFFFF));
}
-uint GetGridLevel(float3 samplePosition, GridParameters gridParameters)
+uint HashGridGetLevel(float3 samplePosition, HashGridParameters gridParameters)
{
const float distance2 = dot(gridParameters.cameraPosition - samplePosition, gridParameters.cameraPosition - samplePosition);
- return uint(clamp(0.5f * LogBase(distance2, gridParameters.logarithmBase) + HASH_GRID_LEVEL_BIAS, 1.0f, float(HASH_GRID_LEVEL_BIT_MASK)));
+ return uint(clamp(0.5f * HashGridLogBase(distance2, gridParameters.logarithmBase) + gridParameters.levelBias, 1.0f, float(HASH_GRID_LEVEL_BIT_MASK)));
}
-float GetVoxelSize(uint gridLevel, GridParameters gridParameters)
+float HashGridGetVoxelSize(uint gridLevel, HashGridParameters gridParameters)
{
- return pow(gridParameters.logarithmBase, gridLevel) / (gridParameters.sceneScale * pow(gridParameters.logarithmBase, HASH_GRID_LEVEL_BIAS));
+ return pow(gridParameters.logarithmBase, gridLevel) / (gridParameters.sceneScale * pow(gridParameters.logarithmBase, gridParameters.levelBias));
}
// Based on logarithmic caching by Johannes Jendersie
-int4 CalculateGridPositionLog(float3 samplePosition, GridParameters gridParameters)
+int4 HashGridCalculatePositionLog(float3 samplePosition, HashGridParameters gridParameters)
{
samplePosition += float3(HASH_GRID_POSITION_BIAS, HASH_GRID_POSITION_BIAS, HASH_GRID_POSITION_BIAS);
- uint gridLevel = GetGridLevel(samplePosition, gridParameters);
- float voxelSize = GetVoxelSize(gridLevel, gridParameters);
- int3 gridPosition = int3(floor(samplePosition / voxelSize));
+ uint gridLevel = HashGridGetLevel(samplePosition, gridParameters);
+ float voxelSize = HashGridGetVoxelSize(gridLevel, gridParameters);
+ int3 gridPosition = int3(floor(samplePosition / voxelSize));
return int4(gridPosition.xyz, gridLevel);
}
-HashKey ComputeSpatialHash(float3 samplePosition, float3 sampleNormal, GridParameters gridParameters)
+HashGridKey HashGridComputeSpatialHash(float3 samplePosition, float3 sampleNormal, HashGridParameters gridParameters)
{
- uint4 gridPosition = uint4(CalculateGridPositionLog(samplePosition, gridParameters));
+ uint4 gridPosition = uint4(HashGridCalculatePositionLog(samplePosition, gridParameters));
- HashKey hashKey = ((uint64_t(gridPosition.x) & HASH_GRID_POSITION_BIT_MASK) << (HASH_GRID_POSITION_BIT_NUM * 0))
- | ((uint64_t(gridPosition.y) & HASH_GRID_POSITION_BIT_MASK) << (HASH_GRID_POSITION_BIT_NUM * 1))
- | ((uint64_t(gridPosition.z) & HASH_GRID_POSITION_BIT_MASK) << (HASH_GRID_POSITION_BIT_NUM * 2))
- | ((uint64_t(gridPosition.w) & HASH_GRID_LEVEL_BIT_MASK) << (HASH_GRID_POSITION_BIT_NUM * 3));
+ HashGridKey hashKey = ((uint64_t(gridPosition.x) & HASH_GRID_POSITION_BIT_MASK) << (HASH_GRID_POSITION_BIT_NUM * 0)) |
+ ((uint64_t(gridPosition.y) & HASH_GRID_POSITION_BIT_MASK) << (HASH_GRID_POSITION_BIT_NUM * 1)) |
+ ((uint64_t(gridPosition.z) & HASH_GRID_POSITION_BIT_MASK) << (HASH_GRID_POSITION_BIT_NUM * 2)) |
+ ((uint64_t(gridPosition.w) & HASH_GRID_LEVEL_BIT_MASK) << (HASH_GRID_POSITION_BIT_NUM * 3));
#if HASH_GRID_USE_NORMALS
uint normalBits =
- (sampleNormal.x + HASH_GRID_NORMAL_BIAS >= 0 ? 1 : 0) +
- (sampleNormal.y + HASH_GRID_NORMAL_BIAS >= 0 ? 2 : 0) +
- (sampleNormal.z + HASH_GRID_NORMAL_BIAS >= 0 ? 4 : 0);
+ (sampleNormal.x + HASH_GRID_NORMAL_BIAS >= 0 ? 0 : 1) +
+ (sampleNormal.y + HASH_GRID_NORMAL_BIAS >= 0 ? 0 : 2) +
+ (sampleNormal.z + HASH_GRID_NORMAL_BIAS >= 0 ? 0 : 4);
hashKey |= (uint64_t(normalBits) << (HASH_GRID_POSITION_BIT_NUM * 3 + HASH_GRID_LEVEL_BIT_NUM));
#endif // HASH_GRID_USE_NORMALS
@@ -112,7 +127,7 @@ HashKey ComputeSpatialHash(float3 samplePosition, float3 sampleNormal, GridParam
return hashKey;
}
-float3 GetPositionFromHashKey(const HashKey hashKey, GridParameters gridParameters)
+float3 HashGridGetPositionFromKey(const HashGridKey hashKey, HashGridParameters gridParameters)
{
const int signBit = 1 << (HASH_GRID_POSITION_BIT_NUM - 1);
const int signMask = ~((1 << HASH_GRID_POSITION_BIT_NUM) - 1);
@@ -127,9 +142,9 @@ float3 GetPositionFromHashKey(const HashKey hashKey, GridParameters gridParamete
gridPosition.y = (gridPosition.y & signBit) != 0 ? gridPosition.y | signMask : gridPosition.y;
gridPosition.z = (gridPosition.z & signBit) != 0 ? gridPosition.z | signMask : gridPosition.z;
- uint gridLevel = uint((hashKey >> HASH_GRID_POSITION_BIT_NUM * 3) & HASH_GRID_LEVEL_BIT_MASK);
- float voxelSize = GetVoxelSize(gridLevel, gridParameters);
- float3 samplePosition = (gridPosition + 0.5f) * voxelSize;
+ uint gridLevel = uint((hashKey >> HASH_GRID_POSITION_BIT_NUM * 3) & HASH_GRID_LEVEL_BIT_MASK);
+ float voxelSize = HashGridGetVoxelSize(gridLevel, gridParameters);
+ float3 samplePosition = (gridPosition + 0.5f) * voxelSize;
return samplePosition;
}
@@ -178,42 +193,43 @@ void HashMapAtomicCompareExchange(in HashMapData hashMapData, in uint dstOffset,
#endif // !HASH_GRID_ENABLE_64_BIT_ATOMICS
}
-bool HashMapInsert(in HashMapData hashMapData, const HashKey hashKey, out CacheEntry cacheEntry)
+bool HashMapInsert(in HashMapData hashMapData, const HashGridKey hashKey, out HashGridIndex cacheIndex)
{
- uint hash = Hash32(hashKey);
- uint slot = hash % hashMapData.capacity;
- uint initSlot = slot;
- HashKey prevHashKey = HASH_GRID_INVALID_HASH_KEY;
+ uint hash = HashGridHash32(hashKey);
+ uint slot = hash % hashMapData.capacity;
+ uint initSlot = slot;
+ HashGridKey prevHashGridKey = HASH_GRID_INVALID_HASH_KEY;
- const uint baseSlot = GetBaseSlot(slot, hashMapData.capacity);
+ const uint baseSlot = HashGridGetBaseSlot(slot, hashMapData.capacity);
for (uint bucketOffset = 0; bucketOffset < HASH_GRID_HASH_MAP_BUCKET_SIZE; ++bucketOffset)
{
- HashMapAtomicCompareExchange(hashMapData, baseSlot + bucketOffset, HASH_GRID_INVALID_HASH_KEY, hashKey, prevHashKey);
+ HashMapAtomicCompareExchange(hashMapData, baseSlot + bucketOffset, HASH_GRID_INVALID_HASH_KEY, hashKey, prevHashGridKey);
- if (prevHashKey == HASH_GRID_INVALID_HASH_KEY || prevHashKey == hashKey)
+ if (prevHashGridKey == HASH_GRID_INVALID_HASH_KEY || prevHashGridKey == hashKey)
{
- cacheEntry = baseSlot + bucketOffset;
+ cacheIndex = baseSlot + bucketOffset;
return true;
}
}
- cacheEntry = 0;
+ cacheIndex = 0;
+
return false;
}
-bool HashMapFind(in HashMapData hashMapData, const HashKey hashKey, inout CacheEntry cacheEntry)
+bool HashMapFind(in HashMapData hashMapData, const HashGridKey hashKey, inout HashGridIndex cacheIndex)
{
- uint hash = Hash32(hashKey);
- uint slot = hash % hashMapData.capacity;
+ uint hash = HashGridHash32(hashKey);
+ uint slot = hash % hashMapData.capacity;
- const uint baseSlot = GetBaseSlot(slot, hashMapData.capacity);
+ const uint baseSlot = HashGridGetBaseSlot(slot, hashMapData.capacity);
for (uint bucketOffset = 0; bucketOffset < HASH_GRID_HASH_MAP_BUCKET_SIZE; ++bucketOffset)
{
- HashKey storedHashKey = BUFFER_AT_OFFSET(hashMapData.hashEntriesBuffer, baseSlot + bucketOffset);
+ HashGridKey storedHashKey = BUFFER_AT_OFFSET(hashMapData.hashEntriesBuffer, baseSlot + bucketOffset);
if (storedHashKey == hashKey)
{
- cacheEntry = baseSlot + bucketOffset;
+ cacheIndex = baseSlot + bucketOffset;
return true;
}
#if HASH_GRID_ALLOW_COMPACTION
@@ -227,26 +243,26 @@ bool HashMapFind(in HashMapData hashMapData, const HashKey hashKey, inout CacheE
return false;
}
-CacheEntry HashMapInsertEntry(in HashMapData hashMapData, float3 samplePosition, float3 sampleNormal, GridParameters gridParameters)
+HashGridIndex HashMapInsertEntry(in HashMapData hashMapData, float3 samplePosition, float3 sampleNormal, HashGridParameters gridParameters)
{
- CacheEntry cacheEntry = HASH_GRID_INVALID_CACHE_ENTRY;
- const HashKey hashKey = ComputeSpatialHash(samplePosition, sampleNormal, gridParameters);
- bool successful = HashMapInsert(hashMapData, hashKey, cacheEntry);
+ HashGridIndex cacheIndex = HASH_GRID_INVALID_CACHE_INDEX;
+ const HashGridKey hashKey = HashGridComputeSpatialHash(samplePosition, sampleNormal, gridParameters);
+ bool successful = HashMapInsert(hashMapData, hashKey, cacheIndex);
- return cacheEntry;
+ return cacheIndex;
}
-CacheEntry HashMapFindEntry(in HashMapData hashMapData, float3 samplePosition, float3 sampleNormal, GridParameters gridParameters)
+HashGridIndex HashMapFindEntry(in HashMapData hashMapData, float3 samplePosition, float3 sampleNormal, HashGridParameters gridParameters)
{
- CacheEntry cacheEntry = HASH_GRID_INVALID_CACHE_ENTRY;
- const HashKey hashKey = ComputeSpatialHash(samplePosition, sampleNormal, gridParameters);
- bool successful = HashMapFind(hashMapData, hashKey, cacheEntry);
+ HashGridIndex cacheIndex = HASH_GRID_INVALID_CACHE_INDEX;
+ const HashGridKey hashKey = HashGridComputeSpatialHash(samplePosition, sampleNormal, gridParameters);
+ bool successful = HashMapFind(hashMapData, hashKey, cacheIndex);
- return cacheEntry;
+ return cacheIndex;
}
// Debug functions
-float3 GetColorFromHash32(uint hash)
+float3 HashGridGetColorFromHash32(uint hash)
{
float3 color;
color.x = ((hash >> 0) & 0x3ff) / 1023.0f;
@@ -257,12 +273,11 @@ float3 GetColorFromHash32(uint hash)
}
// Debug visualization
-float3 HashGridDebugColoredHash(float3 samplePosition, GridParameters gridParameters)
+float3 HashGridDebugColoredHash(float3 samplePosition, HashGridParameters gridParameters)
{
- HashKey hashKey = ComputeSpatialHash(samplePosition, float3(0, 0, 0), gridParameters);
-
- uint gridLevel = GetGridLevel(samplePosition, gridParameters);
- float3 color = GetColorFromHash32(Hash32(hashKey)) * GetColorFromHash32(HashJenkins32(gridLevel)).xyz;
+ HashGridKey hashKey = HashGridComputeSpatialHash(samplePosition, float3(0, 0, 0), gridParameters);
+ uint gridLevel = HashGridGetLevel(samplePosition, gridParameters);
+ float3 color = HashGridGetColorFromHash32(HashGridHash32(hashKey)) * HashGridGetColorFromHash32(HashGridHashJenkins32(gridLevel)).xyz;
return color;
}
@@ -280,9 +295,8 @@ float3 HashGridDebugOccupancy(uint2 pixelPosition, uint2 screenSize, HashMapData
if (elementIndex < hashMapData.capacity && ((pixelPosition.x % blockSize) < elementSize && (pixelPosition.y % blockSize) < elementSize))
{
- HashKey storedHashKey = BUFFER_AT_OFFSET(hashMapData.hashEntriesBuffer, elementIndex);
-
- if (storedHashKey != HASH_GRID_INVALID_HASH_KEY)
+ HashGridKey storedHashGridKey = BUFFER_AT_OFFSET(hashMapData.hashEntriesBuffer, elementIndex);
+ if (storedHashGridKey != HASH_GRID_INVALID_HASH_KEY)
return float3(0.0f, 1.0f, 0.0f);
}
diff --git a/include/SharcCommon.h b/include/SharcCommon.h
index a49f4e2..ff61c7f 100644
--- a/include/SharcCommon.h
+++ b/include/SharcCommon.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023-2024, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2023-2025, NVIDIA CORPORATION. All rights reserved.
*
* NVIDIA CORPORATION and its licensors retain all intellectual property
* and proprietary rights in and to this software, related documentation
@@ -8,32 +8,13 @@
* license agreement from NVIDIA CORPORATION is strictly prohibited.
*/
-#define SHARC_VERSION_MAJOR 1
-#define SHARC_VERSION_MINOR 3
-#define SHARC_VERSION_BUILD 1
-#define SHARC_VERSION_REVISION 0
+// Version
+#define SHARC_VERSION_MAJOR 1
+#define SHARC_VERSION_MINOR 4
+#define SHARC_VERSION_BUILD 3
+#define SHARC_VERSION_REVISION 0
-#if (SHARC_UPDATE || SHARC_QUERY)
-#if SHARC_UPDATE
-#define SHARC_QUERY 0
-#else // !SHARC_UPDATE
-#define SHARC_UPDATE 0
-#endif // !SHARC_UPDATE
-#else // !(SHARC_UPDATE || SHARC_QUERY)
-#define SHARC_QUERY 0
-#define SHARC_UPDATE 0
-#endif // !(SHARC_UPDATE || SHARC_QUERY)
-
-#define SHARC_SAMPLE_NUM_MULTIPLIER 16 // increase sample count internally to make resolve step with low sample count more robust, power of 2 usage may help compiler with optimizations
-#define SHARC_SAMPLE_NUM_THRESHOLD 0 // elements with sample count above this threshold will be used for early-out/resampling
-#define SHARC_SEPARATE_EMISSIVE 0 // if set, emissive values should be passed separately on updates and added to the cache query
-#define SHARC_PROPOGATION_DEPTH 4 // controls the amount of vertices stored in memory for signal backpropagation
-#define SHARC_ENABLE_CACHE_RESAMPLING (SHARC_UPDATE && (SHARC_PROPOGATION_DEPTH > 1)) // resamples the cache during update step
-#define SHARC_RESAMPLING_DEPTH_MIN 1 // controls minimum path depth which can be used with cache resampling
-#define SHARC_RADIANCE_SCALE 1e3f // scale used for radiance values accumulation. Each component uses 32-bit integer for data storage
-#define SHARC_ACCUMULATED_FRAME_NUM_MIN 1 // minimum number of frames to use for data accumulation
-#define SHARC_ACCUMULATED_FRAME_NUM_MAX 64 // maximum number of frames to use for data accumulation
-#define SHARC_STALE_FRAME_NUM_MIN 32 // minimum number of frames to keep the element in the cache
+// Constants
#define SHARC_SAMPLE_NUM_BIT_NUM 18
#define SHARC_SAMPLE_NUM_BIT_OFFSET 0
#define SHARC_SAMPLE_NUM_BIT_MASK ((1u << SHARC_SAMPLE_NUM_BIT_NUM) - 1)
@@ -44,67 +25,63 @@
#define SHARC_STALE_FRAME_NUM_BIT_OFFSET (SHARC_SAMPLE_NUM_BIT_NUM + SHARC_ACCUMULATED_FRAME_NUM_BIT_NUM)
#define SHARC_STALE_FRAME_NUM_BIT_MASK ((1u << SHARC_STALE_FRAME_NUM_BIT_NUM) - 1)
#define SHARC_GRID_LOGARITHM_BASE 2.0f
+#define SHARC_GRID_LEVEL_BIAS 0 // positive bias adds extra levels with content magnification (can be negative as well)
#define SHARC_ENABLE_COMPACTION HASH_GRID_ALLOW_COMPACTION
#define SHARC_BLEND_ADJACENT_LEVELS 1 // combine the data from adjacent levels on camera movement
#define SHARC_DEFERRED_HASH_COMPACTION (SHARC_ENABLE_COMPACTION && SHARC_BLEND_ADJACENT_LEVELS)
#define SHARC_NORMALIZED_SAMPLE_NUM (1u << (SHARC_SAMPLE_NUM_BIT_NUM - 1))
+#define SHARC_ACCUMULATED_FRAME_NUM_MIN 1 // minimum number of frames to use for data accumulation
+#define SHARC_ACCUMULATED_FRAME_NUM_MAX SHARC_ACCUMULATED_FRAME_NUM_BIT_MASK // maximum number of frames to use for data accumulation
-// Debug
-#define SHARC_DEBUG_BITS_OCCUPANCY_THRESHOLD_LOW 0.125
-#define SHARC_DEBUG_BITS_OCCUPANCY_THRESHOLD_MEDIUM 0.5
-
-#if SHARC_ENABLE_GLSL
-
-// Required extensions
-// #extension GL_EXT_buffer_reference : require
-// #extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
-// #extension GL_EXT_shader_atomic_int64 : require
-// #extension GL_KHR_shader_subgroup_ballot : require
-
-// Buffer reference types can be constructed from a 'uint64_t' or a 'uvec2' value.
-// The low - order 32 bits of the reference map to and from the 'x' component
-// of the 'uvec2'.
-#define float2 vec2
-#define float3 vec3
-#define float4 vec4
+// Tweakable parameters
+#ifndef SHARC_SAMPLE_NUM_MULTIPLIER
+#define SHARC_SAMPLE_NUM_MULTIPLIER 16 // increase sample count internally to make resolve step with low sample count more robust, power of 2 usage may help compiler with optimizations
+#endif
-#define uint2 uvec2
-#define uint3 uvec3
-#define uint4 uvec4
+#ifndef SHARC_SAMPLE_NUM_THRESHOLD
+#define SHARC_SAMPLE_NUM_THRESHOLD 0 // elements with sample count above this threshold will be used for early-out/resampling
+#endif
-#define int2 ivec2
-#define int3 ivec3
-#define int4 ivec4
+#ifndef SHARC_SEPARATE_EMISSIVE
+#define SHARC_SEPARATE_EMISSIVE 0 // if set, emissive values should be passed separately on updates and added to the cache query
+#endif
-#define lerp mix
-#define InterlockedAdd atomicAdd
-#define InterlockedCompareExchange atomicCompSwap
-#define WaveActiveCountBits(value) subgroupBallotBitCount(uint4(value, 0, 0, 0))
-#define WaveActiveBallot subgroupBallot
-#define WavePrefixCountBits(value) subgroupBallotExclusiveBitCount(uint4(value, 0, 0, 0))
+#ifndef SHARC_INCLUDE_DIRECT_LIGHTING
+#define SHARC_INCLUDE_DIRECT_LIGHTING 1 // if set cache values include both direct and indirect lighting
+#endif
-#define RW_STRUCTURED_BUFFER(name, type) RWStructuredBuffer_##type name
-#define BUFFER_AT_OFFSET(name, offset) name.data[offset]
+#ifndef SHARC_PROPOGATION_DEPTH
+#define SHARC_PROPOGATION_DEPTH 4 // controls the amount of vertices stored in memory for signal backpropagation
+#endif
-layout(buffer_reference, std430, buffer_reference_align = 8) buffer RWStructuredBuffer_uint64_t {
- uint64_t data[];
-};
+#ifndef SHARC_ENABLE_CACHE_RESAMPLING
+#define SHARC_ENABLE_CACHE_RESAMPLING (SHARC_UPDATE && (SHARC_PROPOGATION_DEPTH > 1)) // resamples the cache during update step
+#endif
-layout(buffer_reference, std430, buffer_reference_align = 4) buffer RWStructuredBuffer_uint {
- uint data[];
-};
+#ifndef SHARC_RESAMPLING_DEPTH_MIN
+#define SHARC_RESAMPLING_DEPTH_MIN 1 // controls minimum path depth which can be used with cache resampling
+#endif
-layout(buffer_reference, std430, buffer_reference_align = 16) buffer RWStructuredBuffer_uint4 {
- uvec4 data[];
-};
+#ifndef SHARC_RADIANCE_SCALE
+#define SHARC_RADIANCE_SCALE 1e3f // scale used for radiance values accumulation. Each component uses 32-bit integer for data storage
+#endif
-#else // !SHARC_ENABLE_GLSL
+#ifndef SHARC_STALE_FRAME_NUM_MIN
+#define SHARC_STALE_FRAME_NUM_MIN 8 // minimum number of frames to keep the element in the cache
+#endif
+#ifndef RW_STRUCTURED_BUFFER
#define RW_STRUCTURED_BUFFER(name, type) RWStructuredBuffer name
+#endif
+
+#ifndef BUFFER_AT_OFFSET
#define BUFFER_AT_OFFSET(name, offset) name[offset]
+#endif
-#endif // !SHARC_ENABLE_GLSL
+// Debug
+#define SHARC_DEBUG_BITS_OCCUPANCY_THRESHOLD_LOW 0.125
+#define SHARC_DEBUG_BITS_OCCUPANCY_THRESHOLD_MEDIUM 0.5
/*
* RTXGI2 DIVERGENCE:
@@ -138,6 +115,34 @@ layout(buffer_reference, std430, buffer_reference_align = 16) buffer RWStructure
#endif
#include "HashGridCommon.h"
+struct SharcParameters
+{
+ HashGridParameters gridParameters;
+ HashMapData hashMapData;
+ bool enableAntiFireflyFilter;
+
+ RW_STRUCTURED_BUFFER(voxelDataBuffer, uint4);
+ RW_STRUCTURED_BUFFER(voxelDataBufferPrev, uint4);
+};
+
+struct SharcState
+{
+#if SHARC_UPDATE
+ HashGridIndex cacheIndices[SHARC_PROPOGATION_DEPTH];
+ float3 sampleWeights[SHARC_PROPOGATION_DEPTH];
+ uint pathLength;
+#endif // SHARC_UPDATE
+};
+
+struct SharcHitData
+{
+ float3 positionWorld;
+ float3 normalWorld;
+#if SHARC_SEPARATE_EMISSIVE
+ float3 emissive;
+#endif // SHARC_SEPARATE_EMISSIVE
+};
+
struct SharcVoxelData
{
uint3 accumulatedRadiance;
@@ -146,6 +151,14 @@ struct SharcVoxelData
uint staleFrameNum;
};
+struct SharcResolveParameters
+{
+ float3 cameraPositionPrev;
+ uint accumulationFrameNum;
+ uint staleFrameNumMax;
+ bool enableAntiFireflyFilter;
+};
+
uint SharcGetSampleNum(uint packedData)
{
return (packedData >> SHARC_SAMPLE_NUM_BIT_OFFSET) & SHARC_SAMPLE_NUM_BIT_MASK;
@@ -176,7 +189,7 @@ SharcVoxelData SharcUnpackVoxelData(uint4 voxelDataPacked)
return voxelData;
}
-SharcVoxelData SharcGetVoxelData(RW_STRUCTURED_BUFFER(voxelDataBuffer, uint4), CacheEntry cacheEntry)
+SharcVoxelData SharcGetVoxelData(RW_STRUCTURED_BUFFER(voxelDataBuffer, uint4), HashGridIndex cacheIndex)
{
SharcVoxelData voxelData;
voxelData.accumulatedRadiance = uint3(0, 0, 0);
@@ -184,53 +197,52 @@ SharcVoxelData SharcGetVoxelData(RW_STRUCTURED_BUFFER(voxelDataBuffer, uint4), C
voxelData.accumulatedFrameNum = 0;
voxelData.staleFrameNum = 0;
- if (cacheEntry == HASH_GRID_INVALID_CACHE_ENTRY)
+ if (cacheIndex == HASH_GRID_INVALID_CACHE_INDEX)
return voxelData;
- uint4 voxelDataPacked = BUFFER_AT_OFFSET(voxelDataBuffer, cacheEntry);
+ uint4 voxelDataPacked = BUFFER_AT_OFFSET(voxelDataBuffer, cacheIndex);
return SharcUnpackVoxelData(voxelDataPacked);
}
-void SharcAddVoxelData(RW_STRUCTURED_BUFFER(voxelDataBuffer, uint4), CacheEntry cacheEntry, float3 value, uint sampleData)
+void SharcAddVoxelData(in SharcParameters sharcParameters, HashGridIndex cacheIndex, float3 sampleValue, float3 sampleWeight, uint sampleData)
{
- if (cacheEntry == HASH_GRID_INVALID_CACHE_ENTRY)
+ if (cacheIndex == HASH_GRID_INVALID_CACHE_INDEX)
return;
- uint3 scaledRadiance = uint3(value * SHARC_RADIANCE_SCALE);
-
- if (scaledRadiance.x != 0) InterlockedAdd(BUFFER_AT_OFFSET(voxelDataBuffer, cacheEntry).x, scaledRadiance.x);
- if (scaledRadiance.y != 0) InterlockedAdd(BUFFER_AT_OFFSET(voxelDataBuffer, cacheEntry).y, scaledRadiance.y);
- if (scaledRadiance.z != 0) InterlockedAdd(BUFFER_AT_OFFSET(voxelDataBuffer, cacheEntry).z, scaledRadiance.z);
- if (sampleData != 0) InterlockedAdd(BUFFER_AT_OFFSET(voxelDataBuffer, cacheEntry).w, sampleData);
-}
-
-struct SharcState
-{
- GridParameters gridParameters;
- HashMapData hashMapData;
-
-#if SHARC_UPDATE
- CacheEntry cacheEntry[SHARC_PROPOGATION_DEPTH];
- float3 sampleWeight[SHARC_PROPOGATION_DEPTH];
- uint pathLength;
-#endif // SHARC_UPDATE
+ if (sharcParameters.enableAntiFireflyFilter)
+ {
+ float scalarWeight = dot(sampleWeight, float3(0.213f, 0.715f, 0.072f));
+ scalarWeight = max(scalarWeight, 1.0f);
- RW_STRUCTURED_BUFFER(voxelDataBuffer, uint4);
+ const float sampleWeightThreshold = 2.0f;
+ if (scalarWeight > sampleWeightThreshold)
+ {
+ uint4 voxelDataPackedPrev = BUFFER_AT_OFFSET(sharcParameters.voxelDataBufferPrev, cacheIndex);
+ uint sampleNumPrev = SharcGetSampleNum(voxelDataPackedPrev.w);
+ const uint sampleConfidenceThreshold = 2;
+ if (sampleNumPrev > SHARC_SAMPLE_NUM_MULTIPLIER * sampleConfidenceThreshold)
+ {
+ float luminancePrev = max(dot(SharcResolveAccumulatedRadiance(voxelDataPackedPrev.xyz, sampleNumPrev), float3(0.213f, 0.715f, 0.072f)), 1.0f);
+ float luminanceCur = max(dot(sampleValue * sampleWeight, float3(0.213f, 0.715f, 0.072f)), 1.0f);
+ float confidenceScale = lerp(5.0f, 10.0f, 1.0f / sampleNumPrev);
+ sampleWeight *= saturate(confidenceScale * luminancePrev / luminanceCur);
+ }
+ else
+ {
+ scalarWeight = pow(scalarWeight, 0.5f);
+ sampleWeight /= scalarWeight;
+ }
+ }
+ }
-#if SHARC_ENABLE_CACHE_RESAMPLING
- RW_STRUCTURED_BUFFER(voxelDataBufferPrev, uint4);
-#endif // SHARC_ENABLE_CACHE_RESAMPLING
-};
+ uint3 scaledRadiance = uint3(sampleValue * sampleWeight * SHARC_RADIANCE_SCALE);
-struct SharcHitData
-{
- float3 positionWorld;
- float3 normalWorld;
-#if SHARC_SEPARATE_EMISSIVE
- float3 emissive;
-#endif // SHARC_SEPARATE_EMISSIVE
-};
+ if (scaledRadiance.x != 0) InterlockedAdd(BUFFER_AT_OFFSET(sharcParameters.voxelDataBuffer, cacheIndex).x, scaledRadiance.x);
+ if (scaledRadiance.y != 0) InterlockedAdd(BUFFER_AT_OFFSET(sharcParameters.voxelDataBuffer, cacheIndex).y, scaledRadiance.y);
+ if (scaledRadiance.z != 0) InterlockedAdd(BUFFER_AT_OFFSET(sharcParameters.voxelDataBuffer, cacheIndex).z, scaledRadiance.z);
+ if (sampleData != 0) InterlockedAdd(BUFFER_AT_OFFSET(sharcParameters.voxelDataBuffer, cacheIndex).w, sampleData);
+}
void SharcInit(inout SharcState sharcState)
{
@@ -239,40 +251,49 @@ void SharcInit(inout SharcState sharcState)
#endif // SHARC_UPDATE
}
-void SharcUpdateMiss(inout SharcState sharcState, float3 radiance)
+void SharcUpdateMiss(in SharcParameters sharcParameters, in SharcState sharcState, float3 radiance)
{
#if SHARC_UPDATE
for (int i = 0; i < sharcState.pathLength; ++i)
{
- radiance *= sharcState.sampleWeight[i];
- SharcAddVoxelData(sharcState.voxelDataBuffer, sharcState.cacheEntry[i], radiance, 0);
+ SharcAddVoxelData(sharcParameters, sharcState.cacheIndices[i], radiance, sharcState.sampleWeights[i], 0);
+ radiance *= sharcState.sampleWeights[i];
}
#endif // SHARC_UPDATE
}
-bool SharcUpdateHit(inout SharcState sharcState, SharcHitData sharcHitData, float3 lighting, float random)
+bool SharcUpdateHit(in SharcParameters sharcParameters, inout SharcState sharcState, SharcHitData sharcHitData, float3 directLighting, float random)
{
bool continueTracing = true;
#if SHARC_UPDATE
- CacheEntry cacheEntry = HashMapInsertEntry(sharcState.hashMapData, sharcHitData.positionWorld, sharcHitData.normalWorld, sharcState.gridParameters);
+ HashGridIndex cacheIndex = HashMapInsertEntry(sharcParameters.hashMapData, sharcHitData.positionWorld, sharcHitData.normalWorld, sharcParameters.gridParameters);
- float3 sharcRadiance = lighting;
+ float3 sharcRadiance = directLighting;
#if SHARC_ENABLE_CACHE_RESAMPLING
uint resamplingDepth = uint(round(lerp(SHARC_RESAMPLING_DEPTH_MIN, SHARC_PROPOGATION_DEPTH - 1, random)));
if (resamplingDepth <= sharcState.pathLength)
{
- SharcVoxelData voxelData = SharcGetVoxelData(sharcState.voxelDataBufferPrev, cacheEntry);
+ SharcVoxelData voxelData = SharcGetVoxelData(sharcParameters.voxelDataBufferPrev, cacheIndex);
if (voxelData.accumulatedSampleNum > SHARC_SAMPLE_NUM_THRESHOLD)
{
sharcRadiance = SharcResolveAccumulatedRadiance(voxelData.accumulatedRadiance, voxelData.accumulatedSampleNum);
+#if !SHARC_INCLUDE_DIRECT_LIGHTING
+ sharcRadiance += directLighting;
+#endif // !SHARC_INCLUDE_DIRECT_LIGHTING
continueTracing = false;
}
}
#endif // SHARC_ENABLE_CACHE_RESAMPLING
if (continueTracing)
- SharcAddVoxelData(sharcState.voxelDataBuffer, cacheEntry, lighting, 1);
+ {
+#if SHARC_INCLUDE_DIRECT_LIGHTING
+ SharcAddVoxelData(sharcParameters, cacheIndex, directLighting, float3(1.0f, 1.0f, 1.0f), 1);
+#else // !SHARC_INCLUDE_DIRECT_LIGHTING
+ SharcAddVoxelData(sharcParameters, cacheIndex, float3(0.0f, 0.0f, 0.0f), float3(0.0f, 0.0f, 0.0f), 1);
+#endif // !SHARC_INCLUDE_DIRECT_LIGHTING
+ }
#if SHARC_SEPARATE_EMISSIVE
sharcRadiance += sharcHitData.emissive;
@@ -281,17 +302,17 @@ bool SharcUpdateHit(inout SharcState sharcState, SharcHitData sharcHitData, floa
uint i;
for (i = 0; i < sharcState.pathLength; ++i)
{
- sharcRadiance *= sharcState.sampleWeight[i];
- SharcAddVoxelData(sharcState.voxelDataBuffer, sharcState.cacheEntry[i], sharcRadiance, 0);
+ SharcAddVoxelData(sharcParameters, sharcState.cacheIndices[i], sharcRadiance, sharcState.sampleWeights[i], 0);
+ sharcRadiance *= sharcState.sampleWeights[i];
}
for (i = sharcState.pathLength; i > 0; --i)
{
- sharcState.cacheEntry[i] = sharcState.cacheEntry[i - 1];
- sharcState.sampleWeight[i] = sharcState.sampleWeight[i - 1];
+ sharcState.cacheIndices[i] = sharcState.cacheIndices[i - 1];
+ sharcState.sampleWeights[i] = sharcState.sampleWeights[i - 1];
}
- sharcState.cacheEntry[0] = cacheEntry;
+ sharcState.cacheIndices[0] = cacheIndex;
sharcState.pathLength = min(++sharcState.pathLength, SHARC_PROPOGATION_DEPTH - 1);
#endif // SHARC_UPDATE
return continueTracing;
@@ -300,20 +321,20 @@ bool SharcUpdateHit(inout SharcState sharcState, SharcHitData sharcHitData, floa
void SharcSetThroughput(inout SharcState sharcState, float3 throughput)
{
#if SHARC_UPDATE
- sharcState.sampleWeight[0] = throughput;
+ sharcState.sampleWeights[0] = throughput;
#endif // SHARC_UPDATE
}
-bool SharcGetCachedRadiance(in SharcState sharcState, in SharcHitData sharcHitData, out float3 radiance, bool debug)
+bool SharcGetCachedRadiance(in SharcParameters sharcParameters, in SharcHitData sharcHitData, out float3 radiance, bool debug)
{
if (debug) radiance = float3(0, 0, 0);
const uint sampleThreshold = debug ? 0 : SHARC_SAMPLE_NUM_THRESHOLD;
- CacheEntry cacheEntry = HashMapFindEntry(sharcState.hashMapData, sharcHitData.positionWorld, sharcHitData.normalWorld, sharcState.gridParameters);
- if (cacheEntry == HASH_GRID_INVALID_CACHE_ENTRY)
+ HashGridIndex cacheIndex = HashMapFindEntry(sharcParameters.hashMapData, sharcHitData.positionWorld, sharcHitData.normalWorld, sharcParameters.gridParameters);
+ if (cacheIndex == HASH_GRID_INVALID_CACHE_INDEX)
return false;
- SharcVoxelData voxelData = SharcGetVoxelData(sharcState.voxelDataBuffer, cacheEntry);
+ SharcVoxelData voxelData = SharcGetVoxelData(sharcParameters.voxelDataBuffer, cacheIndex);
if (voxelData.accumulatedSampleNum > sampleThreshold)
{
radiance = SharcResolveAccumulatedRadiance(voxelData.accumulatedRadiance, voxelData.accumulatedSampleNum);
@@ -338,13 +359,13 @@ void SharcCopyHashEntry(uint entryIndex, HashMapData hashMapData, RW_STRUCTURED_
if (copyOffset == 0)
return;
- if (copyOffset == HASH_GRID_INVALID_CACHE_ENTRY)
+ if (copyOffset == HASH_GRID_INVALID_CACHE_INDEX)
{
BUFFER_AT_OFFSET(hashMapData.hashEntriesBuffer, entryIndex) = HASH_GRID_INVALID_HASH_KEY;
}
else if (copyOffset != 0)
{
- HashKey hashKey = BUFFER_AT_OFFSET(hashMapData.hashEntriesBuffer, entryIndex);
+ HashGridKey hashKey = BUFFER_AT_OFFSET(hashMapData.hashEntriesBuffer, entryIndex);
BUFFER_AT_OFFSET(hashMapData.hashEntriesBuffer, entryIndex) = HASH_GRID_INVALID_HASH_KEY;
BUFFER_AT_OFFSET(hashMapData.hashEntriesBuffer, copyOffset) = hashKey;
}
@@ -358,7 +379,7 @@ int SharcGetGridDistance2(int3 position)
return position.x * position.x + position.y * position.y + position.z * position.z;
}
-HashKey SharcGetAdjacentLevelHashKey(HashKey hashKey, GridParameters gridParameters)
+HashGridKey SharcGetAdjacentLevelHashKey(HashGridKey hashKey, HashGridParameters gridParameters, float3 cameraPositionPrev)
{
const int signBit = 1 << (HASH_GRID_POSITION_BIT_NUM - 1);
const int signMask = ~((1 << HASH_GRID_POSITION_BIT_NUM) - 1);
@@ -375,12 +396,12 @@ HashKey SharcGetAdjacentLevelHashKey(HashKey hashKey, GridParameters gridParamet
int level = int((hashKey >> (HASH_GRID_POSITION_BIT_NUM * 3)) & HASH_GRID_LEVEL_BIT_MASK);
- float voxelSize = GetVoxelSize(level, gridParameters);
+ float voxelSize = HashGridGetVoxelSize(level, gridParameters);
int3 cameraGridPosition = int3(floor((gridParameters.cameraPosition + HASH_GRID_POSITION_OFFSET) / voxelSize));
int3 cameraVector = cameraGridPosition - gridPosition;
int cameraDistance = SharcGetGridDistance2(cameraVector);
- int3 cameraGridPositionPrev = int3(floor((gridParameters.cameraPositionPrev + HASH_GRID_POSITION_OFFSET) / voxelSize));
+ int3 cameraGridPositionPrev = int3(floor((cameraPositionPrev + HASH_GRID_POSITION_OFFSET) / voxelSize));
int3 cameraVectorPrev = cameraGridPositionPrev - gridPosition;
int cameraDistancePrev = SharcGetGridDistance2(cameraVectorPrev);
@@ -395,50 +416,56 @@ HashKey SharcGetAdjacentLevelHashKey(HashKey hashKey, GridParameters gridParamet
level = max(level - 1, 1);
}
- HashKey modifiedHashKey = ((uint64_t(gridPosition.x) & HASH_GRID_POSITION_BIT_MASK) << (HASH_GRID_POSITION_BIT_NUM * 0))
+ HashGridKey modifiedHashGridKey = ((uint64_t(gridPosition.x) & HASH_GRID_POSITION_BIT_MASK) << (HASH_GRID_POSITION_BIT_NUM * 0))
| ((uint64_t(gridPosition.y) & HASH_GRID_POSITION_BIT_MASK) << (HASH_GRID_POSITION_BIT_NUM * 1))
| ((uint64_t(gridPosition.z) & HASH_GRID_POSITION_BIT_MASK) << (HASH_GRID_POSITION_BIT_NUM * 2))
| ((uint64_t(level) & HASH_GRID_LEVEL_BIT_MASK) << (HASH_GRID_POSITION_BIT_NUM * 3));
#if HASH_GRID_USE_NORMALS
- modifiedHashKey |= hashKey & (uint64_t(HASH_GRID_NORMAL_BIT_MASK) << (HASH_GRID_POSITION_BIT_NUM * 3 + HASH_GRID_LEVEL_BIT_NUM));
+ modifiedHashGridKey |= hashKey & (uint64_t(HASH_GRID_NORMAL_BIT_MASK) << (HASH_GRID_POSITION_BIT_NUM * 3 + HASH_GRID_LEVEL_BIT_NUM));
#endif // HASH_GRID_USE_NORMALS
- return modifiedHashKey;
+ return modifiedHashGridKey;
}
-void SharcResolveEntry(uint entryIndex, GridParameters gridParameters, HashMapData hashMapData, RW_STRUCTURED_BUFFER(copyOffsetBuffer, uint),
- RW_STRUCTURED_BUFFER(voxelDataBuffer, uint4), RW_STRUCTURED_BUFFER(voxelDataBufferPrev, uint4), uint accumulationFrameNum, uint staleFrameNumMax)
+void SharcResolveEntry(uint entryIndex, SharcParameters sharcParameters, SharcResolveParameters resolveParameters
+#if SHARC_DEFERRED_HASH_COMPACTION
+ , RW_STRUCTURED_BUFFER(copyOffsetBuffer, uint)
+#endif // SHARC_DEFERRED_HASH_COMPACTION
+)
{
- if (entryIndex >= hashMapData.capacity)
+ if (entryIndex >= sharcParameters.hashMapData.capacity)
return;
- HashKey hashKey = BUFFER_AT_OFFSET(hashMapData.hashEntriesBuffer, entryIndex);
+ HashGridKey hashKey = BUFFER_AT_OFFSET(sharcParameters.hashMapData.hashEntriesBuffer, entryIndex);
if (hashKey == HASH_GRID_INVALID_HASH_KEY)
return;
- uint4 voxelDataPackedPrev = BUFFER_AT_OFFSET(voxelDataBufferPrev, entryIndex);
- uint4 voxelDataPacked = BUFFER_AT_OFFSET(voxelDataBuffer, entryIndex);
+ uint4 voxelDataPackedPrev = BUFFER_AT_OFFSET(sharcParameters.voxelDataBufferPrev, entryIndex);
+ uint4 voxelDataPacked = BUFFER_AT_OFFSET(sharcParameters.voxelDataBuffer, entryIndex);
uint sampleNum = SharcGetSampleNum(voxelDataPacked.w);
uint sampleNumPrev = SharcGetSampleNum(voxelDataPackedPrev.w);
- uint accumulatedFrameNum = SharcGetAccumulatedFrameNum(voxelDataPackedPrev.w);
+ uint accumulatedFrameNum = SharcGetAccumulatedFrameNum(voxelDataPackedPrev.w) + 1;
uint staleFrameNum = SharcGetStaleFrameNum(voxelDataPackedPrev.w);
- uint3 accumulatedRadiance = voxelDataPacked.xyz * SHARC_SAMPLE_NUM_MULTIPLIER + voxelDataPackedPrev.xyz;
- uint accumulatedSampleNum = SharcGetSampleNum(voxelDataPacked.w) * SHARC_SAMPLE_NUM_MULTIPLIER + SharcGetSampleNum(voxelDataPackedPrev.w);
+ voxelDataPacked.xyz *= SHARC_SAMPLE_NUM_MULTIPLIER;
+ sampleNum *= SHARC_SAMPLE_NUM_MULTIPLIER;
+
+ uint3 accumulatedRadiance = voxelDataPacked.xyz + voxelDataPackedPrev.xyz;
+ uint accumulatedSampleNum = sampleNum + sampleNumPrev;
#if SHARC_BLEND_ADJACENT_LEVELS
// Reproject sample from adjacent level
- float3 cameraOffset = gridParameters.cameraPosition.xyz - gridParameters.cameraPositionPrev.xyz;
- if ((dot(cameraOffset, cameraOffset) != 0) && (accumulatedFrameNum < accumulationFrameNum))
+ float3 cameraOffset = sharcParameters.gridParameters.cameraPosition.xyz - resolveParameters.cameraPositionPrev.xyz;
+ if ((dot(cameraOffset, cameraOffset) != 0) && (accumulatedFrameNum < resolveParameters.accumulationFrameNum))
{
- HashKey adjacentLevelHashKey = SharcGetAdjacentLevelHashKey(hashKey, gridParameters);
+ HashGridKey adjacentLevelHashKey = SharcGetAdjacentLevelHashKey(hashKey, sharcParameters.gridParameters, resolveParameters.cameraPositionPrev);
- CacheEntry cacheEntry = HASH_GRID_INVALID_CACHE_ENTRY;
- if (HashMapFind(hashMapData, adjacentLevelHashKey, cacheEntry))
+ HashGridIndex cacheIndex = HASH_GRID_INVALID_CACHE_INDEX;
+ if (HashMapFind(sharcParameters.hashMapData, adjacentLevelHashKey, cacheIndex))
{
- uint4 adjacentPackedDataPrev = BUFFER_AT_OFFSET(voxelDataBufferPrev, cacheEntry);
+ uint4 adjacentPackedDataPrev = BUFFER_AT_OFFSET(sharcParameters.voxelDataBufferPrev, cacheIndex);
uint adjacentSampleNum = SharcGetSampleNum(adjacentPackedDataPrev.w);
if (adjacentSampleNum > SHARC_SAMPLE_NUM_THRESHOLD)
{
@@ -457,7 +484,7 @@ void SharcResolveEntry(uint entryIndex, GridParameters gridParameters, HashMapDa
accumulatedRadiance >>= 1;
}
- accumulationFrameNum = clamp(accumulationFrameNum, SHARC_ACCUMULATED_FRAME_NUM_MIN, SHARC_ACCUMULATED_FRAME_NUM_MAX);
+ uint accumulationFrameNum = clamp(resolveParameters.accumulationFrameNum, SHARC_ACCUMULATED_FRAME_NUM_MIN, SHARC_ACCUMULATED_FRAME_NUM_MAX);
if (accumulatedFrameNum > accumulationFrameNum)
{
float normalizedAccumulatedSampleNum = round(accumulatedSampleNum * float(accumulationFrameNum) / accumulatedFrameNum);
@@ -468,7 +495,6 @@ void SharcResolveEntry(uint entryIndex, GridParameters gridParameters, HashMapDa
accumulatedFrameNum = uint(accumulatedFrameNum * normalizationScale);
}
- ++accumulatedFrameNum;
staleFrameNum = (sampleNum != 0) ? 0 : staleFrameNum + 1;
uint4 packedData;
@@ -478,13 +504,13 @@ void SharcResolveEntry(uint entryIndex, GridParameters gridParameters, HashMapDa
packedData.w |= (min(accumulatedFrameNum, SHARC_ACCUMULATED_FRAME_NUM_BIT_MASK) << SHARC_ACCUMULATED_FRAME_NUM_BIT_OFFSET);
packedData.w |= (min(staleFrameNum, SHARC_STALE_FRAME_NUM_BIT_MASK) << SHARC_STALE_FRAME_NUM_BIT_OFFSET);
- bool isValidElement = (staleFrameNum < max(staleFrameNumMax, SHARC_STALE_FRAME_NUM_MIN)) ? true : false;
+ bool isValidElement = (staleFrameNum < max(resolveParameters.staleFrameNumMax, SHARC_STALE_FRAME_NUM_MIN)) ? true : false;
if (!isValidElement)
{
packedData = uint4(0, 0, 0, 0);
#if !SHARC_ENABLE_COMPACTION
- BUFFER_AT_OFFSET(hashMapData.hashEntriesBuffer, entryIndex) = HASH_GRID_INVALID_HASH_KEY;
+ BUFFER_AT_OFFSET(sharcParameters.hashMapData.hashEntriesBuffer, entryIndex) = HASH_GRID_INVALID_HASH_KEY;
#endif // !SHARC_ENABLE_COMPACTION
}
@@ -501,7 +527,7 @@ void SharcResolveEntry(uint entryIndex, GridParameters gridParameters, HashMapDa
hashMapData.hashEntriesBuffer[entryIndex] = HASH_GRID_INVALID_HASH_KEY;
#endif // !SHARC_DEFERRED_HASH_COMPACTION
- BUFFER_AT_OFFSET(voxelDataBuffer, entryIndex) = uint4(0, 0, 0, 0);
+ BUFFER_AT_OFFSET(sharcParameters.voxelDataBuffer, entryIndex) = uint4(0, 0, 0, 0);
if (isValidElement)
{
@@ -512,12 +538,12 @@ void SharcResolveEntry(uint entryIndex, GridParameters gridParameters, HashMapDa
{
if (emptySlotIndex == movableElementIndex)
{
- writeOffset += GetBaseSlot(entryIndex, hashMapData.capacity);
+ writeOffset += HashGridGetBaseSlot(entryIndex, sharcParameters.hashMapData.capacity);
#if !SHARC_DEFERRED_HASH_COMPACTION
hashMapData.hashEntriesBuffer[writeOffset] = hashKey;
#endif // !SHARC_DEFERRED_HASH_COMPACTION
- BUFFER_AT_OFFSET(voxelDataBuffer, writeOffset) = packedData;
+ BUFFER_AT_OFFSET(sharcParameters.voxelDataBuffer, writeOffset) = packedData;
break;
}
@@ -529,18 +555,18 @@ void SharcResolveEntry(uint entryIndex, GridParameters gridParameters, HashMapDa
}
#if SHARC_DEFERRED_HASH_COMPACTION
- BUFFER_AT_OFFSET(copyOffsetBuffer, entryIndex) = (writeOffset != 0) ? writeOffset : HASH_GRID_INVALID_CACHE_ENTRY;
+ BUFFER_AT_OFFSET(copyOffsetBuffer, entryIndex) = (writeOffset != 0) ? writeOffset : HASH_GRID_INVALID_CACHE_INDEX;
#endif // SHARC_DEFERRED_HASH_COMPACTION
}
else if (isValidElement)
#endif // SHARC_ENABLE_COMPACTION
{
- BUFFER_AT_OFFSET(voxelDataBuffer, entryIndex) = packedData;
+ BUFFER_AT_OFFSET(sharcParameters.voxelDataBuffer, entryIndex) = packedData;
}
#if !SHARC_BLEND_ADJACENT_LEVELS
// Clear buffer entry for the next frame
- //BUFFER_AT_OFFSET(voxelDataBufferPrev, entryIndex) = uint4(0, 0, 0, 0);
+ //BUFFER_AT_OFFSET(sharcParameters.voxelDataBufferPrev, entryIndex) = uint4(0, 0, 0, 0);
#endif // !SHARC_BLEND_ADJACENT_LEVELS
}
@@ -556,22 +582,22 @@ float3 SharcDebugGetBitsOccupancyColor(float occupancy)
}
// Debug visualization
-float3 SharcDebugBitsOccupancySampleNum(in SharcState sharcState, in SharcHitData sharcHitData)
+float3 SharcDebugBitsOccupancySampleNum(in SharcParameters sharcParameters, in SharcHitData sharcHitData)
{
- CacheEntry cacheEntry = HashMapFindEntry(sharcState.hashMapData, sharcHitData.positionWorld, sharcHitData.normalWorld, sharcState.gridParameters);
- SharcVoxelData voxelData = SharcGetVoxelData(sharcState.voxelDataBuffer, cacheEntry);
+ HashGridIndex cacheIndex = HashMapFindEntry(sharcParameters.hashMapData, sharcHitData.positionWorld, sharcHitData.normalWorld, sharcParameters.gridParameters);
+ SharcVoxelData voxelData = SharcGetVoxelData(sharcParameters.voxelDataBuffer, cacheIndex);
float occupancy = float(voxelData.accumulatedSampleNum) / SHARC_SAMPLE_NUM_BIT_MASK;
return SharcDebugGetBitsOccupancyColor(occupancy);
}
-float3 SharcDebugBitsOccupancyRadiance(in SharcState sharcState, in SharcHitData sharcHitData)
+float3 SharcDebugBitsOccupancyRadiance(in SharcParameters sharcParameters, in SharcHitData sharcHitData)
{
- CacheEntry cacheEntry = HashMapFindEntry(sharcState.hashMapData, sharcHitData.positionWorld, sharcHitData.normalWorld, sharcState.gridParameters);
- SharcVoxelData voxelData = SharcGetVoxelData(sharcState.voxelDataBuffer, cacheEntry);
+ HashGridIndex cacheIndex = HashMapFindEntry(sharcParameters.hashMapData, sharcHitData.positionWorld, sharcHitData.normalWorld, sharcParameters.gridParameters);
+ SharcVoxelData voxelData = SharcGetVoxelData(sharcParameters.voxelDataBuffer, cacheIndex);
- float occupancy = float(max(voxelData.accumulatedRadiance.x, max(voxelData.accumulatedRadiance.y, voxelData.accumulatedRadiance.z))) / 0xffffffff;
+ float occupancy = float(max(voxelData.accumulatedRadiance.x, max(voxelData.accumulatedRadiance.y, voxelData.accumulatedRadiance.z))) / 0xFFFFFFFF;
return SharcDebugGetBitsOccupancyColor(occupancy);
}
diff --git a/include/SharcGlsl.h b/include/SharcGlsl.h
new file mode 100644
index 0000000..45fa959
--- /dev/null
+++ b/include/SharcGlsl.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2023-2025, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#if SHARC_ENABLE_GLSL
+
+// Required extensions
+// #extension GL_EXT_buffer_reference : require
+// #extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
+// #extension GL_EXT_shader_atomic_int64 : require
+// #extension GL_KHR_shader_subgroup_ballot : require
+
+// Buffer reference types can be constructed from a 'uint64_t' or a 'uvec2' value.
+// The low - order 32 bits of the reference map to and from the 'x' component
+// of the 'uvec2'.
+
+#define float2 vec2
+#define float3 vec3
+#define float4 vec4
+
+#define uint2 uvec2
+#define uint3 uvec3
+#define uint4 uvec4
+
+#define int2 ivec2
+#define int3 ivec3
+#define int4 ivec4
+
+#define lerp mix
+#define InterlockedAdd atomicAdd
+#define InterlockedCompareExchange atomicCompSwap
+#define WaveActiveCountBits(value) subgroupBallotBitCount(uint4(value, 0, 0, 0))
+#define WaveActiveBallot subgroupBallot
+#define WavePrefixCountBits(value) subgroupBallotExclusiveBitCount(uint4(value, 0, 0, 0))
+
+#define RW_STRUCTURED_BUFFER(name, type) RWStructuredBuffer_##type name
+#define BUFFER_AT_OFFSET(name, offset) name.data[offset]
+
+layout(buffer_reference, std430, buffer_reference_align = 8) buffer RWStructuredBuffer_uint64_t {
+ uint64_t data[];
+};
+
+layout(buffer_reference, std430, buffer_reference_align = 4) buffer RWStructuredBuffer_uint {
+ uint data[];
+};
+
+layout(buffer_reference, std430, buffer_reference_align = 16) buffer RWStructuredBuffer_uint4 {
+ uvec4 data[];
+};
+
+#endif // SHARC_ENABLE_GLSL