Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
221 changes: 221 additions & 0 deletions src/Features/DeepDVC.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
#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 };
if (!upscaling.streamline.slSetTag) {
logger::warn("[DeepDVC] slSetTag not available");
return;
}
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 = 0;
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;
};
20 changes: 19 additions & 1 deletion src/Features/Upscaling/Streamline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ 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 };

pref.featuresToLoad = featuresToLoad;
pref.numFeaturesToLoad = _countof(featuresToLoad);
Comment thread
YtzyFvra marked this conversation as resolved.
Expand Down Expand Up @@ -244,6 +244,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 +314,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