From be74c8049f7e1933c876cbdb2e13343cefc56ec2 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Sat, 12 Jul 2025 22:54:32 +0100 Subject: [PATCH 01/43] perf: RTTI optimisation --- src/Features/ExtendedTranslucency.cpp | 4 +--- src/Features/LightLimitFix.cpp | 6 +++--- src/Globals.cpp | 10 ++++++++++ src/Globals.h | 9 +++++++++ src/TruePBR.cpp | 4 ++-- 5 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/Features/ExtendedTranslucency.cpp b/src/Features/ExtendedTranslucency.cpp index 6bf210db1e..55d851c331 100644 --- a/src/Features/ExtendedTranslucency.cpp +++ b/src/Features/ExtendedTranslucency.cpp @@ -24,9 +24,7 @@ void ExtendedTranslucency::BSLightingShader_SetupGeometry(RE::BSRenderPass* pass globals::state->currentExtraFeatureDescriptor &= ~(ExtraFeatureDescriptorMask << ExtraFeatureDescriptorShift); // TODO: PERFORMANCE: Caching the feature descriptor in map if this get more complex if (auto* data = pass->geometry->GetExtraData(NiExtraDataName_AnisotropicAlphaMaterial)) { - static const REL::Relocation NiIntegerExtraDataRTTI{ RE::NiIntegerExtraData::Ni_RTTI }; - // netimmerse_cast(data) seems not working here - if (data->GetRTTI() == NiIntegerExtraDataRTTI.get()) { + if (data->GetRTTI() == globals::rtti::NiIntegerExtraDataRTTI.get()) { uint32_t material = static_cast(static_cast(data)->value) & ExtraFeatureDescriptorMask; if (material == MaterialModel::Disabled) { // MaterialModel::Disabled (0) is the flag when this extra does not exist diff --git a/src/Features/LightLimitFix.cpp b/src/Features/LightLimitFix.cpp index 80f6edd345..8b0cc09d7c 100644 --- a/src/Features/LightLimitFix.cpp +++ b/src/Features/LightLimitFix.cpp @@ -487,14 +487,14 @@ LightLimitFix::ParticleLightReference LightLimitFix::GetParticleLightConfigs(RE: // see https://www.nexusmods.com/skyrimspecialedition/articles/1391 if (settings.EnableParticleLights) { - if (auto shaderProperty = netimmerse_cast(a_pass->shaderProperty)) { + if (auto shaderProperty = a_pass->shaderProperty->GetRTTI() == globals::rtti::BSEffectShaderPropertyRTTI.get() ? static_cast(a_pass->shaderProperty) : nullptr) { if (!shaderProperty->lightData) { if (auto material = shaderProperty->GetMaterial()) { // Check if it's a valid particle light bool billboard = false; - if (!netimmerse_cast(a_pass->geometry)) { + if (a_pass->geometry->GetRTTI() != globals::rtti::NiParticleSystemRTTI.get()){ if (auto parent = a_pass->geometry->parent) { - if (auto billboardNode = netimmerse_cast(parent)) { + if (auto billboardNode = parent->GetRTTI() == globals::rtti::NiBillboardNodeRTTI.get() ? static_cast(parent) : nullptr) { billboard = true; } else { return { false }; diff --git a/src/Globals.cpp b/src/Globals.cpp index 5f9b0d4607..416c8e1629 100644 --- a/src/Globals.cpp +++ b/src/Globals.cpp @@ -194,6 +194,16 @@ namespace globals perFrame = { REL::RelocationID(524768, 411384) }; } + + { + using namespace rtti; + NiIntegerExtraDataRTTI = { RE::NiIntegerExtraData::Ni_RTTI }; + BSLightingShaderPropertyRTTI = { RE::BSLightingShaderProperty::Ni_RTTI }; + BSEffectShaderPropertyRTTI = { RE::BSEffectShaderProperty::Ni_RTTI }; + NiParticleSystemRTTI = { RE::NiParticleSystem::Ni_RTTI }; + NiBillboardNodeRTTI = { RE::NiBillboardNode::Ni_RTTI }; + } + d3d::device = reinterpret_cast(game::renderer->GetRuntimeData().forwarder); d3d::context = reinterpret_cast(game::renderer->GetRuntimeData().context); d3d::swapChain = reinterpret_cast(game::renderer->GetRuntimeData().renderWindows->swapChain); diff --git a/src/Globals.h b/src/Globals.h index 75a6cb0a19..c85a610a73 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -116,6 +116,15 @@ namespace globals extern REL::Relocation perFrame; } + namespace rtti + { + extern REL::Relocation NiIntegerExtraDataRTTI; + extern REL::Relocation BSLightingShaderPropertyRTTI; + extern REL::Relocation BSEffectShaderPropertyRTTI; + extern REL::Relocation NiParticleSystemRTTI; + extern REL::Relocation NiBillboardNodeRTTI; + } + extern State* state; extern Deferred* deferred; extern TruePBR* truePBR; diff --git a/src/TruePBR.cpp b/src/TruePBR.cpp index d5c34a52ca..6d0ad5f9b2 100644 --- a/src/TruePBR.cpp +++ b/src/TruePBR.cpp @@ -1232,8 +1232,8 @@ struct BSTempEffectSimpleDecal_SetupGeometry { func(decal, geometry, textureSet, blended); auto* singleton = globals::truePBR; - - if (auto* shaderProperty = netimmerse_cast(geometry->GetGeometryRuntimeData().properties[1].get()); + auto property = geometry->GetGeometryRuntimeData().properties[1].get(); + if (auto shaderProperty = property->GetRTTI() == globals::rtti::BSLightingShaderPropertyRTTI.get() ? static_cast(geometry->GetGeometryRuntimeData().properties[1].get()) : nullptr; shaderProperty != nullptr && singleton->IsPBRTextureSet(textureSet)) { { BSLightingShaderMaterialPBR srcMaterial; From 0de2ccaa25a317fdaaf046ae03f7d77187cbee31 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Sat, 12 Jul 2025 22:57:22 +0100 Subject: [PATCH 02/43] refactor: cleanup --- src/TruePBR.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TruePBR.cpp b/src/TruePBR.cpp index 6d0ad5f9b2..a2290378ef 100644 --- a/src/TruePBR.cpp +++ b/src/TruePBR.cpp @@ -1232,8 +1232,8 @@ struct BSTempEffectSimpleDecal_SetupGeometry { func(decal, geometry, textureSet, blended); auto* singleton = globals::truePBR; - auto property = geometry->GetGeometryRuntimeData().properties[1].get(); - if (auto shaderProperty = property->GetRTTI() == globals::rtti::BSLightingShaderPropertyRTTI.get() ? static_cast(geometry->GetGeometryRuntimeData().properties[1].get()) : nullptr; + auto uncastedProperty = geometry->GetGeometryRuntimeData().properties[1].get(); + if (auto shaderProperty = uncastedProperty->GetRTTI() == globals::rtti::BSLightingShaderPropertyRTTI.get() ? static_cast(uncastedProperty) : nullptr; shaderProperty != nullptr && singleton->IsPBRTextureSet(textureSet)) { { BSLightingShaderMaterialPBR srcMaterial; From b07b979823c76a0bc825a154d6973ea591a5f14f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 12 Jul 2025 22:00:52 +0000 Subject: [PATCH 03/43] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20pre-commi?= =?UTF-8?q?t.ci=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated formatting by clang-format, prettier, and other hooks. See https://pre-commit.ci for details. --- src/Features/LightLimitFix.cpp | 2 +- src/Globals.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Features/LightLimitFix.cpp b/src/Features/LightLimitFix.cpp index 8b0cc09d7c..aca6a6adad 100644 --- a/src/Features/LightLimitFix.cpp +++ b/src/Features/LightLimitFix.cpp @@ -492,7 +492,7 @@ LightLimitFix::ParticleLightReference LightLimitFix::GetParticleLightConfigs(RE: if (auto material = shaderProperty->GetMaterial()) { // Check if it's a valid particle light bool billboard = false; - if (a_pass->geometry->GetRTTI() != globals::rtti::NiParticleSystemRTTI.get()){ + if (a_pass->geometry->GetRTTI() != globals::rtti::NiParticleSystemRTTI.get()) { if (auto parent = a_pass->geometry->parent) { if (auto billboardNode = parent->GetRTTI() == globals::rtti::NiBillboardNodeRTTI.get() ? static_cast(parent) : nullptr) { billboard = true; diff --git a/src/Globals.cpp b/src/Globals.cpp index 416c8e1629..299ea09f54 100644 --- a/src/Globals.cpp +++ b/src/Globals.cpp @@ -194,7 +194,6 @@ namespace globals perFrame = { REL::RelocationID(524768, 411384) }; } - { using namespace rtti; NiIntegerExtraDataRTTI = { RE::NiIntegerExtraData::Ni_RTTI }; From 470971fcafd2cd40b0e6d95a63d2ddbd101fbd85 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Sat, 12 Jul 2025 22:58:00 +0100 Subject: [PATCH 04/43] refactor: rename var --- src/TruePBR.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TruePBR.cpp b/src/TruePBR.cpp index a2290378ef..8c5e138f90 100644 --- a/src/TruePBR.cpp +++ b/src/TruePBR.cpp @@ -1232,8 +1232,8 @@ struct BSTempEffectSimpleDecal_SetupGeometry { func(decal, geometry, textureSet, blended); auto* singleton = globals::truePBR; - auto uncastedProperty = geometry->GetGeometryRuntimeData().properties[1].get(); - if (auto shaderProperty = uncastedProperty->GetRTTI() == globals::rtti::BSLightingShaderPropertyRTTI.get() ? static_cast(uncastedProperty) : nullptr; + auto unknownProperty = geometry->GetGeometryRuntimeData().properties[1].get(); + if (auto shaderProperty = unknownProperty->GetRTTI() == globals::rtti::BSLightingShaderPropertyRTTI.get() ? static_cast(unknownProperty) : nullptr; shaderProperty != nullptr && singleton->IsPBRTextureSet(textureSet)) { { BSLightingShaderMaterialPBR srcMaterial; From 252ffc6c3f3b93ea5c69e6e5ab39330cbcb5ce43 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Mon, 21 Jul 2025 02:52:45 +0100 Subject: [PATCH 05/43] chore: random opt stuff --- package/Shaders/Common/Permutation.hlsli | 3 +- package/Shaders/Lighting.hlsl | 2 +- src/State.cpp | 110 +++++++++++------------ src/State.h | 3 +- 4 files changed, 58 insertions(+), 60 deletions(-) diff --git a/package/Shaders/Common/Permutation.hlsli b/package/Shaders/Common/Permutation.hlsli index 1ac28e6afe..b851c8c87e 100644 --- a/package/Shaders/Common/Permutation.hlsli +++ b/package/Shaders/Common/Permutation.hlsli @@ -60,8 +60,7 @@ namespace Permutation static const uint InReflection = (1 << 1); static const uint IsBeastRace = (1 << 2); static const uint EffectShadows = (1 << 3); - static const uint IsDecal = (1 << 4); - static const uint IsTree = (1 << 5); + static const uint IsTree = (1 << 4); } namespace ExtraFeatureFlags diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 6e81d6e1dc..d5a9705285 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -2344,7 +2344,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(DEFERRED) bool useScreenSpaceShadows = true; # else - bool useScreenSpaceShadows = inWorld && !SharedData::InInterior && Permutation::ExtraShaderDescriptor & Permutation::ExtraFlags::IsDecal; + bool useScreenSpaceShadows = inWorld && !SharedData::InInterior; # endif if (useScreenSpaceShadows) diff --git a/src/State.cpp b/src/State.cpp index 33d943f4d2..f665ac8a44 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -18,14 +18,14 @@ void State::Draw() { - auto lock = Lock(); + //auto lock = Lock(); auto shaderCache = globals::shaderCache; auto deferred = globals::deferred; auto terrainBlending = globals::features::terrainBlending; auto terrainHelper = globals::features::terrainHelper; auto cloudShadows = globals::features::cloudShadows; - auto truePBR = globals::truePBR; - auto smState = globals::game::smState; +// auto truePBR = globals::truePBR; +// auto smState = globals::game::smState; auto context = globals::d3d::context; if (shaderCache->IsEnabled()) { @@ -38,16 +38,16 @@ void State::Draw() if (terrainHelper->loaded) terrainHelper->SetShaderResouces(context); - truePBR->SetShaderResouces(context); + // truePBR->SetShaderResouces(context); - if (!deferred->inReflections) { - if (auto accumulator = RE::BSGraphics::BSShaderAccumulator::GetCurrentAccumulator()) { - // Set an unused bit to indicate if we are rendering an object in the main rendering passes - if (accumulator->GetRuntimeData().activeShadowSceneNode == smState->shadowSceneNode[0]) { - currentExtraDescriptor |= (uint32_t)ExtraShaderDescriptors::InWorld; - } - } - } + //if (!deferred->inReflections) { + // if (auto accumulator = RE::BSGraphics::BSShaderAccumulator::GetCurrentAccumulator()) { + // // Set an unused bit to indicate if we are rendering an object in the main rendering passes + // if (accumulator->GetRuntimeData().activeShadowSceneNode == smState->shadowSceneNode[0]) { + // currentExtraDescriptor |= (uint32_t)ExtraShaderDescriptors::InWorld; + // } + // } + //} if (deferred->inReflections) currentExtraDescriptor |= (uint32_t)ExtraShaderDescriptors::IsReflections; @@ -80,22 +80,22 @@ void State::Draw() if (frameChecker.IsNewFrame()) { // Smooth draw calls and frame times for all shader types - for (int i = 0; i < magic_enum::enum_integer(RE::BSShader::Type::Total) + 1; ++i) { - smoothDrawCalls[i] = smoothDrawCalls[i] * static_cast(0.95) + drawCalls[i] * static_cast(0.05); - smoothFrameTimePerType[i] = smoothFrameTimePerType[i] * static_cast(0.95) + frameTimePerType[i] * static_cast(0.05); - } - // Reset counters for next frame - for (auto& c : drawCalls) - c = 0; - for (auto& ft : frameTimePerType) - ft = 0.0f; - - // Start timing for this frame - if (frameTimingFrequency.QuadPart == 0) { - QueryPerformanceFrequency(&frameTimingFrequency); - } - QueryPerformanceCounter(&frameStartTime); - frameTimingActive = true; + //for (int i = 0; i < magic_enum::enum_integer(RE::BSShader::Type::Total) + 1; ++i) { + // smoothDrawCalls[i] = smoothDrawCalls[i] * static_cast(0.95) + drawCalls[i] * static_cast(0.05); + // smoothFrameTimePerType[i] = smoothFrameTimePerType[i] * static_cast(0.95) + frameTimePerType[i] * static_cast(0.05); + //} + //// Reset counters for next frame + //for (auto& c : drawCalls) + // c = 0; + //for (auto& ft : frameTimePerType) + // ft = 0.0f; + + //// Start timing for this frame + //if (frameTimingFrequency.QuadPart == 0) { + // QueryPerformanceFrequency(&frameTimingFrequency); + //} + //QueryPerformanceCounter(&frameStartTime); + //frameTimingActive = true; ID3D11Buffer* buffers[3] = { permutationCB->CB(), sharedDataCB->CB(), featureDataCB->CB() }; context->PSSetConstantBuffers(4, 3, buffers); @@ -103,25 +103,25 @@ void State::Draw() } // Track time for current shader type if timing is active - if (frameTimingActive && currentShader) { - LARGE_INTEGER currentTime; - QueryPerformanceCounter(¤tTime); + //if (frameTimingActive && currentShader) { + // LARGE_INTEGER currentTime; + // QueryPerformanceCounter(¤tTime); - // Calculate elapsed time in milliseconds - float elapsed = (currentTime.QuadPart - frameStartTime.QuadPart) * 1000.0f / frameTimingFrequency.QuadPart; + // // Calculate elapsed time in milliseconds + // float elapsed = (currentTime.QuadPart - frameStartTime.QuadPart) * 1000.0f / frameTimingFrequency.QuadPart; - // Add elapsed time to the current shader type - frameTimePerType[magic_enum::enum_integer(currentShader->shaderType.get())] += elapsed; - frameTimePerType[magic_enum::enum_integer(RE::BSShader::Type::Total)] += elapsed; + // // Add elapsed time to the current shader type + // frameTimePerType[magic_enum::enum_integer(currentShader->shaderType.get())] += elapsed; + // frameTimePerType[magic_enum::enum_integer(RE::BSShader::Type::Total)] += elapsed; - // Update start time for next measurement - frameStartTime = currentTime; - } + // // Update start time for next measurement + // frameStartTime = currentTime; + //} - if (currentShader) { - drawCalls[magic_enum::enum_integer(currentShader->shaderType.get())]++; - drawCalls[magic_enum::enum_integer(RE::BSShader::Type::Total)]++; - } + //if (currentShader) { + // drawCalls[magic_enum::enum_integer(currentShader->shaderType.get())]++; + // drawCalls[magic_enum::enum_integer(RE::BSShader::Type::Total)]++; + //} if (currentShader && updateShader) { auto type = magic_enum::enum_integer(currentShader->shaderType.get()); @@ -131,18 +131,18 @@ void State::Draw() } } - if (type > 0 && type < magic_enum::enum_integer(RE::BSShader::Type::Total)) { - if (enabledClasses[type - 1]) { - // Only check against non-shader bits - currentPixelDescriptor &= ~modifiedPixelDescriptor; - - if (frameAnnotations) { - BeginPerfEvent(std::format("Draw: CS {}::{:x}::{}", magic_enum::enum_name(currentShader->shaderType.get()), currentPixelDescriptor, currentShader->fxpFilename)); - SetPerfMarker(std::format("Defines: {}", SIE::ShaderCache::GetDefinesString(*currentShader, currentPixelDescriptor))); - EndPerfEvent(); - } - } - } + //if (type > 0 && type < magic_enum::enum_integer(RE::BSShader::Type::Total)) { + // if (enabledClasses[type - 1]) { + // // Only check against non-shader bits + // currentPixelDescriptor &= ~modifiedPixelDescriptor; + + // if (frameAnnotations) { + // BeginPerfEvent(std::format("Draw: CS {}::{:x}::{}", magic_enum::enum_name(currentShader->shaderType.get()), currentPixelDescriptor, currentShader->fxpFilename)); + // SetPerfMarker(std::format("Defines: {}", SIE::ShaderCache::GetDefinesString(*currentShader, currentPixelDescriptor))); + // EndPerfEvent(); + // } + // } + //} } updateShader = false; } diff --git a/src/State.h b/src/State.h index 88ed451e52..1eb1d9275e 100644 --- a/src/State.h +++ b/src/State.h @@ -158,8 +158,7 @@ class State IsReflections = 1 << 1, IsBeastRace = 1 << 2, EffectShadows = 1 << 3, - IsDecal = 1 << 4, - IsTree = 1 << 5 + IsTree = 1 << 4 }; enum class ExtraFeatureDescriptors : uint32_t From 4780ee1121f3ceffbf774fd2cf14610fa28da70b Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Mon, 21 Jul 2025 02:54:11 +0100 Subject: [PATCH 06/43] fix: compile error --- src/State.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/State.cpp b/src/State.cpp index f665ac8a44..598d38d377 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -52,9 +52,6 @@ void State::Draw() if (deferred->inReflections) currentExtraDescriptor |= (uint32_t)ExtraShaderDescriptors::IsReflections; - if (deferred->inDecals) - currentExtraDescriptor |= (uint32_t)ExtraShaderDescriptors::IsDecal; - if (isTree) currentExtraDescriptor |= (uint32_t)ExtraShaderDescriptors::IsTree; From a040562788ea58c92921363105c3aada341dd244 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Mon, 21 Jul 2025 03:02:16 +0100 Subject: [PATCH 07/43] perf: optimise flags --- src/Deferred.cpp | 7 +++---- src/Deferred.h | 2 -- src/Hooks.cpp | 4 ++-- src/State.cpp | 9 --------- src/State.h | 2 -- 5 files changed, 5 insertions(+), 19 deletions(-) diff --git a/src/Deferred.cpp b/src/Deferred.cpp index 697daaa3fe..ee8e2b449d 100644 --- a/src/Deferred.cpp +++ b/src/Deferred.cpp @@ -796,9 +796,7 @@ void Deferred::Hooks::Main_RenderWorld_BlendedDecals::thunk(RE::BSShaderAccumula // Deferred blended decals - deferred->inDecals = true; func(This, RenderFlags); - deferred->inDecals = false; deferred->EndDeferred(); @@ -808,9 +806,10 @@ void Deferred::Hooks::Main_RenderWorld_BlendedDecals::thunk(RE::BSShaderAccumula void Deferred::Hooks::BSCubeMapCamera_RenderCubemap::thunk(RE::NiAVObject* camera, int a2, bool a3, bool a4, bool a5) { auto deferred = globals::deferred; + auto state = globals::state; - deferred->inReflections = true; deferred->ReflectionsPrepasses(); + state->currentExtraDescriptor |= (uint32_t)State::ExtraShaderDescriptors::IsReflections; func(camera, a2, a3, a4, a5); - deferred->inReflections = false; + state->currentExtraDescriptor &= ~(uint32_t)State::ExtraShaderDescriptors::IsReflections; } diff --git a/src/Deferred.h b/src/Deferred.h index 0f6080c39c..fea7e5c363 100644 --- a/src/Deferred.h +++ b/src/Deferred.h @@ -46,8 +46,6 @@ class Deferred ID3D11ComputeShader* mainCompositeCS = nullptr; ID3D11ComputeShader* mainCompositeInteriorCS = nullptr; - bool inDecals = false; - bool inReflections = false; bool deferredPass = false; Texture2D* prevDiffuseAmbientTexture = nullptr; diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 87b1d2f176..a72778213c 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -184,12 +184,12 @@ namespace LightingExtensions { func(shader, pass, renderFlags); - globals::state->isTree = false; + globals::state->currentExtraDescriptor &= ~(uint32_t)State::ExtraShaderDescriptors::IsTree; if (auto userData = pass->geometry->GetUserData()) if (auto baseObject = userData->GetBaseObject()) if (baseObject->As()) - globals::state->isTree = true; + globals::state->currentExtraDescriptor |= (uint32_t)State::ExtraShaderDescriptors::IsTree; } static inline REL::Relocation func; }; diff --git a/src/State.cpp b/src/State.cpp index 598d38d377..29dc61cd63 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -49,12 +49,6 @@ void State::Draw() // } //} - if (deferred->inReflections) - currentExtraDescriptor |= (uint32_t)ExtraShaderDescriptors::IsReflections; - - if (isTree) - currentExtraDescriptor |= (uint32_t)ExtraShaderDescriptors::IsTree; - if (forceUpdatePermutationBuffer || currentPixelDescriptor != lastPixelDescriptor || currentExtraDescriptor != lastExtraDescriptor || currentExtraFeatureDescriptor != lastExtraFeatureDescriptor) { PermutationCB data{}; data.VertexShaderDescriptor = currentVertexDescriptor; @@ -72,9 +66,6 @@ void State::Draw() forceUpdatePermutationBuffer = false; } - currentExtraDescriptor = 0; - currentExtraFeatureDescriptor = 0; - if (frameChecker.IsNewFrame()) { // Smooth draw calls and frame times for all shader types //for (int i = 0; i < magic_enum::enum_integer(RE::BSShader::Type::Total) + 1; ++i) { diff --git a/src/State.h b/src/State.h index 1eb1d9275e..90ed6bcceb 100644 --- a/src/State.h +++ b/src/State.h @@ -150,8 +150,6 @@ class State uint lastExtraFeatureDescriptor = 0; bool forceUpdatePermutationBuffer = true; - bool isTree = false; - enum class ExtraShaderDescriptors : uint32_t { InWorld = 1 << 0, From 4944f030565bd9439d1204f65bb60816583a5def Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Mon, 21 Jul 2025 03:05:00 +0100 Subject: [PATCH 08/43] fix: why was this removed --- src/State.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/State.cpp b/src/State.cpp index 29dc61cd63..895d2093b0 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -48,6 +48,9 @@ void State::Draw() // } // } //} + + // Only check against non-shader bits + currentPixelDescriptor &= ~modifiedPixelDescriptor; if (forceUpdatePermutationBuffer || currentPixelDescriptor != lastPixelDescriptor || currentExtraDescriptor != lastExtraDescriptor || currentExtraFeatureDescriptor != lastExtraFeatureDescriptor) { PermutationCB data{}; From fb0c575a9bd095c7349225b51381abafccea177e Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Mon, 21 Jul 2025 03:07:06 +0100 Subject: [PATCH 09/43] perf: optimise shader setting --- src/Hooks.cpp | 3 +++ src/State.cpp | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index a72778213c..493a17926c 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -129,6 +129,9 @@ bool Hooks::BSShader_BeginTechnique::thunk(RE::BSShader* shader, uint32_t vertex state->ModifyShaderLookup(*shader, state->modifiedVertexDescriptor, state->modifiedPixelDescriptor); + // Only check against non-shader bits + state->currentPixelDescriptor &= ~state->modifiedPixelDescriptor; + bool shaderFound = func(shader, vertexDescriptor, pixelDescriptor, skipPixelShader); if (!shaderFound && shader->shaderType.get() != RE::BSShader::Type::Effect) { diff --git a/src/State.cpp b/src/State.cpp index 895d2093b0..c91c22fc48 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -48,9 +48,7 @@ void State::Draw() // } // } //} - - // Only check against non-shader bits - currentPixelDescriptor &= ~modifiedPixelDescriptor; + if (forceUpdatePermutationBuffer || currentPixelDescriptor != lastPixelDescriptor || currentExtraDescriptor != lastExtraDescriptor || currentExtraFeatureDescriptor != lastExtraFeatureDescriptor) { PermutationCB data{}; From 00854324b248affa4fb64bc481abc82b3a6619c5 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Mon, 21 Jul 2025 03:36:49 +0100 Subject: [PATCH 10/43] chore: more optimisation for hopefully better vectorisation --- src/Deferred.cpp | 4 ++-- src/Features/ExtendedTranslucency.cpp | 6 +++--- src/Features/SubsurfaceScattering.cpp | 4 +++- src/Features/TerrainHelper.cpp | 4 ++-- src/Hooks.cpp | 13 ++++++++----- src/State.cpp | 24 ++++++------------------ src/State.h | 16 ++++++++++++---- 7 files changed, 36 insertions(+), 35 deletions(-) diff --git a/src/Deferred.cpp b/src/Deferred.cpp index ee8e2b449d..f5d7809691 100644 --- a/src/Deferred.cpp +++ b/src/Deferred.cpp @@ -809,7 +809,7 @@ void Deferred::Hooks::BSCubeMapCamera_RenderCubemap::thunk(RE::NiAVObject* camer auto state = globals::state; deferred->ReflectionsPrepasses(); - state->currentExtraDescriptor |= (uint32_t)State::ExtraShaderDescriptors::IsReflections; + state->permutationData.ExtraShaderDescriptor |= (uint32_t)State::ExtraShaderDescriptors::IsReflections; func(camera, a2, a3, a4, a5); - state->currentExtraDescriptor &= ~(uint32_t)State::ExtraShaderDescriptors::IsReflections; + state->permutationData.ExtraShaderDescriptor &= ~(uint32_t)State::ExtraShaderDescriptors::IsReflections; } diff --git a/src/Features/ExtendedTranslucency.cpp b/src/Features/ExtendedTranslucency.cpp index 62fac27fba..bfcdcc956e 100644 --- a/src/Features/ExtendedTranslucency.cpp +++ b/src/Features/ExtendedTranslucency.cpp @@ -21,7 +21,7 @@ ExtendedTranslucency* ExtendedTranslucency::GetSingleton() void ExtendedTranslucency::BSLightingShader_SetupGeometry(RE::BSRenderPass* pass) { - globals::state->currentExtraFeatureDescriptor &= ~(ExtraFeatureDescriptorMask << ExtraFeatureDescriptorShift); + globals::state->permutationData.ExtraFeatureDescriptor &= ~(ExtraFeatureDescriptorMask << ExtraFeatureDescriptorShift); // TODO: PERFORMANCE: Caching the feature descriptor in map if this get more complex auto& unknownProperty = pass->geometry->GetGeometryRuntimeData().properties[RE::BSGeometry::States::kProperty]; static const REL::Relocation NiAlphaPropertyRTTI{ RE::NiAlphaProperty::Ni_RTTI }; @@ -38,7 +38,7 @@ void ExtendedTranslucency::BSLightingShader_SetupGeometry(RE::BSRenderPass* pass // Ensure this is disabled by using the ForceDisabled flag material = MaterialModel::ForceDisabled; } - globals::state->currentExtraFeatureDescriptor |= (material << ExtraFeatureDescriptorShift); + globals::state->permutationData.ExtraFeatureDescriptor |= (material << ExtraFeatureDescriptorShift); // TODO: Per-material settings from Nif // Mods supporting this feature should adjust their alpha value in texture already @@ -46,7 +46,7 @@ void ExtendedTranslucency::BSLightingShader_SetupGeometry(RE::BSRenderPass* pass } } } else { - globals::state->currentExtraFeatureDescriptor |= ((MaterialModel::ForceDisabled) << ExtraFeatureDescriptorShift); + globals::state->permutationData.ExtraFeatureDescriptor |= ((MaterialModel::ForceDisabled) << ExtraFeatureDescriptorShift); } } diff --git a/src/Features/SubsurfaceScattering.cpp b/src/Features/SubsurfaceScattering.cpp index 0525970b85..6bbec3bbed 100644 --- a/src/Features/SubsurfaceScattering.cpp +++ b/src/Features/SubsurfaceScattering.cpp @@ -370,7 +370,9 @@ void SubsurfaceScattering::BSLightingShader_SetupSkin(RE::BSRenderPass* a_pass) validMaterials = true; if (isBeastRace) - state->currentExtraDescriptor |= (uint)State::ExtraShaderDescriptors::IsBeastRace; + state->permutationData.ExtraShaderDescriptor |= (uint)State::ExtraShaderDescriptors::IsBeastRace; + else + state->permutationData.ExtraShaderDescriptor &= ~(uint)State::ExtraShaderDescriptors::IsBeastRace; } } } diff --git a/src/Features/TerrainHelper.cpp b/src/Features/TerrainHelper.cpp index 11c96620db..733075599a 100644 --- a/src/Features/TerrainHelper.cpp +++ b/src/Features/TerrainHelper.cpp @@ -160,10 +160,10 @@ void TerrainHelper::BSLightingShader_SetupMaterial(RE::BSLightingShaderMaterialB for (uint32_t textureI = 0; textureI < 6; ++textureI) { if (materialBase.parallax[textureI] != nullptr && materialBase.parallax[textureI] != stateData.defaultTextureNormalMap) { thExtendedRendererState.SetPSTexture(textureI, materialBase.parallax[textureI]->rendererTexture); - state->currentExtraFeatureDescriptor |= 1 << textureI; + state->permutationData.ExtraFeatureDescriptor |= 1 << textureI; } else { thExtendedRendererState.SetPSTexture(textureI, nullptr); - state->currentExtraFeatureDescriptor &= ~(1 << textureI); + state->permutationData.ExtraFeatureDescriptor &= ~(1 << textureI); } } } \ No newline at end of file diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 493a17926c..6a2c123d68 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -120,17 +120,20 @@ bool Hooks::BSShader_BeginTechnique::thunk(RE::BSShader* shader, uint32_t vertex state->updateShader = true; state->currentShader = shader; - + state->currentVertexDescriptor = vertexDescriptor; state->currentPixelDescriptor = pixelDescriptor; + state->permutationData.VertexShaderDescriptor = vertexDescriptor; + state->permutationData.PixelShaderDescriptor = pixelDescriptor; + state->modifiedVertexDescriptor = vertexDescriptor; state->modifiedPixelDescriptor = pixelDescriptor; state->ModifyShaderLookup(*shader, state->modifiedVertexDescriptor, state->modifiedPixelDescriptor); // Only check against non-shader bits - state->currentPixelDescriptor &= ~state->modifiedPixelDescriptor; + state->permutationData.PixelShaderDescriptor &= ~state->modifiedPixelDescriptor; bool shaderFound = func(shader, vertexDescriptor, pixelDescriptor, skipPixelShader); @@ -171,7 +174,7 @@ namespace EffectExtensions if (auto* shaderProperty = static_cast(pass->geometry->GetGeometryRuntimeData().properties[1].get())) { if (shaderProperty->flags.any(RE::BSShaderProperty::EShaderPropertyFlag::kUniformScale)) { auto state = globals::state; - state->currentExtraDescriptor |= (uint)State::ExtraShaderDescriptors::EffectShadows; + state->permutationData.ExtraShaderDescriptor |= (uint)State::ExtraShaderDescriptors::EffectShadows; } } } @@ -187,12 +190,12 @@ namespace LightingExtensions { func(shader, pass, renderFlags); - globals::state->currentExtraDescriptor &= ~(uint32_t)State::ExtraShaderDescriptors::IsTree; + globals::state->permutationData.ExtraShaderDescriptor &= ~(uint32_t)State::ExtraShaderDescriptors::IsTree; if (auto userData = pass->geometry->GetUserData()) if (auto baseObject = userData->GetBaseObject()) if (baseObject->As()) - globals::state->currentExtraDescriptor |= (uint32_t)State::ExtraShaderDescriptors::IsTree; + globals::state->permutationData.ExtraShaderDescriptor |= (uint32_t)State::ExtraShaderDescriptors::IsTree; } static inline REL::Relocation func; }; diff --git a/src/State.cpp b/src/State.cpp index c91c22fc48..0fc889d784 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -24,7 +24,7 @@ void State::Draw() auto terrainBlending = globals::features::terrainBlending; auto terrainHelper = globals::features::terrainHelper; auto cloudShadows = globals::features::cloudShadows; -// auto truePBR = globals::truePBR; + auto truePBR = globals::truePBR; // auto smState = globals::game::smState; auto context = globals::d3d::context; @@ -38,7 +38,7 @@ void State::Draw() if (terrainHelper->loaded) terrainHelper->SetShaderResouces(context); - // truePBR->SetShaderResouces(context); + truePBR->SetShaderResouces(context); //if (!deferred->inReflections) { // if (auto accumulator = RE::BSGraphics::BSShaderAccumulator::GetCurrentAccumulator()) { @@ -50,21 +50,9 @@ void State::Draw() //} - if (forceUpdatePermutationBuffer || currentPixelDescriptor != lastPixelDescriptor || currentExtraDescriptor != lastExtraDescriptor || currentExtraFeatureDescriptor != lastExtraFeatureDescriptor) { - PermutationCB data{}; - data.VertexShaderDescriptor = currentVertexDescriptor; - data.PixelShaderDescriptor = currentPixelDescriptor; - data.ExtraShaderDescriptor = currentExtraDescriptor; - data.ExtraFeatureDescriptor = currentExtraFeatureDescriptor; - - permutationCB->Update(data); - - lastVertexDescriptor = currentVertexDescriptor; - lastPixelDescriptor = currentPixelDescriptor; - lastExtraDescriptor = currentExtraDescriptor; - lastExtraFeatureDescriptor = currentExtraFeatureDescriptor; - - forceUpdatePermutationBuffer = false; + if (permutationData != permutationDataPrevious) { + permutationCB->Update(permutationData); + permutationDataPrevious = permutationData; } if (frameChecker.IsNewFrame()) { @@ -149,7 +137,7 @@ void State::Reset() lastPixelDescriptor = 0; lastVertexDescriptor = 0; initialized = false; - forceUpdatePermutationBuffer = true; + std::memset(&permutationDataPrevious, 0xFF, sizeof(PermutationCB)); frameCount++; } diff --git a/src/State.h b/src/State.h index 90ed6bcceb..f2712c597e 100644 --- a/src/State.h +++ b/src/State.h @@ -144,11 +144,8 @@ class State uint modifiedPixelDescriptor = 0; uint lastModifiedVertexDescriptor = 0; uint lastModifiedPixelDescriptor = 0; - uint currentExtraDescriptor = 0; uint lastExtraDescriptor = 0; - uint currentExtraFeatureDescriptor = 0; uint lastExtraFeatureDescriptor = 0; - bool forceUpdatePermutationBuffer = true; enum class ExtraShaderDescriptors : uint32_t { @@ -174,12 +171,20 @@ class State void UpdateSharedData(bool a_inWorld, bool a_prepass); - struct alignas(16) PermutationCB + struct PermutationCB { uint VertexShaderDescriptor; uint PixelShaderDescriptor; uint ExtraShaderDescriptor; uint ExtraFeatureDescriptor; + + bool operator==(const PermutationCB& other) const + { + return VertexShaderDescriptor == other.VertexShaderDescriptor && + PixelShaderDescriptor == other.PixelShaderDescriptor && + ExtraShaderDescriptor == other.ExtraShaderDescriptor && + ExtraFeatureDescriptor == other.ExtraFeatureDescriptor; + } }; ConstantBuffer* permutationCB = nullptr; @@ -205,6 +210,9 @@ class State ConstantBuffer* sharedDataCB = nullptr; ConstantBuffer* featureDataCB = nullptr; + PermutationCB permutationData{}; + PermutationCB permutationDataPrevious{}; + Util::FrameChecker frameChecker; uint frameCount = 0; From 791c90090d3bbf2d66b3db9b84ce0024dc0220f9 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Mon, 21 Jul 2025 03:37:18 +0100 Subject: [PATCH 11/43] perf: vibe code truepbr opt --- src/TruePBR.cpp | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/src/TruePBR.cpp b/src/TruePBR.cpp index 25d0178b44..ab3d5bbaa0 100644 --- a/src/TruePBR.cpp +++ b/src/TruePBR.cpp @@ -1604,10 +1604,44 @@ void TruePBR::SetupDefaultPBRLandTextureSet() void TruePBR::SetShaderResouces(ID3D11DeviceContext* a_context) { - for (uint32_t textureIndex = 0; textureIndex < ExtendedRendererState::NumPSTextures; ++textureIndex) { - if (extendedRendererState.PSResourceModifiedBits & (1 << textureIndex)) { - a_context->PSSetShaderResources(ExtendedRendererState::FirstPSTexture + textureIndex, 1, &extendedRendererState.PSTexture[textureIndex]); + uint32_t mask = extendedRendererState.PSResourceModifiedBits; + + if (mask == 0) [[likely]] { + // No dirty slots, early exit + return; + } + + constexpr uint32_t firstTexture = ExtendedRendererState::FirstPSTexture; + auto& textures = extendedRendererState.PSTexture; + + while (mask) { + unsigned long index; + + // Find index of the least significant set bit + _BitScanForward(&index, mask); + + // Start batching from this index + uint32_t batchStart = index; + uint32_t batchCount = 1; + + // Check for consecutive set bits and batch them + uint32_t shiftedMask = mask >> (index + 1); + while ((shiftedMask & 1) != 0) { + ++batchCount; + shiftedMask >>= 1; } + + // Issue one API call for this batch + a_context->PSSetShaderResources( + firstTexture + batchStart, + batchCount, + &textures[batchStart]); + + // Clear the bits we just processed + uint32_t clearMask = ((1u << batchCount) - 1u) << batchStart; + mask &= ~clearMask; } + + // Reset modified bits extendedRendererState.PSResourceModifiedBits = 0; -} +} \ No newline at end of file From bf98ca632b16c6046fcb91d3eee10322846338ec Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Mon, 21 Jul 2025 03:38:29 +0100 Subject: [PATCH 12/43] perf: vibe code terrain helper --- src/Features/TerrainHelper.cpp | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/Features/TerrainHelper.cpp b/src/Features/TerrainHelper.cpp index 733075599a..d8d496a926 100644 --- a/src/Features/TerrainHelper.cpp +++ b/src/Features/TerrainHelper.cpp @@ -122,11 +122,38 @@ struct THExtendedRendererState void TerrainHelper::SetShaderResouces(ID3D11DeviceContext* a_context) { - for (uint32_t textureIndex = 0; textureIndex < THExtendedRendererState::NumPSTextures; ++textureIndex) { - if (thExtendedRendererState.PSResourceModifiedBits & (1 << textureIndex)) { - a_context->PSSetShaderResources(THExtendedRendererState::FirstPSTexture + textureIndex, 1, &thExtendedRendererState.PSTexture[textureIndex]); + uint32_t mask = thExtendedRendererState.PSResourceModifiedBits; + + if (mask == 0) [[likely]] { + return; // Nothing to update + } + + constexpr uint32_t firstTexture = THExtendedRendererState::FirstPSTexture; + auto& textures = thExtendedRendererState.PSTexture; + + while (mask) { + unsigned long index; + + _BitScanForward(&index, mask); + + uint32_t batchStart = index; + uint32_t batchCount = 1; + + uint32_t shiftedMask = mask >> (index + 1); + while ((shiftedMask & 1) != 0) { + ++batchCount; + shiftedMask >>= 1; } + + a_context->PSSetShaderResources( + firstTexture + batchStart, + batchCount, + &textures[batchStart]); + + uint32_t clearMask = ((1u << batchCount) - 1u) << batchStart; + mask &= ~clearMask; } + thExtendedRendererState.PSResourceModifiedBits = 0; } From 997db845e308455923119e9f2d32c6e6992bb512 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Mon, 21 Jul 2025 04:27:33 +0100 Subject: [PATCH 13/43] perf: no new frame in setdirtystates --- src/Deferred.cpp | 31 +++++++++++++++++++++++++++++-- src/Deferred.h | 17 +++++++++++++++++ src/State.cpp | 42 +++++++++++++++++++----------------------- src/TruePBR.cpp | 14 -------------- 4 files changed, 65 insertions(+), 39 deletions(-) diff --git a/src/Deferred.cpp b/src/Deferred.cpp index f5d7809691..043c981118 100644 --- a/src/Deferred.cpp +++ b/src/Deferred.cpp @@ -768,9 +768,12 @@ void Deferred::Hooks::Main_RenderShadowMaps::thunk() void Deferred::Hooks::Main_RenderWorld::thunk(bool a1) { - globals::state->inWorld = true; + auto* const state = globals::state; + state->permutationData.ExtraShaderDescriptor |= (uint32_t)State::ExtraShaderDescriptors::InWorld; + state->inWorld = true; func(a1); - globals::state->inWorld = false; + state->inWorld = false; + state->permutationData.ExtraShaderDescriptor &= ~(uint32_t)State::ExtraShaderDescriptors::InWorld; }; void Deferred::Hooks::Main_RenderWorld_Start::thunk(RE::BSBatchRenderer* This, uint32_t StartRange, uint32_t EndRanges, uint32_t RenderFlags, int GeometryGroup) @@ -813,3 +816,27 @@ void Deferred::Hooks::BSCubeMapCamera_RenderCubemap::thunk(RE::NiAVObject* camer func(camera, a2, a3, a4, a5); state->permutationData.ExtraShaderDescriptor &= ~(uint32_t)State::ExtraShaderDescriptors::IsReflections; } + + +void Deferred::Hooks::Main_RenderFirstPersonView::thunk(bool a1, bool a2) +{ + auto* const state = globals::state; + state->permutationData.ExtraShaderDescriptor |= (uint32_t)State::ExtraShaderDescriptors::InWorld; + func(a1, a2); + state->permutationData.ExtraShaderDescriptor &= ~(uint32_t)State::ExtraShaderDescriptors::InWorld; +} + +void Deferred::Hooks::Renderer_ResetState::thunk(void* This) +{ + func(This); + + auto* const state = globals::state; + auto* const context = globals::d3d::context; + + ID3D11Buffer* buffers[3] = { state->permutationCB->CB(), state->sharedDataCB->CB(), state->featureDataCB->CB() }; + context->PSSetConstantBuffers(4, 3, buffers); + context->CSSetConstantBuffers(5, 2, buffers + 1); + + auto* singleton = globals::truePBR; + singleton->SetupFrame(); +} diff --git a/src/Deferred.h b/src/Deferred.h index fea7e5c363..283a0dc749 100644 --- a/src/Deferred.h +++ b/src/Deferred.h @@ -128,6 +128,18 @@ class Deferred static inline REL::Relocation func; }; + struct Main_RenderFirstPersonView + { + static void thunk(bool a1, bool a2); + static inline REL::Relocation func; + }; + + struct Renderer_ResetState + { + static void thunk(void* This); + static inline REL::Relocation func; + }; + static void Install() { stl::write_vfunc<0x35, BSCubeMapCamera_RenderCubemap>(RE::VTABLE_BSCubeMapCamera[0]); @@ -137,6 +149,11 @@ class Deferred stl::write_thunk_call(REL::RelocationID(35560, 36559).address() + REL::Relocate(0x831, 0x841, 0x791)); stl::write_thunk_call(REL::RelocationID(99938, 106583).address() + REL::Relocate(0x8E, 0x84)); stl::write_thunk_call(REL::RelocationID(99938, 106583).address() + REL::Relocate(0x319, 0x308, 0x321)); + + if (!REL::Module::IsVR()) + stl::write_thunk_call(REL::RelocationID(35560, 36559).address() + REL::Relocate(0x944, 0x954)); + + stl::detour_thunk(REL::RelocationID(75570, 77371)); stl::write_vfunc<0x2, BSImagespaceShaderHDRTonemapBlendCinematic_SetupTechnique>(RE::VTABLE_BSImagespaceShaderHDRTonemapBlendCinematic[0]); stl::write_vfunc<0x2, BSImagespaceShaderHDRTonemapBlendCinematicFade_SetupTechnique>(RE::VTABLE_BSImagespaceShaderHDRTonemapBlendCinematicFade[0]); diff --git a/src/State.cpp b/src/State.cpp index 0fc889d784..c95f936411 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -55,29 +55,25 @@ void State::Draw() permutationDataPrevious = permutationData; } - if (frameChecker.IsNewFrame()) { - // Smooth draw calls and frame times for all shader types - //for (int i = 0; i < magic_enum::enum_integer(RE::BSShader::Type::Total) + 1; ++i) { - // smoothDrawCalls[i] = smoothDrawCalls[i] * static_cast(0.95) + drawCalls[i] * static_cast(0.05); - // smoothFrameTimePerType[i] = smoothFrameTimePerType[i] * static_cast(0.95) + frameTimePerType[i] * static_cast(0.05); - //} - //// Reset counters for next frame - //for (auto& c : drawCalls) - // c = 0; - //for (auto& ft : frameTimePerType) - // ft = 0.0f; - - //// Start timing for this frame - //if (frameTimingFrequency.QuadPart == 0) { - // QueryPerformanceFrequency(&frameTimingFrequency); - //} - //QueryPerformanceCounter(&frameStartTime); - //frameTimingActive = true; - - ID3D11Buffer* buffers[3] = { permutationCB->CB(), sharedDataCB->CB(), featureDataCB->CB() }; - context->PSSetConstantBuffers(4, 3, buffers); - context->CSSetConstantBuffers(5, 2, buffers + 1); - } + //if (frameChecker.IsNewFrame()) { + // // Smooth draw calls and frame times for all shader types + // //for (int i = 0; i < magic_enum::enum_integer(RE::BSShader::Type::Total) + 1; ++i) { + // // smoothDrawCalls[i] = smoothDrawCalls[i] * static_cast(0.95) + drawCalls[i] * static_cast(0.05); + // // smoothFrameTimePerType[i] = smoothFrameTimePerType[i] * static_cast(0.95) + frameTimePerType[i] * static_cast(0.05); + // //} + // //// Reset counters for next frame + // //for (auto& c : drawCalls) + // // c = 0; + // //for (auto& ft : frameTimePerType) + // // ft = 0.0f; + + // //// Start timing for this frame + // //if (frameTimingFrequency.QuadPart == 0) { + // // QueryPerformanceFrequency(&frameTimingFrequency); + // //} + // //QueryPerformanceCounter(&frameStartTime); + // //frameTimingActive = true; + //} // Track time for current shader type if timing is active //if (frameTimingActive && currentShader) { diff --git a/src/TruePBR.cpp b/src/TruePBR.cpp index ab3d5bbaa0..ed353ec01e 100644 --- a/src/TruePBR.cpp +++ b/src/TruePBR.cpp @@ -1213,17 +1213,6 @@ struct TESForm_SetFormEditorID static inline REL::Relocation func; }; -struct SetPerFrameBuffers -{ - static void thunk(void* renderer) - { - func(renderer); - auto* singleton = globals::truePBR; - singleton->SetupFrame(); - } - static inline REL::Relocation func; -}; - struct BSTempEffectSimpleDecal_SetupGeometry { static void thunk(RE::BSTempEffectSimpleDecal* decal, RE::BSGeometry* geometry, RE::BGSTextureSet* textureSet, bool blended) @@ -1562,9 +1551,6 @@ void TruePBR::PostPostLoad() stl::write_vfunc<0x32, TESForm_GetFormEditorID>(RE::VTABLE_TESWeather[0]); stl::write_vfunc<0x33, TESForm_SetFormEditorID>(RE::VTABLE_TESWeather[0]); - logger::info("Hooking SetPerFrameBuffers"); - stl::detour_thunk(REL::RelocationID(75570, 77371)); - logger::info("Hooking BSTempEffectSimpleDecal"); stl::detour_thunk(REL::RelocationID(29253, 30108)); From 162772849e361874e72d01e5ffc72bee036c1ebe Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Mon, 21 Jul 2025 04:36:50 +0100 Subject: [PATCH 14/43] fix: comparison --- src/State.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/State.h b/src/State.h index f2712c597e..76c0f9a2e5 100644 --- a/src/State.h +++ b/src/State.h @@ -180,8 +180,7 @@ class State bool operator==(const PermutationCB& other) const { - return VertexShaderDescriptor == other.VertexShaderDescriptor && - PixelShaderDescriptor == other.PixelShaderDescriptor && + return PixelShaderDescriptor == other.PixelShaderDescriptor && ExtraShaderDescriptor == other.ExtraShaderDescriptor && ExtraFeatureDescriptor == other.ExtraFeatureDescriptor; } From 4cd8f8cc6a022fab0a1e0ce297611531c32020bd Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 03:37:04 +0000 Subject: [PATCH 15/43] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20pre-commi?= =?UTF-8?q?t.ci=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated formatting by clang-format, prettier, and other hooks. See https://pre-commit.ci for details. --- src/Deferred.cpp | 3 +-- src/Deferred.h | 2 +- src/Hooks.cpp | 2 +- src/State.cpp | 5 ++--- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Deferred.cpp b/src/Deferred.cpp index 043c981118..76a4c69919 100644 --- a/src/Deferred.cpp +++ b/src/Deferred.cpp @@ -768,7 +768,7 @@ void Deferred::Hooks::Main_RenderShadowMaps::thunk() void Deferred::Hooks::Main_RenderWorld::thunk(bool a1) { - auto* const state = globals::state; + auto* const state = globals::state; state->permutationData.ExtraShaderDescriptor |= (uint32_t)State::ExtraShaderDescriptors::InWorld; state->inWorld = true; func(a1); @@ -817,7 +817,6 @@ void Deferred::Hooks::BSCubeMapCamera_RenderCubemap::thunk(RE::NiAVObject* camer state->permutationData.ExtraShaderDescriptor &= ~(uint32_t)State::ExtraShaderDescriptors::IsReflections; } - void Deferred::Hooks::Main_RenderFirstPersonView::thunk(bool a1, bool a2) { auto* const state = globals::state; diff --git a/src/Deferred.h b/src/Deferred.h index 283a0dc749..3413db7bd2 100644 --- a/src/Deferred.h +++ b/src/Deferred.h @@ -149,7 +149,7 @@ class Deferred stl::write_thunk_call(REL::RelocationID(35560, 36559).address() + REL::Relocate(0x831, 0x841, 0x791)); stl::write_thunk_call(REL::RelocationID(99938, 106583).address() + REL::Relocate(0x8E, 0x84)); stl::write_thunk_call(REL::RelocationID(99938, 106583).address() + REL::Relocate(0x319, 0x308, 0x321)); - + if (!REL::Module::IsVR()) stl::write_thunk_call(REL::RelocationID(35560, 36559).address() + REL::Relocate(0x944, 0x954)); diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 6a2c123d68..470dc3bbb3 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -120,7 +120,7 @@ bool Hooks::BSShader_BeginTechnique::thunk(RE::BSShader* shader, uint32_t vertex state->updateShader = true; state->currentShader = shader; - + state->currentVertexDescriptor = vertexDescriptor; state->currentPixelDescriptor = pixelDescriptor; diff --git a/src/State.cpp b/src/State.cpp index c95f936411..2de8eea4b2 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -25,7 +25,7 @@ void State::Draw() auto terrainHelper = globals::features::terrainHelper; auto cloudShadows = globals::features::cloudShadows; auto truePBR = globals::truePBR; -// auto smState = globals::game::smState; + // auto smState = globals::game::smState; auto context = globals::d3d::context; if (shaderCache->IsEnabled()) { @@ -49,9 +49,8 @@ void State::Draw() // } //} - if (permutationData != permutationDataPrevious) { - permutationCB->Update(permutationData); + permutationCB->Update(permutationData); permutationDataPrevious = permutationData; } From 6ad82d215262ab25850ad7a17548d549cb734250 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Mon, 21 Jul 2025 16:16:49 +0100 Subject: [PATCH 16/43] refactor: separate into debug function --- src/State.cpp | 162 +++++++++++++++++++++++++++++--------------------- src/State.h | 2 + 2 files changed, 97 insertions(+), 67 deletions(-) diff --git a/src/State.cpp b/src/State.cpp index 2de8eea4b2..c225349ee6 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -18,14 +18,12 @@ void State::Draw() { - //auto lock = Lock(); auto shaderCache = globals::shaderCache; auto deferred = globals::deferred; auto terrainBlending = globals::features::terrainBlending; auto terrainHelper = globals::features::terrainHelper; auto cloudShadows = globals::features::cloudShadows; auto truePBR = globals::truePBR; - // auto smState = globals::game::smState; auto context = globals::d3d::context; if (shaderCache->IsEnabled()) { @@ -40,86 +38,116 @@ void State::Draw() truePBR->SetShaderResouces(context); - //if (!deferred->inReflections) { - // if (auto accumulator = RE::BSGraphics::BSShaderAccumulator::GetCurrentAccumulator()) { - // // Set an unused bit to indicate if we are rendering an object in the main rendering passes - // if (accumulator->GetRuntimeData().activeShadowSceneNode == smState->shadowSceneNode[0]) { - // currentExtraDescriptor |= (uint32_t)ExtraShaderDescriptors::InWorld; - // } - // } - //} - if (permutationData != permutationDataPrevious) { permutationCB->Update(permutationData); permutationDataPrevious = permutationData; } - //if (frameChecker.IsNewFrame()) { - // // Smooth draw calls and frame times for all shader types - // //for (int i = 0; i < magic_enum::enum_integer(RE::BSShader::Type::Total) + 1; ++i) { - // // smoothDrawCalls[i] = smoothDrawCalls[i] * static_cast(0.95) + drawCalls[i] * static_cast(0.05); - // // smoothFrameTimePerType[i] = smoothFrameTimePerType[i] * static_cast(0.95) + frameTimePerType[i] * static_cast(0.05); - // //} - // //// Reset counters for next frame - // //for (auto& c : drawCalls) - // // c = 0; - // //for (auto& ft : frameTimePerType) - // // ft = 0.0f; - - // //// Start timing for this frame - // //if (frameTimingFrequency.QuadPart == 0) { - // // QueryPerformanceFrequency(&frameTimingFrequency); - // //} - // //QueryPerformanceCounter(&frameStartTime); - // //frameTimingActive = true; - //} - - // Track time for current shader type if timing is active - //if (frameTimingActive && currentShader) { - // LARGE_INTEGER currentTime; - // QueryPerformanceCounter(¤tTime); - - // // Calculate elapsed time in milliseconds - // float elapsed = (currentTime.QuadPart - frameStartTime.QuadPart) * 1000.0f / frameTimingFrequency.QuadPart; - - // // Add elapsed time to the current shader type - // frameTimePerType[magic_enum::enum_integer(currentShader->shaderType.get())] += elapsed; - // frameTimePerType[magic_enum::enum_integer(RE::BSShader::Type::Total)] += elapsed; - - // // Update start time for next measurement - // frameStartTime = currentTime; - //} - - //if (currentShader) { - // drawCalls[magic_enum::enum_integer(currentShader->shaderType.get())]++; - // drawCalls[magic_enum::enum_integer(RE::BSShader::Type::Total)]++; - //} - if (currentShader && updateShader) { - auto type = magic_enum::enum_integer(currentShader->shaderType.get()); - if (type == magic_enum::enum_integer(RE::BSShader::Type::Utility)) { - if (currentPixelDescriptor & magic_enum::enum_integer(SIE::ShaderCache::UtilityShaderFlags::RenderShadowmask)) { + if (currentShader->shaderType.get() == RE::BSShader::Type::Utility) { + if (currentPixelDescriptor & (uint32_t)SIE::ShaderCache::UtilityShaderFlags::RenderShadowmask) { deferred->CopyShadowData(); } } + } + + updateShader = false; + } +} - //if (type > 0 && type < magic_enum::enum_integer(RE::BSShader::Type::Total)) { - // if (enabledClasses[type - 1]) { - // // Only check against non-shader bits - // currentPixelDescriptor &= ~modifiedPixelDescriptor; - - // if (frameAnnotations) { - // BeginPerfEvent(std::format("Draw: CS {}::{:x}::{}", magic_enum::enum_name(currentShader->shaderType.get()), currentPixelDescriptor, currentShader->fxpFilename)); - // SetPerfMarker(std::format("Defines: {}", SIE::ShaderCache::GetDefinesString(*currentShader, currentPixelDescriptor))); - // EndPerfEvent(); - // } - // } - //} +void State::DrawDebug() +{ + auto shaderCache = globals::shaderCache; + auto deferred = globals::deferred; + auto terrainBlending = globals::features::terrainBlending; + auto terrainHelper = globals::features::terrainHelper; + auto cloudShadows = globals::features::cloudShadows; + auto truePBR = globals::truePBR; + auto context = globals::d3d::context; + + if (shaderCache->IsEnabled()) { + if (terrainBlending->loaded) + terrainBlending->TerrainShaderHacks(); + + if (cloudShadows->loaded) + cloudShadows->SkyShaderHacks(); + + if (terrainHelper->loaded) + terrainHelper->SetShaderResouces(context); + + truePBR->SetShaderResouces(context); + + if (permutationData != permutationDataPrevious) { + permutationCB->Update(permutationData); + permutationDataPrevious = permutationData; } + + if (currentShader && updateShader && currentShader->shaderType.get() == RE::BSShader::Type::Utility) { + if (currentShader->shaderType.get() == RE::BSShader::Type::Utility) { + if (currentPixelDescriptor & (uint32_t)SIE::ShaderCache::UtilityShaderFlags::RenderShadowmask) { + deferred->CopyShadowData(); + } + } + } + + Debug(); + updateShader = false; } } +void State::Debug() +{ + auto lock = Lock(); + + if (frameChecker.IsNewFrame()) { + // Smooth draw calls and frame times for all shader types + for (int i = 0; i < magic_enum::enum_integer(RE::BSShader::Type::Total) + 1; ++i) { + smoothDrawCalls[i] = smoothDrawCalls[i] * static_cast(0.95) + drawCalls[i] * static_cast(0.05); + smoothFrameTimePerType[i] = smoothFrameTimePerType[i] * static_cast(0.95) + frameTimePerType[i] * static_cast(0.05); + } + // Reset counters for next frame + for (auto& c : drawCalls) + c = 0; + for (auto& ft : frameTimePerType) + ft = 0.0f; + + // Start timing for this frame + if (frameTimingFrequency.QuadPart == 0) { + QueryPerformanceFrequency(&frameTimingFrequency); + } + QueryPerformanceCounter(&frameStartTime); + frameTimingActive = true; + } + + // Track time for current shader type if timing is active + if (frameTimingActive && currentShader) { + LARGE_INTEGER currentTime; + QueryPerformanceCounter(¤tTime); + + // Calculate elapsed time in milliseconds + float elapsed = (currentTime.QuadPart - frameStartTime.QuadPart) * 1000.0f / frameTimingFrequency.QuadPart; + + // Add elapsed time to the current shader type + frameTimePerType[magic_enum::enum_integer(currentShader->shaderType.get())] += elapsed; + frameTimePerType[magic_enum::enum_integer(RE::BSShader::Type::Total)] += elapsed; + + // Update start time for next measurement + frameStartTime = currentTime; + } + + if (currentShader) { + drawCalls[magic_enum::enum_integer(currentShader->shaderType.get())]++; + drawCalls[magic_enum::enum_integer(RE::BSShader::Type::Total)]++; + } + + if (currentShader && updateShader && frameAnnotations) { + BeginPerfEvent(std::format("Draw: CS {}::{:x}::{}", magic_enum::enum_name(currentShader->shaderType.get()), permutationData.PixelShaderDescriptor, currentShader->fxpFilename)); + SetPerfMarker(std::format("Defines: {}", SIE::ShaderCache::GetDefinesString(*currentShader, permutationData.PixelShaderDescriptor))); + EndPerfEvent(); + } +} + void State::Reset() { for (auto* feature : Feature::GetFeatureList()) diff --git a/src/State.h b/src/State.h index 76c0f9a2e5..819457eece 100644 --- a/src/State.h +++ b/src/State.h @@ -81,6 +81,8 @@ class State }; void Draw(); + void DrawDebug(); + void Debug(); void Reset(); void Setup(); From 92d98f8d4a23d8c729d46d3c3a50257d1b9c86bc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 15:22:52 +0000 Subject: [PATCH 17/43] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20pre-commi?= =?UTF-8?q?t.ci=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated formatting by clang-format, prettier, and other hooks. See https://pre-commit.ci for details. --- src/State.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/State.cpp b/src/State.cpp index c225349ee6..3559c339e9 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -91,7 +91,7 @@ void State::DrawDebug() } Debug(); - + updateShader = false; } } From a24f23c0fa82206657afbfbb2ec0704a3c918f9a Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Tue, 22 Jul 2025 16:21:50 +0100 Subject: [PATCH 18/43] perf: remove asm hooks --- package/Shaders/Lighting.hlsl | 2 +- src/Features/LightLimitFix.cpp | 8 +------- src/Features/LightLimitFix.h | 16 +-------------- src/Hooks.cpp | 37 ++++++++++++---------------------- 4 files changed, 16 insertions(+), 47 deletions(-) diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index bc9c9d209e..d99028d33a 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -2308,7 +2308,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) dirLightColorMultiplier *= WaterEffects::ComputeCaustics(waterData, input.WorldPosition.xyz, eyeIndex); # endif - float dirLightAngle = dot(worldNormal.xyz, DirLightDirection.xyz); + float dirLightAngle = dot(worldNormal.xyz, SharedData::DirLightDirection.xyz); if ((Permutation::PixelShaderDescriptor & Permutation::LightingFlags::DefShadow) && (Permutation::PixelShaderDescriptor & Permutation::LightingFlags::ShadowDir)) { dirLightColorMultiplier *= shadowColor.x; diff --git a/src/Features/LightLimitFix.cpp b/src/Features/LightLimitFix.cpp index 4b77e31df9..9acd5a98f1 100644 --- a/src/Features/LightLimitFix.cpp +++ b/src/Features/LightLimitFix.cpp @@ -301,7 +301,7 @@ void LightLimitFix::BSLightingShader_SetupGeometry_Before(RE::BSRenderPass* a_pa } } -void LightLimitFix::BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights(RE::BSRenderPass* a_pass, DirectX::XMMATRIX&, uint32_t, uint32_t, float, Space) +void LightLimitFix::BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights(RE::BSRenderPass* a_pass) { auto shaderCache = globals::shaderCache; auto isl = globals::features::inverseSquareLighting; @@ -1069,12 +1069,6 @@ float LightLimitFix::Hooks::AIProcess_CalculateLightValue_GetLuminance::thunk(RE return ret; } -void LightLimitFix::Hooks::BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights::thunk(RE::BSGraphics::PixelShader* PixelShader, RE::BSRenderPass* Pass, DirectX::XMMATRIX& Transform, uint32_t LightCount, uint32_t ShadowLightCount, float WorldScale, Space RenderSpace) -{ - globals::features::lightLimitFix->BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights(Pass, Transform, LightCount, ShadowLightCount, WorldScale, RenderSpace); - func(PixelShader, Pass, Transform, LightCount, ShadowLightCount, WorldScale, RenderSpace); -} - void LightLimitFix::Hooks::NiNode_Destroy::thunk(RE::NiNode* This) { globals::features::lightLimitFix->CleanupParticleLights(This); diff --git a/src/Features/LightLimitFix.h b/src/Features/LightLimitFix.h index ade8a09717..b86c20cafd 100644 --- a/src/Features/LightLimitFix.h +++ b/src/Features/LightLimitFix.h @@ -225,13 +225,7 @@ struct LightLimitFix : Feature void BSLightingShader_SetupGeometry_Before(RE::BSRenderPass* a_pass); - enum class Space - { - World = 0, - Model = 1, - }; - - void BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights(RE::BSRenderPass* a_pass, DirectX::XMMATRIX& Transform, uint32_t, uint32_t, float WorldScale, Space RenderSpace); + void BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights(RE::BSRenderPass* a_pass); void BSLightingShader_SetupGeometry_After(RE::BSRenderPass* a_pass); @@ -269,12 +263,6 @@ struct LightLimitFix : Feature static inline REL::Relocation func; }; - struct BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights - { - static void thunk(RE::BSGraphics::PixelShader* PixelShader, RE::BSRenderPass* Pass, DirectX::XMMATRIX& Transform, uint32_t LightCount, uint32_t ShadowLightCount, float WorldScale, Space RenderSpace); - static inline REL::Relocation func; - }; - struct NiNode_Destroy { static void thunk(RE::NiNode* This); @@ -303,8 +291,6 @@ struct LightLimitFix : Feature stl::write_vfunc<0x6, BSEffectShader_SetupGeometry>(RE::VTABLE_BSEffectShader[0]); stl::write_vfunc<0x6, BSWaterShader_SetupGeometry>(RE::VTABLE_BSWaterShader[0]); - stl::write_thunk_call(REL::RelocationID(100565, 107300).address() + REL::Relocate(0x523, 0xB0E, 0x5fe)); - stl::detour_thunk(REL::RelocationID(68937, 70288)); stl::write_thunk_call(REL::RelocationID(100994, 107781).address() + 0x92); diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 9ec1375887..9a6c366049 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -1003,6 +1003,17 @@ namespace Hooks { PatchMemory(Address, Data.begin(), Data.size()); } + + struct BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights + { + static void thunk(RE::BSGraphics::PixelShader* PixelShader, RE::BSRenderPass* Pass, DirectX::XMMATRIX& Transform, uint32_t LightCount, uint32_t ShadowLightCount, float WorldScale, uint32_t) + { + if (globals::features::lightLimitFix->loaded) + globals::features::lightLimitFix->BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights(Pass); + func(PixelShader, Pass, Transform, LightCount, ShadowLightCount, WorldScale, 0); + } + static inline REL::Relocation func; + }; /** * @brief Installs hooks, detours, and memory patches for graphics, input, and rendering subsystems. @@ -1112,35 +1123,13 @@ namespace Hooks REL::Relocation(renderPassCacheCtor, 0x191 - 2).address(), reinterpret_cast(&passCountSE), 4); } + if (!REL::Module::IsVR()) { stl::write_thunk_call(REL::RelocationID(35565, 36564).address() + REL::Relocate(0x53, 0x6E)); stl::write_thunk_call(REL::RelocationID(35565, 36564).address() + REL::Relocate(0x5D2, 0xA97)); } - // Patch render space in BSLightingShader::SetupGeometry to always use world space - // The variable updateEyePosition is set to 1 when not skinned. By patching to be 0 it will always use world space - // We offset from the base address of the containing function to the start of the patch - { - logger::info("Patching BSLightingShader::SetupGeometry::updateEyePosition"); - auto setupGeometryUpdateRenderSpace = REL::RelocationID(100565, 107300).address(); - - if (REL::Module::IsAE()) { - std::uint8_t patch[] = { 0x41, 0x83, 0xE7, 0x00 }; // and r15d, 0 - REL::safe_write(setupGeometryUpdateRenderSpace + 0x71, patch, sizeof(patch)); - } else if (REL::Module::IsVR()) { - std::uint8_t patch[] = { 0x41, 0x83, 0xE4, 0x00 }; // and r12d, 0 - REL::safe_write(setupGeometryUpdateRenderSpace + 0x65, patch, sizeof(patch)); - } else { - std::uint8_t patch1[] = { 0xB8, 0x00, 0x00 }; // mov eax, 0 - REL::safe_write(setupGeometryUpdateRenderSpace + 0x73, patch1, sizeof(patch1)); - - std::uint8_t patch2[] = { 0x45, 0x31, 0xC9 }; // xor r9d, r9d (zeros r9d) - REL::safe_write(setupGeometryUpdateRenderSpace + 0x36D, patch2, sizeof(patch2)); - - std::uint8_t patch3[] = { 0x45, 0x31, 0xC0 }; // xor r8d, r8d (zeros r8d) - REL::safe_write(setupGeometryUpdateRenderSpace + 0x378, patch3, sizeof(patch3)); - } - } + stl::write_thunk_call(REL::RelocationID(100565, 107300).address() + REL::Relocate(0x523, 0xB0E, 0x5fe)); } /** From bb2066c0d55406d03738d419d6ac328b14bef6b3 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Tue, 22 Jul 2025 16:22:26 +0100 Subject: [PATCH 19/43] fix: directional ambient --- package/Shaders/Lighting.hlsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index d99028d33a..c55236fae4 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -2740,7 +2740,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) diffuseColor += emitColor.xyz; # endif - float3 directionalAmbientColor = max(0, mul(DirectionalAmbient, float4(worldNormal, 1.0))); + float3 directionalAmbientColor = max(0, mul(SharedData::DirectionalAmbient, float4(worldNormal, 1.0))); # if defined(IBL) if (SharedData::iblSettings.EnableDiffuseIBL && !SharedData::InInterior) { From 605105e2daaf2b96cbcc22b556a588d15edee77a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 22 Jul 2025 15:27:49 +0000 Subject: [PATCH 20/43] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20pre-commi?= =?UTF-8?q?t.ci=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated formatting by clang-format, prettier, and other hooks. See https://pre-commit.ci for details. --- src/Hooks.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 9a6c366049..0703631525 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -1003,7 +1003,7 @@ namespace Hooks { PatchMemory(Address, Data.begin(), Data.size()); } - + struct BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights { static void thunk(RE::BSGraphics::PixelShader* PixelShader, RE::BSRenderPass* Pass, DirectX::XMMATRIX& Transform, uint32_t LightCount, uint32_t ShadowLightCount, float WorldScale, uint32_t) From 808e23f2b1f0a1af62fd7b1e77b8ede6207f7c4f Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Tue, 22 Jul 2025 21:39:50 +0100 Subject: [PATCH 21/43] fix: dir light direction --- package/Shaders/Lighting.hlsl | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index c55236fae4..8b0032c01c 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1270,7 +1270,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) if (SharedData::extendedMaterialSettings.EnableShadows && (parallaxShadowQuality > 0.0f || SharedData::extendedMaterialSettings.ExtendShadows)) { # if defined(TERRAIN_VARIATION) sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); - float shadowMultiplier = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, DirLightDirection, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dx, dy); + float shadowMultiplier = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, SharedData::DirLightDirection.xyz, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dx, dy); # else sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); # endif @@ -2325,12 +2325,12 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) bool inDirShadow = ((Permutation::PixelShaderDescriptor & Permutation::LightingFlags::DefShadow) && (Permutation::PixelShaderDescriptor & Permutation::LightingFlags::ShadowDir) && shadowColor.x == 0) && dirLightAngle > 0.0; # endif - float3 refractedDirLightDirection = DirLightDirection; + float3 refractedDirLightDirection = SharedData::DirLightDirection.xyz; # if defined(TRUE_PBR) && !defined(LANDSCAPE) && !defined(LODLANDSCAPE) [branch] if ((PBRFlags & PBR::Flags::InterlayerParallax) != 0) { - if (dot(DirLightDirection, coatWorldNormal) > 0) - refractedDirLightDirection = -refract(-DirLightDirection, coatWorldNormal, eta); + if (dot(SharedData::DirLightDirection.xyz, coatWorldNormal) > 0) + refractedDirLightDirection = -refract(-SharedData::DirLightDirection.xyz, coatWorldNormal, eta); } # endif @@ -2402,7 +2402,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) { PBR::LightProperties lightProperties = PBR::InitLightProperties(dirLightColor, dirLightColorMultiplier * dirDetailShadow, parallaxShadow); float3 dirDiffuseColor, coatDirDiffuseColor, dirTransmissionColor, dirSpecularColor; - PBR::GetDirectLightInput(dirDiffuseColor, coatDirDiffuseColor, dirTransmissionColor, dirSpecularColor, worldNormal.xyz, coatWorldNormal, refractedViewDirection, viewDirection, refractedDirLightDirection, DirLightDirection, lightProperties, pbrSurfaceProperties, tbnTr, uvOriginal); + PBR::GetDirectLightInput(dirDiffuseColor, coatDirDiffuseColor, dirTransmissionColor, dirSpecularColor, worldNormal.xyz, coatWorldNormal, refractedViewDirection, viewDirection, refractedDirLightDirection, SharedData::DirLightDirection.xyz, lightProperties, pbrSurfaceProperties, tbnTr, uvOriginal); lightsDiffuseColor += dirDiffuseColor; coatLightsDiffuseColor += coatDirDiffuseColor; transmissionColor += dirTransmissionColor; @@ -2412,7 +2412,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # endif # if defined(WETNESS_EFFECTS) if (waterRoughnessSpecular < 1.0) - specularColorPBR += PBR::GetWetnessDirectLightSpecularInput(wetnessNormal, viewDirection, DirLightDirection, lightProperties.CoatLightColor, waterRoughnessSpecular) * wetnessGlossinessSpecular; + specularColorPBR += PBR::GetWetnessDirectLightSpecularInput(wetnessNormal, viewDirection, SharedData::DirLightDirection.xyz, lightProperties.CoatLightColor, waterRoughnessSpecular) * wetnessGlossinessSpecular; # endif } # else @@ -2420,14 +2420,14 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) dirLightColor *= dirLightColorMultiplier; float3 dirDiffuseColor = dirLightColor * saturate(dirLightAngle) * dirDetailShadow; - float dirBacklighting = 1.0 + saturate(-dot(DirLightDirection.xyz, viewDirection)); + float dirBacklighting = 1.0 + saturate(-dot(SharedData::DirLightDirection.xyz, viewDirection)); # if defined(SOFT_LIGHTING) lightsDiffuseColor += dirBacklighting * dirLightColor * GetSoftLightMultiplier(dirLightAngle) * rimSoftLightColor.xyz; # endif # if defined(RIM_LIGHTING) - lightsDiffuseColor += dirBacklighting * dirLightColor * GetRimLightMultiplier(DirLightDirection, viewDirection, worldNormal.xyz) * rimSoftLightColor.xyz; + lightsDiffuseColor += dirBacklighting * dirLightColor * GetRimLightMultiplier(SharedData::DirLightDirection.xyz, viewDirection, worldNormal.xyz) * rimSoftLightColor.xyz; # endif # if defined(BACK_LIGHTING) @@ -2442,17 +2442,17 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(HAIR) && defined(CS_HAIR) if (SharedData::hairSpecularSettings.Enabled) { float3 dirTransmissionColor = 0.0; - float hairShadow = Hair::HairSelfShadow(input.WorldPosition.xyz, DirLightDirection, screenNoise, eyeIndex); - Hair::GetHairDirectLight(dirDiffuseColor, lightsSpecularColor, dirTransmissionColor, hairT, DirLightDirection, viewDirection, worldNormal.xyz, vertexNormal.xyz, dirLightColor.xyz * dirDetailShadow, SharedData::hairSpecularSettings.HairGlossiness, hairShadow, uv, baseColor.xyz); + float hairShadow = Hair::HairSelfShadow(input.WorldPosition.xyz, SharedData::DirLightDirection.xyz, screenNoise, eyeIndex); + Hair::GetHairDirectLight(dirDiffuseColor, lightsSpecularColor, dirTransmissionColor, hairT, SharedData::DirLightDirection.xyz, viewDirection, worldNormal.xyz, vertexNormal.xyz, dirLightColor.xyz * dirDetailShadow, SharedData::hairSpecularSettings.HairGlossiness, hairShadow, uv, baseColor.xyz); transmissionColor += dirTransmissionColor; } else { # if defined(SPECULAR) - lightsSpecularColor = GetLightSpecularInput(input, DirLightDirection, viewDirection, worldNormal.xyz, dirLightColor.xyz * dirDetailShadow, shininess, uv); + lightsSpecularColor = GetLightSpecularInput(input, SharedData::DirLightDirection.xyz, viewDirection, worldNormal.xyz, dirLightColor.xyz * dirDetailShadow, shininess, uv); # endif } # elif defined(SPECULAR) || defined(SPARKLE) - lightsSpecularColor = GetLightSpecularInput(input, DirLightDirection, viewDirection, worldNormal.xyz, dirLightColor.xyz * dirDetailShadow, shininess, uv); + lightsSpecularColor = GetLightSpecularInput(input, SharedData::DirLightDirection.xyz, viewDirection, worldNormal.xyz, dirLightColor.xyz * dirDetailShadow, shininess, uv); # endif } @@ -2460,7 +2460,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(WETNESS_EFFECTS) if (waterRoughnessSpecular < 1.0) - wetnessSpecular += WetnessEffects::GetWetnessSpecular(wetnessNormal, DirLightDirection, viewDirection, dirLightColor * dirDetailShadow, waterRoughnessSpecular); + wetnessSpecular += WetnessEffects::GetWetnessSpecular(wetnessNormal, SharedData::DirLightDirection.xyz, viewDirection, dirLightColor * dirDetailShadow, waterRoughnessSpecular); # endif # endif From 793bc086b33877fcac6bebfd5c558891252d4244 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Tue, 22 Jul 2025 21:43:19 +0100 Subject: [PATCH 22/43] fix: vanilla rendering --- src/Hooks.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 0703631525..ba6fd4fb9c 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -1006,11 +1006,11 @@ namespace Hooks struct BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights { - static void thunk(RE::BSGraphics::PixelShader* PixelShader, RE::BSRenderPass* Pass, DirectX::XMMATRIX& Transform, uint32_t LightCount, uint32_t ShadowLightCount, float WorldScale, uint32_t) + static void thunk(RE::BSGraphics::PixelShader* PixelShader, RE::BSRenderPass* Pass, DirectX::XMMATRIX& Transform, uint32_t LightCount, uint32_t ShadowLightCount, float WorldScale, uint32_t RenderSpace) { if (globals::features::lightLimitFix->loaded) globals::features::lightLimitFix->BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights(Pass); - func(PixelShader, Pass, Transform, LightCount, ShadowLightCount, WorldScale, 0); + func(PixelShader, Pass, Transform, LightCount, ShadowLightCount, WorldScale, globals::shaderCache->IsEnabled() ? 0 : RenderSpace); } static inline REL::Relocation func; }; From 4b613b3bd7dec0a6f725c98be5bf1cf68e363a16 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Wed, 23 Jul 2025 01:49:06 +0100 Subject: [PATCH 23/43] perf: more optimisations --- src/Deferred.cpp | 3 +-- src/Features/LightLimitFix.cpp | 10 +++------- src/Features/ScreenSpaceShadows.cpp | 2 +- src/Features/TerrainShadows.cpp | 2 +- src/Globals.cpp | 3 +++ src/Globals.h | 1 + src/Hooks.cpp | 12 ++++++++---- src/Menu.cpp | 2 +- 8 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/Deferred.cpp b/src/Deferred.cpp index 76a4c69919..e493caf728 100644 --- a/src/Deferred.cpp +++ b/src/Deferred.cpp @@ -336,8 +336,7 @@ void Deferred::StartDeferred() { auto context = globals::d3d::context; - static REL::Relocation perFrame{ REL::RelocationID(524768, 411384) }; - ID3D11Buffer* buffers[1] = { *perFrame.get() }; + ID3D11Buffer* buffers[1] = { *globals::game::perFrame.get() }; ID3D11Buffer* vrBuffer = nullptr; diff --git a/src/Features/LightLimitFix.cpp b/src/Features/LightLimitFix.cpp index 9acd5a98f1..5d3666c938 100644 --- a/src/Features/LightLimitFix.cpp +++ b/src/Features/LightLimitFix.cpp @@ -303,13 +303,9 @@ void LightLimitFix::BSLightingShader_SetupGeometry_Before(RE::BSRenderPass* a_pa void LightLimitFix::BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights(RE::BSRenderPass* a_pass) { - auto shaderCache = globals::shaderCache; auto isl = globals::features::inverseSquareLighting; - if (!shaderCache->IsEnabled()) - return; - - auto accumulator = RE::BSGraphics::BSShaderAccumulator::GetCurrentAccumulator(); + auto accumulator = *globals::game::currentAccumulator.get(); bool inWorld = accumulator->GetRuntimeData().activeShadowSceneNode == globals::game::smState->shadowSceneNode[0]; strictLightDataTemp.NumStrictLights = inWorld ? 0 : (a_pass->numLights - 1); @@ -335,7 +331,7 @@ void LightLimitFix::BSLightingShader_SetupGeometry_GeometrySetupConstantPointLig SetLightPosition(light, niLight->world.translate, inWorld); - if (bsLight->IsShadowLight()) { + if (i < a_pass->numShadowLights) { auto* shadowLight = static_cast(bsLight); GET_INSTANCE_MEMBER(shadowLightIndex, shadowLight); light.shadowMaskIndex = shadowLightIndex; @@ -362,7 +358,7 @@ void LightLimitFix::BSLightingShader_SetupGeometry_After(RE::BSRenderPass*) if (!shaderCache->IsEnabled()) return; - auto accumulator = RE::BSGraphics::BSShaderAccumulator::GetCurrentAccumulator(); + auto accumulator = *globals::game::currentAccumulator.get(); auto shadowSceneNode = smState->shadowSceneNode[0]; diff --git a/src/Features/ScreenSpaceShadows.cpp b/src/Features/ScreenSpaceShadows.cpp index d48480f001..0ed56e97ac 100644 --- a/src/Features/ScreenSpaceShadows.cpp +++ b/src/Features/ScreenSpaceShadows.cpp @@ -91,7 +91,7 @@ void ScreenSpaceShadows::DrawShadows() auto renderer = globals::game::renderer; auto context = globals::d3d::context; - auto accumulator = RE::BSGraphics::BSShaderAccumulator::GetCurrentAccumulator(); + auto accumulator = *globals::game::currentAccumulator.get(); auto dirLight = skyrim_cast(accumulator->GetRuntimeData().activeShadowSceneNode->GetRuntimeData().sunLight->light.get()); auto& directionNi = dirLight->GetWorldDirection(); diff --git a/src/Features/TerrainShadows.cpp b/src/Features/TerrainShadows.cpp index 46471bfc41..b36d1e01ee 100644 --- a/src/Features/TerrainShadows.cpp +++ b/src/Features/TerrainShadows.cpp @@ -320,7 +320,7 @@ void TerrainShadows::UpdateShadow() context->CSSetShaderResources(60, (uint)srvs.size(), srvs.data()); } - auto accumulator = RE::BSGraphics::BSShaderAccumulator::GetCurrentAccumulator(); + auto accumulator = *globals::game::currentAccumulator.get(); auto sunLight = skyrim_cast(accumulator->GetRuntimeData().activeShadowSceneNode->GetRuntimeData().sunLight->light.get()); if (!sunLight) return; diff --git a/src/Globals.cpp b/src/Globals.cpp index a6b9345435..d0c5913ee8 100644 --- a/src/Globals.cpp +++ b/src/Globals.cpp @@ -116,6 +116,7 @@ namespace globals RE::Setting* shadowMaskQuarter = nullptr; REL::Relocation perFrame; + REL::Relocation currentAccumulator; } State* state = nullptr; @@ -195,6 +196,8 @@ namespace globals ui = RE::UI::GetSingleton(); perFrame = { REL::RelocationID(524768, 411384) }; + + currentAccumulator = { REL::RelocationID(527650, 527650) }; } d3d::device = reinterpret_cast(game::renderer->GetRuntimeData().forwarder); diff --git a/src/Globals.h b/src/Globals.h index e93bdf6d4f..5636b86b4c 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -116,6 +116,7 @@ namespace globals extern RE::Setting* bShadowsOnGrass; extern RE::Setting* shadowMaskQuarter; extern REL::Relocation perFrame; + extern REL::Relocation currentAccumulator; } extern State* state; diff --git a/src/Hooks.cpp b/src/Hooks.cpp index ba6fd4fb9c..4f52eb3de9 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -1008,9 +1008,13 @@ namespace Hooks { static void thunk(RE::BSGraphics::PixelShader* PixelShader, RE::BSRenderPass* Pass, DirectX::XMMATRIX& Transform, uint32_t LightCount, uint32_t ShadowLightCount, float WorldScale, uint32_t RenderSpace) { - if (globals::features::lightLimitFix->loaded) - globals::features::lightLimitFix->BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights(Pass); - func(PixelShader, Pass, Transform, LightCount, ShadowLightCount, WorldScale, globals::shaderCache->IsEnabled() ? 0 : RenderSpace); + if (globals::shaderCache->IsEnabled()) + if (globals::features::lightLimitFix->loaded) + globals::features::lightLimitFix->BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights(Pass); + else + func(PixelShader, Pass, Transform, LightCount, ShadowLightCount, WorldScale, 0); + else + func(PixelShader, Pass, Transform, LightCount, ShadowLightCount, WorldScale, RenderSpace); } static inline REL::Relocation func; }; @@ -1129,7 +1133,7 @@ namespace Hooks stl::write_thunk_call(REL::RelocationID(35565, 36564).address() + REL::Relocate(0x5D2, 0xA97)); } - stl::write_thunk_call(REL::RelocationID(100565, 107300).address() + REL::Relocate(0x523, 0xB0E, 0x5fe)); + stl::write_thunk_call(REL::RelocationID(100565, 107300).address() + REL::Relocate(0x523, 0xB0E, 0x5FE)); } /** diff --git a/src/Menu.cpp b/src/Menu.cpp index 4fa6a77ccc..e128865923 100644 --- a/src/Menu.cpp +++ b/src/Menu.cpp @@ -1495,7 +1495,7 @@ void Menu::DrawAdvancedSettings() } if (ImGui::TreeNodeEx("Addresses")) { auto Renderer = globals::game::renderer; - auto BSShaderAccumulator = RE::BSGraphics::BSShaderAccumulator::GetCurrentAccumulator(); + auto BSShaderAccumulator = *globals::game::currentAccumulator.get(); auto RendererShadowState = globals::game::shadowState; ADDRESS_NODE(Renderer) ADDRESS_NODE(BSShaderAccumulator) From bba13344e0b2e936404e5fbddaec3309a3f1805c Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Wed, 23 Jul 2025 01:51:27 +0100 Subject: [PATCH 24/43] fix: fix compile error --- src/Globals.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Globals.cpp b/src/Globals.cpp index 299ea09f54..eae81a3003 100644 --- a/src/Globals.cpp +++ b/src/Globals.cpp @@ -116,6 +116,15 @@ namespace globals REL::Relocation perFrame; } + namespace rtti + { + REL::Relocation NiIntegerExtraDataRTTI; + REL::Relocation BSLightingShaderPropertyRTTI; + REL::Relocation BSEffectShaderPropertyRTTI; + REL::Relocation NiParticleSystemRTTI; + REL::Relocation NiBillboardNodeRTTI; + } + State* state = nullptr; Deferred* deferred = nullptr; TruePBR* truePBR = nullptr; From f88ea98fa5bd7e77d2705dc7ad5104ab3aebac91 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Wed, 23 Jul 2025 01:59:16 +0100 Subject: [PATCH 25/43] chore: more things --- src/Features/ExtendedTranslucency.cpp | 5 ++--- src/Globals.cpp | 4 +++- src/Globals.h | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Features/ExtendedTranslucency.cpp b/src/Features/ExtendedTranslucency.cpp index b92c9860d3..b48cb9284d 100644 --- a/src/Features/ExtendedTranslucency.cpp +++ b/src/Features/ExtendedTranslucency.cpp @@ -24,12 +24,11 @@ void ExtendedTranslucency::BSLightingShader_SetupGeometry(RE::BSRenderPass* pass globals::state->permutationData.ExtraFeatureDescriptor &= ~(ExtraFeatureDescriptorMask << ExtraFeatureDescriptorShift); // TODO: PERFORMANCE: Caching the feature descriptor in map if this get more complex auto& unknownProperty = pass->geometry->GetGeometryRuntimeData().properties[RE::BSGeometry::States::kProperty]; - static const REL::Relocation NiAlphaPropertyRTTI{ RE::NiAlphaProperty::Ni_RTTI }; - auto alphaProperty = unknownProperty && unknownProperty->GetRTTI() == NiAlphaPropertyRTTI.get() ? static_cast(unknownProperty.get()) : nullptr; + auto alphaProperty = unknownProperty && unknownProperty->GetRTTI() == globals::rtti::NiAlphaPropertyRTTI.get() ? static_cast(unknownProperty.get()) : nullptr; // Check alpha property exists and blending is enabled if (alphaProperty && alphaProperty->GetAlphaBlending()) { if (auto* data = pass->geometry->GetExtraData(NiExtraDataName_AnisotropicAlphaMaterial)) { - i f (data->GetRTTI() == globals::rtti::NiIntegerExtraDataRTTI.get()) { + if (data->GetRTTI() == globals::rtti::NiIntegerExtraDataRTTI.get()) { uint32_t material = static_cast(static_cast(data)->value) & ExtraFeatureDescriptorMask; if (material == MaterialModel::Disabled) { // MaterialModel::Disabled (0) is the flag when this extra does not exist diff --git a/src/Globals.cpp b/src/Globals.cpp index 62da30497c..10f02e8b2f 100644 --- a/src/Globals.cpp +++ b/src/Globals.cpp @@ -126,6 +126,7 @@ namespace globals REL::Relocation BSEffectShaderPropertyRTTI; REL::Relocation NiParticleSystemRTTI; REL::Relocation NiBillboardNodeRTTI; + REL::Relocation NiAlphaPropertyRTTI; } State* state = nullptr; @@ -206,7 +207,7 @@ namespace globals ui = RE::UI::GetSingleton(); perFrame = { REL::RelocationID(524768, 411384) }; - currentAccumulator = { REL::RelocationID(527650, 527650) }; + currentAccumulator = { REL::RelocationID(527650, 414600) }; } { @@ -216,6 +217,7 @@ namespace globals BSEffectShaderPropertyRTTI = { RE::BSEffectShaderProperty::Ni_RTTI }; NiParticleSystemRTTI = { RE::NiParticleSystem::Ni_RTTI }; NiBillboardNodeRTTI = { RE::NiBillboardNode::Ni_RTTI }; + NiAlphaPropertyRTTI = { RE::NiAlphaProperty::Ni_RTTI }; } d3d::device = reinterpret_cast(game::renderer->GetRuntimeData().forwarder); diff --git a/src/Globals.h b/src/Globals.h index 01f7583680..9626dc28c9 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -126,6 +126,7 @@ namespace globals extern REL::Relocation BSEffectShaderPropertyRTTI; extern REL::Relocation NiParticleSystemRTTI; extern REL::Relocation NiBillboardNodeRTTI; + extern REL::Relocation NiAlphaPropertyRTTI; } extern State* state; From d054ed3445a9662f923e8c5bc7053ebe862bc4ca Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 23 Jul 2025 00:59:38 +0000 Subject: [PATCH 26/43] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20pre-commi?= =?UTF-8?q?t.ci=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated formatting by clang-format, prettier, and other hooks. See https://pre-commit.ci for details. --- src/Features/ExtendedTranslucency.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Features/ExtendedTranslucency.cpp b/src/Features/ExtendedTranslucency.cpp index b92c9860d3..c1d4d7f536 100644 --- a/src/Features/ExtendedTranslucency.cpp +++ b/src/Features/ExtendedTranslucency.cpp @@ -29,7 +29,8 @@ void ExtendedTranslucency::BSLightingShader_SetupGeometry(RE::BSRenderPass* pass // Check alpha property exists and blending is enabled if (alphaProperty && alphaProperty->GetAlphaBlending()) { if (auto* data = pass->geometry->GetExtraData(NiExtraDataName_AnisotropicAlphaMaterial)) { - i f (data->GetRTTI() == globals::rtti::NiIntegerExtraDataRTTI.get()) { + i f(data->GetRTTI() == globals::rtti::NiIntegerExtraDataRTTI.get()) + { uint32_t material = static_cast(static_cast(data)->value) & ExtraFeatureDescriptorMask; if (material == MaterialModel::Disabled) { // MaterialModel::Disabled (0) is the flag when this extra does not exist From 25a05ce5fc19b6dae9ac61ffad5f29f291ff89ad Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Wed, 23 Jul 2025 02:07:11 +0100 Subject: [PATCH 27/43] chore: vr offset --- src/Globals.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Globals.cpp b/src/Globals.cpp index 10f02e8b2f..104547a0a3 100644 --- a/src/Globals.cpp +++ b/src/Globals.cpp @@ -207,7 +207,7 @@ namespace globals ui = RE::UI::GetSingleton(); perFrame = { REL::RelocationID(524768, 411384) }; - currentAccumulator = { REL::RelocationID(527650, 414600) }; + currentAccumulator = { REL::VariantID(527650, 414600, 0x3423058) }; } { From 40b859a9c3b0088cbc723b175b9bc6546d5aa1b5 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Wed, 23 Jul 2025 15:35:56 +0100 Subject: [PATCH 28/43] chore: leave in asm patch --- src/Hooks.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 4f52eb3de9..587b6ab12f 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -1133,6 +1133,32 @@ namespace Hooks stl::write_thunk_call(REL::RelocationID(35565, 36564).address() + REL::Relocate(0x5D2, 0xA97)); } + + // Patch render space in BSLightingShader::SetupGeometry to always use world space + // The variable updateEyePosition is set to 1 when not skinned. By patching to be 0 it will always use world space + // We offset from the base address of the containing function to the start of the patch + { + logger::info("Patching BSLightingShader::SetupGeometry::updateEyePosition"); + auto setupGeometryUpdateRenderSpace = REL::RelocationID(100565, 107300).address(); + + if (REL::Module::IsAE()) { + std::uint8_t patch[] = { 0x41, 0x83, 0xE7, 0x00 }; // and r15d, 0 + REL::safe_write(setupGeometryUpdateRenderSpace + 0x71, patch, sizeof(patch)); + } else if (REL::Module::IsVR()) { + std::uint8_t patch[] = { 0x41, 0x83, 0xE4, 0x00 }; // and r12d, 0 + REL::safe_write(setupGeometryUpdateRenderSpace + 0x65, patch, sizeof(patch)); + } else { + std::uint8_t patch1[] = { 0xB8, 0x00, 0x00 }; // mov eax, 0 + REL::safe_write(setupGeometryUpdateRenderSpace + 0x73, patch1, sizeof(patch1)); + + std::uint8_t patch2[] = { 0x45, 0x31, 0xC9 }; // xor r9d, r9d (zeros r9d) + REL::safe_write(setupGeometryUpdateRenderSpace + 0x36D, patch2, sizeof(patch2)); + + std::uint8_t patch3[] = { 0x45, 0x31, 0xC0 }; // xor r8d, r8d (zeros r8d) + REL::safe_write(setupGeometryUpdateRenderSpace + 0x378, patch3, sizeof(patch3)); + } + } + stl::write_thunk_call(REL::RelocationID(100565, 107300).address() + REL::Relocate(0x523, 0xB0E, 0x5FE)); } From c9a90aa2960b10f44744effdf3041be69159f031 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Wed, 23 Jul 2025 15:37:25 +0100 Subject: [PATCH 29/43] chore: remove drawdebug --- src/State.cpp | 39 --------------------------------------- src/State.h | 1 - 2 files changed, 40 deletions(-) diff --git a/src/State.cpp b/src/State.cpp index 3559c339e9..c3d7bd8f18 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -51,45 +51,6 @@ void State::Draw() } } - updateShader = false; - } -} - -void State::DrawDebug() -{ - auto shaderCache = globals::shaderCache; - auto deferred = globals::deferred; - auto terrainBlending = globals::features::terrainBlending; - auto terrainHelper = globals::features::terrainHelper; - auto cloudShadows = globals::features::cloudShadows; - auto truePBR = globals::truePBR; - auto context = globals::d3d::context; - - if (shaderCache->IsEnabled()) { - if (terrainBlending->loaded) - terrainBlending->TerrainShaderHacks(); - - if (cloudShadows->loaded) - cloudShadows->SkyShaderHacks(); - - if (terrainHelper->loaded) - terrainHelper->SetShaderResouces(context); - - truePBR->SetShaderResouces(context); - - if (permutationData != permutationDataPrevious) { - permutationCB->Update(permutationData); - permutationDataPrevious = permutationData; - } - - if (currentShader && updateShader && currentShader->shaderType.get() == RE::BSShader::Type::Utility) { - if (currentShader->shaderType.get() == RE::BSShader::Type::Utility) { - if (currentPixelDescriptor & (uint32_t)SIE::ShaderCache::UtilityShaderFlags::RenderShadowmask) { - deferred->CopyShadowData(); - } - } - } - Debug(); updateShader = false; diff --git a/src/State.h b/src/State.h index 819457eece..9b62847e75 100644 --- a/src/State.h +++ b/src/State.h @@ -81,7 +81,6 @@ class State }; void Draw(); - void DrawDebug(); void Debug(); void Reset(); void Setup(); From 9e1b7b2c78c4734728a30507385b5c1ec984c519 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 23 Jul 2025 14:41:58 +0000 Subject: [PATCH 30/43] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20pre-commi?= =?UTF-8?q?t.ci=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated formatting by clang-format, prettier, and other hooks. See https://pre-commit.ci for details. --- src/Hooks.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 587b6ab12f..d8d2f549f4 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -1133,7 +1133,6 @@ namespace Hooks stl::write_thunk_call(REL::RelocationID(35565, 36564).address() + REL::Relocate(0x5D2, 0xA97)); } - // Patch render space in BSLightingShader::SetupGeometry to always use world space // The variable updateEyePosition is set to 1 when not skinned. By patching to be 0 it will always use world space // We offset from the base address of the containing function to the start of the patch From f4ca6af1d481843a5ab6f5992f0cf75fc0463f96 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Wed, 23 Jul 2025 15:40:03 +0100 Subject: [PATCH 31/43] chore: bump addresslib --- src/Globals.cpp | 2 +- src/XSEPlugin.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Globals.cpp b/src/Globals.cpp index 104547a0a3..10f02e8b2f 100644 --- a/src/Globals.cpp +++ b/src/Globals.cpp @@ -207,7 +207,7 @@ namespace globals ui = RE::UI::GetSingleton(); perFrame = { REL::RelocationID(524768, 411384) }; - currentAccumulator = { REL::VariantID(527650, 414600, 0x3423058) }; + currentAccumulator = { REL::RelocationID(527650, 414600) }; } { diff --git a/src/XSEPlugin.cpp b/src/XSEPlugin.cpp index 3a8aed640a..9689b31bff 100644 --- a/src/XSEPlugin.cpp +++ b/src/XSEPlugin.cpp @@ -154,7 +154,7 @@ bool Load() } if (REL::Module::IsVR()) { - REL::IDDatabase::get().IsVRAddressLibraryAtLeastVersion("0.181.0", true); + REL::IDDatabase::get().IsVRAddressLibraryAtLeastVersion("0.182.0", true); } auto privateProfileRedirectorVersion = Util::GetDllVersion(L"Data/SKSE/Plugins/PrivateProfileRedirector.dll"); From 500a9935c523171b334f607b2224a0383f355abd Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Wed, 23 Jul 2025 15:42:42 +0100 Subject: [PATCH 32/43] refactor: use std::countr_zero/countr_one --- src/Features/TerrainHelper.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/Features/TerrainHelper.cpp b/src/Features/TerrainHelper.cpp index d8d496a926..192a379ce5 100644 --- a/src/Features/TerrainHelper.cpp +++ b/src/Features/TerrainHelper.cpp @@ -132,24 +132,19 @@ void TerrainHelper::SetShaderResouces(ID3D11DeviceContext* a_context) auto& textures = thExtendedRendererState.PSTexture; while (mask) { - unsigned long index; - - _BitScanForward(&index, mask); - - uint32_t batchStart = index; - uint32_t batchCount = 1; - - uint32_t shiftedMask = mask >> (index + 1); - while ((shiftedMask & 1) != 0) { - ++batchCount; - shiftedMask >>= 1; - } + // Find the position of the first set bit + uint32_t batchStart = std::countr_zero(mask); + + // Count consecutive 1s starting from batchStart + uint32_t shiftedMask = mask >> batchStart; + uint32_t batchCount = std::countr_one(shiftedMask); a_context->PSSetShaderResources( firstTexture + batchStart, batchCount, &textures[batchStart]); + // Clear the processed bits uint32_t clearMask = ((1u << batchCount) - 1u) << batchStart; mask &= ~clearMask; } From 36887896011d622d1fe269563f63974f0f288fff Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Wed, 23 Jul 2025 15:44:26 +0100 Subject: [PATCH 33/43] refactor: update truepbr --- src/TruePBR.cpp | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/TruePBR.cpp b/src/TruePBR.cpp index c9d5d11795..8959c077d2 100644 --- a/src/TruePBR.cpp +++ b/src/TruePBR.cpp @@ -1601,21 +1601,12 @@ void TruePBR::SetShaderResouces(ID3D11DeviceContext* a_context) auto& textures = extendedRendererState.PSTexture; while (mask) { - unsigned long index; - // Find index of the least significant set bit - _BitScanForward(&index, mask); - - // Start batching from this index - uint32_t batchStart = index; - uint32_t batchCount = 1; - + uint32_t batchStart = std::countr_zero(mask); + // Check for consecutive set bits and batch them - uint32_t shiftedMask = mask >> (index + 1); - while ((shiftedMask & 1) != 0) { - ++batchCount; - shiftedMask >>= 1; - } + uint32_t shiftedMask = mask >> batchStart; + uint32_t batchCount = std::countr_one(shiftedMask); // Issue one API call for this batch a_context->PSSetShaderResources( From 763ade09558b6cbf80bad386b521fbdb86e9c530 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 23 Jul 2025 14:48:42 +0000 Subject: [PATCH 34/43] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20pre-commi?= =?UTF-8?q?t.ci=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated formatting by clang-format, prettier, and other hooks. See https://pre-commit.ci for details. --- src/Features/TerrainHelper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Features/TerrainHelper.cpp b/src/Features/TerrainHelper.cpp index 192a379ce5..883076be4e 100644 --- a/src/Features/TerrainHelper.cpp +++ b/src/Features/TerrainHelper.cpp @@ -134,7 +134,7 @@ void TerrainHelper::SetShaderResouces(ID3D11DeviceContext* a_context) while (mask) { // Find the position of the first set bit uint32_t batchStart = std::countr_zero(mask); - + // Count consecutive 1s starting from batchStart uint32_t shiftedMask = mask >> batchStart; uint32_t batchCount = std::countr_one(shiftedMask); From f42b2f63a5d6850fdbf942a80e62332a212e9e4e Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Wed, 23 Jul 2025 15:47:16 +0100 Subject: [PATCH 35/43] chore: use cpp cast --- src/Deferred.cpp | 12 ++++++------ src/Hooks.cpp | 4 ++-- src/State.cpp | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Deferred.cpp b/src/Deferred.cpp index e493caf728..8956c7e7e6 100644 --- a/src/Deferred.cpp +++ b/src/Deferred.cpp @@ -768,11 +768,11 @@ void Deferred::Hooks::Main_RenderShadowMaps::thunk() void Deferred::Hooks::Main_RenderWorld::thunk(bool a1) { auto* const state = globals::state; - state->permutationData.ExtraShaderDescriptor |= (uint32_t)State::ExtraShaderDescriptors::InWorld; + state->permutationData.ExtraShaderDescriptor |= static_cast(State::ExtraShaderDescriptors::InWorld); state->inWorld = true; func(a1); state->inWorld = false; - state->permutationData.ExtraShaderDescriptor &= ~(uint32_t)State::ExtraShaderDescriptors::InWorld; + state->permutationData.ExtraShaderDescriptor &= ~static_cast(State::ExtraShaderDescriptors::InWorld); }; void Deferred::Hooks::Main_RenderWorld_Start::thunk(RE::BSBatchRenderer* This, uint32_t StartRange, uint32_t EndRanges, uint32_t RenderFlags, int GeometryGroup) @@ -811,17 +811,17 @@ void Deferred::Hooks::BSCubeMapCamera_RenderCubemap::thunk(RE::NiAVObject* camer auto state = globals::state; deferred->ReflectionsPrepasses(); - state->permutationData.ExtraShaderDescriptor |= (uint32_t)State::ExtraShaderDescriptors::IsReflections; + state->permutationData.ExtraShaderDescriptor |= static_cast(State::ExtraShaderDescriptors::IsReflections); func(camera, a2, a3, a4, a5); - state->permutationData.ExtraShaderDescriptor &= ~(uint32_t)State::ExtraShaderDescriptors::IsReflections; + state->permutationData.ExtraShaderDescriptor &= ~static_cast(State::ExtraShaderDescriptors::IsReflections); } void Deferred::Hooks::Main_RenderFirstPersonView::thunk(bool a1, bool a2) { auto* const state = globals::state; - state->permutationData.ExtraShaderDescriptor |= (uint32_t)State::ExtraShaderDescriptors::InWorld; + state->permutationData.ExtraShaderDescriptor |= static_cast(State::ExtraShaderDescriptors::InWorld); func(a1, a2); - state->permutationData.ExtraShaderDescriptor &= ~(uint32_t)State::ExtraShaderDescriptors::InWorld; + state->permutationData.ExtraShaderDescriptor &= ~static_cast(State::ExtraShaderDescriptors::InWorld); } void Deferred::Hooks::Renderer_ResetState::thunk(void* This) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index d8d2f549f4..536edb03b6 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -190,12 +190,12 @@ namespace LightingExtensions { func(shader, pass, renderFlags); - globals::state->permutationData.ExtraShaderDescriptor &= ~(uint32_t)State::ExtraShaderDescriptors::IsTree; + globals::state->permutationData.ExtraShaderDescriptor &= ~static_cast(State::ExtraShaderDescriptors::IsTree); if (auto userData = pass->geometry->GetUserData()) if (auto baseObject = userData->GetBaseObject()) if (baseObject->As()) - globals::state->permutationData.ExtraShaderDescriptor |= (uint32_t)State::ExtraShaderDescriptors::IsTree; + globals::state->permutationData.ExtraShaderDescriptor |= static_cast(State::ExtraShaderDescriptors::IsTree); } static inline REL::Relocation func; }; diff --git a/src/State.cpp b/src/State.cpp index c3d7bd8f18..350722f40d 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -45,7 +45,7 @@ void State::Draw() if (currentShader && updateShader) { if (currentShader->shaderType.get() == RE::BSShader::Type::Utility) { - if (currentPixelDescriptor & (uint32_t)SIE::ShaderCache::UtilityShaderFlags::RenderShadowmask) { + if (currentPixelDescriptor & static_cast(SIE::ShaderCache::UtilityShaderFlags::RenderShadowmask)) { deferred->CopyShadowData(); } } From 208264fc1cc8e139e5d3f2f7bace438566064a10 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Wed, 23 Jul 2025 15:48:38 +0100 Subject: [PATCH 36/43] chore: revert direct light changes --- package/Shaders/Lighting.hlsl | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 8b0032c01c..1d29835eac 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1270,7 +1270,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) if (SharedData::extendedMaterialSettings.EnableShadows && (parallaxShadowQuality > 0.0f || SharedData::extendedMaterialSettings.ExtendShadows)) { # if defined(TERRAIN_VARIATION) sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, sharedOffset, dx, dy, weights); - float shadowMultiplier = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, SharedData::DirLightDirection.xyz, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dx, dy); + float shadowMultiplier = ExtendedMaterials::GetParallaxSoftShadowMultiplierTerrain(input, uv, mipLevels, DirLightDirection, sh0, parallaxShadowQuality, screenNoise, displacementParams, sharedOffset, dx, dy); # else sh0 = ExtendedMaterials::GetTerrainHeight(screenNoise, input, uv, mipLevels, displacementParams, parallaxShadowQuality, input.LandBlendWeights1, input.LandBlendWeights2.xy, weights); # endif @@ -2308,7 +2308,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) dirLightColorMultiplier *= WaterEffects::ComputeCaustics(waterData, input.WorldPosition.xyz, eyeIndex); # endif - float dirLightAngle = dot(worldNormal.xyz, SharedData::DirLightDirection.xyz); + float dirLightAngle = dot(worldNormal.xyz, DirLightDirection); if ((Permutation::PixelShaderDescriptor & Permutation::LightingFlags::DefShadow) && (Permutation::PixelShaderDescriptor & Permutation::LightingFlags::ShadowDir)) { dirLightColorMultiplier *= shadowColor.x; @@ -2325,12 +2325,12 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) bool inDirShadow = ((Permutation::PixelShaderDescriptor & Permutation::LightingFlags::DefShadow) && (Permutation::PixelShaderDescriptor & Permutation::LightingFlags::ShadowDir) && shadowColor.x == 0) && dirLightAngle > 0.0; # endif - float3 refractedDirLightDirection = SharedData::DirLightDirection.xyz; + float3 refractedDirLightDirection = DirLightDirection; # if defined(TRUE_PBR) && !defined(LANDSCAPE) && !defined(LODLANDSCAPE) [branch] if ((PBRFlags & PBR::Flags::InterlayerParallax) != 0) { - if (dot(SharedData::DirLightDirection.xyz, coatWorldNormal) > 0) - refractedDirLightDirection = -refract(-SharedData::DirLightDirection.xyz, coatWorldNormal, eta); + if (dot(DirLightDirection, coatWorldNormal) > 0) + refractedDirLightDirection = -refract(-DirLightDirection, coatWorldNormal, eta); } # endif @@ -2402,7 +2402,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) { PBR::LightProperties lightProperties = PBR::InitLightProperties(dirLightColor, dirLightColorMultiplier * dirDetailShadow, parallaxShadow); float3 dirDiffuseColor, coatDirDiffuseColor, dirTransmissionColor, dirSpecularColor; - PBR::GetDirectLightInput(dirDiffuseColor, coatDirDiffuseColor, dirTransmissionColor, dirSpecularColor, worldNormal.xyz, coatWorldNormal, refractedViewDirection, viewDirection, refractedDirLightDirection, SharedData::DirLightDirection.xyz, lightProperties, pbrSurfaceProperties, tbnTr, uvOriginal); + PBR::GetDirectLightInput(dirDiffuseColor, coatDirDiffuseColor, dirTransmissionColor, dirSpecularColor, worldNormal.xyz, coatWorldNormal, refractedViewDirection, viewDirection, refractedDirLightDirection, DirLightDirection, lightProperties, pbrSurfaceProperties, tbnTr, uvOriginal); lightsDiffuseColor += dirDiffuseColor; coatLightsDiffuseColor += coatDirDiffuseColor; transmissionColor += dirTransmissionColor; @@ -2412,7 +2412,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # endif # if defined(WETNESS_EFFECTS) if (waterRoughnessSpecular < 1.0) - specularColorPBR += PBR::GetWetnessDirectLightSpecularInput(wetnessNormal, viewDirection, SharedData::DirLightDirection.xyz, lightProperties.CoatLightColor, waterRoughnessSpecular) * wetnessGlossinessSpecular; + specularColorPBR += PBR::GetWetnessDirectLightSpecularInput(wetnessNormal, viewDirection, DirLightDirection, lightProperties.CoatLightColor, waterRoughnessSpecular) * wetnessGlossinessSpecular; # endif } # else @@ -2420,14 +2420,14 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) dirLightColor *= dirLightColorMultiplier; float3 dirDiffuseColor = dirLightColor * saturate(dirLightAngle) * dirDetailShadow; - float dirBacklighting = 1.0 + saturate(-dot(SharedData::DirLightDirection.xyz, viewDirection)); + float dirBacklighting = 1.0 + saturate(-dot(DirLightDirection, viewDirection)); # if defined(SOFT_LIGHTING) lightsDiffuseColor += dirBacklighting * dirLightColor * GetSoftLightMultiplier(dirLightAngle) * rimSoftLightColor.xyz; # endif # if defined(RIM_LIGHTING) - lightsDiffuseColor += dirBacklighting * dirLightColor * GetRimLightMultiplier(SharedData::DirLightDirection.xyz, viewDirection, worldNormal.xyz) * rimSoftLightColor.xyz; + lightsDiffuseColor += dirBacklighting * dirLightColor * GetRimLightMultiplier(DirLightDirection, viewDirection, worldNormal.xyz) * rimSoftLightColor.xyz; # endif # if defined(BACK_LIGHTING) @@ -2442,17 +2442,17 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(HAIR) && defined(CS_HAIR) if (SharedData::hairSpecularSettings.Enabled) { float3 dirTransmissionColor = 0.0; - float hairShadow = Hair::HairSelfShadow(input.WorldPosition.xyz, SharedData::DirLightDirection.xyz, screenNoise, eyeIndex); - Hair::GetHairDirectLight(dirDiffuseColor, lightsSpecularColor, dirTransmissionColor, hairT, SharedData::DirLightDirection.xyz, viewDirection, worldNormal.xyz, vertexNormal.xyz, dirLightColor.xyz * dirDetailShadow, SharedData::hairSpecularSettings.HairGlossiness, hairShadow, uv, baseColor.xyz); + float hairShadow = Hair::HairSelfShadow(input.WorldPosition.xyz, DirLightDirection, screenNoise, eyeIndex); + Hair::GetHairDirectLight(dirDiffuseColor, lightsSpecularColor, dirTransmissionColor, hairT, DirLightDirection, viewDirection, worldNormal.xyz, vertexNormal.xyz, dirLightColor.xyz * dirDetailShadow, SharedData::hairSpecularSettings.HairGlossiness, hairShadow, uv, baseColor.xyz); transmissionColor += dirTransmissionColor; } else { # if defined(SPECULAR) - lightsSpecularColor = GetLightSpecularInput(input, SharedData::DirLightDirection.xyz, viewDirection, worldNormal.xyz, dirLightColor.xyz * dirDetailShadow, shininess, uv); + lightsSpecularColor = GetLightSpecularInput(input, DirLightDirection, viewDirection, worldNormal.xyz, dirLightColor.xyz * dirDetailShadow, shininess, uv); # endif } # elif defined(SPECULAR) || defined(SPARKLE) - lightsSpecularColor = GetLightSpecularInput(input, SharedData::DirLightDirection.xyz, viewDirection, worldNormal.xyz, dirLightColor.xyz * dirDetailShadow, shininess, uv); + lightsSpecularColor = GetLightSpecularInput(input, DirLightDirection, viewDirection, worldNormal.xyz, dirLightColor.xyz * dirDetailShadow, shininess, uv); # endif } @@ -2460,7 +2460,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) # if defined(WETNESS_EFFECTS) if (waterRoughnessSpecular < 1.0) - wetnessSpecular += WetnessEffects::GetWetnessSpecular(wetnessNormal, SharedData::DirLightDirection.xyz, viewDirection, dirLightColor * dirDetailShadow, waterRoughnessSpecular); + wetnessSpecular += WetnessEffects::GetWetnessSpecular(wetnessNormal, DirLightDirection, viewDirection, dirLightColor * dirDetailShadow, waterRoughnessSpecular); # endif # endif From bb04a8a8a6e989728e92a58116ae6ef521d8399c Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Wed, 23 Jul 2025 15:49:06 +0100 Subject: [PATCH 37/43] chore: revert dalc --- package/Shaders/Lighting.hlsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 1d29835eac..3284958365 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -2740,7 +2740,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) diffuseColor += emitColor.xyz; # endif - float3 directionalAmbientColor = max(0, mul(SharedData::DirectionalAmbient, float4(worldNormal, 1.0))); + float3 directionalAmbientColor = max(0, mul(DirectionalAmbient, float4(worldNormal, 1.0))); # if defined(IBL) if (SharedData::iblSettings.EnableDiffuseIBL && !SharedData::InInterior) { From 3bf1399931ba72a7db1d5abc62da4fa1a102d8c4 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Wed, 23 Jul 2025 15:51:49 +0100 Subject: [PATCH 38/43] chore: revert dir light xyz change --- package/Shaders/Lighting.hlsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 3284958365..00f1820fe5 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -2420,7 +2420,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) dirLightColor *= dirLightColorMultiplier; float3 dirDiffuseColor = dirLightColor * saturate(dirLightAngle) * dirDetailShadow; - float dirBacklighting = 1.0 + saturate(-dot(DirLightDirection, viewDirection)); + float dirBacklighting = 1.0 + saturate(-dot(DirLightDirection.xyz, viewDirection)); # if defined(SOFT_LIGHTING) lightsDiffuseColor += dirBacklighting * dirLightColor * GetSoftLightMultiplier(dirLightAngle) * rimSoftLightColor.xyz; From 94febe62dbfa530ce52673de7c00245590ceae07 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 23 Jul 2025 14:56:21 +0000 Subject: [PATCH 39/43] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20pre-commi?= =?UTF-8?q?t.ci=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated formatting by clang-format, prettier, and other hooks. See https://pre-commit.ci for details. --- src/TruePBR.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TruePBR.cpp b/src/TruePBR.cpp index 8959c077d2..5e525212c8 100644 --- a/src/TruePBR.cpp +++ b/src/TruePBR.cpp @@ -1603,7 +1603,7 @@ void TruePBR::SetShaderResouces(ID3D11DeviceContext* a_context) while (mask) { // Find index of the least significant set bit uint32_t batchStart = std::countr_zero(mask); - + // Check for consecutive set bits and batch them uint32_t shiftedMask = mask >> batchStart; uint32_t batchCount = std::countr_one(shiftedMask); From 655f5a5e46c92d6fcda0d35acfceecc102dd2ee0 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Wed, 23 Jul 2025 16:11:49 +0100 Subject: [PATCH 40/43] perf: only use debug when overlay enabled --- src/State.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/State.cpp b/src/State.cpp index 350722f40d..edacaa8eb5 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -10,6 +10,7 @@ #include "Features/CloudShadows.h" #include "Features/TerrainBlending.h" #include "Features/TerrainHelper.h" +#include "Features/PerformanceOverlay.h" #include "Menu.h" #include "ShaderCache.h" #include "Streamline.h" @@ -51,7 +52,8 @@ void State::Draw() } } - Debug(); + if (globals::menu->overlayVisible && globals::features::performanceOverlay->loaded && globals::features::performanceOverlay->IsOverlayVisible()) + Debug(); updateShader = false; } From 22341ba15ddbb269492adbd97e32675216a4f325 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 23 Jul 2025 15:17:53 +0000 Subject: [PATCH 41/43] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20pre-commi?= =?UTF-8?q?t.ci=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated formatting by clang-format, prettier, and other hooks. See https://pre-commit.ci for details. --- src/State.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/State.cpp b/src/State.cpp index edacaa8eb5..464e163d36 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -8,9 +8,9 @@ #include "Deferred.h" #include "FeatureIssues.h" #include "Features/CloudShadows.h" +#include "Features/PerformanceOverlay.h" #include "Features/TerrainBlending.h" #include "Features/TerrainHelper.h" -#include "Features/PerformanceOverlay.h" #include "Menu.h" #include "ShaderCache.h" #include "Streamline.h" From 5bd236fad1835f96125aa83b76a7f8ca1263ea19 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Wed, 23 Jul 2025 18:00:38 +0100 Subject: [PATCH 42/43] chore: cleanup hook --- src/Hooks.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 536edb03b6..ff04ff4e95 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -1006,15 +1006,12 @@ namespace Hooks struct BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights { - static void thunk(RE::BSGraphics::PixelShader* PixelShader, RE::BSRenderPass* Pass, DirectX::XMMATRIX& Transform, uint32_t LightCount, uint32_t ShadowLightCount, float WorldScale, uint32_t RenderSpace) + static void thunk(RE::BSGraphics::PixelShader* PixelShader, RE::BSRenderPass* Pass, DirectX::XMMATRIX& Transform, uint32_t LightCount, uint32_t ShadowLightCount, float WorldScale, uint32_t) { - if (globals::shaderCache->IsEnabled()) - if (globals::features::lightLimitFix->loaded) - globals::features::lightLimitFix->BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights(Pass); - else - func(PixelShader, Pass, Transform, LightCount, ShadowLightCount, WorldScale, 0); + if (globals::features::lightLimitFix->loaded) + globals::features::lightLimitFix->BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights(Pass); else - func(PixelShader, Pass, Transform, LightCount, ShadowLightCount, WorldScale, RenderSpace); + func(PixelShader, Pass, Transform, LightCount, ShadowLightCount, WorldScale, 0); } static inline REL::Relocation func; }; From 33a6145b92f9ad1457f96161ee7ac4f361c2d758 Mon Sep 17 00:00:00 2001 From: Tim <15017472+doodlum@users.noreply.github.com> Date: Wed, 23 Jul 2025 21:05:01 +0100 Subject: [PATCH 43/43] fix: dir light direction xyz --- package/Shaders/Lighting.hlsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 00f1820fe5..bc9c9d209e 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -2308,7 +2308,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) dirLightColorMultiplier *= WaterEffects::ComputeCaustics(waterData, input.WorldPosition.xyz, eyeIndex); # endif - float dirLightAngle = dot(worldNormal.xyz, DirLightDirection); + float dirLightAngle = dot(worldNormal.xyz, DirLightDirection.xyz); if ((Permutation::PixelShaderDescriptor & Permutation::LightingFlags::DefShadow) && (Permutation::PixelShaderDescriptor & Permutation::LightingFlags::ShadowDir)) { dirLightColorMultiplier *= shadowColor.x;