Skip to content

Commit c5b0cef

Browse files
committed
[renderer] fixed shutdown assert and blurry image due to 0.990 resolution scale
1 parent 1e6dceb commit c5b0cef

File tree

15 files changed

+179
-54
lines changed

15 files changed

+179
-54
lines changed

data/shaders/auto_exposure.hlsl

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -77,19 +77,18 @@ void main_cs(uint3 thread_id : SV_DispatchThreadID)
7777
avg_nits = exp2(weighted_log_sum / max(weight_sum, 0.000001f));
7878
}
7979

80-
// 2. auto exposure works on top of the manual camera exposure, so the target is in post-camera scene-linear space
80+
// 2. keep the existing camera-relative metering so artistic exposure choices remain intact
8181
float camera_exposure = max(buffer_frame.camera_exposure, 0.000001f);
8282
float current_brightness = avg_nits * camera_exposure;
8383

84-
// 3. target middle gray so auto exposure refines the camera settings
85-
// instead of pushing every scene toward a bright daytime look.
84+
// 3. target middle gray using the final exposure value that the renderer applies.
85+
// storing the resolved exposure keeps temporal upscalers in sync with output.
8686
const float target_luminance = 0.18f;
8787

88-
// 4. compute the ae multiplier needed to bring the current average toward middle gray
88+
// 4. compute the camera-relative auto exposure trim
8989
float desired_exposure = target_luminance / max(current_brightness, 0.000001f);
9090

91-
// 5. keep auto exposure as a trim around the physical camera settings.
92-
// this preserves intentionally dark scenes such as night shots.
91+
// 5. clamp the auto exposure trim to a practical range
9392
const float min_ev = -4.0f;
9493
const float max_ev = 3.0f;
9594

@@ -98,19 +97,20 @@ void main_cs(uint3 thread_id : SV_DispatchThreadID)
9897

9998
desired_exposure = clamp(desired_exposure, min_exposure, max_exposure);
10099

101-
// 6. temporal adaptation in ev space so large changes remain stable
100+
// 6. resolve the final exposure and adapt it in ev space so large changes remain stable
101+
float desired_total_exposure = camera_exposure * desired_exposure;
102102
float prev_exposure = tex2.Load(int3(0, 0, 0)).r;
103103
float adaptation_speed = pass_get_f3_value().x;
104104

105105
// start from the current target to avoid a first-frame flash
106106
if (isnan(prev_exposure) || prev_exposure <= 0.0f)
107107
{
108-
prev_exposure = desired_exposure;
108+
prev_exposure = desired_total_exposure;
109109
}
110110

111111
// higher values should adapt faster, so the response scales with the user-controlled speed directly
112112
float prev_ev = log2(max(prev_exposure, 0.000001f));
113-
float desired_ev = log2(max(desired_exposure, 0.000001f));
113+
float desired_ev = log2(max(desired_total_exposure, 0.000001f));
114114
float adaptation_alpha = 1.0f - exp(-max(adaptation_speed, 0.0f) * 4.0f * buffer_frame.delta_time);
115115
float exposure = exp2(lerp(prev_ev, desired_ev, adaptation_alpha));
116116

data/shaders/output.hlsl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -392,10 +392,10 @@ void main_cs(uint3 thread_id : SV_DispatchThreadID)
392392
const float luminous_efficacy = 683.0f;
393393
color.rgb *= luminous_efficacy;
394394

395-
// apply exposure (camera and auto-exposure)
396-
// applied in nits domain, so physical camera units work correctly
397-
float exposure = is_auto_exposure ? tex2.Load(int3(0, 0, 0)).r : 1.0f;
398-
color.rgb *= buffer_frame.camera_exposure * exposure;
395+
// apply exposure
396+
// auto exposure stores the resolved final scale, while manual mode falls back to the camera settings
397+
float exposure = is_auto_exposure ? tex2.Load(int3(0, 0, 0)).r : buffer_frame.camera_exposure;
398+
color.rgb *= exposure;
399399

