Skip to content

[mod:mafiade] HDR10 swap chain output option (fixes Intel XeFG frame generation) - #696

Open
williamstosh wants to merge 1 commit into
clshortfuse:mainfrom
williamstosh:feat/mafiade-hdr10
Open

williamstosh wants to merge 1 commit into
clshortfuse:mainfrom
williamstosh:feat/mafiade-hdr10

Conversation

@williamstosh

Copy link
Copy Markdown

PR: [mod:mafiade] HDR10 swap chain output option (fixes Intel XeFG frame generation)

  • Base: main @ da608c4 (fix(state): reduce tracking overhead) — verified still the tip
  • Branch: feat/mafiade-hdr10
  • Diff: 4 files, +89 / -4 (src/games/mafiade/{addon.cpp, shared.h, common.hlsl, swap_chain_proxy_pixel_shader.ps_5_0.hlsl})
  • Commit message: feat(mafiade): add HDR10 swap chain output option

What

Adds a Swap Chain Format option to the Mafia: Definitive Edition addon and lets the swap chain proxy
shaders encode for the format that is actually in use, instead of assuming scRGB.

Setting (global, advanced) Values Effect
Swap Chain Format HDR10 (default) / scRGB writes through to renodx::mods::swapchain::SetUseHDR10()
Output Dither On (default) / Off dithers the 10-bit HDR10 store (unused by FP16 scRGB)

Why

Intel XeFG frame generation (OptiScaler FGOutput=XeFG) rejects the FP16/scRGB back buffer RenoDX
produces by default, and the failure takes the whole swap chain — and the game — down with it:

[RenoDX]     OnCreateSwapchain(swap: r8g8b8a8_unorm => r16g16b16a16_float, ...)
[E] XeFG Log: Backbuffer format is not valid. Found 40.
XeFG_Dx12::CreateSwapchain D3D12InitFromSwapChainDesc error: XEFG_SWAPCHAIN_RESULT_ERROR_INVALID_ARGUMENT
[W] FG swapchain creation failed: 80070057; creating plain DX12 swapchain
[W] swapchain creation failed: real 0, fg 80070005
ReShade: IDXGIFactory::CreateSwapChain failed with error code 0x80070005

With HDR10 the same stack comes up cleanly:

[RenoDX]     OnCreateSwapchain(swap: r8g8b8a8_unorm => r10g10b10a2_unorm, ...)
[RenoDX]     utils::swapchain::OnInitEffectRuntime(colorspace: hdr10_st2084)
[OptiScaler] XeFG_Dx12::Activate SetEnabled: true, result: XEFG_SWAPCHAIN_RESULT_SUCCESS (0)

