mirror of
https://github.com/stenzek/duckstation.git
synced 2025-06-06 19:45:33 +00:00
GPU: Rewrite automatic resolution scaling
Make it play nice with rewind/runahead.
This commit is contained in:
parent
d812463649
commit
3ea26cc910
@ -1018,9 +1018,9 @@ void GPU::UpdateCRTCDisplayParameters()
|
||||
}
|
||||
|
||||
if ((cs.display_vram_width != old_vram_width || cs.display_vram_height != old_vram_height) &&
|
||||
g_settings.gpu_resolution_scale == 0)
|
||||
g_settings.gpu_automatic_resolution_scale)
|
||||
{
|
||||
GPUBackend::QueueUpdateResolutionScale();
|
||||
System::UpdateAutomaticResolutionScale();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1980,6 +1980,38 @@ void GPU::QueuePresentCurrentFrame()
|
||||
}
|
||||
}
|
||||
|
||||
u8 GPU::CalculateAutomaticResolutionScale() const
|
||||
{
|
||||
// Auto scaling.
|
||||
// When the system is starting and all borders crop is enabled, the registers are zero, and
|
||||
// display_height therefore is also zero. Keep the existing resolution until it updates.
|
||||
u32 scale = 1;
|
||||
if (const WindowInfo& main_window_info = GPUThread::GetRenderWindowInfo();
|
||||
!main_window_info.IsSurfaceless() && m_crtc_state.display_width > 0 && m_crtc_state.display_height > 0 &&
|
||||
m_crtc_state.display_vram_width > 0 && m_crtc_state.display_vram_height > 0)
|
||||
{
|
||||
GSVector4i display_rect, draw_rect;
|
||||
CalculateDrawRect(main_window_info.surface_width, main_window_info.surface_height, m_crtc_state.display_width,
|
||||
m_crtc_state.display_height, m_crtc_state.display_origin_left, m_crtc_state.display_origin_top,
|
||||
m_crtc_state.display_vram_width, m_crtc_state.display_vram_height, g_settings.display_rotation,
|
||||
g_settings.display_alignment, g_settings.gpu_show_vram ? 1.0f : ComputePixelAspectRatio(),
|
||||
g_settings.IsUsingIntegerDisplayScaling(), &display_rect, &draw_rect);
|
||||
|
||||
// We use the draw rect to determine scaling. This way we match the resolution as best we can, regardless of the
|
||||
// anamorphic aspect ratio.
|
||||
const s32 draw_width = draw_rect.width();
|
||||
const s32 draw_height = draw_rect.height();
|
||||
scale = static_cast<u32>(
|
||||
std::ceil(std::max(static_cast<float>(draw_width) / static_cast<float>(m_crtc_state.display_vram_width),
|
||||
static_cast<float>(draw_height) / static_cast<float>(m_crtc_state.display_vram_height))));
|
||||
scale = std::min<u32>(scale, std::numeric_limits<decltype(g_settings.gpu_resolution_scale)>::max());
|
||||
VERBOSE_LOG("Draw Size = {}x{}, VRAM Size = {}x{}, Preferred Scale = {}", draw_width, draw_height,
|
||||
m_crtc_state.display_vram_width, m_crtc_state.display_vram_height, scale);
|
||||
}
|
||||
|
||||
return Truncate8(scale);
|
||||
}
|
||||
|
||||
bool GPU::DumpVRAMToFile(const char* filename)
|
||||
{
|
||||
ReadVRAM(0, 0, VRAM_WIDTH, VRAM_HEIGHT);
|
||||
|
@ -230,6 +230,9 @@ public:
|
||||
// Queues the current frame for presentation. Should only be used with runahead.
|
||||
void QueuePresentCurrentFrame();
|
||||
|
||||
/// Computes the effective resolution scale when it is set to automatic.
|
||||
u8 CalculateAutomaticResolutionScale() const;
|
||||
|
||||
/// Helper function for computing the draw rectangle in a larger window.
|
||||
static void CalculateDrawRect(u32 window_width, u32 window_height, u32 crtc_display_width, u32 crtc_display_height,
|
||||
s32 display_origin_left, s32 display_origin_top, u32 display_vram_width,
|
||||
|
@ -398,20 +398,6 @@ bool GPUBackend::AllocateMemorySaveStates(std::span<System::MemorySaveState> sta
|
||||
return result;
|
||||
}
|
||||
|
||||
void GPUBackend::QueueUpdateResolutionScale()
|
||||
{
|
||||
DebugAssert(!GPUThread::IsOnThread());
|
||||
|
||||
GPUThread::RunOnBackend(
|
||||
[](GPUBackend* backend) {
|
||||
Error error;
|
||||
if (!backend->UpdateResolutionScale(&error)) [[unlikely]]
|
||||
GPUThread::ReportFatalErrorAndShutdown(
|
||||
fmt::format("Failed to update resolution scale: {}", error.GetDescription()));
|
||||
},
|
||||
false, true);
|
||||
}
|
||||
|
||||
void GPUBackend::HandleCommand(const GPUThreadCommand* cmd)
|
||||
{
|
||||
switch (cmd->type)
|
||||
@ -837,7 +823,6 @@ public:
|
||||
bool UpdateSettings(const GPUSettings& old_settings, Error* error) override;
|
||||
|
||||
u32 GetResolutionScale() const override;
|
||||
bool UpdateResolutionScale(Error* error) override;
|
||||
|
||||
void RestoreDeviceContext() override;
|
||||
void FlushRender() override;
|
||||
@ -891,11 +876,6 @@ u32 GPUNullBackend::GetResolutionScale() const
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool GPUNullBackend::UpdateResolutionScale(Error* error)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void GPUNullBackend::RestoreDeviceContext()
|
||||
{
|
||||
}
|
||||
|
@ -69,8 +69,6 @@ public:
|
||||
|
||||
static bool AllocateMemorySaveStates(std::span<System::MemorySaveState> states, Error* error);
|
||||
|
||||
static void QueueUpdateResolutionScale();
|
||||
|
||||
public:
|
||||
GPUBackend(GPUPresenter& presenter);
|
||||
virtual ~GPUBackend();
|
||||
@ -86,9 +84,6 @@ public:
|
||||
/// Returns the current resolution scale.
|
||||
virtual u32 GetResolutionScale() const = 0;
|
||||
|
||||
/// Updates the resolution scale when it's set to automatic.
|
||||
virtual bool UpdateResolutionScale(Error* error) = 0;
|
||||
|
||||
// Graphics API state reset/restore - call when drawing the UI etc.
|
||||
// TODO: replace with "invalidate cached state"
|
||||
virtual void RestoreDeviceContext() = 0;
|
||||
|
@ -726,40 +726,7 @@ void GPU_HW::CheckSettings()
|
||||
|
||||
u32 GPU_HW::CalculateResolutionScale() const
|
||||
{
|
||||
u32 scale;
|
||||
if (g_gpu_settings.gpu_resolution_scale != 0)
|
||||
{
|
||||
scale = g_gpu_settings.gpu_resolution_scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Auto scaling.
|
||||
if (m_presenter.GetDisplayWidth() == 0 || m_presenter.GetDisplayHeight() == 0 ||
|
||||
m_presenter.GetDisplayVRAMWidth() == 0 || m_presenter.GetDisplayVRAMHeight() == 0 ||
|
||||
!m_presenter.HasDisplayTexture() || !g_gpu_device->HasMainSwapChain())
|
||||
{
|
||||
// When the system is starting and all borders crop is enabled, the registers are zero, and
|
||||
// display_height therefore is also zero. Keep the existing resolution until it updates.
|
||||
scale = m_resolution_scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
GSVector4i display_rect, draw_rect;
|
||||
m_presenter.CalculateDrawRect(g_gpu_device->GetMainSwapChain()->GetWidth(),
|
||||
g_gpu_device->GetMainSwapChain()->GetHeight(), true, true, &display_rect,
|
||||
&draw_rect);
|
||||
|
||||
// We use the draw rect to determine scaling. This way we match the resolution as best we can, regardless of the
|
||||
// anamorphic aspect ratio.
|
||||
const s32 draw_width = draw_rect.width();
|
||||
const s32 draw_height = draw_rect.height();
|
||||
scale = static_cast<u32>(
|
||||
std::ceil(std::max(static_cast<float>(draw_width) / static_cast<float>(m_presenter.GetDisplayVRAMWidth()),
|
||||
static_cast<float>(draw_height) / static_cast<float>(m_presenter.GetDisplayVRAMHeight()))));
|
||||
VERBOSE_LOG("Draw Size = {}x{}, VRAM Size = {}x{}, Preferred Scale = {}", draw_width, draw_height,
|
||||
m_presenter.GetDisplayVRAMWidth(), m_presenter.GetDisplayVRAMHeight(), scale);
|
||||
}
|
||||
}
|
||||
u32 scale = g_gpu_settings.gpu_resolution_scale;
|
||||
|
||||
if (g_gpu_settings.gpu_downsample_mode == GPUDownsampleMode::Adaptive && scale > 1 && !Common::IsPow2(scale))
|
||||
{
|
||||
@ -782,14 +749,6 @@ u32 GPU_HW::CalculateResolutionScale() const
|
||||
return std::clamp<u32>(scale, 1, GetMaxResolutionScale());
|
||||
}
|
||||
|
||||
bool GPU_HW::UpdateResolutionScale(Error* error)
|
||||
{
|
||||
if (CalculateResolutionScale() == m_resolution_scale)
|
||||
return true;
|
||||
|
||||
return UpdateSettings(g_gpu_settings, error);
|
||||
}
|
||||
|
||||
GPUDownsampleMode GPU_HW::GetDownsampleMode(u32 resolution_scale) const
|
||||
{
|
||||
return (resolution_scale == 1) ? GPUDownsampleMode::Disabled : g_gpu_settings.gpu_downsample_mode;
|
||||
|
@ -74,8 +74,6 @@ public:
|
||||
bool UpdateSettings(const GPUSettings& old_settings, Error* error) override;
|
||||
void UpdatePostProcessingSettings(bool force_reload) override;
|
||||
|
||||
bool UpdateResolutionScale(Error* error) override;
|
||||
|
||||
void FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color, bool interlaced_rendering, u8 active_line_lsb) override;
|
||||
void ReadVRAM(u32 x, u32 y, u32 width, u32 height) override;
|
||||
void UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, bool set_mask, bool check_mask) override;
|
||||
|
@ -1004,8 +1004,7 @@ bool GPUPresenter::ApplyChromaSmoothing()
|
||||
void GPUPresenter::CalculateDrawRect(s32 window_width, s32 window_height, bool apply_aspect_ratio, bool apply_alignment,
|
||||
GSVector4i* display_rect, GSVector4i* draw_rect) const
|
||||
{
|
||||
const bool integer_scale = (g_gpu_settings.display_scaling == DisplayScalingMode::NearestInteger ||
|
||||
g_gpu_settings.display_scaling == DisplayScalingMode::BilinearInteger);
|
||||
const bool integer_scale = g_gpu_settings.IsUsingIntegerDisplayScaling();
|
||||
const bool show_vram = g_gpu_settings.gpu_show_vram;
|
||||
const u32 display_width = show_vram ? VRAM_WIDTH : m_display_width;
|
||||
const u32 display_height = show_vram ? VRAM_HEIGHT : m_display_height;
|
||||
|
@ -65,11 +65,6 @@ void GPU_SW::ClearVRAM()
|
||||
std::memset(g_gpu_clut, 0, sizeof(g_gpu_clut));
|
||||
}
|
||||
|
||||
bool GPU_SW::UpdateResolutionScale(Error* error)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void GPU_SW::LoadState(const GPUBackendLoadStateCommand* cmd)
|
||||
{
|
||||
std::memcpy(g_vram, cmd->vram_data, sizeof(g_vram));
|
||||
|
@ -46,8 +46,6 @@ public:
|
||||
|
||||
void ClearVRAM() override;
|
||||
|
||||
bool UpdateResolutionScale(Error* error) override;
|
||||
|
||||
void LoadState(const GPUBackendLoadStateCommand* cmd) override;
|
||||
|
||||
bool AllocateMemorySaveState(System::MemorySaveState& mss, Error* error) override;
|
||||
|
@ -1287,13 +1287,6 @@ void GPUThread::DisplayWindowResizedOnThread()
|
||||
Internal::PresentFrameAndRestoreContext();
|
||||
Internal::PresentFrameAndRestoreContext();
|
||||
}
|
||||
|
||||
if (g_gpu_settings.gpu_resolution_scale == 0)
|
||||
{
|
||||
Error error;
|
||||
if (!s_state.gpu_backend->UpdateResolutionScale(&error)) [[unlikely]]
|
||||
ReportFatalErrorAndShutdown(fmt::format("Failed to update resolution scale: {}", error.GetDescription()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,6 +199,7 @@ void Settings::Load(const SettingsInterface& si, const SettingsInterface& contro
|
||||
.value_or(DEFAULT_GPU_RENDERER);
|
||||
gpu_adapter = si.GetStringValue("GPU", "Adapter", "");
|
||||
gpu_resolution_scale = static_cast<u8>(si.GetUIntValue("GPU", "ResolutionScale", 1u));
|
||||
gpu_automatic_resolution_scale = (gpu_resolution_scale == 0);
|
||||
gpu_multisamples = static_cast<u8>(si.GetUIntValue("GPU", "Multisamples", 1u));
|
||||
gpu_use_debug_device = si.GetBoolValue("GPU", "UseDebugDevice", false);
|
||||
gpu_disable_shader_cache = si.GetBoolValue("GPU", "DisableShaderCache", false);
|
||||
@ -972,6 +973,7 @@ void Settings::FixIncompatibleSettings(const SettingsInterface& si, bool display
|
||||
g_settings.enable_8mb_ram = false;
|
||||
g_settings.gpu_resolution_scale = 1;
|
||||
g_settings.gpu_multisamples = 1;
|
||||
g_settings.gpu_automatic_resolution_scale = false;
|
||||
g_settings.gpu_per_sample_shading = false;
|
||||
g_settings.gpu_true_color = false;
|
||||
g_settings.gpu_scaled_dithering = false;
|
||||
|
@ -102,6 +102,7 @@ struct GPUSettings
|
||||
bool gpu_disable_raster_order_views : 1 = false;
|
||||
bool gpu_disable_compute_shaders : 1 = false;
|
||||
bool gpu_disable_compressed_textures : 1 = false;
|
||||
bool gpu_automatic_resolution_scale : 1 = false;
|
||||
bool gpu_per_sample_shading : 1 = false;
|
||||
bool gpu_true_color : 1 = true;
|
||||
bool gpu_scaled_dithering : 1 = true;
|
||||
@ -210,6 +211,11 @@ struct GPUSettings
|
||||
|
||||
ALWAYS_INLINE bool IsUsingSoftwareRenderer() const { return (gpu_renderer == GPURenderer::Software); }
|
||||
ALWAYS_INLINE bool IsUsingAccurateBlending() const { return (gpu_accurate_blending && !gpu_true_color); }
|
||||
ALWAYS_INLINE bool IsUsingIntegerDisplayScaling() const
|
||||
{
|
||||
return (display_scaling == DisplayScalingMode::NearestInteger ||
|
||||
display_scaling == DisplayScalingMode::BilinearInteger);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE bool UsingPGXPCPUMode() const { return gpu_pgxp_enable && gpu_pgxp_cpu; }
|
||||
ALWAYS_INLINE bool UsingPGXPDepthBuffer() const { return gpu_pgxp_enable && gpu_pgxp_depth_buffer; }
|
||||
|
@ -1219,6 +1219,10 @@ void System::LoadSettings(bool display_osd_messages)
|
||||
(g_settings.disable_all_enhancements ||
|
||||
Host::Internal::GetBaseSettingsLayer()->GetBoolValue("Main", "DisableAllEnhancements", false));
|
||||
|
||||
// Fix up automatic resolution scale, yuck.
|
||||
if (g_settings.gpu_automatic_resolution_scale && IsValid())
|
||||
g_settings.gpu_resolution_scale = g_gpu.CalculateAutomaticResolutionScale();
|
||||
|
||||
Settings::UpdateLogConfig(si);
|
||||
Host::LoadSettings(si, lock);
|
||||
InputManager::ReloadSources(controller_si, lock);
|
||||
@ -1934,6 +1938,7 @@ bool System::Initialize(std::unique_ptr<CDImage> disc, DiscRegion disc_region, b
|
||||
PCDrv::Initialize();
|
||||
|
||||
UpdateGTEAspectRatio();
|
||||
UpdateAutomaticResolutionScale();
|
||||
UpdateThrottlePeriod();
|
||||
UpdateMemorySaveStateSettings();
|
||||
|
||||
@ -2592,7 +2597,7 @@ void System::ClearMemorySaveStates(bool reallocate_resources, bool recycle_textu
|
||||
}
|
||||
|
||||
// immediately save a rewind state next frame
|
||||
s_state.rewind_save_counter = (s_state.rewind_save_frequency > 0) ? 0 : -1;
|
||||
s_state.rewind_save_counter = (s_state.rewind_save_frequency >= 0) ? 0 : -1;
|
||||
}
|
||||
|
||||
void System::FreeMemoryStateStorage(bool release_memory, bool release_textures, bool recycle_textures)
|
||||
@ -4220,8 +4225,8 @@ void System::UpdateRunningGame(const std::string& path, CDImage* image, bool boo
|
||||
|
||||
UpdateRichPresence(booting);
|
||||
|
||||
FullscreenUI::OnRunningGameChanged(s_state.running_game_path, s_state.running_game_serial,
|
||||
s_state.running_game_title, s_state.running_game_hash);
|
||||
FullscreenUI::OnRunningGameChanged(s_state.running_game_path, s_state.running_game_serial, s_state.running_game_title,
|
||||
s_state.running_game_hash);
|
||||
|
||||
Host::OnGameChanged(s_state.running_game_path, s_state.running_game_serial, s_state.running_game_title,
|
||||
s_state.running_game_hash);
|
||||
@ -4508,7 +4513,8 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
|
||||
|
||||
// NOTE: Must come after the GPU thread settings update, otherwise it allocs the wrong size textures.
|
||||
const bool use_existing_textures = (g_settings.gpu_resolution_scale == old_settings.gpu_resolution_scale);
|
||||
ClearMemorySaveStates(true, use_existing_textures);
|
||||
FreeMemoryStateStorage(false, true, use_existing_textures);
|
||||
ClearMemorySaveStates(true, true);
|
||||
|
||||
if (IsPaused())
|
||||
{
|
||||
@ -5823,6 +5829,7 @@ void System::DisplayWindowResized()
|
||||
return;
|
||||
|
||||
UpdateGTEAspectRatio();
|
||||
UpdateAutomaticResolutionScale();
|
||||
}
|
||||
|
||||
void System::UpdateGTEAspectRatio()
|
||||
@ -5866,6 +5873,28 @@ void System::UpdateGTEAspectRatio()
|
||||
GTE::SetAspectRatio(gte_ar, custom_num, custom_denom);
|
||||
}
|
||||
|
||||
void System::UpdateAutomaticResolutionScale()
|
||||
{
|
||||
if (!IsValidOrInitializing() || !g_settings.gpu_automatic_resolution_scale)
|
||||
return;
|
||||
|
||||
const u32 new_scale = g_gpu.CalculateAutomaticResolutionScale();
|
||||
if (g_settings.gpu_resolution_scale == new_scale)
|
||||
return;
|
||||
|
||||
g_settings.gpu_resolution_scale = Truncate8(new_scale);
|
||||
GPUThread::UpdateSettings(true, false, false);
|
||||
FreeMemoryStateStorage(false, true, false);
|
||||
ClearMemorySaveStates(true, false);
|
||||
|
||||
if (IsPaused())
|
||||
{
|
||||
// resolution change needs display updated
|
||||
g_gpu.UpdateDisplay(false);
|
||||
GPUThread::PresentCurrentFrame();
|
||||
}
|
||||
}
|
||||
|
||||
bool System::ChangeGPUDump(std::string new_path)
|
||||
{
|
||||
Error error;
|
||||
|
@ -50,6 +50,9 @@ void DisplayWindowResized();
|
||||
/// Updates the internal GTE aspect ratio. Use with "match display" aspect ratio setting.
|
||||
void UpdateGTEAspectRatio();
|
||||
|
||||
/// Updates the resolution scale when it is set to automatic.
|
||||
void UpdateAutomaticResolutionScale();
|
||||
|
||||
/// Called on card read/write, handles fast forwarding.
|
||||
void OnMemoryCardAccessed();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user