Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
31e050d
perf: use ps for deferred
doodlum Apr 18, 2026
d5b8c04
perf: more optimisations
doodlum Apr 18, 2026
1944cd7
chore: delete cs shader
doodlum Apr 18, 2026
1f6e17e
perf: more optimisations
doodlum Apr 19, 2026
6fa9405
style: 🎨 apply pre-commit.ci formatting
pre-commit-ci[bot] Apr 19, 2026
80a7d1f
refactor: clean up bindings
doodlum Apr 19, 2026
1334849
Merge branch 'ps-opt' of https://github.com/doodlum/skyrim-community-…
doodlum Apr 19, 2026
01d90aa
Merge branch 'dev' into ps-opt
doodlum Apr 19, 2026
53c6593
Merge branch 'ps-opt' of https://github.com/doodlum/skyrim-community-…
doodlum Apr 19, 2026
ec4ffb5
chore: clanker changes
doodlum Apr 19, 2026
866ca15
refactor: dont use half
doodlum Apr 19, 2026
e978647
style: 🎨 apply pre-commit.ci formatting
pre-commit-ci[bot] Apr 19, 2026
5d024b4
perf: remove normalroughness entirely
doodlum Apr 19, 2026
751fcbd
Merge branch 'ps-opt' of https://github.com/doodlum/skyrim-community-…
doodlum Apr 19, 2026
be1f481
fix: fix normals
doodlum Apr 19, 2026
d50e3dc
perf: ignore sky
doodlum Apr 19, 2026
4ca2a78
fix: fix normal srv
doodlum Apr 19, 2026
dbd478c
style: 🎨 apply pre-commit.ci formatting
pre-commit-ci[bot] Apr 19, 2026
2a0b214
fix: fix test failure due to view space normal
doodlum Apr 19, 2026
4ecf278
style: 🎨 apply pre-commit.ci formatting
pre-commit-ci[bot] Apr 19, 2026
73a2b64
chore: ignore gs
doodlum Apr 19, 2026
d96e1df
Merge branch 'ps-opt' of https://github.com/doodlum/skyrim-community-…
doodlum Apr 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions features/IBL/Shaders/IBL/IBL.hlsli
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
namespace ImageBasedLighting
{
#if defined(IBL_DEFERRED)
Texture2D<sh2> EnvIBLTexture : register(t14);
Texture2D<sh2> SkyIBLTexture : register(t15);
Texture2D<sh2> EnvIBLTexture : register(t15);
Texture2D<sh2> SkyIBLTexture : register(t16);
#else
Texture2D<sh2> EnvIBLTexture : register(t76);
Texture2D<sh2> SkyIBLTexture : register(t77);
Expand Down
38 changes: 11 additions & 27 deletions package/Shaders/Common/GBuffer.hlsli
Original file line number Diff line number Diff line change
@@ -1,40 +1,24 @@
#ifndef __GBUFFER_DEPENDENCY_HLSL__
#define __GBUFFER_DEPENDENCY_HLSL__

// https://knarkowicz.wordpress.com/2014/04/16/octahedron-normal-vector-encoding/

namespace GBuffer
{

half2 OctWrap(half2 v)
float2 EncodeNormal(float3 n)
{
return (1.0h - abs(v.yx)) * (v.xy >= 0.0h ? 1.0h : -1.0h);
}

half2 EncodeNormal(half3 n)
{
n = -n;
n /= (abs(n.x) + abs(n.y) + abs(n.z));
n.xy = n.z >= 0.0h ? n.xy : OctWrap(n.xy);
n.xy = n.xy * 0.5h + 0.5h;
return n.xy;
}

half3 DecodeNormal(half2 f)
{
f = f * 2.0h - 1.0h;
// https://twitter.com/Stubbesaurus/status/937994790553227264
half3 n = half3(f.x, f.y, 1.0h - abs(f.x) - abs(f.y));
half t = saturate(-n.z);
n.xy += n.xy >= 0.0h ? -t : t;
return -normalize(n);
n.z = max(0.001, sqrt(8.0 - 8.0 * n.z));
n.xy /= n.z;
return n.xy + 0.5;
}

half2 EncodeNormalVanilla(half3 n)
float3 DecodeNormal(float2 enc)
{
n.z = max(1.0h / 1000.0h, sqrt(8.0h + -8.0h * n.z));
n.xy /= n.z;
return n.xy + 0.5h;
float2 fenc = enc * 4.0 - 2.0;
float f = dot(fenc, fenc);
float3 n;
n.xy = fenc * sqrt(1.0 - f / 4.0);
n.z = f / 2.0 - 1.0;
return n;
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,50 @@
#include "Common/Color.hlsli"
#include "Common/FrameBuffer.hlsli"
#include "Common/GBuffer.hlsli"
#include "Common/MotionBlur.hlsli"
#include "Common/Shading.hlsli"
#include "Common/SharedData.hlsli"
#include "Common/Spherical Harmonics/SphericalHarmonics.hlsli"
#include "Common/VR.hlsli"

Texture2D<float3> SpecularTexture : register(t0);
Texture2D<unorm float3> AlbedoTexture : register(t1);
Texture2D<float4> MainInputTexture : register(t0);
Texture2D<float3> SpecularTexture : register(t1);

#if defined(SSGI) || defined(DYNAMIC_CUBEMAPS) || defined(DEBUG)
Texture2D<unorm float3> NormalRoughnessTexture : register(t2);
Texture2D<float3> MasksTexture : register(t3);
#endif

RWTexture2D<float4> MainRW : register(u0);
RWTexture2D<float4> NormalTAAMaskSpecularMaskRW : register(u1);
RWTexture2D<float2> MotionVectorsRW : register(u2);
Texture2D<float> DepthTexture : register(t4);
#if defined(SSGI) || defined(DYNAMIC_CUBEMAPS)
Texture2D<float> DepthTexture : register(t3);
#endif

#if defined(SSGI) || defined(DEBUG)
Texture2D<unorm float3> AlbedoTexture : register(t4);
#endif

#if defined(VR_STEREO_OPT)
# include "VRStereoOptimizations/modes.hlsli"
Texture2D<uint> StereoOptModeTexture : register(t16);
#if defined(SSGI)
Texture2D<float3> MasksTexture : register(t5);
#endif

#if defined(DYNAMIC_CUBEMAPS)
Texture2D<float3> ReflectanceTexture : register(t5);
TextureCube<float3> EnvTexture : register(t6);
TextureCube<float3> EnvReflectionsTexture : register(t7);
Texture2D<float3> ReflectanceTexture : register(t6);
TextureCube<float3> EnvTexture : register(t7);
TextureCube<float3> EnvReflectionsTexture : register(t8);

SamplerState LinearSampler : register(s0);
#endif

#if defined(SKYLIGHTING)
# include "Skylighting/Skylighting.hlsli"

Texture3D<sh2> SkylightingProbeArray : register(t8);
Texture2DArray<float3> stbn_vec3_2Dx1D_128x128x64 : register(t9);

Texture3D<sh2> SkylightingProbeArray : register(t9);
Texture2DArray<float3> stbn_vec3_2Dx1D_128x128x64 : register(t10);
#endif

#if defined(SSGI)
Texture2D<float4> SsgiAoTexture : register(t10);
Texture2D<float4> SsgiYTexture : register(t11);
Texture2D<float4> SsgiCoCgTexture : register(t12);
Texture2D<float4> SsgiSpecularTexture : register(t13);
Texture2D<float4> SsgiAoTexture : register(t11);
Texture2D<float4> SsgiYTexture : register(t12);
Texture2D<float4> SsgiCoCgTexture : register(t13);
Texture2D<float4> SsgiSpecularTexture : register(t14);

void SampleSSGI(uint2 pixCoord, float3 normalWS, out float ao, out float3 il)
{
Expand Down Expand Up @@ -88,52 +90,54 @@ void SampleSSGISpecular(uint2 pixCoord, sh2 lobe, inout float ao, out float3 il,
# endif
#endif

[numthreads(8, 8, 1)] void main(uint3 dispatchID : SV_DispatchThreadID) {
// Early exit if dispatch thread is outside screen bounds
if (any(dispatchID.xy >= uint2(SharedData::BufferDim.xy)))
return;
struct PS_INPUT
{
float4 Position: SV_Position;
float2 TexCoord: TEXCOORD0;
};

struct PS_OUTPUT
{
float4 Main: SV_Target0;
float4 NormalRoughness: SV_Target1;
};

float2 uv = float2(dispatchID.xy + 0.5) * SharedData::BufferDim.zw;
PS_OUTPUT main(PS_INPUT input)
{
uint2 pixCoord = uint2(input.Position.xy);

float2 uv = float2(pixCoord + 0.5) * SharedData::BufferDim.zw;
uv *= FrameBuffer::DynamicResolutionParams2.xy; // adjust for dynamic res

uint eyeIndex = Stereo::GetEyeIndexFromTexCoord(uv);

#if defined(VR_STEREO_OPT)
Comment thread
doodlum marked this conversation as resolved.
if (eyeIndex == 1) {
uint mode = StereoOptModeTexture[uint2(dispatchID.xy)] & 0x0F;
if (mode == MODE_MAIN) { // stencil-culled in Eye 1, filled by ReprojectionCS
return;
}
}
#endif

uv = Stereo::ConvertFromStereoUV(uv, eyeIndex);

float3 normalGlossiness = NormalRoughnessTexture[dispatchID.xy];
float3 normalVS = GBuffer::DecodeNormal(normalGlossiness.xy);
float3 diffuseColor = MainInputTexture[pixCoord].xyz;
float3 specularColor = SpecularTexture[pixCoord];
float3 linDiffuseColor = Color::IrradianceToLinear(diffuseColor);

float3 diffuseColor = MainRW[dispatchID.xy].xyz;
float3 specularColor = SpecularTexture[dispatchID.xy];
float3 albedo = AlbedoTexture[dispatchID.xy];
#if defined(SSGI) || defined(DYNAMIC_CUBEMAPS)
float3 normalGlossiness = NormalRoughnessTexture[pixCoord];
float3 normalVS = GBuffer::DecodeNormal(normalGlossiness.xy);
float3 normalWS = normalize(mul(FrameBuffer::CameraViewInverse[eyeIndex], float4(normalVS, 0)).xyz);

float depth = DepthTexture[dispatchID.xy];
float depth = DepthTexture[pixCoord];
float4 positionWS = float4(2 * float2(uv.x, -uv.y + 1) - 1, depth, 1);
positionWS = mul(FrameBuffer::CameraViewProjInverse[eyeIndex], positionWS);
positionWS.xyz = positionWS.xyz / positionWS.w;
#endif

if (depth == 1.0)
MotionVectorsRW[dispatchID.xy] = MotionBlur::GetSSMotionVector(positionWS, positionWS, eyeIndex); // Apply sky motion vectors

#if defined(DYNAMIC_CUBEMAPS)
float glossiness = normalGlossiness.z;

float3 linDiffuseColor = Color::IrradianceToLinear(diffuseColor);
float3 normalWS = normalize(mul(FrameBuffer::CameraViewInverse[eyeIndex], float4(normalVS, 0)).xyz);
#endif

#if defined(SSGI)
float3 albedo = AlbedoTexture[pixCoord];

float ssgiAo;
float3 ssgiIl;
SampleSSGI(dispatchID.xy, normalWS, ssgiAo, ssgiIl);
SampleSSGI(pixCoord, normalWS, ssgiAo, ssgiIl);

float3 linAlbedo = Color::IrradianceToLinear(albedo / Color::PBRLightingScale);
float3 multiBounceSSGIAo = MultiBounceAO(linAlbedo, ssgiAo);
Expand All @@ -150,7 +154,7 @@ void SampleSSGISpecular(uint2 pixCoord, sh2 lobe, inout float ao, out float3 il,
# else
float3 positionMS = positionWS.xyz;
# endif
sh2 skylightingSH = Skylighting::sample(SharedData::skylightingSettings, SkylightingProbeArray, stbn_vec3_2Dx1D_128x128x64, dispatchID.xy, positionMS.xyz, normalWS);
sh2 skylightingSH = Skylighting::sample(SharedData::skylightingSettings, SkylightingProbeArray, stbn_vec3_2Dx1D_128x128x64, pixCoord, positionMS.xyz, normalWS);
float skylightingDiffuse = SphericalHarmonics::FuncProductIntegral(skylightingSH, SphericalHarmonics::EvaluateCosineLobe(normalWS)) / Math::PI;
skylightingDiffuse = saturate(skylightingDiffuse);
skylightingDiffuse = Skylighting::mixDiffuse(SharedData::skylightingSettings, skylightingDiffuse);
Expand All @@ -160,7 +164,7 @@ void SampleSSGISpecular(uint2 pixCoord, sh2 lobe, inout float ao, out float3 il,
# endif

directionalAmbientColor = Color::RGBToYCoCg(directionalAmbientColor);
directionalAmbientColor.x = MasksTexture[dispatchID.xy].z;
directionalAmbientColor.x = MasksTexture[pixCoord].z;
directionalAmbientColor = Color::YCoCgToRGB(directionalAmbientColor);
directionalAmbientColor = max(0, directionalAmbientColor);
} else
Expand All @@ -170,7 +174,7 @@ void SampleSSGISpecular(uint2 pixCoord, sh2 lobe, inout float ao, out float3 il,
directionalAmbientColor *= albedo;

directionalAmbientColor = Color::RGBToYCoCg(directionalAmbientColor);
directionalAmbientColor.x = MasksTexture[dispatchID.xy].z;
directionalAmbientColor.x = MasksTexture[pixCoord].z;
directionalAmbientColor = Color::YCoCgToRGB(directionalAmbientColor);
directionalAmbientColor = max(0, directionalAmbientColor);
}
Expand Down Expand Up @@ -200,7 +204,7 @@ void SampleSSGISpecular(uint2 pixCoord, sh2 lobe, inout float ao, out float3 il,

#if defined(DYNAMIC_CUBEMAPS)

float3 reflectance = ReflectanceTexture[dispatchID.xy];
float3 reflectance = ReflectanceTexture[pixCoord];

if (any(reflectance > 0.0)) {
float3 V = -normalize(positionWS.xyz);
Expand All @@ -222,7 +226,7 @@ void SampleSSGISpecular(uint2 pixCoord, sh2 lobe, inout float ao, out float3 il,
float3 positionMS = positionWS.xyz;
# endif

sh2 skylighting = Skylighting::sample(SharedData::skylightingSettings, SkylightingProbeArray, stbn_vec3_2Dx1D_128x128x64, dispatchID.xy, positionMS.xyz, R);
sh2 skylighting = Skylighting::sample(SharedData::skylightingSettings, SkylightingProbeArray, stbn_vec3_2Dx1D_128x128x64, pixCoord, positionMS.xyz, R);

float skylightingSpecular = SphericalHarmonics::FuncProductIntegral(skylighting, specularLobe);
skylightingSpecular = saturate(skylightingSpecular);
Expand Down Expand Up @@ -295,7 +299,7 @@ void SampleSSGISpecular(uint2 pixCoord, sh2 lobe, inout float ao, out float3 il,

# if defined(SSGI)
float3 ssgiIlSpecular;
SampleSSGISpecular(dispatchID.xy, specularLobe, ssgiAo, ssgiIlSpecular, normalWS, V, roughness);
SampleSSGISpecular(pixCoord, specularLobe, ssgiAo, ssgiIlSpecular, normalWS, V, roughness);

finalIrradiance = (finalIrradiance * ssgiAo);

Expand All @@ -314,9 +318,22 @@ void SampleSSGISpecular(uint2 pixCoord, sh2 lobe, inout float ao, out float3 il,

#if defined(DEBUG)

# if !defined(SSGI) && !defined(DYNAMIC_CUBEMAPS)
float3 normalGlossiness = NormalRoughnessTexture[pixCoord];
float3 normalVS = GBuffer::DecodeNormal(normalGlossiness.xy);
# endif

# if !defined(SSGI)
float3 albedo = AlbedoTexture[pixCoord];
# endif

# if !defined(DYNAMIC_CUBEMAPS)
float glossiness = normalGlossiness.z;
# endif

# if defined(VR)
uv.x += (eyeIndex ? 0.1 : -0.1);
# endif // VR
# endif

if (uv.x < 0.5 && uv.y < 0.5) {
color = color;
Expand All @@ -330,6 +347,8 @@ void SampleSSGISpecular(uint2 pixCoord, sh2 lobe, inout float ao, out float3 il,

#endif

MainRW[dispatchID.xy] = float4(color, 1.0);
NormalTAAMaskSpecularMaskRW[dispatchID.xy] = float4(GBuffer::EncodeNormalVanilla(normalVS), 0.0, 0.0);
}
PS_OUTPUT output;
output.Main = float4(color, 1.0);
output.NormalRoughness = 0;
return output;
}
14 changes: 14 additions & 0 deletions package/Shaders/DeferredCompositeVS.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
struct VS_OUTPUT
{
float4 Position: SV_Position;
float2 TexCoord: TEXCOORD0;
};

VS_OUTPUT main(uint vertexID : SV_VertexID)
{
VS_OUTPUT output;
float2 uv = float2((vertexID << 1) & 2, vertexID & 2);
output.Position = float4(uv * float2(2, -2) + float2(-1, 1), 1, 1);
output.TexCoord = uv;
return output;
}
Loading
Loading