Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions features/DeepDVC/Shaders/Features/DeepDVC.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[Info]
Version = 1-0-0
Binary file not shown.
Binary file not shown.
2 changes: 2 additions & 0 deletions src/Feature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "FeatureIssues.h"
#include "FeatureVersions.h"
#include "Features/CloudShadows.h"
#include "Features/DeepDVC.h"
#include "Features/DynamicCubemaps.h"
#include "Features/ExponentialHeightFog.h"
#include "Features/ExtendedMaterials.h"
Expand Down Expand Up @@ -236,6 +237,7 @@ const std::vector<Feature*>& Feature::GetFeatureList()
&globals::features::ibl,
&globals::features::extendedTranslucency,
&globals::features::upscaling,
&globals::features::deepDVC,
&globals::features::renderDoc,
&globals::features::weatherEditor,
&globals::features::linearLighting,
Expand Down
217 changes: 217 additions & 0 deletions src/Features/DeepDVC.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
#include "DeepDVC.h"

#include "../Globals.h"
#include "Upscaling.h"

#include "RE/B/BSShaderRenderTargets.h"
#include "RE/R/Renderer.h"

// NVIDIA Deep Learning Video Clarity (DeepDVC)
// AI-based post-process filter that significantly enhances color vibrance and
// combats overexposure. Works well alongside traditional post-processing
// (tested with jiayev/pp branch: greatly improves dark-area detail without
// blowing out the overall image).
// Run after tone mapping and before film grain when film grain exists.
//
// Currently VR-only due to lack of an SE/AE test client; flat-screen
// adaptation should be straightforward.

bool DeepDVC::IsSupported() const
{
auto& streamline = globals::features::upscaling.streamline;
return globals::game::isVR && streamline.featureDeepDVC;
}

bool DeepDVC::IsInMenu() const
{
return IsSupported();
}

void DeepDVC::RestoreDefaultSettings()
{
settings = Settings();
}

void DeepDVC::LoadSettings(json& o_json)
{
settings = o_json;
settings.mode = std::clamp(settings.mode, 0u, 1u);
settings.intensity = std::clamp(settings.intensity, 0.0f, 1.0f);
settings.saturationBoost = std::clamp(settings.saturationBoost, 0.0f, 1.0f);
}
Comment thread
YtzyFvra marked this conversation as resolved.

void DeepDVC::SaveSettings(json& o_json)
{
o_json = settings;
}

void DeepDVC::DrawSettings()
{
if (ImGui::TreeNodeEx("DeepDVC Settings", ImGuiTreeNodeFlags_DefaultOpen)) {
const char* modes[] = { "Off", "On" };
ImGui::SliderInt("Mode", (int*)&settings.mode, 0, 1, modes[settings.mode]);
Comment thread
YtzyFvra marked this conversation as resolved.

if (settings.mode == 1) {
if (missingInput) {
ImGui::TextColored({ 1.0f, 0.4f, 0.4f, 1.0f }, "Input render target not found.");
}

ImGui::SliderFloat("Intensity", &settings.intensity, 0.0f, 1.0f, "%.2f");
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Controls how strong or subtle the filter effect will be on an image.");
}

ImGui::SliderFloat("Saturation Boost", &settings.saturationBoost, 0.0f, 1.0f, "%.2f");
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("This feature provides RTX Dynamic Vibrance Control, using AI to enhance digital vibrance and adjust color saturation adaptively based on game content, making them more vibrant and eye-catching.");
}
}

ImGui::TreePop();
}
}

void DeepDVC::Evaluate()
{
if (!IsSupported())
return;

auto& upscaling = globals::features::upscaling;
if (!upscaling.streamline.initialized)
return;

if (settings.mode == 0) {
missingInput = false;
return;
}

auto context = globals::d3d::context;
auto device = globals::d3d::device;
auto viewport = upscaling.streamline.viewport;

if (!context || !device)
return;

if (!upscaling.streamline.EnsureFrameToken())
return;

auto* frameToken = upscaling.streamline.frameToken;
if (!frameToken)
return;
Comment thread
coderabbitai[bot] marked this conversation as resolved.

ID3D11Texture2D* targetBuffer = nullptr;

if (auto renderer = globals::game::renderer) {
auto& rt = renderer->GetRuntimeData().renderTargets[RE::RENDER_TARGETS::kIMAGESPACE_TEMP_COPY];
targetBuffer = rt.texture;
}

if (!targetBuffer) {
missingInput = true;
return;
}

missingInput = false;

D3D11_TEXTURE2D_DESC desc;
targetBuffer->GetDesc(&desc);

sl::Extent extent{};
extent.width = desc.Width;
extent.height = desc.Height;

if (proxyBuffer) {
D3D11_TEXTURE2D_DESC proxyDesc;
proxyBuffer->GetDesc(&proxyDesc);
if (proxyDesc.Width != desc.Width || proxyDesc.Height != desc.Height || proxyDesc.Format != desc.Format) {
proxyBuffer->Release();
proxyBuffer = nullptr;
}
}
Comment thread
YtzyFvra marked this conversation as resolved.

if (!proxyBuffer) {
D3D11_TEXTURE2D_DESC proxyDesc = desc;
proxyDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS;
proxyDesc.Usage = D3D11_USAGE_DEFAULT;
proxyDesc.CPUAccessFlags = 0;
proxyDesc.MiscFlags = 0;

HRESULT hr = device->CreateTexture2D(&proxyDesc, nullptr, &proxyBuffer);
if (FAILED(hr)) {
logger::error("[DeepDVC] Failed to create proxy buffer. HR = {:x}", (uint32_t)hr);
return;
}
logger::info("[DeepDVC] Created UAV-compatible proxy buffer {}x{}", desc.Width, desc.Height);
}

if (!proxyBuffer || !targetBuffer) {
logger::error("[DeepDVC] Invalid buffer pointers for resource copy");
return;
}
context->CopyResource(proxyBuffer, targetBuffer);

sl::Resource colorOut = { sl::ResourceType::eTex2d, proxyBuffer, nullptr, nullptr, 0 };
sl::ResourceTag colorOutTag = sl::ResourceTag{ &colorOut, sl::kBufferTypeScalingOutputColor, sl::ResourceLifecycle::eOnlyValidNow, &extent };

sl::ResourceTag inputs[] = { colorOutTag };
upscaling.streamline.slSetTag(viewport, inputs, _countof(inputs), context);

sl::DeepDVCOptions options{};
options.mode = (sl::DeepDVCMode)settings.mode;
options.intensity = settings.intensity;
options.saturationBoost = settings.saturationBoost;

if (upscaling.streamline.slDeepDVCSetOptions) {
sl::Result res = upscaling.streamline.slDeepDVCSetOptions(viewport, options);
if (res != sl::Result::eOk) {
logger::warn("[DeepDVC] slDeepDVCSetOptions failed: {}", magic_enum::enum_name(res));
}
}

const sl::BaseStructure* inputsEval[] = { &viewport };
if (upscaling.streamline.slEvaluateFeature) {
sl::Result res = upscaling.streamline.slEvaluateFeature(sl::kFeatureDeepDVC, *frameToken, inputsEval, _countof(inputsEval), context);
if (res != sl::Result::eOk) {
static int failCount = 0;
if (failCount < 100) {
logger::warn("[DeepDVC] slEvaluateFeature failed: {}", magic_enum::enum_name(res));
failCount++;
}
}
Comment thread
YtzyFvra marked this conversation as resolved.
}

if (proxyBuffer && targetBuffer) {
context->CopyResource(targetBuffer, proxyBuffer);
}
Comment thread
YtzyFvra marked this conversation as resolved.
}

// ── vtable hook: run DeepDVC after tonemap ──────────────────────

namespace
{
template <RE::ImageSpaceManager::ImageSpaceEffectEnum EffectType>
struct TonemapHook
{
static void thunk(void* imageSpaceShader, RE::BSTriShape* shape, RE::ImageSpaceEffectParam* param)
{
func(imageSpaceShader, shape, param);
globals::features::deepDVC.Evaluate();
}
static inline REL::Relocation<decltype(thunk)> func;
};
}

void DeepDVC::PostPostLoad()
{
if (!globals::game::isVR)
return;

stl::write_vfunc<0x1,
TonemapHook<RE::ImageSpaceManager::ISHDRTonemapBlendCinematic>>(
RE::VTABLE_BSImagespaceShaderHDRTonemapBlendCinematic[3]);
stl::write_vfunc<0x1,
TonemapHook<RE::ImageSpaceManager::ISHDRTonemapBlendCinematicFade>>(
RE::VTABLE_BSImagespaceShaderHDRTonemapBlendCinematicFade[3]);

logger::info("[DeepDVC] Tonemap hooks installed");
}
56 changes: 56 additions & 0 deletions src/Features/DeepDVC.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#pragma once

#include "../Feature.h"
#include "Upscaling/Streamline.h"

struct DeepDVC : public Feature
{
public:
virtual inline std::string GetName() override { return "DeepDVC"; }
virtual inline std::string GetShortName() override { return "DeepDVC"; }
virtual inline std::string_view GetCategory() const override { return "Display"; }

virtual inline std::pair<std::string, std::vector<std::string>> GetFeatureSummary() override
{
return {
"RTX Dynamic Vibrance uses AI to enhance digital vibrance in real-time.",
{ "Improves visual clarity",
"Adjusts color saturation adaptively",
"Requires NVIDIA RTX GPU" }
};
}

virtual inline bool SupportsVR() override { return true; }
virtual inline bool IsCore() const override { return false; }
virtual bool IsInMenu() const override;
virtual void PostPostLoad() override;

struct Settings
{
uint32_t mode = 1;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
float intensity = 0.3f;
float saturationBoost = 0.2f;

NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Settings, mode, intensity, saturationBoost);
} settings;

void Evaluate();

virtual void RestoreDefaultSettings() override;
virtual void LoadSettings(json& o_json) override;
virtual void SaveSettings(json& o_json) override;
virtual void DrawSettings() override;

~DeepDVC()
{
if (proxyBuffer) {
proxyBuffer->Release();
proxyBuffer = nullptr;
}
}

private:
bool IsSupported() const;
ID3D11Texture2D* proxyBuffer = nullptr;
bool missingInput = false;
};
21 changes: 20 additions & 1 deletion src/Features/Upscaling/Streamline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ void Streamline::LoadInterposer()

sl::Preferences pref;

sl::Feature featuresToLoad[] = { sl::kFeatureDLSS, sl::kFeatureReflex, sl::kFeaturePCL };
sl::Feature featuresToLoad[] = { sl::kFeatureDLSS, sl::kFeatureReflex, sl::kFeaturePCL, sl::kFeatureDeepDVC };
sl::Feature featuresToLoadVR[] = { sl::kFeatureDLSS, sl::kFeatureReflex, sl::kFeaturePCL, sl::kFeatureDeepDVC };

pref.featuresToLoad = featuresToLoad;
pref.numFeaturesToLoad = _countof(featuresToLoad);
Comment thread
YtzyFvra marked this conversation as resolved.
Expand Down Expand Up @@ -244,6 +245,10 @@ void Streamline::CheckFeatures(IDXGIAdapter* a_adapter)
}
reflexOptionsCache = {};
lastReflexSleepFrame = UINT32_MAX;

checkFeatureAvailability(sl::kFeatureDeepDVC, "DeepDVC", featureDeepDVC);

logger::info("[Streamline] DeepDVC {} available", featureDeepDVC ? "is" : "is not");
}

void Streamline::PostDevice()
Expand Down Expand Up @@ -310,6 +315,20 @@ void Streamline::PostDevice()

reflexOptionsCache = {};
lastReflexSleepFrame = UINT32_MAX;

slDeepDVCSetOptions = nullptr;
if (featureDeepDVC && slGetFeatureFunction) {
auto fn = (void*)nullptr;
const sl::Result bindResult = slGetFeatureFunction(sl::kFeatureDeepDVC, "slDeepDVCSetOptions", fn);
if (bindResult == sl::Result::eOk && fn) {
slDeepDVCSetOptions = reinterpret_cast<decltype(slDeepDVCSetOptions)>(fn);
logger::info("[Streamline] DeepDVC runtime controls are available");
} else {
logger::warn("[Streamline] DeepDVC options bind failed with {}; DeepDVC will be disabled",
magic_enum::enum_name(bindResult));
featureDeepDVC = false;
}
}
}

/**
Expand Down
4 changes: 4 additions & 0 deletions src/Features/Upscaling/Streamline.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#pragma warning(disable: 4471)
#include <sl.h>
#include <sl_consts.h>
#include <sl_deepdvc.h>
#include <sl_dlss.h>
#include <sl_matrix_helpers.h>
#include <sl_reflex.h>
Expand All @@ -36,6 +37,7 @@ class Streamline
bool featureReflex = false;
bool featurePCL = false;
bool reflexSupportedOnCurrentAdapter = false;
bool featureDeepDVC = false;

sl::ViewportHandle viewport{ 0 };
sl::ViewportHandle viewportRight{ 1 };
Expand Down Expand Up @@ -65,6 +67,8 @@ class Streamline
PFun_slDLSSGetOptimalSettings* slDLSSGetOptimalSettings{};
PFun_slDLSSGetState* slDLSSGetState{};
PFun_slDLSSSetOptions* slDLSSSetOptions{};
// DeepDVC specific functions
PFun_slDeepDVCSetOptions* slDeepDVCSetOptions{};

// Reflex specific functions
PFun_slReflexGetState* slReflexGetState{};
Expand Down
2 changes: 2 additions & 0 deletions src/Globals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "Deferred.h"
#include "Features/CloudShadows.h"
#include "Features/DeepDVC.h"
#include "Features/DynamicCubemaps.h"
#include "Features/ExponentialHeightFog.h"
#include "Features/ExtendedMaterials.h"
Expand Down Expand Up @@ -83,6 +84,7 @@ namespace globals
ExtendedTranslucency extendedTranslucency{};
Upscaling upscaling{};
HDRDisplay hdrDisplay{};
DeepDVC deepDVC{};
RenderDoc renderDoc{};
WeatherEditor weatherEditor{};
ExponentialHeightFog exponentialHeightFog{};
Expand Down
2 changes: 2 additions & 0 deletions src/Globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ struct PerformanceOverlay;
struct WetnessEffects;
struct ExtendedTranslucency;
struct Upscaling;
struct DeepDVC;
struct WeatherEditor;
struct ExponentialHeightFog;
struct HDRDisplay;
Expand Down Expand Up @@ -90,6 +91,7 @@ namespace globals
extern ExtendedTranslucency extendedTranslucency;
extern Upscaling upscaling;
extern HDRDisplay hdrDisplay;
extern DeepDVC deepDVC;
extern RenderDoc renderDoc;
extern WeatherEditor weatherEditor;
extern ExponentialHeightFog exponentialHeightFog;
Expand Down
Loading