16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-22 09:19:18 +02:00

Some renaming

This commit is contained in:
2025-04-15 01:32:56 +02:00
parent 12d6a1578d
commit a39d972126
864 changed files with 29 additions and 34 deletions

View File

@@ -0,0 +1,49 @@
# This file is part of the FidelityFX SDK.
#
# Copyright (C) 2024 Advanced Micro Devices, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files(the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and /or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions :
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
set(CLASSIFIER_BASE_ARGS
-reflection -deps=gcc -DFFX_GPU=1)
set(CLASSIFIER_PERMUTATION_ARGS
-DFFX_CLASSIFIER_OPTION_INVERTED_DEPTH={0,1}
-DFFX_CLASSIFIER_OPTION_CLASSIFIER_MODE={0,1}
)
set(CLASSIFIER_INCLUDE_ARGS
"${FFX_GPU_PATH}"
"${FFX_GPU_PATH}/classifier")
if (NOT CLASSIFIER_SHADER_EXT)
set(CLASSIFIER_SHADER_EXT *)
endif()
file(GLOB CLASSIFIER_SHADERS
"shaders/classifier/ffx_classifier_shadows_pass.${CLASSIFIER_SHADER_EXT}"
"shaders/classifier/ffx_classifier_reflections_pass.${CLASSIFIER_SHADER_EXT}")
compile_shaders_with_depfile(
"${FFX_SC_EXECUTABLE}"
"${CLASSIFIER_BASE_ARGS}" "${CLASSIFIER_API_BASE_ARGS}" "${CLASSIFIER_PERMUTATION_ARGS}" "${CLASSIFIER_INCLUDE_ARGS}"
"${CLASSIFIER_SHADERS}" "${FFX_PASS_SHADER_OUTPUT_PATH}" CLASSIFIER_PERMUTATION_OUTPUTS)
# add the header files they generate to the main list of dependencies
add_shader_output("${CLASSIFIER_PERMUTATION_OUTPUTS}")

View File

@@ -0,0 +1,102 @@
// This file is part of the FidelityFX SDK.
//
// Copyright (C) 2024 Advanced Micro Devices, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#define TILE_SIZE_X 8
#define TILE_SIZE_Y 4
#define k_pushOff 4e-2f
#define k_tileSize FfxUInt32x2(TILE_SIZE_X, TILE_SIZE_Y)
//--------------------------------------------------------------------------------------
// I/O Structures
//--------------------------------------------------------------------------------------
struct Tile
{
#if FFX_HALF
FfxUInt16x2 location;
#else
FfxUInt32x2 location; // Dead code, f32 not supported
#endif
FfxUInt32 mask;
FfxFloat32 minT;
FfxFloat32 maxT;
};
Tile TileCreate(const FfxUInt32x2 id)
{
#if FFX_HALF
FfxUInt16x2 f16ID = FfxUInt16x2(FfxUInt16(id.x), FfxUInt16(id.y));
Tile t = { f16ID, 0, k_pushOff, FFX_POSITIVE_INFINITY_FLOAT }; // skyHeight
#else
Tile t = { id, 0, k_pushOff, FFX_POSITIVE_INFINITY_FLOAT }; //skyHeight
#endif
return t;
}
FfxUInt32x4 TileToUint(const Tile t)
{
const FfxUInt32x4 ui = FfxUInt32x4((FfxUInt32(t.location.y) << 16) | FfxUInt32(t.location.x), t.mask, ffxAsUInt32(t.minT), ffxAsUInt32(t.maxT));
return ui;
}
Tile TileFromUint(const FfxUInt32x4 ui)
{
#if FFX_HALF
FfxUInt16x2 id = FfxUInt16x2(ui.x & 0xffff, (ui.x >> 16) & 0xffff);
#else
FfxUInt32x2 id;
#endif
Tile t = { id, ui.y, ffxAsFloat(ui.z), ffxAsFloat(ui.w) };
return t;
}
//--------------------------------------------------------------------------------------
// helper functions
//--------------------------------------------------------------------------------------
FfxUInt32 LaneIdToBitShift(FfxUInt32x2 localID)
{
return localID.y * TILE_SIZE_X + localID.x;
}
FfxUInt32 BoolToWaveMask(FfxBoolean b, FfxUInt32x2 localID)
{
const FfxUInt32 value = FfxUInt32(b) << LaneIdToBitShift(localID);
return ffxWaveOr(value);
}
FfxBoolean WaveMaskToBool(FfxUInt32 mask, FfxUInt32x2 localID)
{
return FfxBoolean((FfxUInt32(1) << LaneIdToBitShift(localID)) & mask);
}
#define k_pi 3.1415926535897932384f
#define k_2pi 2.0f * k_pi
#define k_pi_over_2 0.5f * k_pi
// made using a modified version of https://www.asawicki.info/news_952_poisson_disc_generator
#define k_poissonDiscSampleCountLow 8
#define k_poissonDiscSampleCountMid 16
#define k_poissonDiscSampleCountHigh 24
#define k_poissonDiscSampleCountUltra 32

View File