400400
// check hdr state
401401
bool is_hdr = buffer_frame.hdr_enabled != 0.0f;

source/editor/WorldPreviews.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "FileSystem/FileSystem.h"
1212
#include "Rendering/Renderer.h"
1313
#include "Resource/ResourceCache.h"
14+
#include "RHI/RHI_Device.h"
1415
#include "RHI/RHI_Texture.h"
1516
#include "World/World.h"
1617

@@ -320,6 +321,16 @@ void WorldPreviews::Tick()
320321
void WorldPreviews::Shutdown()
321322
{
322323
clear_request();
324+
325+
spartan::RHI_Device::QueueWaitAll();
326+
for (auto& [path, texture] : preview_textures)
327+
{
328+
if (texture)
329+
{
330+
texture->DestroyResourceImmediate();
331+
}
332+
}
333+
323334
preview_textures.clear();
324335
}
325336

source/runtime/Core/Settings.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,14 @@ namespace spartan
7272
{
7373
if (name.size() >= 2 && name[0] == 'r' && name[1] == '.')
7474
{
75-
root.append_child(cvar_name_to_xml(string(name).c_str()).c_str()).text().set(get<float>(*cvar.m_value_ptr));
75+
float value = get<float>(*cvar.m_value_ptr);
76+
77+
if (name == "r.resolution_scale" && cvar_dynamic_resolution.GetValueAs<bool>())
78+
{
79+
value = 1.0f;
80+
}
81+
82+
root.append_child(cvar_name_to_xml(string(name).c_str()).c_str()).text().set(value);
7683
}
7784
}
7885

@@ -106,6 +113,7 @@ namespace spartan
106113

107114
Renderer::SetResolutionRender(root.child("ResolutionRenderWidth").text().as_int(), root.child("ResolutionRenderHeight").text().as_int());
108115
Renderer::SetResolutionOutput(root.child("ResolutionOutputWidth").text().as_int(), root.child("ResolutionOutputHeight").text().as_int());
116+
bool dynamic_resolution = root.child("r_dynamic_resolution").text().as_bool();
109117

110118
// load render options from xml
111119
for (const auto& [name, cvar] : ConsoleRegistry::Get().GetAll())
@@ -115,7 +123,14 @@ namespace spartan
115123
pugi::xml_node child = root.child(cvar_name_to_xml(string(name).c_str()).c_str());
116124
if (child)
117125
{
118-
ConsoleRegistry::Get().SetValueFromString(string(name).c_str(), child.text().as_string());
126+
if (name == "r.resolution_scale" && dynamic_resolution)
127+
{
128+
ConsoleRegistry::Get().SetValueFromString(string(name).c_str(), "1.0");
129+
}
130+
else
131+
{
132+
ConsoleRegistry::Get().SetValueFromString(string(name).c_str(), child.text().as_string());
133+
}
119134
}
120135
}
121136
}

source/runtime/Profiling/Profiler.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,7 @@ namespace spartan
543543
static_cast<uint32_t>(Display::GetLuminanceMax()),
544544
static_cast<uint32_t>(res_render.x),
545545
static_cast<uint32_t>(res_render.y),
546-
cvar_resolution_scale.GetValue() * 100.0f,
546+
Renderer::GetResolutionScale() * 100.0f,
547547
static_cast<uint32_t>(res_output.x),
548548
static_cast<uint32_t>(res_output.y),
549549
static_cast<uint32_t>(vp.width),

source/runtime/RHI/D3D12/D3D12_Texture.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,4 +420,9 @@ namespace spartan
420420

421421
m_rhi_srv = nullptr;
422422
}
423+
424+
void RHI_Texture::DestroyResourceImmediate()
425+
{
426+
RHI_DestroyResource();
427+
}
423428
}

source/runtime/RHI/RHI_CommandList.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2323
#include "pch.h"
2424
#include "RHI_CommandList.h"
2525
#include "RHI_Texture.h"
26+
#include "../Rendering/Renderer.h"
2627
//============================
2728

