diff --git a/features/Upscaling/Shaders/Features/Upscaling.ini b/features/Upscaling/Shaders/Features/Upscaling.ini index 19f01444dc..312d7ff985 100644 --- a/features/Upscaling/Shaders/Features/Upscaling.ini +++ b/features/Upscaling/Shaders/Features/Upscaling.ini @@ -1,2 +1,2 @@ [Info] -Version = 1-0-0 \ No newline at end of file +Version = 1-1-0 \ No newline at end of file diff --git a/features/Upscaling/Shaders/Upscaling/Streamline/sl.nis.dll b/features/Upscaling/Shaders/Upscaling/Streamline/sl.nis.dll new file mode 100644 index 0000000000..25553dc87d Binary files /dev/null and b/features/Upscaling/Shaders/Upscaling/Streamline/sl.nis.dll differ diff --git a/features/Upscaling/Shaders/Upscaling/XeSS/LICENSE.txt b/features/Upscaling/Shaders/Upscaling/XeSS/LICENSE.txt deleted file mode 100644 index e49c64eb9c..0000000000 --- a/features/Upscaling/Shaders/Upscaling/XeSS/LICENSE.txt +++ /dev/null @@ -1,27 +0,0 @@ -Intel Simplified Software License (Version October 2022) - -Intel(R) Xe Super Sampling (XeSS) SDK: Copyright (C) 2025 Intel Corporation - -Use and Redistribution. You may use and redistribute the software, which is provided in binary form only, (the "Software"), without modification, provided the following conditions are met: - -* Redistributions must reproduce the above copyright notice and these terms of use in the Software and in the documentation and/or other materials provided with the distribution. -* Neither the name of Intel nor the names of its suppliers may be used to endorse or promote products derived from this Software without specific prior written permission. -* No reverse engineering, decompilation, or disassembly of the Software is permitted, nor any modification or alteration of the Software or its operation at any time, including during execution. - -No other licenses. Except as provided in the preceding section, Intel grants no licenses or other rights by implication, estoppel or otherwise to, patent, copyright, trademark, trade name, service mark or other intellectual property licenses or rights of Intel. - -Third party software. "Third Party Software" means the files (if any) listed in the "third-party-software.txt" or other similarly-named text file that may be included with the Software. Third Party Software, even if included with the distribution of the Software, may be governed by separate license terms, including without limitation, third party license terms, open source software notices and terms, and/or other Intel software license terms. These separate license terms solely govern Your use of the Third Party Software. - -DISCLAIMER. THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED. THIS SOFTWARE IS NOT INTENDED FOR USE IN SYSTEMS OR APPLICATIONS WHERE FAILURE OF THE SOFTWARE MAY CAUSE PERSONAL INJURY OR DEATH AND YOU AGREE THAT YOU ARE FULLY RESPONSIBLE FOR ANY CLAIMS, COSTS, DAMAGES, EXPENSES, AND ATTORNEYS' FEES ARISING OUT OF ANY SUCH USE, EVEN IF ANY CLAIM ALLEGES THAT INTEL WAS NEGLIGENT REGARDING THE DESIGN OR MANUFACTURE OF THE SOFTWARE. - -LIMITATION OF LIABILITY. IN NO EVENT WILL INTEL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -No support. Intel may make changes to the Software, at any time without notice, and is not obligated to support, update or provide training for the Software. - -Termination. Your right to use the Software is terminated in the event of your breach of this license. - -Feedback. Should you provide Intel with comments, modifications, corrections, enhancements or other input (“Feedback”) related to the Software, Intel will be free to use, disclose, reproduce, license or otherwise distribute or exploit the Feedback in its sole discretion without any obligations or restrictions of any kind, including without limitation, intellectual property rights or licensing obligations. - -Compliance with laws. You agree to comply with all relevant laws and regulations governing your use, transfer, import or export (or prohibition thereof) of the Software. - -Governing law. All disputes will be governed by the laws of the United States of America and the State of Delaware without reference to conflict of law principles and subject to the exclusive jurisdiction of the state or federal courts sitting in the State of Delaware, and each party agrees that it submits to the personal jurisdiction and venue of those courts and waives any objections. THE UNITED NATIONS CONVENTION ON CONTRACTS FOR THE INTERNATIONAL SALE OF GOODS (1980) IS SPECIFICALLY EXCLUDED AND WILL NOT APPLY TO THE SOFTWARE. diff --git a/features/Upscaling/Shaders/Upscaling/XeSS/libxess.dll b/features/Upscaling/Shaders/Upscaling/XeSS/libxess.dll deleted file mode 100644 index 8583438c67..0000000000 Binary files a/features/Upscaling/Shaders/Upscaling/XeSS/libxess.dll and /dev/null differ diff --git a/src/Features/Upscaling.cpp b/src/Features/Upscaling.cpp index 8edea61f04..277ef2ba12 100644 --- a/src/Features/Upscaling.cpp +++ b/src/Features/Upscaling.cpp @@ -14,6 +14,7 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT( Upscaling::Settings, upscaleMethod, + upscaleMethodNoDLSS, qualityMode, frameLimitMode, frameGenerationMode, @@ -166,6 +167,8 @@ void Upscaling::DrawSettings() availableModes = 2; // Add FSR if (featureDLSS) availableModes = 3; // Add DLSS if available + else + currentUpscaleMode = &settings.upscaleMethodNoDLSS; // Slider for method selection // Clamp the index used to read from the built label vector to avoid OOB if the stored value is stale @@ -203,6 +206,12 @@ void Upscaling::DrawSettings() if (baseLabel) { ImGui::SliderInt("Upscale Preset", (int*)&settings.qualityMode, 0, 4, baseLabel); } + + if (upscaleMethod == UpscaleMethod::kFSR) { + ImGui::SliderFloat("Sharpness", &settings.sharpnessFSR, 0.0f, 1.0f, "%.1f"); + } else if (upscaleMethod == UpscaleMethod::kDLSS) { + ImGui::SliderFloat("Sharpness", &settings.sharpnessDLSS, 0.0f, 1.0f, "%.1f"); + } } } else { ImGui::Text("Upscaling from lower resolutions is not currently available for VR"); @@ -415,28 +424,28 @@ void Upscaling::PostPostLoad() Upscaling::UpscaleMethod Upscaling::GetUpscaleMethod() { - settings.upscaleMethod = std::clamp(settings.upscaleMethod, (uint)UpscaleMethod::kNONE, (uint)UpscaleMethod::kDLSS); - settings.qualityMode = std::clamp(settings.qualityMode, 0u, 4u); - return (UpscaleMethod)settings.upscaleMethod; + if (streamline.featureDLSS) + return (UpscaleMethod)settings.upscaleMethod; + return (UpscaleMethod)settings.upscaleMethodNoDLSS; } void Upscaling::CreateUpscalingTextureResources(UpscaleMethod a_upscalemethod) { logger::debug("[Upscaling] Creating texture resources for method {}", (int)a_upscalemethod); - if (a_upscalemethod == UpscaleMethod::kDLSS || a_upscalemethod == UpscaleMethod::kFSR) { - auto renderer = globals::game::renderer; - auto& main = renderer->GetRuntimeData().renderTargets[RE::RENDER_TARGETS::kMAIN]; + auto renderer = globals::game::renderer; + auto& main = renderer->GetRuntimeData().renderTargets[RE::RENDER_TARGETS::kMAIN]; - D3D11_TEXTURE2D_DESC texDesc{}; - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; - D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; + D3D11_TEXTURE2D_DESC texDesc{}; + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; + main.texture->GetDesc(&texDesc); + main.SRV->GetDesc(&srvDesc); + main.UAV->GetDesc(&uavDesc); - main.texture->GetDesc(&texDesc); - main.SRV->GetDesc(&srvDesc); - main.UAV->GetDesc(&uavDesc); + texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS; - texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS; + if (a_upscalemethod == UpscaleMethod::kDLSS || a_upscalemethod == UpscaleMethod::kFSR) { texDesc.Format = DXGI_FORMAT_R8_UNORM; srvDesc.Format = texDesc.Format; uavDesc.Format = texDesc.Format; @@ -457,24 +466,29 @@ void Upscaling::CreateUpscalingTextureResources(UpscaleMethod a_upscalemethod) // Motion vector copy texture is only needed for DLSS if (a_upscalemethod == UpscaleMethod::kDLSS) { if (!motionVectorCopyTexture) { - auto renderer = globals::game::renderer; auto& motionVector = renderer->GetRuntimeData().renderTargets[RE::RENDER_TARGETS::kMOTION_VECTOR]; D3D11_TEXTURE2D_DESC motionTexDesc{}; - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; - D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; - motionVector.texture->GetDesc(&motionTexDesc); - motionVector.SRV->GetDesc(&srvDesc); - motionVector.UAV->GetDesc(&uavDesc); - srvDesc.Format = motionTexDesc.Format; - uavDesc.Format = motionTexDesc.Format; + texDesc.Format = motionTexDesc.Format; + srvDesc.Format = texDesc.Format; + uavDesc.Format = texDesc.Format; motionVectorCopyTexture = new Texture2D(motionTexDesc); motionVectorCopyTexture->CreateSRV(srvDesc); motionVectorCopyTexture->CreateUAV(uavDesc); } + + if (!nisSharpenerTexture) { + texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + srvDesc.Format = texDesc.Format; + uavDesc.Format = texDesc.Format; + + nisSharpenerTexture = new Texture2D(texDesc); + nisSharpenerTexture->CreateSRV(srvDesc); + nisSharpenerTexture->CreateUAV(uavDesc); + } } } @@ -514,6 +528,14 @@ void Upscaling::DestroyUpscalingTextureResources(UpscaleMethod a_upscalemethod) delete motionVectorCopyTexture; motionVectorCopyTexture = nullptr; } + if (nisSharpenerTexture) { + nisSharpenerTexture->srv = nullptr; + nisSharpenerTexture->uav = nullptr; + nisSharpenerTexture->resource = nullptr; + + delete nisSharpenerTexture; + nisSharpenerTexture = nullptr; + } } } @@ -1196,7 +1218,7 @@ void Upscaling::Upscale() if (upscaleMethod == UpscaleMethod::kDLSS) { streamline.Upscale(main.texture, reactiveMaskTexture->resource.get(), transparencyCompositionMaskTexture->resource.get(), motionVectorCopyTexture->resource.get()); } else if (upscaleMethod == UpscaleMethod::kFSR) { - fidelityFX.Upscale(main.texture, reactiveMaskTexture->resource.get(), transparencyCompositionMaskTexture->resource.get(), motionVector.texture); + fidelityFX.Upscale(main.texture, reactiveMaskTexture->resource.get(), transparencyCompositionMaskTexture->resource.get(), motionVector.texture, settings.sharpnessFSR); } state->EndPerfEvent(); @@ -1328,6 +1350,34 @@ void Upscaling::UpscaleDepth() } } +void Upscaling::ApplyNISSharpening() +{ + if (!streamline.featureNIS || settings.sharpnessDLSS <= 0.0f) { + return; + } + + auto context = globals::d3d::context; + + ID3D11RenderTargetView* renderTarget = nullptr; + context->OMGetRenderTargets(1, &renderTarget, nullptr); + + winrt::com_ptr mainResource; + renderTarget->GetResource(mainResource.put()); + + context->OMSetRenderTargets(0, nullptr, nullptr); // Unbind all bound render targets + + context->CopyResource(nisSharpenerTexture->resource.get(), mainResource.get()); + + streamline.ApplyNISSharpening(nisSharpenerTexture->resource.get(), settings.sharpnessDLSS); + + context->CopyResource(mainResource.get(), nisSharpenerTexture->resource.get()); + + globals::game::stateUpdateFlags->set(RE::BSGraphics::ShaderFlags::DIRTY_RENDERTARGET); // Run OMSetRenderTargets again + + if (renderTarget) + renderTarget->Release(); +} + void Upscaling::Main_UpdateJitter::thunk(RE::BSGraphics::State* a_state) { globals::features::upscaling.ConfigureTAA(); @@ -1359,6 +1409,9 @@ void Upscaling::Main_PostProcessing::thunk(RE::ImageSpaceManager* a1, uint32_t a func(a1, a3, er8_); + if (upscaleMethod == UpscaleMethod::kDLSS) + upscaling.ApplyNISSharpening(); + // Disable TAA in some menus BSImagespaceShaderISTemporalAA->taaEnabled = false; } diff --git a/src/Features/Upscaling.h b/src/Features/Upscaling.h index 30880ee032..2fa808667d 100644 --- a/src/Features/Upscaling.h +++ b/src/Features/Upscaling.h @@ -48,12 +48,15 @@ struct Upscaling : Feature struct Settings { - uint upscaleMethod = (uint)UpscaleMethod::kTAA; + uint upscaleMethod = (uint)UpscaleMethod::kDLSS; + uint upscaleMethodNoDLSS = (uint)UpscaleMethod::kFSR; uint qualityMode = 1; // Default to Quality (1=Quality, 2=Balanced, 3=Performance, 4=Ultra Performance, 0=Native AA) uint frameLimitMode = 1; uint frameGenerationMode = 1; uint frameGenerationForceEnable = 0; uint streamlineLogLevel = 0; // 0=Off, 1=Default, 2=Verbose + float sharpnessFSR = 1.0f; + float sharpnessDLSS = 0.1f; }; Settings settings; @@ -134,6 +137,7 @@ struct Upscaling : Feature Texture2D* reactiveMaskTexture = nullptr; Texture2D* transparencyCompositionMaskTexture = nullptr; Texture2D* motionVectorCopyTexture = nullptr; + Texture2D* nisSharpenerTexture = nullptr; virtual void ClearShaderCache() override; @@ -155,6 +159,8 @@ struct Upscaling : Feature void PerformUpscaling(); void UpscaleDepth(); + void ApplyNISSharpening(); + static void TimerSleepQPC(int64_t targetQPC); void FrameLimiter(); diff --git a/src/Features/Upscaling/FidelityFX.cpp b/src/Features/Upscaling/FidelityFX.cpp index 45948c903d..bb206037c7 100644 --- a/src/Features/Upscaling/FidelityFX.cpp +++ b/src/Features/Upscaling/FidelityFX.cpp @@ -263,7 +263,7 @@ FfxResource ffxGetResource(ID3D11Resource* dx11Resource, return resource; } -void FidelityFX::Upscale(ID3D11Resource* a_upscalingTexture, ID3D11Resource* a_reactiveMask, ID3D11Resource* a_transparencyCompositionMask, ID3D11Resource* a_motionVectors) +void FidelityFX::Upscale(ID3D11Resource* a_upscalingTexture, ID3D11Resource* a_reactiveMask, ID3D11Resource* a_transparencyCompositionMask, ID3D11Resource* a_motionVectors, float a_sharpness) { auto renderer = globals::game::renderer; auto context = globals::d3d::context; @@ -302,7 +302,7 @@ void FidelityFX::Upscale(ID3D11Resource* a_upscalingTexture, ID3D11Resource* a_r dispatchParameters.cameraNear = *globals::game::cameraNear; dispatchParameters.enableSharpening = true; - dispatchParameters.sharpness = 0.0f; + dispatchParameters.sharpness = a_sharpness; dispatchParameters.cameraFovAngleVertical = Util::GetVerticalFOVRad(); dispatchParameters.viewSpaceToMetersFactor = 0.01428222656f; diff --git a/src/Features/Upscaling/FidelityFX.h b/src/Features/Upscaling/FidelityFX.h index f888b2db94..392c7d73c3 100644 --- a/src/Features/Upscaling/FidelityFX.h +++ b/src/Features/Upscaling/FidelityFX.h @@ -46,7 +46,7 @@ class FidelityFX float GetInputResolutionScale(uint32_t outputWidth, uint32_t outputHeight, uint32_t qualityMode); - void Upscale(ID3D11Resource* a_upscalingTexture, ID3D11Resource* a_reactiveMask, ID3D11Resource* a_transparencyCompositionMask, ID3D11Resource* a_motionVectors); + void Upscale(ID3D11Resource* a_upscalingTexture, ID3D11Resource* a_reactiveMask, ID3D11Resource* a_transparencyCompositionMask, ID3D11Resource* a_motionVectors, float a_sharpness); private: // FSR scratch buffer - needs to be freed in DestroyFSRResources diff --git a/src/Features/Upscaling/Streamline.cpp b/src/Features/Upscaling/Streamline.cpp index 76baccaa91..536c39f8ed 100644 --- a/src/Features/Upscaling/Streamline.cpp +++ b/src/Features/Upscaling/Streamline.cpp @@ -102,8 +102,8 @@ void Streamline::LoadInterposer() sl::Preferences pref; - sl::Feature featuresToLoad[] = { sl::kFeatureDLSS }; - sl::Feature featuresToLoadVR[] = { sl::kFeatureDLSS }; + sl::Feature featuresToLoad[] = { sl::kFeatureDLSS, sl::kFeatureNIS }; + sl::Feature featuresToLoadVR[] = { sl::kFeatureDLSS, sl::kFeatureNIS }; pref.featuresToLoad = REL::Module::IsVR() ? featuresToLoadVR : featuresToLoad; pref.numFeaturesToLoad = REL::Module::IsVR() ? _countof(featuresToLoadVR) : _countof(featuresToLoad); @@ -181,7 +181,21 @@ void Streamline::CheckFeatures(IDXGIAdapter* a_adapter) } } + slIsFeatureLoaded(sl::kFeatureNIS, featureNIS); + if (featureNIS) { + logger::info("[Streamline] NIS feature is loaded"); + featureNIS = slIsFeatureSupported(sl::kFeatureNIS, adapterInfo) == sl::Result::eOk; + } else { + logger::info("[Streamline] NIS feature is not loaded"); + sl::FeatureRequirements featureRequirements; + sl::Result result = slGetFeatureRequirements(sl::kFeatureNIS, featureRequirements); + if (result != sl::Result::eOk) { + logger::info("[Streamline] NIS feature failed to load due to: {}", magic_enum::enum_name(result)); + } + } + logger::info("[Streamline] DLSS {} available", featureDLSS ? "is" : "is not"); + logger::info("[Streamline] NIS {} available", featureNIS ? "is" : "is not"); } void Streamline::PostDevice() @@ -193,6 +207,11 @@ void Streamline::PostDevice() slGetFeatureFunction(sl::kFeatureDLSS, "slDLSSGetState", (void*&)slDLSSGetState); slGetFeatureFunction(sl::kFeatureDLSS, "slDLSSSetOptions", (void*&)slDLSSSetOptions); } + + if (featureNIS) { + slGetFeatureFunction(sl::kFeatureNIS, "slNISSetOptions", (void*&)slNISSetOptions); + slGetFeatureFunction(sl::kFeatureNIS, "slNISGetState", (void*&)slNISGetState); + } } /** @@ -394,4 +413,42 @@ void Streamline::DestroyDLSSResources() dlssOptions.mode = sl::DLSSMode::eOff; slDLSSSetOptions(viewport, dlssOptions); slFreeResources(sl::kFeatureDLSS, viewport); +} + +void Streamline::ApplyNISSharpening(ID3D11Resource* a_texture, float sharpness) +{ + if (!featureNIS) { + return; + } + + CheckFrameConstants(); + + sl::NISOptions nisOptions{}; + nisOptions.mode = sl::NISMode::eSharpen; + nisOptions.sharpness = std::clamp(sharpness, 0.0f, 1.0f); + nisOptions.hdrMode = sl::NISHDR::eNone; + + if (SL_FAILED(result, slNISSetOptions(viewport, nisOptions))) { + logger::error("[Streamline] Could not set NIS options"); + return; + } + + auto state = globals::state; + sl::Extent fullExtent{ 0, 0, (uint)state->screenSize.x, (uint)state->screenSize.y }; + + sl::Resource colorIn = { sl::ResourceType::eTex2d, a_texture, 0 }; + sl::Resource colorOut = { sl::ResourceType::eTex2d, a_texture, 0 }; + + sl::ResourceTag colorInTag = sl::ResourceTag{ &colorIn, sl::kBufferTypeScalingInputColor, sl::ResourceLifecycle::eOnlyValidNow, &fullExtent }; + sl::ResourceTag colorOutTag = sl::ResourceTag{ &colorOut, sl::kBufferTypeScalingOutputColor, sl::ResourceLifecycle::eOnlyValidNow, &fullExtent }; + + sl::ResourceTag resourceTags[] = { colorInTag, colorOutTag }; + + slSetTag(viewport, resourceTags, _countof(resourceTags), globals::d3d::context); + + sl::ViewportHandle view(viewport); + const sl::BaseStructure* inputs[] = { &view }; + if (SL_FAILED(result, slEvaluateFeature(sl::kFeatureNIS, *frameToken, inputs, _countof(inputs), globals::d3d::context))) { + logger::error("[Streamline] Failed to evaluate NIS feature"); + } } \ No newline at end of file diff --git a/src/Features/Upscaling/Streamline.h b/src/Features/Upscaling/Streamline.h index 08c51fdda9..954a8a5bdb 100644 --- a/src/Features/Upscaling/Streamline.h +++ b/src/Features/Upscaling/Streamline.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #pragma warning(pop) @@ -31,6 +32,7 @@ class Streamline bool triedInitialization = false; bool featureDLSS = false; + bool featureNIS = false; sl::ViewportHandle viewport{ 0 }; @@ -60,6 +62,10 @@ class Streamline PFun_slDLSSGetState* slDLSSGetState{}; PFun_slDLSSSetOptions* slDLSSSetOptions{}; + // NIS specific functions + PFun_slNISSetOptions* slNISSetOptions{}; + PFun_slNISGetState* slNISGetState{}; + Util::FrameChecker frameChecker; sl::FrameToken* frameToken = nullptr; @@ -79,4 +85,6 @@ class Streamline float GetInputResolutionScale(uint32_t outputWidth, uint32_t outputHeight, uint32_t qualityPreset); void DestroyDLSSResources(); + + void ApplyNISSharpening(ID3D11Resource* a_texture, float sharpness); };