@@ -0,0 +1,378 @@
// This file is part of the FidelityFX SDK.
//
// Copyright (C) 2024 Advanced Micro Devices, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#define TILE_CLASS_FULL_SW 0
#define TILE_CLASS_HALF_SW 1
#define TILE_CLASS_FULL_HW 2
#define FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED
#include "ffx_classifier_reflections_common.h"
FfxFloat32x2 Hash22(FfxFloat32x2 p)
{
FfxFloat32x3 p3 = ffxFract(FfxFloat32x3(p.xyx) * FfxFloat32x3(.1031, .1030, .0973));
p3 += dot(p3, p3.yzx + 33.33);
return ffxFract((p3.xx + p3.yz) * p3.zy);
}
FfxFloat32x2 GetRandom(FfxUInt32x2 index)
{
FfxFloat32 v = 0.152f;
FfxFloat32x2 pos = (FfxFloat32x2(index) * v + FfxFloat32(FrameIndex()) / 60.0f * 1500.0f + 50.0f);
return Hash22(pos);
}
FfxFloat32x2 GetRandomLastFrame(FfxUInt32x2 index)
{
FfxFloat32 v = 0.152f;
FfxFloat32x2 pos = (FfxFloat32x2(index) * v + FfxFloat32(FrameIndex() - 1) / 60.0f * 1500.0f + 50.0f);
return Hash22(pos);
}
FfxBoolean IsSW(FfxFloat32 hitcounter, FfxFloat32 misscounter, FfxFloat32 rnd)
{
// Turn a random tile full hybrid once in a while to get the opportunity for testing HiZ traversal
return rnd <= (+HybridSpawnRate() + hitcounter - misscounter * HybridMissWeight());
}
FfxBoolean IsConverged(FfxUInt32x2 pixel_coordinate, FfxFloat32x2 uv)
{
FfxFloat32x2 motion_vector = LoadMotionVector(FfxInt32x2(pixel_coordinate));
;
return SampleVarianceHistory(uv - motion_vector) < VRTVarianceThreshold();
}
// In case no ray is traced we need to clear the buffers
void FillEnvironment(FfxUInt32x2 ray_coord, FfxFloat32 factor)
{
// Fall back to the environment probe
FfxUInt32x2 screen_size = FfxUInt32x2(ReflectionWidth(), ReflectionHeight());
FfxFloat32x2 uv = (ray_coord + 0.5) * InverseRenderSize();
FfxFloat32x3 world_space_normal = LoadWorldSpaceNormal(FfxInt32x2(ray_coord));
FfxFloat32 roughness = LoadRoughnessFromMaterialParametersInput(FfxUInt32x3(ray_coord, 0));
FfxFloat32 z = GetInputDepth(ray_coord);
FfxFloat32x3 screen_uv_space_ray_origin = FfxFloat32x3(uv, z);
FfxFloat32x3 view_space_ray = ScreenSpaceToViewSpace(screen_uv_space_ray_origin);
FfxFloat32x3 view_space_ray_direction = normalize(view_space_ray);
FfxFloat32x3 view_space_surface_normal = FFX_MATRIX_MULTIPLY(ViewMatrix(), FfxFloat32x4(world_space_normal, 0)).xyz;
FfxFloat32x3 view_space_reflected_direction = reflect(view_space_ray_direction, view_space_surface_normal);
FfxFloat32x3 world_space_reflected_direction = FFX_MATRIX_MULTIPLY(InvView(), FfxFloat32x4(view_space_reflected_direction, 0)).xyz;
FfxFloat32x3 world_space_ray_origin = FFX_MATRIX_MULTIPLY(InvView(), FfxFloat32x4(view_space_ray, 1)).xyz;
FfxFloat32x3 env_sample = SampleEnvironmentMap(world_space_reflected_direction, sqrt(roughness));
if (!any(isnan(env_sample)))
StoreRadiance(ray_coord, env_sample.xyzz * factor);
else
StoreRadiance(ray_coord, (0.0f).xxxx);
}
void ZeroBuffers(FfxUInt32x2 dispatch_thread_id)
{
StoreRadiance(dispatch_thread_id, (0.0f).xxxx);
}
FfxFloat32x2 GetSurfaceReprojection(FfxFloat32x2 uv, FfxFloat32x2 motion_vector)
{
// Reflector position reprojection
FfxFloat32x2 history_uv = uv - motion_vector;
return history_uv;
}
FfxBoolean IsBaseRay(FfxUInt32x2 dispatch_thread_id, FfxUInt32 samples_per_quad)
{
switch (samples_per_quad)
{
case 1:
return ((dispatch_thread_id.x & 1) | (dispatch_thread_id.y & 1)) == 0; // Deactivates 3 out of 4 rays
case 2:
return (dispatch_thread_id.x & 1) == (dispatch_thread_id.y & 1); // Deactivates 2 out of 4 rays. Keeps diagonal.
default: // case 4:
return true;
}
}
FFX_GROUPSHARED FfxUInt32 g_TileCount;
FFX_GROUPSHARED FfxInt32 g_TileClass;
FFX_GROUPSHARED FfxUInt32 g_SWCount;
FFX_GROUPSHARED FfxUInt32 g_SWCountTotal;
FFX_GROUPSHARED FfxUInt32 g_base_ray_index_sw;
void ClassifyTiles(FfxUInt32x2 dispatch_thread_id,
FfxUInt32x2 group_thread_id,
FfxFloat32 roughness,
FfxFloat32x3 view_space_surface_normal,
FfxFloat32 depth,
FfxInt32x2 screen_size,
FfxUInt32 samples_per_quad,
FfxBoolean enable_temporal_variance_guided_tracing,
FfxBoolean enable_hitcounter,
FfxBoolean enable_screen_space_tracing,
FfxBoolean enable_hw_ray_tracing)
{
FfxUInt32 flat_group_thread_id = group_thread_id.x + group_thread_id.y * 8;
FfxBoolean is_first_lane_of_wave = ffxWaveIsFirstLane();
if (group_thread_id.x == 0 && group_thread_id.y == 0)
{
// Initialize group shared variables
g_TileCount = 0;
g_SWCount = 0;
g_SWCountTotal = 0;
g_base_ray_index_sw = 0;
#ifdef FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED
// Initialize per 8x8 tile hit counter
if (enable_hitcounter)
{
// In case we do hybrid
if (enable_screen_space_tracing && enable_hw_ray_tracing)
{
// Feedback counters
// See Intersect.hlsl
FfxUInt32 hitcounter = 0;
// Use surface motion vectors of one of the 8x8 pixels in the tile to reproject statistics from the previous frame
// Helps a lot in movement to sustain temoporal coherence
#define FFX_CLASSIFIER_CLASSIFICATION_REPROJECT_HITCOUNTER
#ifdef FFX_CLASSIFIER_CLASSIFICATION_REPROJECT_HITCOUNTER
{
// Grab motion vector from a random point in the subgroup
FfxFloat32x2 xi = GetRandom(dispatch_thread_id.xy / 8);
FfxInt32x2 mix = FfxInt32x2(xi * 8.0f);
FfxFloat32x2 motion_vector = LoadMotionVector(FfxInt32x2(dispatch_thread_id) + mix);
FfxFloat32x2 uv8 = (FfxFloat32x2(dispatch_thread_id.xy + mix)) / FFX_DNSR_Reflections_RoundUp8(screen_size);
FfxFloat32x2 surface_reprojection_uv = GetSurfaceReprojection(uv8, motion_vector);
hitcounter = LoadHitCounterHistory(FfxUInt32x2(surface_reprojection_uv * (FFX_DNSR_Reflections_RoundUp8(screen_size) / 8)));
}
#endif // FFX_CLASSIFIER_CLASSIFICATION_REPROJECT_HITCOUNTER
// Use 3x3 region to grab the biggest success rate and create a safe band of hybrid rays to hide artefacts in movements
#define FFX_CLASSIFIER_CLASSIFICATION_SAFEBAND
#ifdef FFX_CLASSIFIER_CLASSIFICATION_SAFEBAND
FfxUInt32 same_pixel_hitcounter = 0;
// We need a safe band for some geometry not in the BVH to avoid fireflies
const FfxInt32 radius = 1;
for (FfxInt32 y = -radius; y <= radius; y++)
{
for (FfxInt32 x = -radius; x <= radius; x++)
{
FfxUInt32 pt = LoadHitCounterHistory(dispatch_thread_id.xy / 8 + FfxInt32x2(x, y));
if (FFX_Hitcounter_GetSWHits(pt) > FFX_Hitcounter_GetSWHits(same_pixel_hitcounter))
same_pixel_hitcounter = pt;
}
}
#else // FFX_CLASSIFIER_CLASSIFICATION_SAFEBAND
FfxUInt32 same_pixel_hitcounter = LoadHitCounterHistory(dispatch_thread_id.xy / 8);
#endif // FFX_CLASSIFIER_CLASSIFICATION_SAFEBAND
// Again compare with the same pixel and Pick the one with the biggest success rate
if (FFX_Hitcounter_GetSWHits(hitcounter) < FFX_Hitcounter_GetSWHits(same_pixel_hitcounter))
hitcounter = same_pixel_hitcounter;
FfxFloat32 rnd = GetRandom(dispatch_thread_id.xy / 8).x;
FfxFloat32 rnd_last = GetRandomLastFrame(dispatch_thread_id.xy / 8).x;
FfxFloat32 sw_hitcount_new = FfxFloat32(FFX_Hitcounter_GetSWHits(hitcounter));
FfxFloat32 sw_hitcount_old = FfxFloat32(FFX_Hitcounter_GetOldSWHits(hitcounter));
FfxFloat32 sw_misscount_new = FfxFloat32(FFX_Hitcounter_GetSWMisses(hitcounter));
FfxFloat32 sw_misscount_old = FfxFloat32(FFX_Hitcounter_GetOldSWMisses(hitcounter));
FfxBoolean new_class = IsSW(sw_hitcount_new, sw_misscount_new, rnd);
FfxBoolean old_class = IsSW(sw_hitcount_old, sw_misscount_old, rnd_last);
// To make transition less obvious we do and extra checkerboard stage
if (new_class == old_class)
{
if (new_class)
{
g_TileClass = TILE_CLASS_FULL_SW;
}
else
{
g_TileClass = TILE_CLASS_FULL_HW;
}
}
else
{
g_TileClass = TILE_CLASS_HALF_SW;
}
sw_hitcount_old = sw_hitcount_new;
sw_misscount_old = sw_misscount_new;
StoreHitCounter(dispatch_thread_id.xy / 8,
(FfxUInt32(clamp(sw_hitcount_old, 0.0f, 255.0f)) << 8) | (FfxUInt32(clamp(sw_misscount_old, 0.0f, 255.0f)) << 24));
}
}
else
{
g_TileClass = TILE_CLASS_FULL_SW;
}
#endif // FFX_HYBRID_REFLECTIONS
}
FFX_GROUP_MEMORY_BARRIER;
// First we figure out on a per thread basis if we need to shoot a reflection ray
FfxBoolean is_on_screen = (dispatch_thread_id.x < screen_size.x) && (dispatch_thread_id.y < screen_size.y);
// Allow for additional engine side checks. For example engines could additionally only cast reflection rays for specific depth ranges
FfxBoolean is_surface = !IsBackground(depth);
// Don't shoot a ray on very rough surfaces
FfxBoolean is_glossy_reflection = is_surface && IsGlossyReflection(roughness);
FfxBoolean needs_ray = is_on_screen && is_glossy_reflection;
// Decide which ray to keep
FfxBoolean is_base_ray = IsBaseRay(dispatch_thread_id, samples_per_quad);
FfxBoolean is_converged = true;
if (enable_temporal_variance_guided_tracing)
{
FfxFloat32x2 uv = (dispatch_thread_id + 0.5) / screen_size;
is_converged = IsConverged(dispatch_thread_id, uv);
}
needs_ray = needs_ray && (is_base_ray || !is_converged);
// Extra check for back-facing rays, fresnel, mirror etc.
if (abs(view_space_surface_normal.z) > ReflectionsBackfacingThreshold())
{
FillEnvironment(dispatch_thread_id, IBLFactor());
needs_ray = false;
}
// We need denoiser even for mirrors since ssr/hw transition ends up creating poping tile firefies.
FfxBoolean needs_denoiser = is_glossy_reflection;
// Next we have to figure out for which pixels that ray is creating the values for. Thus, if we have to copy its value horizontal, vertical or across.
FfxBoolean require_copy =
!needs_ray && needs_denoiser; // Our pixel only requires a copy if we want to run a denoiser on it but don't want to shoot a ray for it.
FfxBoolean copy_horizontal = FfxBoolean(ffxWaveXorU1(FfxUInt32(require_copy), 1)) && (samples_per_quad != 4) && is_base_ray; // QuadReadAcrossX
FfxBoolean copy_vertical = FfxBoolean(ffxWaveXorU1(FfxUInt32(require_copy), 2)) && (samples_per_quad == 1) && is_base_ray; // QuadReadAcrossY
FfxBoolean copy_diagonal = FfxBoolean(ffxWaveXorU1(FfxUInt32(require_copy), 3)) && (samples_per_quad == 1) && is_base_ray; // QuadReadAcrossDiagonal
FfxBoolean needs_sw_ray = true;
// In case there's only software rays we don't do hybridization
#ifdef FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED
needs_sw_ray = needs_ray && enable_screen_space_tracing;
FfxBoolean needs_hw_ray = false;
if (enable_hw_ray_tracing && roughness < RTRoughnessThreshold())
{
FfxBoolean checkerboard = ((group_thread_id.x ^ group_thread_id.y) & 1) == 0;
needs_sw_ray = needs_sw_ray && ((g_TileClass == TILE_CLASS_FULL_SW ? true : (g_TileClass == TILE_CLASS_HALF_SW ? checkerboard : false)));
needs_hw_ray = needs_ray && !needs_sw_ray;
}
#endif // FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED
FfxUInt32 local_ray_index_in_wave_sw = ffxWavePrefixCountBits(needs_sw_ray);
FfxUInt32 wave_ray_offset_in_group_sw;
FfxUInt32 wave_ray_count_sw = ffxWaveActiveCountBits(needs_sw_ray);
#ifdef FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED
FfxUInt32 local_ray_index_in_wave_hw = ffxWavePrefixCountBits(needs_hw_ray);
FfxUInt32 wave_ray_count_hw = ffxWaveActiveCountBits(needs_hw_ray);
FfxUInt32 base_ray_index_hw = 0;
#endif // FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED
if (is_first_lane_of_wave)
{
if (wave_ray_count_sw > 0)
{
#ifdef FFX_GLSL
wave_ray_offset_in_group_sw = FFX_ATOMIC_ADD(g_SWCount, FfxInt32(wave_ray_count_sw));
#else
InterlockedAdd(g_SWCount, wave_ray_count_sw, wave_ray_offset_in_group_sw);
#endif
}
#ifdef FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED
if (wave_ray_count_hw > 0)
IncrementRayCounterHW(wave_ray_count_hw, base_ray_index_hw);
#endif // FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED
}
base_ray_index_hw = ffxWaveReadLaneFirstU1(base_ray_index_hw);
wave_ray_offset_in_group_sw = ffxWaveReadLaneFirstU1(wave_ray_offset_in_group_sw);
FFX_GROUP_MEMORY_BARRIER;
if (flat_group_thread_id == 0 && g_SWCount > 0)
{
// [IMPORTANT] We need to round up to the multiple of 32 for software rays, because of the atomic increment coalescing optimization
g_SWCountTotal = g_SWCount < 32 ? 32 : (g_SWCount > 32 ? 64 : 32);
IncrementRayCounterSW(g_SWCountTotal, g_base_ray_index_sw);
}
FFX_GROUP_MEMORY_BARRIER;
if (needs_sw_ray)
{
FfxUInt32 ray_index_sw = g_base_ray_index_sw + wave_ray_offset_in_group_sw + local_ray_index_in_wave_sw;
StoreRay(ray_index_sw, dispatch_thread_id, copy_horizontal, copy_vertical, copy_diagonal);
}
#ifdef FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED
else if (needs_hw_ray)
{
FfxUInt32 ray_index_hw = base_ray_index_hw + local_ray_index_in_wave_hw;
StoreRayHW(ray_index_hw, dispatch_thread_id, copy_horizontal, copy_vertical, copy_diagonal);
}
#endif // FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED
if (flat_group_thread_id < g_SWCountTotal - g_SWCount)
{
// [IMPORTANT] We need to round up to the multiple of 32 for software rays, because of the atomic increment coalescing optimization
// Emit helper(dead) lanes to fill up 32 lanes per 8x8 tile
FfxUInt32 ray_index_sw = g_base_ray_index_sw + g_SWCount + flat_group_thread_id;
StoreRaySWHelper(ray_index_sw);
}
// We only need denoiser if we trace any rays in the tile
if (is_first_lane_of_wave && (wave_ray_count_sw > 0
#ifdef FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED
|| wave_ray_count_hw > 0
#endif // FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED
))
{
FFX_ATOMIC_ADD(g_TileCount, 1);
}
FFX_GROUP_MEMORY_BARRIER; // Wait until all waves wrote into g_TileCount
if (g_TileCount > 0)
{
if (group_thread_id.x == 0 && group_thread_id.y == 0)
{
FfxUInt32 tile_index;
IncrementDenoiserTileCounter(tile_index);
StoreDenoiserTile(tile_index, dispatch_thread_id);
}
}
if ((!needs_ray && !require_copy) // Discarded for some reason
|| (needs_ray && !needs_hw_ray && !needs_sw_ray) // Or needs a ray but was discarded for some other reason
)
{
if (is_surface)
{
FillEnvironment(dispatch_thread_id, IBLFactor());
}
else
ZeroBuffers(dispatch_thread_id);
}
}

View File