2829
//= NAMESPACES ========
@@ -33,15 +34,12 @@ namespace spartan
3334
{
3435
void RHI_CommandList::Dispatch(RHI_Texture* texture, float resolution_scale /*= 1.0f*/)
3536
{
36-
// clamp scale
37-
resolution_scale = clamp(resolution_scale, 0.5f, 1.0f);
38-
3937
const uint32_t thread_group_size = 8;
4038

41-
// scaled dimensions (round up to ensure coverage)
42-
const uint32_t scaled_width = static_cast<uint32_t>(ceil(texture->GetWidth() * resolution_scale));
43-
const uint32_t scaled_height = static_cast<uint32_t>(ceil(texture->GetHeight() * resolution_scale));
44-
const uint32_t scaled_depth = (texture->GetType() == RHI_Texture_Type::Type3D) ? static_cast<uint32_t>(ceil(texture->GetDepth() * resolution_scale)): 1;
39+
// scaled dimensions
40+
const uint32_t scaled_width = Renderer::GetScaledDimension(texture->GetWidth(), resolution_scale);
41+
const uint32_t scaled_height = Renderer::GetScaledDimension(texture->GetHeight(), resolution_scale);
42+
const uint32_t scaled_depth = (texture->GetType() == RHI_Texture_Type::Type3D) ? Renderer::GetScaledDimension(texture->GetDepth(), resolution_scale) : 1;
4543

4644
// conservative dispatch counts
4745
const uint32_t dispatch_x = (scaled_width + thread_group_size - 1) / thread_group_size;

source/runtime/RHI/RHI_PipelineState.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,8 @@ namespace spartan
168168

169169
if (pso.resolution_scale)
170170
{
171-
float resolution_scale = cvar_resolution_scale.GetValue();
172-
*width = static_cast<uint32_t>(*width * resolution_scale);
173-
*height = static_cast<uint32_t>(*height * resolution_scale);
171+
*width = Renderer::GetScaledDimension(*width);
172+
*height = Renderer::GetScaledDimension(*height);
174173
}
175174
}
176175
}

source/runtime/RHI/RHI_Texture.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ namespace spartan
114114
// misc
115115
void ClearData();
116116
void PrepareForGpu();
117+
void DestroyResourceImmediate();
117118
static size_t CalculateMipSize(uint32_t width, uint32_t height, uint32_t depth, RHI_Format format, uint32_t bits_per_channel, uint32_t channel_count);
118119

119120
// data

source/runtime/RHI/Vulkan/Vulkan_CommandList.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,7 +1296,7 @@ namespace spartan
12961296
if (m_pso.render_target_depth_texture != nullptr)
12971297
{
12981298
RHI_Texture* rt = m_pso.render_target_depth_texture;
1299-
if (cvar_resolution_scale.GetValue() == 1.0f)
1299+
if (Renderer::GetResolutionScale() == 1.0f)
13001300
{
13011301
SP_ASSERT_MSG(rt->GetWidth() == rendering_info.renderArea.extent.width, "The depth buffer doesn't match the output resolution");
13021302
}
@@ -1634,8 +1634,8 @@ namespace spartan
16341634
for (uint32_t mip_index = 0; mip_index < blit_region_count; mip_index++)
16351635
{
16361636
VkOffset3D& source_blit_size = blit_offsets_source[mip_index];
1637-
source_blit_size.x = static_cast<int32_t>(source->GetWidth() * source_scaling) >> mip_index;
1638-
source_blit_size.y = static_cast<int32_t>(source->GetHeight() * source_scaling) >> mip_index;
1637+
source_blit_size.x = static_cast<int32_t>(Renderer::GetScaledDimension(source->GetWidth(), source_scaling)) >> mip_index;
1638+
source_blit_size.y = static_cast<int32_t>(Renderer::GetScaledDimension(source->GetHeight(), source_scaling)) >> mip_index;
16391639
source_blit_size.z = 1;
16401640

16411641
VkOffset3D& destination_blit_size = blit_offsets_destination[mip_index];

0 commit comments

Comments
 (0)