scRGB is kept as the alternative (and remains the mod's previous behaviour); HDR10 defaults on because
it is the only one of the two that frame generation accepts.

Implementation notes

  • The shaders follow the swap chain that exists, not the setting. OnInitSwapchain reads the created
    back buffer's format into shader_injection.swap_chain_output_preset (1 = HDR10, 2 = scRGB), i.e.
    the same preset numbering used by renodx::draw::SwapChainPass. A Swap Chain Format change only
    applies once the swap chain is recreated, and this way the shaders can never encode for a container
    that is not there yet.
  • FinalizeOutput(color, position) ends with the container encode, so it keeps a single call site and
    no extra single-use helper was introduced. InvertFinalizeOutput() is untouched (scRGB convention);
    it is only used by the cosmetic fireworks pass.
  • HDR10 encode is bt2020::from::BT709() followed by pq::EncodeSafe(color, 1.f), matching the
    existing HDR10 output paths in src/shaders and other games.
  • Dither follows renodx::draw::SwapChainPass: exp2(bits) - 1 quantisation with
    renodx::random::Generate(position + injectedData.random) (the mod already binds random for its
    film grain).
  • Upgrade_UseSCRGB is deliberately the same global key as wutheringwaves / unrealengine
    (identical labels and value meaning). Easy to change to a mod-specific key if you would rather not
    share it.
  • Constant buffer: the two new fields are floats on purpose — the struct's bool is 1 byte in C++ but
    4 in HLSL, so adding two floats keeps the layout at 8 rows.

Manual verification

  • cmake --preset vs-x64 then cmake --build --preset vs-x64-release --target mafiade (VS 2022, Windows 11) — builds clean.
  • Deployed renodx-mafiade.addon64 (RenoDX v0.2026.1004.717), loaded a save and played for 30-60 s, both formats:
    • HDR10 (default, after a restart):
      [RenoDX] mods::swapchain::OnCreateSwapchain(swap: r8g8b8a8_unorm => r10g10b10a2_unorm, …)
      [RenoDX] utils::swapchain::OnInitEffectRuntime(colorspace: hdr10_st2084)
      [OptiScaler] XeFG_Dx12::Activate SetEnabled: true, result: XEFG_SWAPCHAIN_RESULT_SUCCESS (0)
      ReShade: Unregistered add-on "RenoDX".        ← clean exit
      
      Gradients stay clean with Output Dither on.
    • scRGB (switched in the overlay, restart required):
      [RenoDX] mods::swapchain::OnCreateSwapchain(swap: r8g8b8a8_unorm => r16g16b16a16_float, …)
      [RenoDX] utils::swapchain::OnInitEffectRuntime(colorspace: extended_srgb_linear)
      
      No change from the mod's current behaviour.
  • 0 errors/assertions from the mod across both runs; the only warnings are the known
    SwapchainProxyPass: no clone lines that the mod already tolerates.

Reviewer question

The two new settings use is_visible = []() { return settings[0]->GetValue() >= 2; }, matching the
Upgrade_* precedent, so they only show up in the advanced settings mode.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

It alters the HDR-critical swap-chain output encoding path, which is correct by inspection but warrants a human HDR10/scRGB display check that cannot be performed in this automated review.

Review effort: Balanced
Findings: None

What changed in this PR

This PR adds an HDR10 swap chain output option to the Mafia: Definitive Edition (mafiade) mod. By default RenoDX upgrades this game's back buffer to FP16/scRGB, which Intel XeFG frame generation rejects (killing the swap chain). The change lets the mod output an HDR10 (PQ/BT.2020, r10g10b10a2_unorm) container while keeping scRGB as a fallback, and encodes in the shader for the format that actually exists rather than a requested setting.

Changes:

  • Adds a global, advanced-only Swap Chain Format toggle (HDR10 default / scRGB) that drives renodx::mods::swapchain::SetUseHDR10, plus an Output Dither toggle for the 10-bit store.
  • FinalizeOutput now branches on swap_chain_output_preset: HDR10 does bt2020::from::BT709 + pq::EncodeSafe(color, 1.f) with optional ±0.5 LSB dither; scRGB keeps the prior color / 80 path.
  • OnInitSwapchain reads the real back-buffer format and sets swap_chain_output_preset (1 = HDR10, 2 = scRGB) so shaders never encode for a container that is not present yet.
File Description
src/​games/​mafiade/​addon.cpp Detects actual back-buffer format in OnInitSwapchain; adds Swap Chain Format and Output Dither global settings.
src/​games/​mafiade/​common.hlsl FinalizeOutput gains a position arg and a container-aware encode (HDR10 PQ/BT.2020 + dither, scRGB fallback).
src/​games/​mafiade/​shared.h Adds swap_chain_output_preset and swap_chain_output_dither_bits floats, keeping the cbuffer at 8 rows.
src/​games/​mafiade/​swap_chain_proxy_pixel_shader.ps_5_0.hlsl Passes vpos.xy into FinalizeOutput for dithering.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@williamstosh

Copy link
Copy Markdown
Author

Rebased onto main (bc0ead3) and aligned the settings with the HDR10 output that just landed for ffxiv (3ace130):

  • Presentation Output is a per-game setting now (outputMode, Tone Mapping section, scRGB / HDR10) instead of a shared global key, with the same "restart to apply" hint as ffxiv.
  • The shaders still follow the real back buffer in OnInitSwapchain, so they never encode for a container that isn't there yet.
  • Output Dither only shows up for HDR10.

Re-verified in game after the rebase:

[RenoDX] mods::swapchain::OnCreateSwapchain(swap: r8g8b8a8_unorm => r10g10b10a2_unorm, …)
[RenoDX] utils::swapchain::OnInitEffectRuntime(colorspace: hdr10_st2084)

@voosh @clshortfuse — would appreciate a look when you have a moment. The build workflows (Clang/Ninja/VS, x64/x86) are all sitting in action_required, so they'll need an approval before they can run.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants