diff --git a/features/Volumetric Shadows/Shaders/VolumetricShadows/CopyShadowDataCS.hlsl b/features/Volumetric Shadows/Shaders/VolumetricShadows/CopyShadowDataCS.hlsl deleted file mode 100644 index e2899f3ecb..0000000000 --- a/features/Volumetric Shadows/Shaders/VolumetricShadows/CopyShadowDataCS.hlsl +++ /dev/null @@ -1,129 +0,0 @@ - -struct PerGeometry -{ - float4 VPOSOffset; - float4 ShadowSampleParam; // fPoissonRadiusScale / iShadowMapResolution in z and w - float4 EndSplitDistances; // cascade end distances int xyz, cascade count int z - float4 StartSplitDistances; // cascade start ditances int xyz, 4 int z - float4 FocusShadowFadeParam; - float4 DebugColor; - float4 PropertyColor; - float4 AlphaTestRef; - float4 ShadowLightParam; // Falloff in x, ShadowDistance squared in z - float4x3 FocusShadowMapProj[4]; - // Since PerGeometry is passed between c++ and hlsl, can't have different defines due to strong typing - float4x3 ShadowMapProj[2][3]; - float4x4 CameraViewProjInverse[2]; -}; - -cbuffer PerFrame : register(b0) -{ - float4 VPOSOffset : packoffset(c0); - float4 ShadowSampleParam : packoffset(c1); // fPoissonRadiusScale / iShadowMapResolution in z and w - float4 EndSplitDistances : packoffset(c2); // cascade end distances int xyz, cascade count int z - float4 StartSplitDistances : packoffset(c3); // cascade start ditances int xyz, 4 int z - float4 FocusShadowFadeParam : packoffset(c4); -} - -cbuffer PerFrame2 : register(b1) -{ -#if !defined(VR) - row_major float4x4 CameraView[1] : packoffset(c0); - row_major float4x4 CameraProj[1] : packoffset(c4); - row_major float4x4 CameraViewProj[1] : packoffset(c8); - row_major float4x4 CameraViewProjUnjittered[1] : packoffset(c12); - row_major float4x4 CameraPreviousViewProjUnjittered[1] : packoffset(c16); - row_major float4x4 CameraProjUnjittered[1] : packoffset(c20); - row_major float4x4 CameraProjUnjitteredInverse[1] : packoffset(c24); - row_major float4x4 CameraViewInverse[1] : packoffset(c28); - row_major float4x4 CameraViewProjInverse[1] : packoffset(c32); - row_major float4x4 CameraProjInverse[1] : packoffset(c36); - float4 CameraPosAdjust[1] : packoffset(c40); - float4 CameraPreviousPosAdjust[1] : packoffset(c41); // fDRClampOffset in w - float4 FrameParams : packoffset(c42); // inverse fGamma in x, some flags in yzw - float4 DynamicResolutionParams1 : packoffset(c43); // fDynamicResolutionWidthRatio in x, - // fDynamicResolutionHeightRatio in y, - // fDynamicResolutionPreviousWidthRatio in z, - // fDynamicResolutionPreviousHeightRatio in w - float4 DynamicResolutionParams2 : packoffset(c44); // inverse fDynamicResolutionWidthRatio in x, inverse - // fDynamicResolutionHeightRatio in y, - // fDynamicResolutionWidthRatio - fDRClampOffset in z, - // fDynamicResolutionPreviousWidthRatio - fDRClampOffset in w -#else - row_major float4x4 CameraView[2] : packoffset(c0); - row_major float4x4 CameraProj[2] : packoffset(c8); - row_major float4x4 CameraViewProj[2] : packoffset(c16); - row_major float4x4 CameraViewProjUnjittered[2] : packoffset(c24); - row_major float4x4 CameraPreviousViewProjUnjittered[2] : packoffset(c32); - row_major float4x4 CameraProjUnjittered[2] : packoffset(c40); - row_major float4x4 CameraProjUnjitteredInverse[2] : packoffset(c48); - row_major float4x4 CameraViewInverse[2] : packoffset(c56); - row_major float4x4 CameraViewProjInverse[2] : packoffset(c64); - row_major float4x4 CameraProjInverse[2] : packoffset(c72); - float4 CameraPosAdjust[2] : packoffset(c80); - float4 CameraPreviousPosAdjust[2] : packoffset(c82); // fDRClampOffset in w - float4 FrameParams : packoffset(c84); // inverse fGamma in x, some flags in yzw - float4 DynamicResolutionParams1 : packoffset(c85); // fDynamicResolutionWidthRatio in x, - // fDynamicResolutionHeightRatio in y, - // fDynamicResolutionPreviousWidthRatio in z, - // fDynamicResolutionPreviousHeightRatio in w - float4 DynamicResolutionParams2 : packoffset(c86); // inverse fDynamicResolutionWidthRatio in x, inverse - // fDynamicResolutionHeightRatio in y, - // fDynamicResolutionWidthRatio - fDRClampOffset in z, - // fDynamicResolutionPreviousWidthRatio - fDRClampOffset in w -#endif // !VR -} - -// copied from UtilShader(b2). Assume RENDER_SHADOWMASK -cbuffer PerFrame3 : register(b2) -{ - float4 DebugColor : packoffset(c0); - float4 PropertyColor : packoffset(c1); - float4 AlphaTestRef : packoffset(c2); - float4 ShadowLightParam : packoffset(c3); // Falloff in x, ShadowDistance squared in z -#if !defined(VR) - float4x3 FocusShadowMapProj[4] : packoffset(c4); - float4x3 ShadowMapProj[1][3] : packoffset(c16); // 16, 19, 22 -#else - float4 VRUnknown : packoffset(c4); /* used to multiply by identity matrix, see e.g., 4202499.ps.bin.hlsl - r1.x = dot(cb2[4].xz, icb[r0.w+0].xz); - r1.x = r0.x * cb12[86].x + -r1.x; - r0.w = (int)r0.w + 1; - r0.w = (int)r0.w + -1; - r0.w = dot(cb2[4].yw, icb[r0.w+0].xz); - */ - float4x3 FocusShadowMapProj[4] : packoffset(c5); - float4x3 ShadowMapProj[2][3] : packoffset(c29); // VR has a couple of offsets of 3, e.g., {29, 32, 35} and {38, 41, 44}, compare to Flat which does [16, 19, 22] -#endif // VR -} - -RWStructuredBuffer ShadowData : register(u0); - -[numthreads(1, 1, 1)] void main() { - PerGeometry perGeometry; - perGeometry.DebugColor = DebugColor; - perGeometry.PropertyColor = PropertyColor; - perGeometry.AlphaTestRef = AlphaTestRef; - perGeometry.ShadowLightParam = ShadowLightParam; - perGeometry.FocusShadowMapProj = FocusShadowMapProj; - perGeometry.ShadowMapProj[0] = ShadowMapProj[0]; - - perGeometry.CameraViewProjInverse[0] = CameraViewProjInverse[0]; -#if defined(VR) - perGeometry.ShadowMapProj[1] = ShadowMapProj[1]; - - perGeometry.CameraViewProjInverse[1] = CameraViewProjInverse[1]; -#else - perGeometry.ShadowMapProj[1] = ShadowMapProj[0]; - - perGeometry.CameraViewProjInverse[1] = CameraViewProjInverse[0]; -#endif - - perGeometry.VPOSOffset = VPOSOffset; - perGeometry.ShadowSampleParam = ShadowSampleParam; - perGeometry.EndSplitDistances = EndSplitDistances; - perGeometry.StartSplitDistances = StartSplitDistances; - perGeometry.FocusShadowFadeParam = FocusShadowFadeParam; - - ShadowData[0] = perGeometry; -} diff --git a/features/Volumetric Shadows/Shaders/VolumetricShadows/VolumetricShadows.hlsli b/features/Volumetric Shadows/Shaders/VolumetricShadows/VolumetricShadows.hlsli index b794a277bb..cdfb339ba2 100644 --- a/features/Volumetric Shadows/Shaders/VolumetricShadows/VolumetricShadows.hlsli +++ b/features/Volumetric Shadows/Shaders/VolumetricShadows/VolumetricShadows.hlsli @@ -8,34 +8,9 @@ namespace VolumetricShadows { Texture2D SharedShadowMap : register(t18); - struct ShadowData - { - float4 VPOSOffset; - float4 ShadowSampleParam; // fPoissonRadiusScale / iShadowMapResolution in z and w - float4 EndSplitDistances; // cascade end distances int xyz, cascade count int z - float4 StartSplitDistances; // cascade start distances int xyz, 4 int z - float4 FocusShadowFadeParam; - float4 DebugColor; - float4 PropertyColor; - float4 AlphaTestRef; - float4 ShadowLightParam; // Falloff in x, ShadowDistance squared in z - float4x3 FocusShadowMapProj[4]; - // Since ShadowData is passed between c++ and hlsl, can't have different defines due to strong typing - float4x3 ShadowMapProj[2][3]; - float4x4 CameraViewProjInverse[2]; - }; - - StructuredBuffer SharedShadowData : register(t19); - static const float VSM_MIN_VARIANCE = 0.00001; static const float VSM_BLEEDING_REDUCTION = 0.2; - float GetShadowDepth(float3 positionWS, uint eyeIndex) - { - float4 positionCS = mul(FrameBuffer::CameraViewProj[eyeIndex], float4(positionWS, 1)); - return positionCS.z / positionCS.w; - } - // Chebyshev upper bound on P(X >= t) // moments.x = mean(z), moments.y = mean(z^2) float ComputeVSM(float2 moments, float depth) @@ -84,35 +59,39 @@ namespace VolumetricShadows float GetVSMShadow3D(float3 startPosition, float3 endPosition, float noise, uint baseSampleCount, uint eyeIndex, out float surfaceShadow) { - ShadowData sD = SharedShadowData[0]; + DirectionalShadowLightData directionalShadowLightData = DirectionalShadowLights[0]; + // View-space z — matches the linear cascade split distances from BSShadowDirectionalLight. float3 midPosition = (startPosition + endPosition) * 0.5; - float shadowMapDepth = GetShadowDepth(midPosition, eyeIndex); + float shadowMapDepth = SharedData::GetScreenDepth(FrameBuffer::GetShadowDepth(midPosition, eyeIndex)); + + // Cascade projections are world-space; positions come in camera-relative. + startPosition += FrameBuffer::CameraPosAdjust[eyeIndex].xyz; + endPosition += FrameBuffer::CameraPosAdjust[eyeIndex].xyz; // Early out beyond cascade range - if (shadowMapDepth >= sD.EndSplitDistances.w) { + if (shadowMapDepth >= directionalShadowLightData.EndSplitDistances.y) { surfaceShadow = 1.0; return 1.0; } // Reduce over distance - float distSq = dot(midPosition, midPosition); - float fade = saturate(distSq / sD.ShadowLightParam.z); + float fade = saturate(shadowMapDepth / directionalShadowLightData.EndSplitDistances.y); uint sampleCount = max(1, ceil(float(baseSampleCount) * (1.0 - fade))); float rcpSampleCount = rcp(sampleCount); // Compute cascade blend factor with smoothstep - float cascadeSelect = saturate((shadowMapDepth - sD.StartSplitDistances.y) / (sD.EndSplitDistances.x - sD.StartSplitDistances.y)); + float cascadeSelect = saturate((shadowMapDepth - directionalShadowLightData.StartSplitDistances.y) / (directionalShadowLightData.EndSplitDistances.x - directionalShadowLightData.StartSplitDistances.y)); // Determine which cascade(s) to sample uint primaryCascade = uint(cascadeSelect); bool needsBlending = (cascadeSelect > 0.0) && (cascadeSelect < 1.0); // Transform ray to light space for primary cascade - float4x3 shadowProj = sD.ShadowMapProj[eyeIndex][primaryCascade]; - float3 startLS = mul(transpose(shadowProj), float4(startPosition, 1)); - float3 endLS = mul(transpose(shadowProj), float4(endPosition, 1)); + float4x4 shadowProj = directionalShadowLightData.ShadowProj[primaryCascade]; + float3 startLS = mul(shadowProj, float4(startPosition, 1)).xyz; + float3 endLS = mul(shadowProj, float4(endPosition, 1)).xyz; startLS.xy = saturate(startLS.xy); endLS.xy = saturate(endLS.xy); @@ -126,9 +105,9 @@ namespace VolumetricShadows { uint secondaryCascade = 1 - primaryCascade; - shadowProj = sD.ShadowMapProj[eyeIndex][secondaryCascade]; - startLS = mul(transpose(shadowProj), float4(startPosition, 1)); - endLS = mul(transpose(shadowProj), float4(endPosition, 1)); + shadowProj = directionalShadowLightData.ShadowProj[secondaryCascade]; + startLS = mul(shadowProj, float4(startPosition, 1)).xyz; + endLS = mul(shadowProj, float4(endPosition, 1)).xyz; startLS.xy = saturate(startLS.xy); endLS.xy = saturate(endLS.xy); @@ -139,7 +118,7 @@ namespace VolumetricShadows } // Apply distance fade - float fadeFactor = 1.0 - pow(fade, 8); + float fadeFactor = 1.0 - pow(fade * fade, 8); surfaceShadow = lerp(1.0, surfaceShadow, fadeFactor); return lerp(1.0, shadow, fadeFactor); } @@ -153,30 +132,31 @@ namespace VolumetricShadows float GetVSMShadow2D(float3 position, uint eyeIndex, out float detailedShadow) { - ShadowData sD = SharedShadowData[0]; + DirectionalShadowLightData directionalShadowLightData = DirectionalShadowLights[0]; - float shadowMapDepth = GetShadowDepth(position, eyeIndex); + float shadowMapDepth = SharedData::GetScreenDepth(FrameBuffer::GetShadowDepth(position, eyeIndex)); // Early out beyond cascade range - if (shadowMapDepth >= sD.EndSplitDistances.w) { + if (shadowMapDepth >= directionalShadowLightData.EndSplitDistances.y) { detailedShadow = 1.0; return 1.0; } // Reduce over distance - float distSq = dot(position, position); - float fade = saturate(distSq / sD.ShadowLightParam.z); + float fade = saturate(shadowMapDepth / directionalShadowLightData.EndSplitDistances.y); + + // Cascade projections are world-space; position comes in camera-relative. + float3 positionWS = position + FrameBuffer::CameraPosAdjust[eyeIndex].xyz; // Compute cascade blend factor with smoothstep - float cascadeSelect = saturate((shadowMapDepth - sD.StartSplitDistances.y) / (sD.EndSplitDistances.x - sD.StartSplitDistances.y)); + float cascadeSelect = saturate((shadowMapDepth - directionalShadowLightData.StartSplitDistances.y) / (directionalShadowLightData.EndSplitDistances.x - directionalShadowLightData.StartSplitDistances.y)); // Determine which cascade(s) to sample uint primaryCascade = uint(cascadeSelect); bool needsBlending = (cascadeSelect > 0.0) && (cascadeSelect < 1.0); - // Transform ray to light space for primary cascade - float4x3 shadowProj = sD.ShadowMapProj[eyeIndex][primaryCascade]; - float3 positionLS = mul(transpose(shadowProj), float4(position, 1)); + // Transform position to light space for primary cascade + float3 positionLS = mul(directionalShadowLightData.ShadowProj[primaryCascade], float4(positionWS, 1)).xyz; positionLS.xy = saturate(positionLS.xy); // Sample primary cascade @@ -187,8 +167,7 @@ namespace VolumetricShadows { uint secondaryCascade = 1 - primaryCascade; - shadowProj = sD.ShadowMapProj[eyeIndex][secondaryCascade]; - positionLS = mul(transpose(shadowProj), float4(position, 1)); + positionLS = mul(directionalShadowLightData.ShadowProj[secondaryCascade], float4(positionWS, 1)).xyz; positionLS.xy = saturate(positionLS.xy); float shadowBlend = SampleVSMCascade2D(secondaryCascade, positionLS); @@ -196,7 +175,7 @@ namespace VolumetricShadows } // Apply distance fade - float fadeFactor = 1.0 - pow(fade, 8); + float fadeFactor = 1.0 - pow(fade * fade, 8); detailedShadow = lerp(1.0, ReduceBleeding(shadow, VSM_BLEEDING_REDUCTION), fadeFactor); return lerp(1.0, shadow, fadeFactor); } diff --git a/package/Shaders/Common/FrameBuffer.hlsli b/package/Shaders/Common/FrameBuffer.hlsli index 1d541e71eb..68f0f90371 100644 --- a/package/Shaders/Common/FrameBuffer.hlsli +++ b/package/Shaders/Common/FrameBuffer.hlsli @@ -85,6 +85,15 @@ namespace FrameBuffer return clamp(screenPositionDR, minValue, maxValue); } + // Projects a world-space (camera-relative) point into NDC using the eye's CameraViewProj + // and returns the post-perspective z (NDC depth). Combine with SharedData::GetScreenDepth + // to get a linear view-space distance suitable for cascade-split comparisons. + float GetShadowDepth(float3 positionWS, uint eyeIndex) + { + float4 positionCS = mul(FrameBuffer::CameraViewProj[eyeIndex], float4(positionWS, 1)); + return positionCS.z / positionCS.w; + } + /** * @brief Converts normalized screen UVs to dynamic-resolution UVs and clamps them. * diff --git a/package/Shaders/Common/ShadowSampling.hlsli b/package/Shaders/Common/ShadowSampling.hlsli index f8b9b4a928..a472c97602 100644 --- a/package/Shaders/Common/ShadowSampling.hlsli +++ b/package/Shaders/Common/ShadowSampling.hlsli @@ -21,6 +21,19 @@ # include "Common/Spherical Harmonics/SphericalHarmonics.hlsli" #endif +// Populated once per frame by Deferred::CopyShadowLightData from BSShadowDirectionalLight. +// Column-major float4x4 projections so HLSL `mul(proj, float4(pos, 1))` matches the +// XMMATRIX layout written by XMStoreFloat4x4 on the C++ side. +struct DirectionalShadowLightData +{ + column_major float4x4 ShadowProj[2]; + column_major float4x4 InvShadowProj[2]; + float2 EndSplitDistances; + float2 StartSplitDistances; +}; + +StructuredBuffer DirectionalShadowLights : register(t98); + #if defined(VOLUMETRIC_SHADOWS) # include "VolumetricShadows/VolumetricShadows.hlsli" #endif diff --git a/src/Deferred.cpp b/src/Deferred.cpp index 81d9b9258d..442ed4df06 100644 --- a/src/Deferred.cpp +++ b/src/Deferred.cpp @@ -167,6 +167,28 @@ void Deferred::SetupResources() rsDesc.DepthClipEnable = FALSE; DX::ThrowIfFailed(device->CreateRasterizerState(&rsDesc, compositeRasterizerState.put())); } + + // Directional shadow structured buffer (t98): CPU-written each frame, read-only on GPU. + // One element holds the sun cascade data uploaded from BSShadowDirectionalLight. + { + D3D11_BUFFER_DESC sbDesc{}; + sbDesc.Usage = D3D11_USAGE_DYNAMIC; + sbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + sbDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + sbDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; + sbDesc.StructureByteStride = sizeof(DirectionalShadowLightData); + sbDesc.ByteWidth = sizeof(DirectionalShadowLightData); + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc{}; + srvDesc.Format = DXGI_FORMAT_UNKNOWN; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + srvDesc.Buffer.FirstElement = 0; + srvDesc.Buffer.NumElements = 1; + + delete directionalShadowLights; + directionalShadowLights = new Buffer(sbDesc); + directionalShadowLights->CreateSRV(srvDesc); + } } void Deferred::ReflectionsPrepasses() @@ -211,6 +233,9 @@ void Deferred::EarlyPrepasses() globals::game::stateUpdateFlags->set(RE::BSGraphics::ShaderFlags::DIRTY_RENDERTARGET); // Run OMSetRenderTargets again + // Shadow maps have just been rendered — upload BSShadowDirectionalLight data to t98. + CopyShadowLightData(); + Feature::ForEachLoadedFeature("EarlyPrepass", [](Feature* feature) { feature->EarlyPrepass(); }); @@ -570,6 +595,53 @@ void Deferred::ResetBlendStates() globals::game::stateUpdateFlags->set(RE::BSGraphics::ShaderFlags::DIRTY_ALPHA_BLEND); } +template +void Deferred::SetShadowCascadeParameters(T& lightData, DirectionalShadowLightData& dd) +{ + const auto count = std::min(lightData.shadowmapDescriptors.size(), static_cast(std::size(dd.ShadowProj))); + for (uint32_t i = 0; i < count; i++) { + auto proj = DirectX::XMLoadFloat4x4(reinterpret_cast(&lightData.shadowmapDescriptors[i].lightTransform)); + DirectX::XMStoreFloat4x4(&dd.ShadowProj[i], proj); + + DirectX::XMMATRIX invProj = DirectX::XMMatrixInverse(nullptr, proj); + DirectX::XMStoreFloat4x4(&dd.InvShadowProj[i], invProj); + } +} + +void Deferred::CopyShadowLightData() +{ + ZoneScoped; + TracyD3D11Zone(globals::state->tracyCtx, "CopyShadowLightData"); + + auto* shadowSceneNode = globals::game::smState->shadowSceneNode[0]; + if (!shadowSceneNode) + return; + + auto* sunShadowLight = shadowSceneNode->GetRuntimeData().sunShadowDirLight; + if (!sunShadowLight) + return; + + DirectionalShadowLightData dd{}; + auto context = globals::d3d::context; + + auto& dirData = sunShadowLight->GetShadowDirectionalLightRuntimeData(); + dd.EndSplitDistances = { dirData.endSplitDistances[0], dirData.endSplitDistances[1] }; + dd.StartSplitDistances = { dirData.startSplitDistances[0], dirData.startSplitDistances[1] }; + + if (globals::game::isVR) + SetShadowCascadeParameters(sunShadowLight->GetVRRuntimeData(), dd); + else + SetShadowCascadeParameters(sunShadowLight->GetRuntimeData(), dd); + + D3D11_MAPPED_SUBRESOURCE mapped{}; + DX::ThrowIfFailed(context->Map(directionalShadowLights->resource.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped)); + memcpy(mapped.pData, &dd, sizeof(DirectionalShadowLightData)); + context->Unmap(directionalShadowLights->resource.get(), 0); + + ID3D11ShaderResourceView* srv = directionalShadowLights->srv.get(); + context->PSSetShaderResources(98, 1, &srv); +} + void Deferred::ClearShaderCache() { if (compositePS) { diff --git a/src/Deferred.h b/src/Deferred.h index e7cad8bfc5..d75f293399 100644 --- a/src/Deferred.h +++ b/src/Deferred.h @@ -1,6 +1,9 @@ #pragma once +#include + #include "Buffer.h" +#include "RE/B/BSShadowDirectionalLight.h" #include #define ALBEDO RE::RENDER_TARGETS::kINDIRECT @@ -18,6 +21,15 @@ class Deferred return &singleton; } + struct alignas(16) DirectionalShadowLightData + { + float4x4 ShadowProj[2]; + float4x4 InvShadowProj[2]; + float2 EndSplitDistances; + float2 StartSplitDistances; + }; + STATIC_ASSERT_ALIGNAS_16(DirectionalShadowLightData); + void SetupResources(); void ReflectionsPrepasses(); void EarlyPrepasses(); @@ -31,6 +43,13 @@ class Deferred void ClearShaderCache(); + // Reads directional shadow parameters from BSShadowDirectionalLight and uploads + // to the structured buffer at t98 (DirectionalShadowLightData — cascade splits + + // world-to-shadow projections). Called during EarlyPrepasses once shadow maps + // have been rendered. Replaces the previous compute-shader dispatch that copied + // constant-buffer fields into a UAV. + void CopyShadowLightData(); + ID3D11PixelShader* GetCompositePS(bool interior); ID3D11VertexShader* GetCompositeVS(); @@ -50,11 +69,19 @@ class Deferred RE::RENDER_TARGET normalRoughnessRT = RE::RENDER_TARGETS::kNORMAL_TAAMASK_SSRMASK; + // Directional shadow structured buffer (t98): cascade splits and projections. + Buffer* directionalShadowLights = nullptr; + bool deferredPass = false; ID3D11SamplerState* linearSampler = nullptr; ID3D11SamplerState* pointSampler = nullptr; +private: + template + void SetShadowCascadeParameters(T& lightData, DirectionalShadowLightData& dd); + +public: struct Hooks { struct Main_RenderShadowMaps diff --git a/src/Features/VolumetricShadows.cpp b/src/Features/VolumetricShadows.cpp index abea313cdb..66b5430f37 100644 --- a/src/Features/VolumetricShadows.cpp +++ b/src/Features/VolumetricShadows.cpp @@ -19,39 +19,7 @@ void VolumetricShadows::SetupResources() DX::ThrowIfFailed(device->CreateSamplerState(&samplerDesc, &linearSampler)); } - // Create shadow data buffer - { - D3D11_BUFFER_DESC sbDesc{}; - sbDesc.Usage = D3D11_USAGE_DEFAULT; - sbDesc.CPUAccessFlags = 0; - sbDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS; - sbDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; - - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc{}; - srvDesc.Format = DXGI_FORMAT_UNKNOWN; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; - srvDesc.Buffer.FirstElement = 0; - - D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc{}; - uavDesc.Format = DXGI_FORMAT_UNKNOWN; - uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; - uavDesc.Buffer.FirstElement = 0; - uavDesc.Buffer.Flags = 0; - - std::uint32_t numElements = 1; - - sbDesc.StructureByteStride = sizeof(PerGeometry); - sbDesc.ByteWidth = sizeof(PerGeometry) * numElements; - perShadow = new Buffer(sbDesc); - srvDesc.Buffer.NumElements = numElements; - perShadow->CreateSRV(srvDesc); - uavDesc.Buffer.NumElements = numElements; - perShadow->CreateUAV(uavDesc); - } - // Compile compute shaders - copyShadowCS = static_cast(Util::CompileShader(L"Data\\Shaders\\VolumetricShadows\\CopyShadowDataCS.hlsl", {}, "cs_5_0")); - std::vector> defines; defines.push_back({ "DOWNSAMPLE_SHADOW_MIP0", nullptr }); downsampleShadowMip0CS = static_cast(Util::CompileShader(L"Data\\Shaders\\VolumetricShadows\\DownsampleShadowCS.hlsl", defines, "cs_5_0")); @@ -69,10 +37,6 @@ void VolumetricShadows::SetupResources() void VolumetricShadows::ClearShaderCache() { - if (copyShadowCS) { - copyShadowCS->Release(); - copyShadowCS = nullptr; - } if (downsampleShadowMip0CS) { downsampleShadowMip0CS->Release(); downsampleShadowMip0CS = nullptr; @@ -90,9 +54,6 @@ void VolumetricShadows::ClearShaderCache() blurShadowVerticalCS = nullptr; } - // Re-compile compute shaders (same as in SetupResources) - copyShadowCS = static_cast(Util::CompileShader(L"Data\\Shaders\\VolumetricShadows\\CopyShadowDataCS.hlsl", {}, "cs_5_0")); - std::vector> defines; defines.push_back({ "DOWNSAMPLE_SHADOW_MIP0", nullptr }); downsampleShadowMip0CS = static_cast(Util::CompileShader(L"Data\\Shaders\\VolumetricShadows\\DownsampleShadowCS.hlsl", defines, "cs_5_0")); @@ -108,45 +69,13 @@ void VolumetricShadows::ClearShaderCache() blurShadowVerticalCS = static_cast(Util::CompileShader(L"Data\\Shaders\\VolumetricShadows\\BlurShadowCS.hlsl", defines, "cs_5_0")); } -void VolumetricShadows::CopyShadowData() +void VolumetricShadows::CopyShadowLightData() { ZoneScoped; - TracyD3D11Zone(globals::state->tracyCtx, "CopyShadowData"); + TracyD3D11Zone(globals::state->tracyCtx, "VolumetricShadows::CopyShadowLightData"); auto context = globals::d3d::context; - ID3D11UnorderedAccessView* uavs[1]{ perShadow->uav.get() }; - context->CSSetUnorderedAccessViews(0, 1, uavs, nullptr); - - ID3D11Buffer* buffers[3]; - context->PSGetConstantBuffers(0, 3, buffers); - - // Release the buffer at slot 1 before overwriting - if (buffers[1]) - buffers[1]->Release(); - - context->PSGetConstantBuffers(12, 1, buffers + 1); - - context->CSSetConstantBuffers(0, 3, buffers); - - context->CSSetShader(copyShadowCS, nullptr, 0); - - context->Dispatch(1, 1, 1); - - uavs[0] = nullptr; - context->CSSetUnorderedAccessViews(0, 1, uavs, nullptr); - - // Release all COM references from PSGetConstantBuffers - for (auto& buf : buffers) { - if (buf) - buf->Release(); - buf = nullptr; - } - - context->CSSetConstantBuffers(0, 3, buffers); - - context->CSSetShader(nullptr, nullptr, 0); - { context->PSGetShaderResources(4, 1, &shadowView); @@ -341,14 +270,9 @@ void VolumetricShadows::CopyShadowData() } } - ID3D11ShaderResourceView* srvs[2]{ - shadowCopySRV ? shadowCopySRV : shadowView, - perShadow->srv.get(), - }; - - context->PSSetShaderResources(18, ARRAYSIZE(srvs), srvs); + ID3D11ShaderResourceView* srv = shadowView ? (shadowCopySRV ? shadowCopySRV : shadowView) : nullptr; + context->PSSetShaderResources(18, 1, &srv); - // Release COM object to prevent memory leak if (shadowView) shadowView->Release(); shadowView = nullptr; diff --git a/src/Features/VolumetricShadows.h b/src/Features/VolumetricShadows.h index 00a3ee2a38..8d3442d669 100644 --- a/src/Features/VolumetricShadows.h +++ b/src/Features/VolumetricShadows.h @@ -26,33 +26,12 @@ struct VolumetricShadows : Feature bool HasShaderDefine(RE::BSShader::Type shaderType) override; - struct alignas(16) PerGeometry - { - float4 VPOSOffset; - float4 ShadowSampleParam; // fPoissonRadiusScale / iShadowMapResolution in z and w - float4 EndSplitDistances; // cascade end distances int xyz, cascade count int z - float4 StartSplitDistances; // cascade start ditances int xyz, 4 int z - float4 FocusShadowFadeParam; - float4 DebugColor; - float4 PropertyColor; - float4 AlphaTestRef; - float4 ShadowLightParam; // Falloff in x, ShadowDistance squared in z - DirectX::XMFLOAT4X3 FocusShadowMapProj[4]; - // Since PerGeometry is passed between c++ and hlsl, can't have different defines due to strong typing - DirectX::XMFLOAT4X3 ShadowMapProj[2][3]; - DirectX::XMFLOAT4X3 CameraViewProjInverse[2]; - }; - STATIC_ASSERT_ALIGNAS_16(PerGeometry); - // Compute shaders - ID3D11ComputeShader* copyShadowCS = nullptr; ID3D11ComputeShader* downsampleShadowMip0CS = nullptr; ID3D11ComputeShader* downsampleShadowMip1CS = nullptr; ID3D11ComputeShader* blurShadowHorizontalCS = nullptr; ID3D11ComputeShader* blurShadowVerticalCS = nullptr; - // Shadow data buffer - Buffer* perShadow = nullptr; ID3D11ShaderResourceView* shadowView = nullptr; // Downsampled shadow texture with 2 mip levels @@ -79,7 +58,7 @@ struct VolumetricShadows : Feature virtual void SetupResources() override; virtual void ClearShaderCache() override; - void CopyShadowData(); + void CopyShadowLightData(); virtual void LoadSettings(json& o_json) override; virtual void SaveSettings(json& o_json) override; diff --git a/src/State.cpp b/src/State.cpp index e355a3766b..71878b72ed 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -94,7 +94,7 @@ void State::Draw() if (currentShader->shaderType.get() == RE::BSShader::Type::Utility) { if (currentPixelDescriptor & static_cast(SIE::ShaderCache::UtilityShaderFlags::RenderShadowmask)) { if (volumetricShadows.loaded) - volumetricShadows.CopyShadowData(); + volumetricShadows.CopyShadowLightData(); } } }