@@ -0,0 +1,527 @@
// This file is part of the FidelityFX SDK.
//
// Copyright (C) 2024 Advanced Micro Devices, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "ffx_classifier_resources.h"
#if defined(FFX_GPU)
#include "ffx_core.h"
#ifndef FFX_PREFER_WAVE64
#define FFX_PREFER_WAVE64
#endif // #ifndef FFX_PREFER_WAVE64
#if defined(CLASSIFIER_BIND_CB_CLASSIFIER)
layout (set = 0, binding = CLASSIFIER_BIND_CB_CLASSIFIER, std140) uniform cbClassifierReflections_t
{
FfxFloat32Mat4 invViewProjection;
FfxFloat32Mat4 projection;
FfxFloat32Mat4 invProjection;
FfxFloat32Mat4 viewMatrix;
FfxFloat32Mat4 invView;
FfxFloat32Mat4 prevViewProjection;
FfxUInt32x2 renderSize;
FfxFloat32x2 inverseRenderSize;
FfxFloat32 iblFactor;
FfxUInt32 frameIndex;
FfxUInt32 samplesPerQuad;
FfxUInt32 temporalVarianceGuidedTracingEnabled;
FfxFloat32 globalRoughnessThreshold;
FfxFloat32 rtRoughnessThreshold;
FfxUInt32 mask;
FfxUInt32 reflectionWidth;
FfxUInt32 reflectionHeight;
FfxFloat32 hybridMissWeight;
FfxFloat32 hybridSpawnRate;
FfxFloat32 vrtVarianceThreshold;
FfxFloat32 reflectionsBackfacingThreshold;
FfxUInt32 randomSamplesPerPixel;
FfxFloat32x2 motionVectorScale;
FfxFloat32 normalsUnpackMul;
FfxFloat32 normalsUnpackAdd;
FfxUInt32 roughnessChannel;
FfxUInt32 isRoughnessPerceptual;
} cbClassifierReflection;
FfxFloat32Mat4 InvViewProjection()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.invViewProjection;
#else
return FfxFloat32Mat4(0.0f);
#endif
}
FfxFloat32Mat4 Projection()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.projection;
#else
return FfxFloat32Mat4(0.0f);
#endif
}
FfxFloat32Mat4 InvProjection()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.invProjection;
#else
return FfxFloat32Mat4(0.0f);
#endif
}
FfxFloat32Mat4 ViewMatrix()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.viewMatrix;
#else
return FfxFloat32Mat4(0.0f);
#endif
}
FfxFloat32Mat4 InvView()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.invView;
#else
return FfxFloat32Mat4(0.0f);
#endif
}
FfxFloat32Mat4 PrevViewProjection()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.prevViewProjection;
#else
return FfxFloat32Mat4(0.0f);
#endif
}
FfxUInt32x2 RenderSize()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.renderSize;
#else
return FfxUInt32x2(0);
#endif
}
FfxFloat32x2 InverseRenderSize()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.inverseRenderSize;
#else
return FfxFloat32x2(0.0f);
#endif
}
FfxFloat32 IBLFactor()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.iblFactor;
#else
return 0.0f;
#endif
}
FfxUInt32 FrameIndex()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.frameIndex;
#else
return 0;
#endif
}
FfxUInt32 SamplesPerQuad()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.samplesPerQuad;
#else
return 0;
#endif
}
FfxBoolean TemporalVarianceGuidedTracingEnabled()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return FfxBoolean(cbClassifierReflection.temporalVarianceGuidedTracingEnabled);
#else
return false;
#endif
}
FfxFloat32 RoughnessThreshold()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.globalRoughnessThreshold;
#else
return 0.0f;
#endif
}
FfxFloat32 RTRoughnessThreshold()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.rtRoughnessThreshold;
#else
return 0.0f;
#endif
}
FfxUInt32 Mask()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.mask;
#else
return 0;
#endif
}
FfxUInt32 ReflectionWidth()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.reflectionWidth;
#else
return 0;
#endif
}
FfxUInt32 ReflectionHeight()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.reflectionHeight;
#else
return 0;
#endif
}
FfxFloat32 HybridMissWeight()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.hybridMissWeight;
#else
return 0.f;
#endif
}
FfxFloat32 HybridSpawnRate()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.hybridSpawnRate;
#else
return 0.f;
#endif
}
FfxFloat32 VRTVarianceThreshold()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.vrtVarianceThreshold;
#else
return 0.f;
#endif
}
FfxFloat32 ReflectionsBackfacingThreshold()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.reflectionsBackfacingThreshold;
#else
return 0.f;
#endif
}
FfxUInt32 RandomSamplesPerPixel()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.randomSamplesPerPixel;
#else
return 0;
#endif
}
FfxFloat32x2 MotionVectorScale()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.motionVectorScale;
#else
return FfxFloat32x2(0.0f);
#endif
}
FfxFloat32 NormalsUnpackMul()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.normalsUnpackMul;
#else
return 0.0f;
#endif
}
FfxFloat32 NormalsUnpackAdd()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.normalsUnpackAdd;
#else
return 0.0f;
#endif
}
FfxUInt32 RoughnessChannel()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return cbClassifierReflection.roughnessChannel;
#else
return 0;
#endif
}
FfxBoolean IsRoughnessPerceptual()
{
#if defined CLASSIFIER_BIND_CB_CLASSIFIER
return FfxBoolean(cbClassifierReflection.isRoughnessPerceptual);
#else
return false;
#endif
}
#endif // #if defined(CLASSIFIER_BIND_CB_CLASSIFIER)
layout (set = 0, binding = 1000) uniform sampler s_EnvironmentMapSampler;
layout (set = 0, binding = 1001) uniform sampler s_LinearSampler;
// SRVs
#if defined CLASSIFIER_BIND_SRV_INPUT_DEPTH
layout (set = 0, binding = CLASSIFIER_BIND_SRV_INPUT_DEPTH) uniform texture2D r_input_depth;
#endif
#if defined CLASSIFIER_BIND_SRV_INPUT_MOTION_VECTORS
layout (set = 0, binding = CLASSIFIER_BIND_SRV_INPUT_MOTION_VECTORS) uniform texture2D r_input_motion_vectors;
#endif
#if defined CLASSIFIER_BIND_SRV_INPUT_NORMAL
layout (set = 0, binding = CLASSIFIER_BIND_SRV_INPUT_NORMAL) uniform texture2D r_input_normal;
#endif
#if defined CLASSIFIER_BIND_SRV_INPUT_MATERIAL_PARAMETERS
layout (set = 0, binding = CLASSIFIER_BIND_SRV_INPUT_MATERIAL_PARAMETERS) uniform texture2D r_input_material_parameters;
#endif
#if defined CLASSIFIER_BIND_SRV_INPUT_ENVIRONMENT_MAP
layout (set = 0, binding = CLASSIFIER_BIND_SRV_INPUT_ENVIRONMENT_MAP) uniform textureCube r_input_environment_map;
#endif
#if defined CLASSIFIER_BIND_SRV_VARIANCE_HISTORY
layout (set = 0, binding = CLASSIFIER_BIND_SRV_VARIANCE_HISTORY) uniform texture2D r_variance_history;
#endif
#if defined CLASSIFIER_BIND_SRV_HIT_COUNTER_HISTORY
layout(set = 0, binding = CLASSIFIER_BIND_SRV_HIT_COUNTER_HISTORY) uniform utexture2D r_hit_counter_history;
#endif
// UAVs
#if defined CLASSIFIER_BIND_UAV_RADIANCE
layout (set = 0, binding = CLASSIFIER_BIND_UAV_RADIANCE, rgba32f) uniform image2D rw_radiance;
#endif
#if defined CLASSIFIER_BIND_UAV_RAY_LIST
layout (set = 0, binding = CLASSIFIER_BIND_UAV_RAY_LIST, std430) buffer rw_ray_list_t
{
FfxUInt32 data[];
} rw_ray_list;
#endif
#if defined CLASSIFIER_BIND_UAV_HW_RAY_LIST
layout(set = 0, binding = CLASSIFIER_BIND_UAV_HW_RAY_LIST, std430) buffer rw_hw_ray_list_t
{
FfxUInt32 data[];
} rw_hw_ray_list;
#endif
#if defined CLASSIFIER_BIND_UAV_DENOISER_TILE_LIST
layout (set = 0, binding = CLASSIFIER_BIND_UAV_DENOISER_TILE_LIST, std430) buffer rw_denoiser_tile_list_t
{
FfxUInt32 data[];
} rw_denoiser_tile_list;
#endif
#if defined CLASSIFIER_BIND_UAV_RAY_COUNTER
layout (set = 0, binding = CLASSIFIER_BIND_UAV_RAY_COUNTER, std430) buffer rw_ray_counter_t
{
FfxUInt32 data[];
} rw_ray_counter;
#endif
#if defined CLASSIFIER_BIND_UAV_EXTRACTED_ROUGHNESS
layout (set = 0, binding = CLASSIFIER_BIND_UAV_EXTRACTED_ROUGHNESS, r32f) uniform image2D rw_extracted_roughness;
#endif
#if defined CLASSIFIER_BIND_UAV_HIT_COUNTER
layout(set = 0, binding = CLASSIFIER_BIND_UAV_HIT_COUNTER, r32ui) uniform uimage2D rw_hit_counter;
#endif
FfxFloat32x3 LoadWorldSpaceNormal(FfxInt32x2 pixel_coordinate)
{
#if defined(CLASSIFIER_BIND_SRV_INPUT_NORMAL)
return normalize(NormalsUnpackMul() * texelFetch(r_input_normal, pixel_coordinate, 0).xyz + NormalsUnpackAdd());
#else
return FfxFloat32x3(0.f);
#endif
}
FfxFloat32x3 SampleEnvironmentMap(FfxFloat32x3 direction, FfxFloat32 preceptualRoughness)
{
#if defined(CLASSIFIER_BIND_SRV_INPUT_ENVIRONMENT_MAP)
FfxInt32x2 cubeSize = textureSize(r_input_environment_map, 0);
FfxInt32 maxMipLevel = FfxInt32(log2(FfxFloat32(cubeSize.x > 0 ? cubeSize.x : 1)));
FfxFloat32 lod = clamp(preceptualRoughness * FfxFloat32(maxMipLevel), 0.0, FfxFloat32(maxMipLevel));
return textureLod(samplerCube(r_input_environment_map, s_EnvironmentMapSampler), direction, lod).xyz * IBLFactor();
#else
return FfxFloat32x3(0.0f);
#endif
}
void IncrementRayCounterSW(FfxUInt32 value, FFX_PARAMETER_OUT FfxUInt32 original_value)
{
#if defined (CLASSIFIER_BIND_UAV_RAY_COUNTER)
original_value = atomicAdd(rw_ray_counter.data[0], value);
#endif
}
void IncrementRayCounterHW(FfxUInt32 value, FFX_PARAMETER_OUT FfxUInt32 original_value)
{
#if defined (CLASSIFIER_BIND_UAV_RAY_COUNTER)
original_value = atomicAdd(rw_ray_counter.data[4], value);
#endif
}
void IncrementDenoiserTileCounter(FFX_PARAMETER_OUT FfxUInt32 original_value)
{
#if defined (CLASSIFIER_BIND_UAV_RAY_COUNTER)
original_value = atomicAdd(rw_ray_counter.data[2], 1);
#endif
}
FfxUInt32 PackRayCoords(FfxUInt32x2 ray_coord, FfxBoolean copy_horizontal, FfxBoolean copy_vertical, FfxBoolean copy_diagonal)
{
FfxUInt32 ray_x_15bit = ray_coord.x & 32767; // 0b111111111111111
FfxUInt32 ray_y_14bit = ray_coord.y & 16383; // 0b11111111111111;
FfxUInt32 copy_horizontal_1bit = copy_horizontal ? 1 : 0;
FfxUInt32 copy_vertical_1bit = copy_vertical ? 1 : 0;
FfxUInt32 copy_diagonal_1bit = copy_diagonal ? 1 : 0;
FfxUInt32 packed = (copy_diagonal_1bit << 31) | (copy_vertical_1bit << 30) | (copy_horizontal_1bit << 29) | (ray_y_14bit << 15) | (ray_x_15bit << 0);
return packed;
}
void StoreRay(FfxUInt32 index, FfxUInt32x2 ray_coord, FfxBoolean copy_horizontal, FfxBoolean copy_vertical, FfxBoolean copy_diagonal)
{
#if defined (CLASSIFIER_BIND_UAV_RAY_LIST)
FfxUInt32 packedRayCoords = PackRayCoords(ray_coord, copy_horizontal, copy_vertical, copy_diagonal); // Store out pixel to trace
rw_ray_list.data[index] = packedRayCoords;
#endif
}
void StoreRaySWHelper(FfxUInt32 index)
{
#if defined (CLASSIFIER_BIND_UAV_RAY_LIST)
rw_ray_list.data[index] = 0xffffffffu;
#endif
}
void StoreRayHW(FfxUInt32 index, FfxUInt32x2 ray_coord, FfxBoolean copy_horizontal, FfxBoolean copy_vertical, FfxBoolean copy_diagonal)
{
#if defined (CLASSIFIER_BIND_UAV_RAY_LIST)
FfxUInt32 packedRayCoords = PackRayCoords(ray_coord, copy_horizontal, copy_vertical, copy_diagonal); // Store out pixel to trace
rw_hw_ray_list.data[index] = packedRayCoords;
#endif
}
void StoreDenoiserTile(FfxUInt32 index, FfxUInt32x2 tile_coord)
{
#if defined (CLASSIFIER_BIND_UAV_DENOISER_TILE_LIST)
rw_denoiser_tile_list.data[index] = ((tile_coord.y & 0xffffu) << 16) | ((tile_coord.x & 0xffffu) << 0); // Store out pixel to trace
#endif
}
void StoreExtractedRoughness(FfxUInt32x2 coordinate, FfxFloat32 roughness)
{
#if defined (CLASSIFIER_BIND_UAV_EXTRACTED_ROUGHNESS)
imageStore(rw_extracted_roughness, FfxInt32x2(coordinate), FfxFloat32x4(roughness));
#endif
}
FfxFloat32 LoadRoughnessFromMaterialParametersInput(FfxUInt32x3 coordinate)
{
#if defined (CLASSIFIER_BIND_SRV_INPUT_MATERIAL_PARAMETERS)
FfxFloat32 rawRoughness = texelFetch(r_input_material_parameters, FfxInt32x2(coordinate.xy), FfxInt32(coordinate.z))[RoughnessChannel()];
if (IsRoughnessPerceptual())
{
rawRoughness *= rawRoughness;
}
return rawRoughness;
#else
return 0.0f;
#endif
}
FfxFloat32 SampleVarianceHistory(FfxFloat32x2 coordinate) /**/
{
#if defined ( CLASSIFIER_BIND_SRV_VARIANCE_HISTORY )
return FfxFloat32(textureLod(sampler2D(r_variance_history, s_LinearSampler), coordinate, 0.0f).x);
#else
return 0.0;
#endif
}
void StoreRadiance(FfxUInt32x2 coordinate, FfxFloat32x4 radiance)
{
#if defined (CLASSIFIER_BIND_UAV_RADIANCE)
imageStore(rw_radiance, FfxInt32x2(coordinate), radiance);
#endif
}
FfxFloat32 GetInputDepth(FfxUInt32x2 coordinate)
{
#if defined (CLASSIFIER_BIND_SRV_INPUT_DEPTH)
return texelFetch(r_input_depth, FfxInt32x2(coordinate), 0).r;
#else
return 0.0f;
#endif
}
void StoreHitCounter(FfxUInt32x2 coordinate, FfxUInt32 value)
{
#if defined(CLASSIFIER_BIND_UAV_HIT_COUNTER)
imageStore(rw_hit_counter, FfxInt32x2(coordinate), FfxUInt32x4(value));
#endif
}
FfxUInt32 LoadHitCounterHistory(FfxUInt32x2 coordinate)
{
#if defined(CLASSIFIER_BIND_SRV_HIT_COUNTER_HISTORY)
return FfxUInt32(texelFetch(r_hit_counter_history, FfxInt32x2(coordinate), 0).r);
#else
return 0;
#endif
}
FfxFloat32x2 LoadMotionVector(FfxInt32x2 pixel_coordinate)
{
#if defined (CLASSIFIER_BIND_SRV_INPUT_MOTION_VECTORS)
return MotionVectorScale() * texelFetch(r_input_motion_vectors, pixel_coordinate, 0).xy;
#else
return FfxFloat32x2(0.0f);
#endif
}
#endif // #if defined(FFX_GPU)

View File

@@ -0,0 +1,477 @@
// This file is part of the FidelityFX SDK.
//
// Copyright (C) 2024 Advanced Micro Devices, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "ffx_classifier_resources.h"
#if defined(FFX_GPU)
#ifdef __hlsl_dx_compiler
#pragma dxc diagnostic push
#pragma dxc diagnostic ignored "-Wambig-lit-shift"
#endif //__hlsl_dx_compiler
#include "ffx_core.h"
#ifdef __hlsl_dx_compiler
#pragma dxc diagnostic pop
#endif //__hlsl_dx_compiler
#ifndef FFX_PREFER_WAVE64
#define FFX_PREFER_WAVE64
#endif // #ifndef FFX_PREFER_WAVE64
#if defined(FFX_GPU)
#pragma warning(disable: 3205) // conversion from larger type to smaller
#endif // #if defined(FFX_GPU)
#define DECLARE_SRV_REGISTER(regIndex) t##regIndex
#define DECLARE_UAV_REGISTER(regIndex) u##regIndex
#define DECLARE_CB_REGISTER(regIndex) b##regIndex
#define FFX_CLASSIFIER_DECLARE_SRV(regIndex) register(DECLARE_SRV_REGISTER(regIndex))
#define FFX_CLASSIFIER_DECLARE_UAV(regIndex) register(DECLARE_UAV_REGISTER(regIndex))
#define FFX_CLASSIFIER_DECLARE_CB(regIndex) register(DECLARE_CB_REGISTER(regIndex))
#if defined(CLASSIFIER_BIND_CB_CLASSIFIER)
cbuffer cbClassifierReflection : FFX_CLASSIFIER_DECLARE_CB(CLASSIFIER_BIND_CB_CLASSIFIER)
{
FfxFloat32Mat4 invViewProjection;
FfxFloat32Mat4 projection;
FfxFloat32Mat4 invProjection;
FfxFloat32Mat4 viewMatrix;
FfxFloat32Mat4 invView;
FfxFloat32Mat4 prevViewProjection;
FfxUInt32x2 renderSize;
FfxFloat32x2 inverseRenderSize;
FfxFloat32 iblFactor;
FfxUInt32 frameIndex;
FfxUInt32 samplesPerQuad;
FfxUInt32 temporalVarianceGuidedTracingEnabled;
FfxFloat32 globalRoughnessThreshold;
FfxFloat32 rtRoughnessThreshold;
FfxUInt32 mask;
FfxUInt32 reflectionWidth;
FfxUInt32 reflectionHeight;
FfxFloat32 hybridMissWeight;
FfxFloat32 hybridSpawnRate;
FfxFloat32 vrtVarianceThreshold;
FfxFloat32 reflectionsBackfacingThreshold;
FfxUInt32 randomSamplesPerPixel;
FfxFloat32x2 motionVectorScale;
FfxFloat32 normalsUnpackMul;
FfxFloat32 normalsUnpackAdd;
FfxUInt32 roughnessChannel;
FfxUInt32 isRoughnessPerceptual;
#define FFX_CLASSIFIER_CONSTANT_BUFFER_1_SIZE 120
};
#else
#define invViewProjection 0
#define projection 0
#define invProjection 0
#define viewMatrix 0
#define invView 0
#define prevViewProjection 0
#define renderSize 0
#define inverseRenderSize 0
#define iblFactor 0
#define roughnessThreshold 0
#define varianceThreshold 0
#define frameIndex 0
#define samplesPerQuad 0
#define temporalVarianceGuidedTracingEnabled 0
#define globalRoughnessThreshold 0
#define rtRoughnessThreshold 0
#define mask 0
#define reflectionWidth 0
#define reflectionHeight 0
#define hybridMissWeight 0
#define hybridSpawnRate 0
#define vrtVarianceThreshold 0
#define reflectionsBackfacingThreshold 0
#define randomSamplesPerPixel 0
#define motionVectorScale 0
#define normalsUnpackMul 0
#define normalsUnpackAdd 0
#define roughnessChannel 0
#define isRoughnessPerceptual 0
#endif
#if defined(FFX_GPU)
#define FFX_CLASSIFIER_ROOTSIG_STRINGIFY(p) FFX_CLASSIFIER_ROOTSIG_STR(p)
#define FFX_CLASSIFIER_ROOTSIG_STR(p) #p
#define FFX_CLASSIFIER_ROOTSIG [RootSignature("DescriptorTable(UAV(u0, numDescriptors = " FFX_CLASSIFIER_ROOTSIG_STRINGIFY(FFX_CLASSIFIER_RESOURCE_IDENTIFIER_COUNT) ")), " \
"DescriptorTable(SRV(t0, numDescriptors = " FFX_CLASSIFIER_ROOTSIG_STRINGIFY(FFX_CLASSIFIER_RESOURCE_IDENTIFIER_COUNT) ")), " \
"CBV(b0), " \
"StaticSampler(s0, filter = FILTER_MIN_MAG_MIP_LINEAR, " \
"addressU = TEXTURE_ADDRESS_CLAMP, " \
"addressV = TEXTURE_ADDRESS_CLAMP, " \
"addressW = TEXTURE_ADDRESS_WRAP, " \
"comparisonFunc = COMPARISON_ALWAYS, " \
"borderColor = STATIC_BORDER_COLOR_TRANSPARENT_BLACK, " \
"maxAnisotropy = 1), " \
"StaticSampler(s1, filter = FILTER_MIN_MAG_MIP_LINEAR, " \
"addressU = TEXTURE_ADDRESS_CLAMP, " \
"addressV = TEXTURE_ADDRESS_CLAMP, " \
"addressW = TEXTURE_ADDRESS_CLAMP, " \
"comparisonFunc = COMPARISON_ALWAYS, " \
"borderColor = STATIC_BORDER_COLOR_TRANSPARENT_BLACK, " \
"maxAnisotropy = 1)" )]
#if defined(FFX_CLASSIFIER_EMBED_ROOTSIG)
#define FFX_CLASSIFIER_EMBED_ROOTSIG_CONTENT FFX_CLASSIFIER_ROOTSIG
#else
#define FFX_CLASSIFIER_EMBED_ROOTSIG_CONTENT
#endif // #if FFX_CLASSIFIER_EMBED_ROOTSIG
#endif // #if defined(FFX_GPU)
SamplerState s_EnvironmentMapSampler : register(s0);
SamplerState s_LinearSampler : register(s1);
FfxFloat32Mat4 InvViewProjection()
{
return invViewProjection;
}
FfxFloat32Mat4 Projection()
{
return projection;
}
FfxFloat32Mat4 InvProjection()
{
return invProjection;
}
FfxFloat32Mat4 ViewMatrix()
{
return viewMatrix;
}
FfxFloat32Mat4 InvView()
{
return invView;
}
FfxFloat32Mat4 PrevViewProjection()
{
return prevViewProjection;
}
FfxUInt32x2 RenderSize()
{
return renderSize;
}
FfxFloat32x2 InverseRenderSize()
{
return inverseRenderSize;
}
FfxFloat32 IBLFactor()
{
return iblFactor;
}
FfxFloat32 RoughnessThreshold()
{
return globalRoughnessThreshold;
}
FfxUInt32 FrameIndex()
{
return frameIndex;
}
FfxUInt32 SamplesPerQuad()
{
return samplesPerQuad;
}
FfxBoolean TemporalVarianceGuidedTracingEnabled()
{
return FfxBoolean(temporalVarianceGuidedTracingEnabled);
}
FfxFloat32 RTRoughnessThreshold()
{
return rtRoughnessThreshold;
}
FfxUInt32 Mask()
{
return mask;
}
FfxUInt32 ReflectionWidth()
{
return reflectionWidth;
}
FfxUInt32 ReflectionHeight()
{
return reflectionHeight;
}
FfxFloat32 HybridMissWeight()
{
return hybridMissWeight;
}
FfxFloat32 HybridSpawnRate()
{
return hybridSpawnRate;
}
FfxFloat32 VRTVarianceThreshold()
{
return vrtVarianceThreshold;
}
FfxFloat32 ReflectionsBackfacingThreshold()
{
return reflectionsBackfacingThreshold;
}
FfxUInt32 RandomSamplesPerPixel()
{
return randomSamplesPerPixel;
}
FfxFloat32x2 MotionVectorScale()
{
return motionVectorScale;
}
FfxFloat32 NormalsUnpackMul()
{
return normalsUnpackMul;
}
FfxFloat32 NormalsUnpackAdd()
{
return normalsUnpackAdd;
}
FfxUInt32 RoughnessChannel()
{
return roughnessChannel;
}
FfxBoolean IsRoughnessPerceptual()
{
return FfxBoolean(isRoughnessPerceptual);
}
#if defined CLASSIFIER_BIND_SRV_INPUT_DEPTH
Texture2D<FfxFloat32> r_input_depth : FFX_CLASSIFIER_DECLARE_SRV(CLASSIFIER_BIND_SRV_INPUT_DEPTH);
#endif
#if defined CLASSIFIER_BIND_SRV_INPUT_MOTION_VECTORS
Texture2D<FfxFloat32x2> r_input_motion_vectors : FFX_CLASSIFIER_DECLARE_SRV(CLASSIFIER_BIND_SRV_INPUT_MOTION_VECTORS);
#endif
#if defined CLASSIFIER_BIND_SRV_INPUT_NORMAL
Texture2D<FfxFloat32x3> r_input_normal : FFX_CLASSIFIER_DECLARE_SRV(CLASSIFIER_BIND_SRV_INPUT_NORMAL);
#endif
#if defined CLASSIFIER_BIND_SRV_INPUT_MATERIAL_PARAMETERS
Texture2D<FfxFloat32x4> r_input_material_parameters : FFX_CLASSIFIER_DECLARE_SRV(CLASSIFIER_BIND_SRV_INPUT_MATERIAL_PARAMETERS);
#endif
#if defined CLASSIFIER_BIND_SRV_INPUT_ENVIRONMENT_MAP
TextureCube r_input_environment_map : FFX_CLASSIFIER_DECLARE_SRV(CLASSIFIER_BIND_SRV_INPUT_ENVIRONMENT_MAP);
#endif
#if defined CLASSIFIER_BIND_SRV_VARIANCE_HISTORY
Texture2D<FfxFloat32> r_variance_history : FFX_CLASSIFIER_DECLARE_SRV(CLASSIFIER_BIND_SRV_VARIANCE_HISTORY);
#endif
#if defined CLASSIFIER_BIND_SRV_HIT_COUNTER_HISTORY
Texture2D<FfxUInt32> r_hit_counter_history : FFX_CLASSIFIER_DECLARE_SRV(CLASSIFIER_BIND_SRV_HIT_COUNTER_HISTORY);
#endif
// UAVs
#if defined CLASSIFIER_BIND_UAV_RADIANCE
RWTexture2D<FfxFloat32x4> rw_radiance : FFX_CLASSIFIER_DECLARE_UAV(CLASSIFIER_BIND_UAV_RADIANCE);
#endif
#if defined CLASSIFIER_BIND_UAV_RAY_LIST
RWStructuredBuffer<FfxUInt32> rw_ray_list : FFX_CLASSIFIER_DECLARE_UAV(CLASSIFIER_BIND_UAV_RAY_LIST);
#endif
#if defined CLASSIFIER_BIND_UAV_HW_RAY_LIST
RWStructuredBuffer<FfxUInt32> rw_hw_ray_list : FFX_CLASSIFIER_DECLARE_UAV(CLASSIFIER_BIND_UAV_HW_RAY_LIST);
#endif
#if defined CLASSIFIER_BIND_UAV_DENOISER_TILE_LIST
RWStructuredBuffer<FfxUInt32> rw_denoiser_tile_list : FFX_CLASSIFIER_DECLARE_UAV(CLASSIFIER_BIND_UAV_DENOISER_TILE_LIST);
#endif
#if defined CLASSIFIER_BIND_UAV_RAY_COUNTER
globallycoherent RWStructuredBuffer<FfxUInt32> rw_ray_counter : FFX_CLASSIFIER_DECLARE_UAV(CLASSIFIER_BIND_UAV_RAY_COUNTER);
#endif
#if defined CLASSIFIER_BIND_UAV_EXTRACTED_ROUGHNESS
RWTexture2D<FfxFloat32> rw_extracted_roughness : FFX_CLASSIFIER_DECLARE_UAV(CLASSIFIER_BIND_UAV_EXTRACTED_ROUGHNESS);
#endif
#if defined CLASSIFIER_BIND_UAV_HIT_COUNTER
RWTexture2D<FfxUInt32> rw_hit_counter : FFX_CLASSIFIER_DECLARE_UAV(CLASSIFIER_BIND_UAV_HIT_COUNTER);
#endif
#if FFX_HALF
#endif // #if defined(FFX_HALF)
#if defined(CLASSIFIER_BIND_SRV_INPUT_NORMAL)
FfxFloat32x3 LoadWorldSpaceNormal(FfxInt32x2 pixel_coordinate)
{
return normalize(NormalsUnpackMul() * r_input_normal.Load(FfxInt32x3(pixel_coordinate, 0)).xyz + NormalsUnpackAdd());
}
#endif // #if defined(CLASSIFIER_BIND_SRV_INPUT_NORMAL)
#if defined(CLASSIFIER_BIND_SRV_INPUT_ENVIRONMENT_MAP)
FfxFloat32x3 SampleEnvironmentMap(FfxFloat32x3 direction, FfxFloat32 preceptualRoughness)
{
FfxFloat32 Width; FfxFloat32 Height;
r_input_environment_map.GetDimensions(Width, Height);
FfxInt32 maxMipLevel = FfxInt32(log2(FfxFloat32(Width > 0 ? Width : 1)));
FfxFloat32 mip = clamp(preceptualRoughness * FfxFloat32(maxMipLevel), 0.0, FfxFloat32(maxMipLevel));
return r_input_environment_map.SampleLevel(s_EnvironmentMapSampler, direction, mip).xyz * IBLFactor();
}
#endif // #if defined(CLASSIFIER_BIND_SRV_INPUT_ENVIRONMENT_MAP)
#if defined (CLASSIFIER_BIND_UAV_RAY_COUNTER)
void IncrementRayCounterSW(FfxUInt32 value, FFX_PARAMETER_OUT FfxUInt32 original_value)
{
InterlockedAdd(rw_ray_counter[0], value, original_value);
}
#endif // #if defined (CLASSIFIER_BIND_UAV_RAY_COUNTER)
#if defined (CLASSIFIER_BIND_UAV_RAY_COUNTER)
void IncrementRayCounterHW(FfxUInt32 value, FFX_PARAMETER_OUT FfxUInt32 original_value)
{
InterlockedAdd(rw_ray_counter[4], value, original_value);
}
#endif // #if defined (CLASSIFIER_BIND_UAV_RAY_COUNTER)
#if defined (CLASSIFIER_BIND_UAV_RAY_COUNTER)
void IncrementDenoiserTileCounter(FFX_PARAMETER_OUT FfxUInt32 original_value)
{
InterlockedAdd(rw_ray_counter[2], 1, original_value);
}
#endif // #if defined (CLASSIFIER_BIND_UAV_RAY_COUNTER)
FfxUInt32 PackRayCoords(FfxUInt32x2 ray_coord, FfxBoolean copy_horizontal, FfxBoolean copy_vertical, FfxBoolean copy_diagonal)
{
FfxUInt32 ray_x_15bit = ray_coord.x & 32767; // 0b111111111111111
FfxUInt32 ray_y_14bit = ray_coord.y & 16383; // 0b11111111111111;
FfxUInt32 copy_horizontal_1bit = copy_horizontal ? 1 : 0;
FfxUInt32 copy_vertical_1bit = copy_vertical ? 1 : 0;
FfxUInt32 copy_diagonal_1bit = copy_diagonal ? 1 : 0;
FfxUInt32 packed = (copy_diagonal_1bit << 31) | (copy_vertical_1bit << 30) | (copy_horizontal_1bit << 29) | (ray_y_14bit << 15) | (ray_x_15bit << 0);
return packed;
}
#if defined (CLASSIFIER_BIND_UAV_RAY_LIST)
void StoreRay(FfxInt32 index, FfxUInt32x2 ray_coord, FfxBoolean copy_horizontal, FfxBoolean copy_vertical, FfxBoolean copy_diagonal)
{
FfxUInt32 packedRayCoords = PackRayCoords(ray_coord, copy_horizontal, copy_vertical, copy_diagonal); // Store out pixel to trace
rw_ray_list[index] = packedRayCoords;
}
#endif // #if defined (CLASSIFIER_BIND_UAV_RAY_LIST)
#if defined (CLASSIFIER_BIND_UAV_RAY_LIST)
void StoreRaySWHelper(FfxInt32 index)
{
rw_ray_list[index] = 0xffffffffu;
}
#endif // #if defined (CLASSIFIER_BIND_UAV_RAY_LIST)
#if defined (CLASSIFIER_BIND_UAV_HW_RAY_LIST)
void StoreRayHW(FfxInt32 index, FfxUInt32x2 ray_coord, FfxBoolean copy_horizontal, FfxBoolean copy_vertical, FfxBoolean copy_diagonal)
{
FfxUInt32 packedRayCoords = PackRayCoords(ray_coord, copy_horizontal, copy_vertical, copy_diagonal); // Store out pixel to trace
rw_hw_ray_list[index] = packedRayCoords;
}
#endif // #if defined (CLASSIFIER_BIND_UAV_HW_RAY_LIST)
#if defined (CLASSIFIER_BIND_UAV_DENOISER_TILE_LIST)
void StoreDenoiserTile(FfxInt32 index, FfxUInt32x2 tile_coord)
{
rw_denoiser_tile_list[index] = ((tile_coord.y & 0xffffu) << 16) | ((tile_coord.x & 0xffffu) << 0); // Store out pixel to trace
}
#endif // #if defined (CLASSIFIER_BIND_UAV_DENOISER_TILE_LIST)
#if defined (CLASSIFIER_BIND_UAV_EXTRACTED_ROUGHNESS)
void StoreExtractedRoughness(FfxUInt32x2 coordinate, FfxFloat32 roughness)
{
rw_extracted_roughness[coordinate] = roughness;
}
#endif // #if defined (CLASSIFIER_BIND_UAV_EXTRACTED_ROUGHNESS)
#if defined (CLASSIFIER_BIND_SRV_INPUT_MATERIAL_PARAMETERS)
FfxFloat32 LoadRoughnessFromMaterialParametersInput(FfxUInt32x3 coordinate) /**/
{
FfxFloat32 rawRoughness = r_input_material_parameters.Load(coordinate)[RoughnessChannel()];
if (IsRoughnessPerceptual())
{
rawRoughness *= rawRoughness;
}
return rawRoughness;
}
#endif // #if defined (CLASSIFIER_BIND_SRV_INPUT_MATERIAL_PARAMETERS)
#if defined (CLASSIFIER_BIND_SRV_VARIANCE_HISTORY)
FfxFloat32 SampleVarianceHistory(FfxFloat32x2 coordinate)
{
return (FfxFloat32)r_variance_history.SampleLevel(s_LinearSampler, coordinate, 0.0f).x;
}
#endif // #if defined (CLASSIFIER_BIND_SRV_VARIANCE_HISTORY)
#if defined (CLASSIFIER_BIND_UAV_RADIANCE)
void StoreRadiance(FfxUInt32x2 coordinate, FfxFloat32x4 radiance) /**/
{
rw_radiance[coordinate] = radiance;
}
#endif // #if defined (CLASSIFIER_BIND_UAV_RADIANCE)
#if defined (CLASSIFIER_BIND_SRV_INPUT_DEPTH)
FfxFloat32 GetInputDepth(FfxUInt32x2 coordinate)
{
return r_input_depth[coordinate];
}
#endif // #if defined (CLASSIFIER_BIND_SRV_INPUT_DEPTH)
#if defined(CLASSIFIER_BIND_SRV_HIT_COUNTER_HISTORY)
FfxUInt32 LoadHitCounterHistory(FfxUInt32x2 coordinate)
{
return r_hit_counter_history[coordinate];
}
#endif // #if defined(CLASSIFIER_BIND_SRV_HIT_COUNTER_HISTORY)
#if defined(CLASSIFIER_BIND_UAV_HIT_COUNTER)
void StoreHitCounter(FfxUInt32x2 coordinate, FfxUInt32 value)
{
rw_hit_counter[coordinate] = value;
}
#endif // #if defined(CLASSIFIER_BIND_UAV_HIT_COUNTER)
#if defined (CLASSIFIER_BIND_SRV_INPUT_MOTION_VECTORS)
FfxFloat32x2 LoadMotionVector(FfxInt32x2 pixel_coordinate)
{
return MotionVectorScale() * r_input_motion_vectors.Load(FfxInt32x3(pixel_coordinate, 0));
}
#endif // #if defined (CLASSIFIER_BIND_SRV_INPUT_MOTION_VECTORS)
#endif // #if defined(FFX_GPU)

View File

@@ -0,0 +1,118 @@
// This file is part of the FidelityFX SDK.
//
// Copyright (C) 2024 Advanced Micro Devices, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// Use hitcounter feedback
#define FFX_CLASSIFIER_FLAGS_USE_HIT_COUNTER (1 << 0)
// Traverse in screen space
#define FFX_CLASSIFIER_FLAGS_USE_SCREEN_SPACE (1 << 1)
// Traverse using HW ray tracing
#define FFX_CLASSIFIER_FLAGS_USE_RAY_TRACING (1 << 2)
// Iterate BVH to search for the opaque fragment
#define FFX_CLASSIFIER_FLAGS_RESOLVE_TRANSPARENT (1 << 3)
// Grab radiance from screen space shaded image for ray traced intersections, when possible
#define FFX_CLASSIFIER_FLAGS_SHADING_USE_SCREEN (1 << 5)
// defines FFX_HSR_OPTION_SHADING_USE_SCREEN
// Extra flags for debugging
#define FFX_CLASSIFIER_FLAGS_FLAG_0 (1 << 9)
#define FFX_CLASSIFIER_FLAGS_FLAG_1 (1 << 10)
#define FFX_CLASSIFIER_FLAGS_FLAG_2 (1 << 11)
#define FFX_CLASSIFIER_FLAGS_FLAG_3 (1 << 12)
// Visualization tweaking
#define FFX_CLASSIFIER_FLAGS_SHOW_DEBUG_TARGET (1 << 13)
#define FFX_CLASSIFIER_FLAGS_SHOW_INTERSECTION (1 << 14)
#define FFX_CLASSIFIER_FLAGS_SHOW_REFLECTION_TARGET (1 << 15)
#define FFX_CLASSIFIER_FLAGS_APPLY_REFLECTIONS (1 << 16)
#define FFX_CLASSIFIER_FLAGS_INTERSECTION_ACCUMULATE (1 << 17)
#define FFX_CLASSIFIER_FLAGS_VISUALIZE_WAVES (1 << 18)
#define FFX_CLASSIFIER_FLAGS_VISUALIZE_AVG_RADIANCE (1 << 19)
#define FFX_CLASSIFIER_FLAGS_VISUALIZE_VARIANCE (1 << 20)
#define FFX_CLASSIFIER_FLAGS_VISUALIZE_NUM_SAMPLES (1 << 21)
#define FFX_CLASSIFIER_FLAGS_VISUALIZE_RAY_LENGTH (1 << 23)
#define FFX_CLASSIFIER_FLAGS_VISUALIZE_REPROJECTION (1 << 25)
#define FFX_CLASSIFIER_FLAGS_VISUALIZE_TRANSPARENT_QUERY (1 << 26)
#define FFX_CLASSIFIER_FLAGS_VISUALIZE_HIT_COUNTER (1 << 27)
#define FFX_CLASSIFIER_FLAGS_VISUALIZE_PRIMARY_RAYS (1 << 28)
#if defined(FFX_GPU)
#define FFX_REFLECTIONS_SKY_DISTANCE 100.0f
// Helper defines for hitcouter and classification
#define FFX_HITCOUNTER_SW_HIT_FLAG (1u << 0u)
#define FFX_HITCOUNTER_SW_HIT_SHIFT 0u
#define FFX_HITCOUNTER_SW_OLD_HIT_SHIFT 8u
#define FFX_HITCOUNTER_MASK 0xffu
#define FFX_HITCOUNTER_SW_MISS_FLAG (1u << 16u)
#define FFX_HITCOUNTER_SW_MISS_SHIFT 16u
#define FFX_HITCOUNTER_SW_OLD_MISS_SHIFT 24u
#define FFX_Hitcounter_GetSWHits(counter) ((counter >> FFX_HITCOUNTER_SW_HIT_SHIFT) & FFX_HITCOUNTER_MASK)
#define FFX_Hitcounter_GetSWMisses(counter) ((counter >> FFX_HITCOUNTER_SW_MISS_SHIFT) & FFX_HITCOUNTER_MASK)
#define FFX_Hitcounter_GetOldSWHits(counter) ((counter >> FFX_HITCOUNTER_SW_OLD_HIT_SHIFT) & FFX_HITCOUNTER_MASK)
#define FFX_Hitcounter_GetOldSWMisses(counter) ((counter >> FFX_HITCOUNTER_SW_OLD_MISS_SHIFT) & FFX_HITCOUNTER_MASK)
//=== Common functions of the HsrSample ===
void UnpackRayCoords(FfxUInt32 packed, FFX_PARAMETER_OUT FfxUInt32x2 ray_coord, FFX_PARAMETER_OUT FfxBoolean copy_horizontal, FFX_PARAMETER_OUT FfxBoolean copy_vertical, FFX_PARAMETER_OUT FfxBoolean copy_diagonal) {
ray_coord.x = (packed >> 0) & 32767; // 0b111111111111111;
ray_coord.y = (packed >> 15) & 16383; // 0b11111111111111;
copy_horizontal = FfxBoolean((packed >> 29) & 1u);
copy_vertical = FfxBoolean((packed >> 30) & 1u);
copy_diagonal = FfxBoolean((packed >> 31) & 1u);
}
// Mat must be able to transform origin from texture space to a linear space.
FfxFloat32x3 InvProjectPosition(FfxFloat32x3 coord, FfxFloat32Mat4 mat) {
coord.y = (1 - coord.y);
coord.xy = 2 * coord.xy - 1;
FfxFloat32x4 projected = FFX_MATRIX_MULTIPLY(mat, FfxFloat32x4(coord, 1));
projected.xyz /= projected.w;
return projected.xyz;
}
FfxBoolean IsGlossyReflection(FfxFloat32 roughness) {
return roughness < RoughnessThreshold();
}
FfxFloat32x3 ScreenSpaceToViewSpace(FfxFloat32x3 screen_uv_coord) {
return InvProjectPosition(screen_uv_coord, InvProjection());
}
FfxBoolean IsBackground(FfxFloat32 depth)
{
#if FFX_CLASSIFIER_OPTION_INVERTED_DEPTH
return depth < 1.e-6f;
#else
return depth >= (1.0f - 1.e-6f);
#endif
}
// Rounds value to the nearest multiple of 8
FfxUInt32x2 FFX_DNSR_Reflections_RoundUp8(FfxUInt32x2 value) {
FfxUInt32x2 round_down = value & ~7; // 0b111;
return FFX_SELECT((round_down == value), value, value + 8);
}
#endif

