Skip to content

Commit

Permalink
Merge branch 'ralston/dev/tonemap_dither_improvements' into 'main'
Browse files Browse the repository at this point in the history
Improve Tonemapping Dithering

See merge request lightspeedrtx/dxvk-remix-nv!716
  • Loading branch information
anon-apple committed Feb 26, 2024
2 parents 58bf1a3 + 3369652 commit ac93a4b
Show file tree
Hide file tree
Showing 18 changed files with 274 additions and 98 deletions.
7 changes: 3 additions & 4 deletions src/dxvk/rtx_render/rtx_bloom.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,10 @@ namespace dxvk {
const Resources::Resource& inOutColorBuffer,
const Resources::Resource& bloomBuffer);

void createTargetResource(Rc<DxvkContext>& ctx, const VkExtent3D& targetExtent);
virtual void createTargetResource(Rc<DxvkContext>& ctx, const VkExtent3D& targetExtent) override;
virtual void releaseTargetResource() override;

void releaseTargetResource();

bool isActive();
virtual bool isActive() override;

Rc<vk::DeviceFn> m_vkd;

Expand Down
20 changes: 19 additions & 1 deletion src/dxvk/rtx_render/rtx_debug_view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -440,8 +440,22 @@ namespace dxvk {

ImGui::Text("Common:");

// NaN/Inf Colorization

ImGui::Checkbox("Color NaN Red/Inf Blue", &m_enableInfNanView);
ImGui::InputInt("Color Code Pixel Radius", &m_colorCodeRadius);

if (m_enableInfNanView) {
ImGui::InputInt("Color Code Pixel Radius", &m_colorCodeRadius);
}

// Input Quantization

ImGui::Checkbox("Quantize Input", &enableInputQuantizationObject());

if (enableInputQuantization()) {
ImGui::InputFloat("Inverse Quantization Step Size", &inverseQuantizationStepSizeObject(), 0.1f, 1.0f);
ImGui::Text("Effective Quantized Step Size: 1.0 / %f", inverseQuantizationStepSizeObject());
}

if (displayType() == DebugViewDisplayType::Standard) {
ImGui::Text("Standard:");
Expand Down Expand Up @@ -631,6 +645,10 @@ namespace dxvk {
debugViewArgs.debugViewIdx = debugViewIdx();
debugViewArgs.colorCodeRadius = std::clamp(m_colorCodeRadius, 0, 8);

debugViewArgs.enableInputQuantization = enableInputQuantization();
debugViewArgs.quantizationStepSize = 1.0f / inverseQuantizationStepSize();
debugViewArgs.quantizationInverseStepSize = inverseQuantizationStepSize();

if (s_disableAnimation)
debugViewArgs.animationTimeSec = 0;
else
Expand Down
22 changes: 15 additions & 7 deletions src/dxvk/rtx_render/rtx_debug_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,10 @@ namespace dxvk {
DebugViewArgs getCommonDebugViewArgs(DxvkContext* ctx, const Resources::RaytracingOutput& rtOutput, DxvkObjects& common);

void generateCompositeImage(Rc<DxvkContext> ctx, Rc<DxvkImage>& outputImage);
void createDownscaledResource(Rc<DxvkContext>& ctx, const VkExtent3D& downscaledExtent);
void releaseDownscaledResource();
virtual void createDownscaledResource(Rc<DxvkContext>& ctx, const VkExtent3D& downscaledExtent) override;
virtual void releaseDownscaledResource() override;

bool isActive();
virtual bool isActive() override;

Rc<DxvkBuffer> m_debugViewConstants;
Rc<vk::DeviceFn> m_vkd;
Expand Down Expand Up @@ -127,18 +127,26 @@ namespace dxvk {
// Common Display
bool m_enableInfNanView = true;
int m_colorCodeRadius = 4;
RTX_OPTION("rtx.debugView", bool, enableInputQuantization, false,
"Enables uniform-step input quantization on debug view input buffers.\n"
"This is mostly useful for when debugging artifacts relating to quantization that may not be visible in a buffer due to higher precision formats in use.\n"
"For example, the final output from tonemapping is a floating point texture in the debug view but will be quantized to 8 bit on some monitors. Using this option the quantization which will be applied to the output can be visualized in advance.");
// Note: Default to standard 8 bit unorm encoding step size ([0, 1] range normalized on a step size of 1/255).
RTX_OPTION("rtx.debugView", float, inverseQuantizationStepSize, 255.0f,
"The inverse of the uniform step size to quantize the debug view input to when Input Quantization is enabled.\n"
"A value of 255 indicates that the input will be quantized to steps of 1/255, the same as the step size used when quantizing the range 0-1 to an 8 bit representation.");

// Standard Display
RTX_OPTION_ENV("rtx.debugView", bool, enablePseudoColor, false, "RTX_DEBUG_VIEW_ENABLE_PSEUDO_COLOR", "Enables RGB color coding of a scalar debug view value.");
RTX_OPTION_ENV("rtx.debugView", bool, enableGammaCorrection, false, "RTX_DEBUG_VIEW_ENABLE_GAMMA_CORRECTION", "Enables gamma correction of a debug view value.");
bool m_enableAlphaChannel = false;
float m_scale = 1.f;
RTX_OPTION_ENV("rtx.debugView", float, minValue, 0.f, "DXVK_RTX_DEBUG_VIEW_MIN_VALUE", "");
RTX_OPTION_ENV("rtx.debugView", float, maxValue, 1.f, "DXVK_RTX_DEBUG_VIEW_MAX_VALUE", "");
RTX_OPTION_ENV("rtx.debugView", float, minValue, 0.f, "DXVK_RTX_DEBUG_VIEW_MIN_VALUE", "The minimum debug view input value to map to 0 in the output when the standard debug display is in use. Values below this value in the input will be clamped to 0 in the output.");
RTX_OPTION_ENV("rtx.debugView", float, maxValue, 1.f, "DXVK_RTX_DEBUG_VIEW_MAX_VALUE", "The maximum debug view input value to map to 1 in the output when the standard debug display is in use. Values above this value in the input will be clamped to 1 in the output.");

// EV100 Display
RTX_OPTION_ENV("rtx.debugView", int32_t, evMinValue, -4, "DXVK_RTX_DEBUG_VIEW_EV_MIN_VALUE", "");
RTX_OPTION_ENV("rtx.debugView", int32_t, evMaxValue, 4, "DXVK_RTX_DEBUG_VIEW_EV_MAX_VALUE", "");
RTX_OPTION_ENV("rtx.debugView", int32_t, evMinValue, -4, "DXVK_RTX_DEBUG_VIEW_EV_MIN_VALUE", "The minimum EV100 debug view input value to map to the bottom of the visualization range when EV100 debug display is in use. Values below this value in the input will be clamped to the bottom of the range.");
RTX_OPTION_ENV("rtx.debugView", int32_t, evMaxValue, 4, "DXVK_RTX_DEBUG_VIEW_EV_MAX_VALUE", "The maximum EV100 debug view input value to map to the top of the visualization range when EV100 debug display is in use. Values above this value in the input will be clamped to the top of the range.")

// HDR Waveform Display
bool m_enableLuminanceMode = false;
Expand Down
15 changes: 14 additions & 1 deletion src/dxvk/rtx_render/rtx_local_tone_mapping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "dxvk_scoped_annotation.h"
#include "rtx_render/rtx_shader_manager.h"
#include "rtx.h"
#include "rtx/pass/tonemap/tonemapping.h"
#include "rtx/pass/local_tonemap/local_tonemapping.h"

#include <rtx_shaders/luminance.h>
Expand Down Expand Up @@ -114,6 +115,7 @@ namespace dxvk {
PUSH_CONSTANTS(FinalCombineArgs)

BEGIN_PARAMETER()
TEXTURE2DARRAY(FINAL_COMBINE_BLUE_NOISE_TEXTURE_INPUT)
SAMPLER2D(FINAL_COMBINE_MIP_ASSEMBLE)
SAMPLER2D(FINAL_COMBINE_ORIGINAL_MIP)
TEXTURE2D(FINAL_COMBINE_ORIGINAL_MIP0)
Expand Down Expand Up @@ -143,10 +145,11 @@ namespace dxvk {
ImGui::DragFloat("Highlight Level", &highlightsObject(), 0.01f, -10.f, 10.f, "%.3f", ImGuiSliderFlags_AlwaysClamp);
ImGui::DragFloat("Exposure Preference Sigma", &exposurePreferenceSigmaObject(), 0.01f, 0.f, 100.f, "%.3f", ImGuiSliderFlags_AlwaysClamp);
ImGui::DragFloat("Exposure Preference Offset", &exposurePreferenceOffsetObject(), 0.001f, -1.f, 1.f, "%.3f", ImGuiSliderFlags_AlwaysClamp);
ImGui::Combo("Dither Mode", &ditherModeObject(), "Disabled\0Spatial\0Spatial + Temporal\0");
}

void DxvkLocalToneMapping::dispatch(
Rc<DxvkContext> ctx,
Rc<RtxContext> ctx,
Rc<DxvkSampler> linearSampler,
Rc<DxvkImageView> exposureView,
const Resources::RaytracingOutput& rtOutput,
Expand Down Expand Up @@ -287,6 +290,7 @@ namespace dxvk {

{
ScopedGpuProfileZone(ctx, "Final Combine");

uvec2 mipResolution = resolutionList[displayMipLevel];
FinalCombineArgs pushArgs = {};
pushArgs.mipPixelSize = vec4 {
Expand All @@ -301,7 +305,16 @@ namespace dxvk {
pushArgs.enableAutoExposure = enableAutoExposure;
pushArgs.performSRGBConversion = performSRGBConversion;
pushArgs.finalizeWithACES = finalizeWithACES();
switch (ditherMode()) {
case DitherMode::None: pushArgs.ditherMode = ditherModeNone; break;
case DitherMode::Spatial: pushArgs.ditherMode = ditherModeSpatialOnly; break;
case DitherMode::SpatialTemporal: pushArgs.ditherMode = ditherModeSpatialTemporal; break;
}
pushArgs.frameIndex = ctx->getDevice()->getCurrentFrameId();

ctx->pushConstants(0, sizeof(pushArgs), &pushArgs);

ctx->bindResourceView(FINAL_COMBINE_BLUE_NOISE_TEXTURE_INPUT, ctx->getResourceManager().getBlueNoiseTexture(ctx), nullptr);
ctx->bindResourceView(FINAL_COMBINE_ORIGINAL_MIP0, m_mips.view[0], nullptr);
ctx->bindResourceView(FINAL_COMBINE_ORIGINAL_MIP, m_mips.view[displayMipLevel], nullptr);
ctx->bindResourceView(FINAL_COMBINE_WEIGHT_MIP0, m_mipsWeights.view[0], nullptr);
Expand Down
21 changes: 16 additions & 5 deletions src/dxvk/rtx_render/rtx_local_tone_mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ namespace dxvk {
~DxvkLocalToneMapping();

void dispatch(
Rc<DxvkContext> ctx,
Rc<RtxContext> ctx,
Rc<DxvkSampler> linearSampler,
Rc<DxvkImageView> exposureView,
const Resources::RaytracingOutput& rtOutput,
Expand All @@ -53,16 +53,21 @@ namespace dxvk {

private:

bool isActive() { return RtxOptions::Get()->tonemappingMode() == TonemappingMode::Local; }
virtual bool isActive() override { return RtxOptions::Get()->tonemappingMode() == TonemappingMode::Local; }

void createTargetResource(Rc<DxvkContext>& ctx, const VkExtent3D& targetExtent);

void releaseTargetResource();
virtual void createTargetResource(Rc<DxvkContext>& ctx, const VkExtent3D& targetExtent) override;
virtual void releaseTargetResource() override;

Resources::MipMapResource m_mips;
Resources::MipMapResource m_mipsWeights;
Resources::MipMapResource m_mipsAssemble;

enum class DitherMode : uint32_t {
None = 0,
Spatial,
SpatialTemporal,
};

// Tone curve settings
RTX_OPTION("rtx.localtonemap", int, mip, 3, "Top mip level of tone map pyramid.");
RTX_OPTION("rtx.localtonemap", int, displayMip, 0, "Bottom mip level of tone map pyramid.");
Expand All @@ -74,6 +79,12 @@ namespace dxvk {
RTX_OPTION("rtx.localtonemap", float, highlights, 4.0, "Highlight area strength. Higher values cause darker highlight.");
RTX_OPTION("rtx.localtonemap", float, exposurePreferenceSigma, 4.0, "Transition sharpness between different areas of exposure. Smaller values result in sharper transitions.");
RTX_OPTION("rtx.localtonemap", float, exposurePreferenceOffset, 0.0, "Offset to reference luminance when calculating the weights a pixel belongs to shadow/normal/highlight areas.");

// Dithering settings
// Todo: In the future it might be good to combine this option and the rtx.tonemap.ditherMode option to reduce code/documentation/UI duplication.
RTX_OPTION("rtx.localtonemap", DitherMode, ditherMode, DitherMode::SpatialTemporal,
"Local tonemap dither mode selection, local tonemapping dithering has the same functionality and values as the global tonemapping dithering option, see rtx.tonemap.ditherMode for a more in-depth description.\n"
"Supported enum values are 0 = None (Disabled), 1 = Spatial (Enabled, Spatial dithering only), 2 = SpatialTemporal (Enabled, Spatial and temporal dithering).\n");
};

}
2 changes: 1 addition & 1 deletion src/dxvk/rtx_render/rtx_postFx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ namespace dxvk {
TEXTURE2D(POST_FX_MOTION_BLUR_PRIMARY_SCREEN_SPACE_MOTION_INPUT)
TEXTURE2D(POST_FX_MOTION_BLUR_PRIMARY_SURFACE_FLAGS_INPUT)
TEXTURE2D(POST_FX_MOTION_BLUR_PRIMARY_LINEAR_VIEW_Z_INPUT)
TEXTURE2D(POST_FX_MOTION_BLUR_BLUE_NOISE_TEXTURE_INPUT)
TEXTURE2DARRAY(POST_FX_MOTION_BLUR_BLUE_NOISE_TEXTURE_INPUT)
TEXTURE2D(POST_FX_MOTION_BLUR_INPUT)
SAMPLER(POST_FX_MOTION_BLUR_NEAREST_SAMPLER)
SAMPLER(POST_FX_MOTION_BLUR_LINEAR_SAMPLER)
Expand Down
2 changes: 1 addition & 1 deletion src/dxvk/rtx_render/rtx_restir_gi_rayquery.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ namespace dxvk {
}

private:
bool isActive() { return RtxOptions::Get()->useReSTIRGI(); }
virtual bool isActive() override { return RtxOptions::Get()->useReSTIRGI(); }

RTX_OPTION("rtx.restirGI", bool, useTemporalReuse, true, "Enables temporal reuse.");
RTX_OPTION("rtx.restirGI", bool, useSpatialReuse, true, "Enables spatial reuse.");
Expand Down
7 changes: 3 additions & 4 deletions src/dxvk/rtx_render/rtx_taa.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,10 @@ namespace dxvk {
void showImguiSettings();

private:
bool isActive() { return RtxOptions::Get()->isTAAEnabled(); }
virtual bool isActive() override { return RtxOptions::Get()->isTAAEnabled(); }

void createTargetResource(Rc<DxvkContext>& ctx, const VkExtent3D&);

void releaseTargetResource();
virtual void createTargetResource(Rc<DxvkContext>& ctx, const VkExtent3D&) override;
virtual void releaseTargetResource() override;

Rc<vk::DeviceFn> m_vkd;

Expand Down
30 changes: 21 additions & 9 deletions src/dxvk/rtx_render/rtx_tone_mapping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
#include "rtx_imgui.h"
#include "rtx/utility/debug_view_indices.h"

static_assert((TONEMAPPING_TONE_CURVE_SAMPLE_COUNT & 1) == 0, "The shader expects a sample count that is a multiply of 2.");
static_assert((TONEMAPPING_TONE_CURVE_SAMPLE_COUNT & 1) == 0, "The shader expects a sample count that is a multiple of 2.");

namespace dxvk {
// Defined within an unnamed namespace to ensure unique definition across binary
Expand Down Expand Up @@ -75,6 +75,7 @@ namespace dxvk {
PUSH_CONSTANTS(ToneMappingApplyToneMappingArgs)

BEGIN_PARAMETER()
TEXTURE2DARRAY(TONEMAPPING_APPLY_BLUE_NOISE_TEXTURE_INPUT)
RW_TEXTURE2D(TONEMAPPING_APPLY_TONEMAPPING_COLOR_INPUT)
SAMPLER1D(TONEMAPPING_APPLY_TONEMAPPING_TONE_CURVE_INPUT)
RW_TEXTURE1D_READONLY(TONEMAPPING_APPLY_TONEMAPPING_EXPOSURE_INPUT)
Expand All @@ -98,9 +99,9 @@ namespace dxvk {
ImGui::Checkbox("Color Grading Enabled", &colorGradingEnabledObject());
if (colorGradingEnabled()) {
ImGui::Indent();
ImGui::DragFloat("Contrast", &contrastObject(), 0.01f, 0.f, 2.f);
ImGui::DragFloat("Saturation", &saturationObject(), 0.01f, 0.f, 2.f);
ImGui::DragFloat3("Color Balance", &colorBalanceObject(), 0.01f, 0.f, 2.f);
ImGui::DragFloat("Contrast", &contrastObject(), 0.01f, 0.f, 1.f);
ImGui::DragFloat("Saturation", &saturationObject(), 0.01f, 0.f, 1.f);
ImGui::DragFloat3("Color Balance", &colorBalanceObject(), 0.01f, 0.f, 1.f);
ImGui::Separator();
ImGui::Unindent();
}
Expand All @@ -110,6 +111,8 @@ namespace dxvk {
ImGui::Indent();
ImGui::Checkbox("Finalize With ACES", &finalizeWithACESObject());

ImGui::Combo("Dither Mode", &ditherModeObject(), "Disabled\0Spatial\0Spatial + Temporal\0");

ImGui::Checkbox("Tuning Mode", &tuningModeObject());
if (tuningMode()) {
ImGui::Indent();
Expand All @@ -131,7 +134,7 @@ namespace dxvk {
}
}

void DxvkToneMapping::createResources(Rc<DxvkContext> ctx) {
void DxvkToneMapping::createResources(Rc<RtxContext> ctx) {
DxvkImageCreateInfo desc;
desc.type = VK_IMAGE_TYPE_1D;
desc.flags = 0;
Expand Down Expand Up @@ -168,7 +171,7 @@ namespace dxvk {
}

void DxvkToneMapping::dispatchHistogram(
Rc<DxvkContext> ctx,
Rc<RtxContext> ctx,
Rc<DxvkImageView> exposureView,
const Resources::Resource& colorBuffer,
bool autoExposureEnabled) {
Expand Down Expand Up @@ -207,7 +210,7 @@ namespace dxvk {
}

void DxvkToneMapping::dispatchToneCurve(
Rc<DxvkContext> ctx) {
Rc<RtxContext> ctx) {

ScopedGpuProfileZone(ctx, "Tonemap: Calculate Tone Curve");

Expand All @@ -233,7 +236,7 @@ namespace dxvk {
}

void DxvkToneMapping::dispatchApplyToneMapping(
Rc<DxvkContext> ctx,
Rc<RtxContext> ctx,
Rc<DxvkSampler> linearSampler,
Rc<DxvkImageView> exposureView,
const Resources::Resource& inputBuffer,
Expand Down Expand Up @@ -266,6 +269,15 @@ namespace dxvk {
pushArgs.contrast = contrast();
pushArgs.saturation = saturation();

// Dither args
switch (ditherMode()) {
case DitherMode::None: pushArgs.ditherMode = ditherModeNone; break;
case DitherMode::Spatial: pushArgs.ditherMode = ditherModeSpatialOnly; break;
case DitherMode::SpatialTemporal: pushArgs.ditherMode = ditherModeSpatialTemporal; break;
}
pushArgs.frameIndex = ctx->getDevice()->getCurrentFrameId();

ctx->bindResourceView(TONEMAPPING_APPLY_BLUE_NOISE_TEXTURE_INPUT, ctx->getResourceManager().getBlueNoiseTexture(ctx), nullptr);
ctx->bindResourceView(TONEMAPPING_APPLY_TONEMAPPING_COLOR_INPUT, inputBuffer.view, nullptr);
ctx->bindResourceView(TONEMAPPING_APPLY_TONEMAPPING_TONE_CURVE_INPUT, m_toneCurve.view, nullptr);
ctx->bindResourceView(TONEMAPPING_APPLY_TONEMAPPING_EXPOSURE_INPUT, exposureView, nullptr);
Expand All @@ -278,7 +290,7 @@ namespace dxvk {
}

void DxvkToneMapping::dispatch(
Rc<DxvkContext> ctx,
Rc<RtxContext> ctx,
Rc<DxvkSampler> linearSampler,
Rc<DxvkImageView> exposureView,
const Resources::RaytracingOutput& rtOutput,
Expand Down

0 comments on commit ac93a4b

Please sign in to comment.