View File

@@ -0,0 +1,59 @@
// This file is part of the FidelityFX SDK.
//
// Copyright (C) 2024 Advanced Micro Devices, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef FFX_CLASSIFIER_RESOURCES_H
#define FFX_CLASSIFIER_RESOURCES_H
#if defined(FFX_CPU) || defined(FFX_GPU)
#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_NULL 0
#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_INPUT_DEPTH 1
#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_INPUT_NORMAL 2
#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_WORK_QUEUE 3
#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_OUTPUT_WORK_QUEUE_COUNTER 4
#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_OUTPUT_RAY_HIT 5
#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_INPUT_SHADOW_MAPS 7
#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_INPUT_MOTION_VECTORS 8
#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_INPUT_SPECULAR_ROUGHNESS 9
#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_INPUT_ENVIRONMENT_MAP 10
#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_VARIANCE_HISTORY 11
#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_HIT_COUNTER_HISTORY 12
#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_HIT_COUNTER 13
#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_RAY_LIST 14
#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_HW_RAY_LIST 15
#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_EXTRACTED_ROUGHNESS 16
#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_RAY_COUNTER 17
#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_DENOISER_TILE_LIST 18
#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_DEBUG_IMAGE 19
#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_RADIANCE 20
#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_COUNT 25 // 21 + FFX_CLASSIFIER_MAX_SHADOW_MAP_TEXTURES_COUNT
#if defined(FFX_CLASSIFIER_MAX_SHADOW_MAP_TEXTURES_COUNT)
static_assert(FFX_CLASSIFIER_MAX_SHADOW_MAP_TEXTURES_COUNT == 4,
"This count represents 21 + FFX_CLASSIFIER_MAX_SHADOW_MAP_TEXTURES_COUNT. This assert monitors if MAX_SHADOW_MAP_TEXTURES_COUNT has changed");
#endif // #if defined(FFX_CLASSIFIER_MAX_SHADOW_MAP_TEXTURES_COUNT)
#define FFX_CLASSIFIER_CONSTANTBUFFER_IDENTIFIER_CLASSIFIER 0
#define FFX_CLASSIFIER_CONSTANTBUFFER_IDENTIFIER_REFLECTION 1
#endif // #if defined(FFX_CPU) || defined(FFX_GPU)
#endif //!defined( FFX_CLASSIFIER_RESOURCES_H )

View File

@@ -0,0 +1,221 @@
// This file is part of the FidelityFX SDK.
//
// Copyright (C) 2024 Advanced Micro Devices, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
/// @defgroup FfxGPUClassifier FidelityFX Classifier
/// FidelityFX Classifier GPU documentation
///
/// @ingroup FfxGPUEffects
#include "ffx_classifier_common.h"
struct ClassifyResults
{
FfxBoolean bIsActiveLane;
FfxBoolean bIsInLight;
FfxFloat32 minT;
FfxFloat32 maxT;
};
ClassifyResults FfxClassify(const FfxUInt32x2 pixelCoord,
const FfxBoolean bUseNormal,
const FfxBoolean bUseCascadeBlocking)
{
const FfxBoolean bIsInViewport = all(FFX_LESS_THAN(pixelCoord, TextureSize().xy));
const FfxFloat32 depth = FfxClassifierSampleDepth(pixelCoord);
#if FFX_CLASSIFIER_OPTION_INVERTED_DEPTH
FfxBoolean bIsActiveLane = bIsInViewport && (depth > 0.0f);
#else
FfxBoolean bIsActiveLane = bIsInViewport && (depth < 1.0f);
#endif
FfxBoolean bIsInLight = FFX_FALSE;
FfxFloat32 minT = FFX_POSITIVE_INFINITY_FLOAT;
FfxFloat32 maxT = 0.f;
if (bUseNormal && bIsActiveLane)
{
const FfxFloat32x3 normal = normalize(FfxClassifierSampleNormal(pixelCoord));
const FfxBoolean bIsNormalFacingLight = dot(normal, -LightDir()) > 0;
bIsActiveLane = bIsActiveLane && bIsNormalFacingLight;
}
if (bUseCascadeBlocking && bIsActiveLane)
{
const FfxFloat32x2 uv = pixelCoord * TextureSize().zw;
const FfxFloat32x4 homogeneous = FFX_MATRIX_MULTIPLY(ViewToWorld(), FfxFloat32x4(2.0f * FfxFloat32x2(uv.x, 1.0f - uv.y) - 1.0f, depth, 1));
const FfxFloat32x3 worldPos = homogeneous.xyz / homogeneous.w;
const FfxFloat32x3 lightViewSpacePos = FFX_MATRIX_MULTIPLY(LightView(), FfxFloat32x4(worldPos, 1)).xyz;
FfxBoolean bIsInActiveCascade = FFX_FALSE;
if (bUseCascadeBlocking)
{
const FfxFloat32 radius = SunSizeLightSpace() * lightViewSpacePos.z;
FfxFloat32x3 shadowCoord = FfxFloat32x3(0, 0, 0);
FfxUInt32 cascadeIndex = 0;
for (FfxUInt32 i = 0; i < CascadeCount(); ++i)
{
shadowCoord = lightViewSpacePos * CascadeScale(i).xyz + CascadeOffset(i).xyz;
if (all(FFX_GREATER_THAN(shadowCoord.xy, FfxFloat32x2(0, 0))) && all(FFX_LESS_THAN(shadowCoord.xy, FfxFloat32x2(1, 1))))
{
cascadeIndex = i;
break;
}
}
// grow search area by a pixel to make sure we search a wide enough area
// also scale everything from UV to pixel coord for image loads.
const FfxFloat32x2 radiusCoord = abs(FfxFloat32x2(radius, radius) * CascadeScale(cascadeIndex).xy) * FfxFloat32x2(CascadeSize(), CascadeSize()) + FfxFloat32x2(1,1);
shadowCoord.xy *= CascadeSize();
#if FFX_CLASSIFIER_OPTION_INVERTED_DEPTH
const FfxFloat32 depthCmp = shadowCoord.z + BlockerOffset();
#else
const FfxFloat32 depthCmp = shadowCoord.z - BlockerOffset();
#endif
#if FFX_CLASSIFIER_OPTION_INVERTED_DEPTH
FfxFloat32 maxD = 1;
FfxFloat32 minD = 0;
FfxFloat32 closetDepth = 1;
#else
FfxFloat32 maxD = 0;
FfxFloat32 minD = 1;
FfxFloat32 closetDepth = 0;
#endif
// With small shadow maps we will be bound on filtering since the shadow map can end up completely in LO cache
// using an image load is faster then a sample in RDNA but we will be losing the benefit of doing some of the ALU
// in the filter and getting 4 pixels of data per tap.
for (FfxUInt32 x = 0; x < k_poissonDiscSampleCountHigh; ++x)
{
const FfxFloat32x2 sampleUV = shadowCoord.xy + k_poissonDisc[x] * radiusCoord + 0.5f;
// UV bounds check
if (!(all(FFX_GREATER_THAN_EQUAL(sampleUV.xy, FfxFloat32x2(0, 0))) &&
all(FFX_LESS_THAN(sampleUV.xy, FfxFloat32x2(CascadeSize(), CascadeSize())))))
continue;
const FfxFloat32 pixelDepth = FfxClassifierSampleShadowMap(sampleUV, cascadeIndex);
// using min and max to reduce number of cmps
#if FFX_CLASSIFIER_OPTION_INVERTED_DEPTH
maxD = min(maxD, pixelDepth);
minD = max(minD, pixelDepth);
// need to find closet point in front of the receiver
if (pixelDepth > depthCmp)
{
closetDepth = min(closetDepth, pixelDepth);
}
#else
maxD = max(maxD, pixelDepth);
minD = min(minD, pixelDepth);
// need to find closet point in front of the receiver
if (pixelDepth < depthCmp)
{
closetDepth = max(closetDepth, pixelDepth);
}
#endif
}
#if FFX_CLASSIFIER_OPTION_INVERTED_DEPTH
const FfxBoolean bIsInShadow = (maxD >= depthCmp);
bIsInLight = RejectLitPixels() && (minD <= depthCmp);
#else
const FfxBoolean bIsInShadow = (maxD <= depthCmp);
bIsInLight = RejectLitPixels() && (minD >= depthCmp);
#endif
bIsInActiveCascade = !bIsInShadow && !bIsInLight;
if (bIsInActiveCascade && UseCascadesForRayT())
{
#if FFX_CLASSIFIER_OPTION_INVERTED_DEPTH
const FfxFloat32 viewMinT = abs(min(shadowCoord.z + closetDepth + BlockerOffset(), 0) / CascadeScale(cascadeIndex).z);
const FfxFloat32 viewMaxT = abs((shadowCoord.z + minD - BlockerOffset()) / CascadeScale(cascadeIndex).z);
#else
const FfxFloat32 viewMinT = abs(max(shadowCoord.z - closetDepth - BlockerOffset(), 0) / CascadeScale(cascadeIndex).z);
const FfxFloat32 viewMaxT = abs((shadowCoord.z - minD + BlockerOffset()) / CascadeScale(cascadeIndex).z);
#endif
// if its known that the light view matrix is only a rotation or has uniform scale this can be optimized.
minT = length(FFX_MATRIX_MULTIPLY(InverseLightView(), FfxFloat32x4(0, 0, viewMinT, 0)).xyz);
maxT = length(FFX_MATRIX_MULTIPLY(InverseLightView(), FfxFloat32x4(0, radius, viewMaxT, 0)).xyz);
}
}
bIsActiveLane = bIsActiveLane && bIsInActiveCascade;
}
const ClassifyResults results = { bIsActiveLane, bIsInLight, minT, maxT };
return results;
}
/// Classifier pass entry point.
///
/// @param LocalThreadId The "flattened" index of a thread within a thread group (SV_GroupIndex).
/// @param WorkGroupId Index of the thread group currently executed (SV_GroupID).
/// @ingroup FfxGPUClassifier
void FfxClassifyShadows(FfxUInt32 LocalThreadId, FfxUInt32x3 WorkGroupId)
{
const FfxUInt32x2 localID = ffxRemapForWaveReduction(LocalThreadId);
const FfxUInt32x2 pixelCoord = WorkGroupId.xy * k_tileSize + localID.xy;
#if FFX_CLASSIFIER_OPTION_CLASSIFIER_MODE == 0
ClassifyResults results = FfxClassify(pixelCoord, FFX_TRUE, FFX_FALSE);
#endif
#if FFX_CLASSIFIER_OPTION_CLASSIFIER_MODE == 1
ClassifyResults results = FfxClassify(pixelCoord, FFX_TRUE, FFX_TRUE);
#endif
Tile currentTile = TileCreate(WorkGroupId.xy);
const FfxUInt32 mask = BoolToWaveMask(results.bIsActiveLane, localID);
currentTile.mask = mask;
#if FFX_CLASSIFIER_OPTION_CLASSIFIER_MODE == 1
if (UseCascadesForRayT())
{
// At lest one lane must be active for the tile to be written out, so the infinitly and zero will be emoved by the wave min and max.
// Otherwise we will get minT to be infinite and maxT to be 0
currentTile.minT = max(ffxWaveMin(results.minT), currentTile.minT);
currentTile.maxT = min(ffxWaveMax(results.maxT), currentTile.maxT);
}
#endif
const FfxUInt32 lightMask = BoolToWaveMask(results.bIsInLight, localID);
const FfxBoolean bDiscardTile = (CountBits(mask) <= TileTolerance());
if (LocalThreadId == 0)
{
if (!bDiscardTile)
{
FfxClassifierStoreTile(TileToUint(currentTile));
}
FfxClassifierStoreLightMask(WorkGroupId.xy, lightMask);
}
}

View File

@@ -0,0 +1,287 @@
// This file is part of the FidelityFX SDK.
//
// Copyright (C) 2024 Advanced Micro Devices, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "ffx_classifier_resources.h"
#include "ffx_core.h"
#if defined(FFX_GPU)
const FfxFloat32x2 k_poissonDisc[] = {
FfxFloat32x2(0.640736f, -0.355205f), FfxFloat32x2(-0.725411f, -0.688316f), FfxFloat32x2(-0.185095f, 0.722648f), FfxFloat32x2(0.770596f, 0.637324f),
FfxFloat32x2(-0.921445f, 0.196997f), FfxFloat32x2(0.076571f, -0.98822f), FfxFloat32x2(-0.1348f, -0.0908536f), FfxFloat32x2(0.320109f, 0.257241f),
FfxFloat32x2(0.994021f, 0.109193f), FfxFloat32x2(0.304934f, 0.952374f), FfxFloat32x2(-0.698577f, 0.715535f), FfxFloat32x2(0.548701f, -0.836019f),
FfxFloat32x2(-0.443159f, 0.296121f), FfxFloat32x2(0.15067f, -0.489731f), FfxFloat32x2(-0.623829f, -0.208167f), FfxFloat32x2(-0.294778f, -0.596545f),
FfxFloat32x2(0.334086f, -0.128208f), FfxFloat32x2(-0.0619831f, 0.311747f), FfxFloat32x2(0.166112f, 0.61626f), FfxFloat32x2(-0.289127f, -0.957291f),
FfxFloat32x2(-0.98748f, -0.157745f), FfxFloat32x2(0.637501f, 0.0651571f), FfxFloat32x2(0.971376f, -0.237545f), FfxFloat32x2(-0.0170599f, 0.98059f),
FfxFloat32x2(-0.442564f, 0.896737f), FfxFloat32x2(0.48619f, 0.518723f), FfxFloat32x2(-0.725272f, 0.419965f), FfxFloat32x2(0.781417f, -0.624009f),
FfxFloat32x2(-0.899227f, -0.437482f), FfxFloat32x2(0.769219f, 0.33372f), FfxFloat32x2(-0.414411f, 0.00375378f), FfxFloat32x2(0.262856f, -0.759514f),
};
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
layout (set = 0, binding = FFX_CLASSIFIER_BIND_CB_CLASSIFIER, std140) uniform cbClassifier_t
{
FfxFloat32x4 textureSize;
FfxFloat32x3 lightDir;
FfxFloat32 skyHeight;
FfxFloat32x4 blockerOffset_cascadeSize_sunSizeLightSpace_pad;
FfxUInt32x4 cascadeCount_tileTolerance_pad_pad;
FfxFloat32x4 bRejectLitPixels_bUseCascadesForRayT_normalsUnpackMul_unpackAdd;
FfxFloat32x4 cascadeScale[4];
FfxFloat32x4 cascadeOffset[4];
// Matrices
FfxFloat32Mat4 viewToWorld;
FfxFloat32Mat4 lightView;
FfxFloat32Mat4 inverseLightView;
//#define FFX_CLASSIFIER_CONSTANT_BUFFER_1_SIZE 18 + 2 booleans + 32 + 48// Number of 32-bit values
} cbClassifier;
#endif
FfxFloat32x4 TextureSize()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return cbClassifier.textureSize;
#endif
return FfxFloat32x4(0,0,0,0);
}
FfxFloat32x3 LightDir()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return cbClassifier.lightDir;
#endif
return FfxFloat32x3(0, 0, 0);
}
FfxFloat32 SkyHeight()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return cbClassifier.skyHeight;
#endif
return FfxFloat32(0);
}
FfxUInt32 CascadeCount()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return cbClassifier.cascadeCount_tileTolerance_pad_pad[0];
#endif
return 0;
}
FfxUInt32 TileTolerance()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return cbClassifier.cascadeCount_tileTolerance_pad_pad[1];
#endif
return 0;
}
FfxFloat32 BlockerOffset()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return cbClassifier.blockerOffset_cascadeSize_sunSizeLightSpace_pad[0];
#endif
return 0;
}
FfxFloat32 CascadeSize()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return cbClassifier.blockerOffset_cascadeSize_sunSizeLightSpace_pad[1];
#endif
return 0;
}
FfxFloat32 SunSizeLightSpace()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return cbClassifier.blockerOffset_cascadeSize_sunSizeLightSpace_pad[2];
#endif
return 0;
}
FfxBoolean RejectLitPixels()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return FfxBoolean(cbClassifier.bRejectLitPixels_bUseCascadesForRayT_normalsUnpackMul_unpackAdd[0]);
#endif
return false;
}
FfxBoolean UseCascadesForRayT()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return FfxBoolean(cbClassifier.bRejectLitPixels_bUseCascadesForRayT_normalsUnpackMul_unpackAdd[1]);
#endif
return false;
}
FfxFloat32 NormalsUnpackMul()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return cbClassifier.bRejectLitPixels_bUseCascadesForRayT_normalsUnpackMul_unpackAdd[2];
#else
return 0;
#endif
}
FfxFloat32 NormalsUnpackAdd()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return cbClassifier.bRejectLitPixels_bUseCascadesForRayT_normalsUnpackMul_unpackAdd[3];
#else
return 0;
#endif
}
FfxFloat32x4 CascadeScale(FfxUInt32 index)
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return cbClassifier.cascadeScale[index];
#else
return FfxFloat32x4(0,0,0,0);
#endif
}
FfxFloat32x4 CascadeOffset(FfxUInt32 index)
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return cbClassifier.cascadeOffset[index];
#else
return FfxFloat32x4(0,0,0,0);
#endif
}
FfxFloat32Mat4 ViewToWorld()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return cbClassifier.viewToWorld;
#endif
return FfxFloat32Mat4(0);
}
FfxFloat32Mat4 LightView()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return cbClassifier.lightView;
#endif
return FfxFloat32Mat4(0);
}
FfxFloat32Mat4 InverseLightView()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return cbClassifier.inverseLightView;
#endif
return FfxFloat32Mat4(0);
}
// SRVs
#if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_DEPTH)
layout (set = 0, binding = FFX_CLASSIFIER_BIND_SRV_INPUT_DEPTH)
uniform texture2D r_input_depth;
#endif
#if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_NORMALS)
layout (set = 0, binding = FFX_CLASSIFIER_BIND_SRV_INPUT_NORMALS)
uniform texture2D r_input_normal;
#endif
#if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_SHADOW_MAPS)
layout (set = 0, binding = FFX_CLASSIFIER_BIND_SRV_INPUT_SHADOW_MAPS)
uniform texture2D r_input_shadowMap[4];
#endif
// UAVs
#if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES)
layout (set = 0, binding = FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES, std430)
buffer rwsb_tiles_t
{
FfxUInt32x4 data[];
} rwsb_tiles;
#endif
#if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES_COUNT)
layout (set = 0, binding = FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES_COUNT, std430)
coherent buffer rwb_tileCount_t
{
FfxUInt32 data[];
} rwb_tileCount;
#endif
#if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_RAY_HIT)
layout (set = 0, binding = FFX_CLASSIFIER_BIND_UAV_OUTPUT_RAY_HIT, r32ui)
uniform uimage2D rwt2d_rayHitResults;
#endif
#if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_TEXTURE)
layout (set = 0, binding = FFX_CLASSIFIER_BIND_UAV_OUTPUT_TEXTURE, rgba32f)
uniform image2D rwt2d_output;
#endif
FfxFloat32 FfxClassifierSampleDepth(FfxUInt32x2 uiPxPos)
{
#if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_DEPTH)
return texelFetch(r_input_depth, ivec2(uiPxPos), 0).r;
#else
return 0.0;
#endif // defined(FFX_CLASSIFIER_BIND_SRV_INPUT_DEPTH)
}
#if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_NORMALS)
FfxFloat32x3 FfxClassifierSampleNormal(FfxUInt32x2 uiPxPos)
{
FfxFloat32x3 normal = texelFetch(r_input_normal, ivec2(uiPxPos), 0).rgb;
normal = normal * NormalsUnpackMul().xxx + NormalsUnpackAdd().xxx;
return normalize(normal);
}
#endif // #if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_NORMALS)
#if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_SHADOW_MAPS)
FfxFloat32 FfxClassifierSampleShadowMap(FfxFloat32x2 sampleUV, FfxUInt32 cascadeIndex)
{
nonuniformEXT FfxUInt32 nonUniformCascadeIndex = cascadeIndex;
return texelFetch(r_input_shadowMap[nonUniformCascadeIndex], ivec2(sampleUV), 0).r;
}
#endif // #if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_SHADOW_MAPS)
#if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_RAY_HIT)
void FfxClassifierStoreLightMask(FfxUInt32x2 index, FfxUInt32 lightMask)
{
imageStore(rwt2d_rayHitResults, ivec2(index), FfxUInt32x4(~lightMask, 0,0,0));
}
#endif // #if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_RAY_HIT)
FfxUInt32 CountBits(const FfxUInt32 mask)
{
return bitCount(mask);
}
#if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES) || defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES_COUNT)
void FfxClassifierStoreTile(FfxUInt32x4 uiTile)
{
uint index = ~0;
index = atomicAdd(rwb_tileCount.data[0], 1);
rwsb_tiles.data[index] = uiTile;
}
#endif // #if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES) || defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES_COUNT)
#endif // #if defined(FFX_GPU)

View File

@@ -0,0 +1,311 @@
// This file is part of the FidelityFX SDK.
//
// Copyright (C) 2024 Advanced Micro Devices, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "ffx_classifier_resources.h"
#if defined(FFX_GPU)
#ifdef __hlsl_dx_compiler
#pragma dxc diagnostic push
#pragma dxc diagnostic ignored "-Wambig-lit-shift"
#endif //__hlsl_dx_compiler
#include "ffx_core.h"
#ifdef __hlsl_dx_compiler
#pragma dxc diagnostic pop
#endif //__hlsl_dx_compiler
#ifndef FFX_PREFER_WAVE64
#define FFX_PREFER_WAVE64
#endif // #ifndef FFX_PREFER_WAVE64
static const FfxFloat32x2 k_poissonDisc[] = {
FfxFloat32x2(0.640736f, -0.355205f), FfxFloat32x2(-0.725411f, -0.688316f), FfxFloat32x2(-0.185095f, 0.722648f), FfxFloat32x2(0.770596f, 0.637324f),
FfxFloat32x2(-0.921445f, 0.196997f), FfxFloat32x2(0.076571f, -0.98822f), FfxFloat32x2(-0.1348f, -0.0908536f), FfxFloat32x2(0.320109f, 0.257241f),
FfxFloat32x2(0.994021f, 0.109193f), FfxFloat32x2(0.304934f, 0.952374f), FfxFloat32x2(-0.698577f, 0.715535f), FfxFloat32x2(0.548701f, -0.836019f),
FfxFloat32x2(-0.443159f, 0.296121f), FfxFloat32x2(0.15067f, -0.489731f), FfxFloat32x2(-0.623829f, -0.208167f), FfxFloat32x2(-0.294778f, -0.596545f),
FfxFloat32x2(0.334086f, -0.128208f), FfxFloat32x2(-0.0619831f, 0.311747f), FfxFloat32x2(0.166112f, 0.61626f), FfxFloat32x2(-0.289127f, -0.957291f),
FfxFloat32x2(-0.98748f, -0.157745f), FfxFloat32x2(0.637501f, 0.0651571f), FfxFloat32x2(0.971376f, -0.237545f), FfxFloat32x2(-0.0170599f, 0.98059f),
FfxFloat32x2(-0.442564f, 0.896737f), FfxFloat32x2(0.48619f, 0.518723f), FfxFloat32x2(-0.725272f, 0.419965f), FfxFloat32x2(0.781417f, -0.624009f),
FfxFloat32x2(-0.899227f, -0.437482f), FfxFloat32x2(0.769219f, 0.33372f), FfxFloat32x2(-0.414411f, 0.00375378f), FfxFloat32x2(0.262856f, -0.759514f),
};
#pragma warning(disable: 3205) // conversion from larger type to smaller
#define DECLARE_SRV_REGISTER(regIndex) t##regIndex
#define DECLARE_UAV_REGISTER(regIndex) u##regIndex
#define DECLARE_CB_REGISTER(regIndex) b##regIndex
#define FFX_CLASSIFIER_DECLARE_SRV(regIndex) register(DECLARE_SRV_REGISTER(regIndex))
#define FFX_CLASSIFIER_DECLARE_UAV(regIndex) register(DECLARE_UAV_REGISTER(regIndex))
#define FFX_CLASSIFIER_DECLARE_CB(regIndex) register(DECLARE_CB_REGISTER(regIndex))
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
cbuffer cbClassifier : FFX_CLASSIFIER_DECLARE_CB(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
{
FfxFloat32x4 textureSize;
FfxFloat32x3 lightDir;
FfxFloat32 skyHeight;
FfxFloat32x4 blockerOffset_cascadeSize_sunSizeLightSpace_pad;
FfxUInt32x4 cascadeCount_tileTolerance_pad_pad;
FfxFloat32x4 bRejectLitPixels_bUseCascadesForRayT_normalsUnpackMul_unpackAdd;
FfxFloat32x4 cascadeScale[4];
FfxFloat32x4 cascadeOffset[4];
// Matrices
FfxFloat32Mat4 viewToWorld;
FfxFloat32Mat4 lightView;
FfxFloat32Mat4 inverseLightView;
#define FFX_CLASSIFIER_CONSTANT_BUFFER_1_SIZE 100
};
#endif
#define FFX_CLASSIFIER_ROOTSIG_STRINGIFY(p) FFX_CLASSIFIER_ROOTSIG_STR(p)
#define FFX_CLASSIFIER_ROOTSIG_STR(p) #p
#define FFX_CLASSIFIER_ROOTSIG [RootSignature( "DescriptorTable(UAV(u0, numDescriptors = " FFX_CLASSIFIER_ROOTSIG_STRINGIFY(FFX_CLASSIFIER_RESOURCE_IDENTIFIER_COUNT) ")), " \
"DescriptorTable(SRV(t0, numDescriptors = " FFX_CLASSIFIER_ROOTSIG_STRINGIFY(FFX_CLASSIFIER_RESOURCE_IDENTIFIER_COUNT) ")), " \
"CBV(b0), " \
"StaticSampler(s0, filter = FILTER_MIN_MAG_MIP_LINEAR, " \
"addressU = TEXTURE_ADDRESS_CLAMP, " \
"addressV = TEXTURE_ADDRESS_CLAMP, " \
"addressW = TEXTURE_ADDRESS_CLAMP, " \
"comparisonFunc = COMPARISON_NEVER, " \
"borderColor = STATIC_BORDER_COLOR_TRANSPARENT_BLACK)" )]
#if defined(FFX_CLASSIFIER_EMBED_ROOTSIG)
#define FFX_CLASSIFIER_EMBED_ROOTSIG_CONTENT FFX_CLASSIFIER_ROOTSIG
#else
#define FFX_CLASSIFIER_EMBED_ROOTSIG_CONTENT
#endif // #if FFX_CLASSIFIER_EMBED_ROOTSIG
FfxFloat32x4 TextureSize()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return textureSize;
#endif
return FfxFloat32x4(0, 0, 0, 0);
}
FfxFloat32x3 LightDir()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return lightDir;
#endif
return FfxFloat32x3(0, 0, 0);
}
FfxFloat32 SkyHeight()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return skyHeight;
#endif
return 0;
}
FfxUInt32 CascadeCount()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return cascadeCount_tileTolerance_pad_pad[0];
#endif
return 0;
}
FfxUInt32 TileTolerance()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return cascadeCount_tileTolerance_pad_pad[1];
#endif
return 0;
}
FfxFloat32 BlockerOffset()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return blockerOffset_cascadeSize_sunSizeLightSpace_pad[0];
#endif
return 0;
}
FfxFloat32 CascadeSize()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return blockerOffset_cascadeSize_sunSizeLightSpace_pad[1];
#endif
return 0;
}
FfxFloat32 SunSizeLightSpace()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return blockerOffset_cascadeSize_sunSizeLightSpace_pad[2];
#endif
return 0;
}
FfxBoolean RejectLitPixels()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return bRejectLitPixels_bUseCascadesForRayT_normalsUnpackMul_unpackAdd[0];
#endif
return false;
}
FfxBoolean UseCascadesForRayT()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return bRejectLitPixels_bUseCascadesForRayT_normalsUnpackMul_unpackAdd[1];
#endif
return false;
}
FfxFloat32 NormalsUnpackMul()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return bRejectLitPixels_bUseCascadesForRayT_normalsUnpackMul_unpackAdd[2];
#else
return 0;
#endif
}
FfxFloat32 NormalsUnpackAdd()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return bRejectLitPixels_bUseCascadesForRayT_normalsUnpackMul_unpackAdd[3];
#else
return 0;
#endif
}
FfxFloat32x4 CascadeScale(int index)
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return cascadeScale[index];
#else
return FfxFloat32x4(0,0,0,0);
#endif
}
FfxFloat32x4 CascadeOffset(int index)
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return cascadeOffset[index];
#else
return FfxFloat32x4(0,0,0,0);
#endif
}
FfxFloat32Mat4 ViewToWorld()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return viewToWorld;
#endif
return 0;
}
FfxFloat32Mat4 LightView()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return lightView;
#endif
return 0;
}
FfxFloat32Mat4 InverseLightView()
{
#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER)
return inverseLightView;
#endif
return 0;
}
// SRVs
#if defined FFX_CLASSIFIER_BIND_SRV_INPUT_DEPTH
Texture2D<FfxFloat32x4> r_input_depth : FFX_CLASSIFIER_DECLARE_SRV(FFX_CLASSIFIER_RESOURCE_IDENTIFIER_INPUT_DEPTH);
#endif
#if defined FFX_CLASSIFIER_BIND_SRV_INPUT_NORMALS
Texture2D<FfxFloat32x4> r_input_normal : FFX_CLASSIFIER_DECLARE_SRV(FFX_CLASSIFIER_RESOURCE_IDENTIFIER_INPUT_NORMAL);
#endif
#if defined FFX_CLASSIFIER_BIND_SRV_INPUT_SHADOW_MAPS
Texture2D<FfxFloat32> r_input_shadowMap[4] : FFX_CLASSIFIER_DECLARE_SRV(FFX_CLASSIFIER_RESOURCE_IDENTIFIER_INPUT_SHADOW_MAPS);
#endif
// UAVs
#if defined FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES
RWStructuredBuffer<FfxUInt32x4> rwsb_tiles : FFX_CLASSIFIER_DECLARE_UAV(FFX_CLASSIFIER_RESOURCE_IDENTIFIER_WORK_QUEUE);
#endif
#if defined FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES_COUNT
globallycoherent RWStructuredBuffer<FfxUInt32> rwb_tileCount : FFX_CLASSIFIER_DECLARE_UAV(FFX_CLASSIFIER_RESOURCE_IDENTIFIER_OUTPUT_WORK_QUEUE_COUNTER);
#endif
#if defined FFX_CLASSIFIER_BIND_UAV_OUTPUT_RAY_HIT
RWTexture2D<FfxUInt32> rwt2d_rayHitResults : FFX_CLASSIFIER_DECLARE_UAV(FFX_CLASSIFIER_RESOURCE_IDENTIFIER_OUTPUT_RAY_HIT);
#endif
#if defined FFX_CLASSIFIER_BIND_UAV_OUTPUT_TEXTURE
RWTexture2D<FfxFloat32x4> rwt2d_output : FFX_CLASSIFIER_DECLARE_UAV(FFX_CLASSIFIER_RESOURCE_IDENTIFIER_OUTPUT_COLOR);
#endif
#if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_DEPTH)
FfxFloat32 FfxClassifierSampleDepth(FfxUInt32x2 uiPxPos)
{
return r_input_depth[uiPxPos].r;
}
#endif // #if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_DEPTH)
#if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_NORMALS)
FfxFloat32x3 FfxClassifierSampleNormal(FfxUInt32x2 uiPxPos)
{
FfxFloat32x3 normal = r_input_normal[uiPxPos].rgb;
normal = normal * NormalsUnpackMul().xxx + NormalsUnpackAdd().xxx;
return normalize(normal);
}
#endif // #if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_NORMALS)
#if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_SHADOW_MAPS)
FfxFloat32 FfxClassifierSampleShadowMap(FfxFloat32x2 sampleUV, FfxUInt32 cascadeIndex)
{
return r_input_shadowMap[NonUniformResourceIndex(cascadeIndex)][FfxUInt32x2(sampleUV)];
}
#endif // #if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_SHADOW_MAPS)
#if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_RAY_HIT)
void FfxClassifierStoreLightMask(FfxUInt32x2 index, FfxUInt32 lightMask)
{
rwt2d_rayHitResults[index] = ~lightMask;
}
#endif // #if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_RAY_HIT)
FfxUInt32 CountBits(const FfxUInt32 mask)
{
return countbits(mask);
}
#if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES) || defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES_COUNT)
void FfxClassifierStoreTile(FfxUInt32x4 uiTile)
{
uint index = ~0;
InterlockedAdd(rwb_tileCount[0], 1, index);
rwsb_tiles[index] = uiTile;
}
#endif // #if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES) || defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES_COUNT)
#endif // #if defined(FFX_GPU)