GPU: Add pixel aspect ratio option

Can display in 4:3, 16:9, 1:1 ratios.
This commit is contained in:
Connor McLaughlin 2020-04-10 15:12:16 +10:00
parent 3325d2c42c
commit fbfd838e22
10 changed files with 101 additions and 41 deletions

View file

@ -29,6 +29,8 @@ bool GPU::Initialize(HostDisplay* host_display, System* system, DMA* dma, Interr
m_timers = timers; m_timers = timers;
m_force_progressive_scan = m_system->GetSettings().display_force_progressive_scan; m_force_progressive_scan = m_system->GetSettings().display_force_progressive_scan;
m_force_ntsc_timings = m_system->GetSettings().gpu_force_ntsc_timings; m_force_ntsc_timings = m_system->GetSettings().gpu_force_ntsc_timings;
m_crtc_state.display_aspect_ratio =
Settings::GetDisplayAspectRatioValue(m_system->GetSettings().display_aspect_ratio);
m_tick_event = m_tick_event =
m_system->CreateTimingEvent("GPU Tick", 1, 1, std::bind(&GPU::Execute, this, std::placeholders::_1), true); m_system->CreateTimingEvent("GPU Tick", 1, 1, std::bind(&GPU::Execute, this, std::placeholders::_1), true);
return true; return true;
@ -44,6 +46,9 @@ void GPU::UpdateSettings()
UpdateCRTCConfig(); UpdateCRTCConfig();
} }
m_crtc_state.display_aspect_ratio =
Settings::GetDisplayAspectRatioValue(m_system->GetSettings().display_aspect_ratio);
// Crop mode calls this, so recalculate the display area // Crop mode calls this, so recalculate the display area
UpdateCRTCDisplayParameters(); UpdateCRTCDisplayParameters();
} }
@ -64,10 +69,14 @@ void GPU::SoftReset()
m_drawing_area.Set(0, 0, 0, 0); m_drawing_area.Set(0, 0, 0, 0);
m_drawing_area_changed = true; m_drawing_area_changed = true;
m_drawing_offset = {}; m_drawing_offset = {};
std::memset(&m_crtc_state, 0, sizeof(m_crtc_state)); std::memset(&m_crtc_state.regs, 0, sizeof(m_crtc_state.regs));
m_crtc_state.regs.display_address_start = 0;
m_crtc_state.regs.horizontal_display_range = 0xC60260; m_crtc_state.regs.horizontal_display_range = 0xC60260;
m_crtc_state.regs.vertical_display_range = 0x3FC10; m_crtc_state.regs.vertical_display_range = 0x3FC10;
m_crtc_state.fractional_ticks = 0;
m_crtc_state.current_tick_in_scanline = 0;
m_crtc_state.current_scanline = 0;
m_crtc_state.in_hblank = false;
m_crtc_state.in_vblank = false;
m_state = State::Idle; m_state = State::Idle;
m_blitter_ticks = 0; m_blitter_ticks = 0;
m_command_total_words = 0; m_command_total_words = 0;
@ -136,7 +145,6 @@ bool GPU::DoState(StateWrapper& sw)
sw.Do(&m_crtc_state.fractional_ticks); sw.Do(&m_crtc_state.fractional_ticks);
sw.Do(&m_crtc_state.current_tick_in_scanline); sw.Do(&m_crtc_state.current_tick_in_scanline);
sw.Do(&m_crtc_state.current_scanline); sw.Do(&m_crtc_state.current_scanline);
sw.Do(&m_crtc_state.display_aspect_ratio);
sw.Do(&m_crtc_state.in_hblank); sw.Do(&m_crtc_state.in_hblank);
sw.Do(&m_crtc_state.in_vblank); sw.Do(&m_crtc_state.in_vblank);
@ -521,9 +529,6 @@ void GPU::UpdateCRTCDisplayParameters()
(vertical_visible_end_line - std::max(vertical_display_start, vertical_visible_start_line)) << height_shift, (vertical_visible_end_line - std::max(vertical_display_start, vertical_visible_start_line)) << height_shift,
VRAM_HEIGHT - cs.display_vram_top); VRAM_HEIGHT - cs.display_vram_top);
} }
// Aspect ratio is always 4:3.
cs.display_aspect_ratio = 4.0f / 3.0f;
} }
TickCount GPU::GetPendingGPUTicks() const TickCount GPU::GetPendingGPUTicks() const

View file

@ -20,32 +20,6 @@ void HostDisplay::WindowResized(s32 new_window_width, s32 new_window_height)
std::tuple<s32, s32, s32, s32> HostDisplay::CalculateDrawRect() const std::tuple<s32, s32, s32, s32> HostDisplay::CalculateDrawRect() const
{ {
#if 0
// convert display region to correct pixel aspect ratio
float display_width, display_height, active_left, active_top, active_width, active_height;
if (m_display_width >= m_display_height)
{
display_width = static_cast<float>(m_display_width);
display_height = static_cast<float>(m_display_width) / m_display_pixel_aspect_ratio;
const float scale = display_height / static_cast<float>(m_display_height);
active_left = static_cast<float>(m_display_active_left);
active_top = static_cast<float>(m_display_active_top) * scale;
active_width = static_cast<float>(m_display_active_width);
active_height = static_cast<float>(m_display_active_width) / m_display_pixel_aspect_ratio;
}
else
{
display_width = static_cast<float>(m_display_height) * m_display_pixel_aspect_ratio;
display_height = static_cast<float>(m_display_height);
const float scale = display_width / static_cast<float>(m_display_width);
active_left = static_cast<float>(m_display_active_left) * scale;
active_top = static_cast<float>(m_display_active_top);
active_width = static_cast<float>(m_display_active_height) * m_display_pixel_aspect_ratio;
active_height = static_cast<float>(m_display_active_height);
}
#else
const float y_scale = const float y_scale =
(static_cast<float>(m_display_width) / static_cast<float>(m_display_height)) / m_display_pixel_aspect_ratio; (static_cast<float>(m_display_width) / static_cast<float>(m_display_height)) / m_display_pixel_aspect_ratio;
const float display_width = static_cast<float>(m_display_width); const float display_width = static_cast<float>(m_display_width);
@ -54,7 +28,6 @@ std::tuple<s32, s32, s32, s32> HostDisplay::CalculateDrawRect() const
const float active_top = static_cast<float>(m_display_active_top) * y_scale; const float active_top = static_cast<float>(m_display_active_top) * y_scale;
const float active_width = static_cast<float>(m_display_active_width); const float active_width = static_cast<float>(m_display_active_width);
const float active_height = static_cast<float>(m_display_active_height) * y_scale; const float active_height = static_cast<float>(m_display_active_height) * y_scale;
#endif
// now fit it within the window // now fit it within the window
const s32 window_width = m_window_width; const s32 window_width = m_window_width;

View file

@ -880,6 +880,7 @@ void HostInterface::SetDefaultSettings(SettingsInterface& si)
si.SetBoolValue("GPU", "ForceNTSCTimings", false); si.SetBoolValue("GPU", "ForceNTSCTimings", false);
si.SetStringValue("Display", "CropMode", "Overscan"); si.SetStringValue("Display", "CropMode", "Overscan");
si.SetStringValue("Display", "PixelAspectRatio", "4:3");
si.SetBoolValue("Display", "ForceProgressiveScan", true); si.SetBoolValue("Display", "ForceProgressiveScan", true);
si.SetBoolValue("Display", "LinearFiltering", true); si.SetBoolValue("Display", "LinearFiltering", true);
si.SetBoolValue("Display", "ShowOSDMessages", true); si.SetBoolValue("Display", "ShowOSDMessages", true);
@ -934,6 +935,7 @@ void HostInterface::UpdateSettings(const std::function<void()>& apply_callback)
const bool old_audio_sync_enabled = m_settings.audio_sync_enabled; const bool old_audio_sync_enabled = m_settings.audio_sync_enabled;
const bool old_speed_limiter_enabled = m_settings.speed_limiter_enabled; const bool old_speed_limiter_enabled = m_settings.speed_limiter_enabled;
const DisplayCropMode old_display_crop_mode = m_settings.display_crop_mode; const DisplayCropMode old_display_crop_mode = m_settings.display_crop_mode;
const DisplayAspectRatio old_display_aspect_ratio = m_settings.display_aspect_ratio;
const bool old_display_linear_filtering = m_settings.display_linear_filtering; const bool old_display_linear_filtering = m_settings.display_linear_filtering;
const bool old_cdrom_read_thread = m_settings.cdrom_read_thread; const bool old_cdrom_read_thread = m_settings.cdrom_read_thread;
std::array<ControllerType, NUM_CONTROLLER_AND_CARD_PORTS> old_controller_types = m_settings.controller_types; std::array<ControllerType, NUM_CONTROLLER_AND_CARD_PORTS> old_controller_types = m_settings.controller_types;
@ -983,7 +985,8 @@ void HostInterface::UpdateSettings(const std::function<void()>& apply_callback)
m_settings.gpu_texture_filtering != old_gpu_texture_filtering || m_settings.gpu_texture_filtering != old_gpu_texture_filtering ||
m_settings.gpu_force_ntsc_timings != old_gpu_force_ntsc_timings || m_settings.gpu_force_ntsc_timings != old_gpu_force_ntsc_timings ||
m_settings.display_force_progressive_scan != old_display_force_progressive_scan || m_settings.display_force_progressive_scan != old_display_force_progressive_scan ||
m_settings.display_crop_mode != old_display_crop_mode) m_settings.display_crop_mode != old_display_crop_mode ||
m_settings.display_aspect_ratio != old_display_aspect_ratio)
{ {
m_system->UpdateGPUSettings(); m_system->UpdateGPUSettings();
} }

View file

@ -2,4 +2,4 @@
#include "types.h" #include "types.h"
static constexpr u32 SAVE_STATE_MAGIC = 0x43435544; static constexpr u32 SAVE_STATE_MAGIC = 0x43435544;
static constexpr u32 SAVE_STATE_VERSION = 20; static constexpr u32 SAVE_STATE_VERSION = 21;

View file

@ -32,6 +32,10 @@ void Settings::Load(SettingsInterface& si)
display_crop_mode = ParseDisplayCropMode( display_crop_mode = ParseDisplayCropMode(
si.GetStringValue("Display", "CropMode", GetDisplayCropModeName(DisplayCropMode::None)).c_str()) si.GetStringValue("Display", "CropMode", GetDisplayCropModeName(DisplayCropMode::None)).c_str())
.value_or(DisplayCropMode::None); .value_or(DisplayCropMode::None);
display_aspect_ratio =
ParseDisplayAspectRatio(
si.GetStringValue("Display", "AspectRatio", GetDisplayAspectRatioName(DisplayAspectRatio::R4_3)).c_str())
.value_or(DisplayAspectRatio::R4_3);
display_force_progressive_scan = si.GetBoolValue("Display", "ForceProgressiveScan", true); display_force_progressive_scan = si.GetBoolValue("Display", "ForceProgressiveScan", true);
display_linear_filtering = si.GetBoolValue("Display", "LinearFiltering", true); display_linear_filtering = si.GetBoolValue("Display", "LinearFiltering", true);
display_show_osd_messages = si.GetBoolValue("Display", "ShowOSDMessages", true); display_show_osd_messages = si.GetBoolValue("Display", "ShowOSDMessages", true);
@ -93,6 +97,7 @@ void Settings::Save(SettingsInterface& si) const
si.SetBoolValue("GPU", "ForceNTSCTimings", gpu_force_ntsc_timings); si.SetBoolValue("GPU", "ForceNTSCTimings", gpu_force_ntsc_timings);
si.SetStringValue("Display", "CropMode", GetDisplayCropModeName(display_crop_mode)); si.SetStringValue("Display", "CropMode", GetDisplayCropModeName(display_crop_mode));
si.SetStringValue("Display", "AspectRatio", GetDisplayAspectRatioName(display_aspect_ratio));
si.SetBoolValue("Display", "ForceProgressiveScan", display_force_progressive_scan); si.SetBoolValue("Display", "ForceProgressiveScan", display_force_progressive_scan);
si.SetBoolValue("Display", "LinearFiltering", display_linear_filtering); si.SetBoolValue("Display", "LinearFiltering", display_linear_filtering);
si.SetBoolValue("Display", "ShowOSDMessages", display_show_osd_messages); si.SetBoolValue("Display", "ShowOSDMessages", display_show_osd_messages);
@ -288,6 +293,33 @@ const char* Settings::GetDisplayCropModeDisplayName(DisplayCropMode crop_mode)
return s_display_crop_mode_display_names[static_cast<int>(crop_mode)]; return s_display_crop_mode_display_names[static_cast<int>(crop_mode)];
} }
static std::array<const char*, 3> s_display_aspect_ratio_names = {{"4:3", "16:9", "1:1"}};
static constexpr std::array<float, 3> s_display_aspect_ratio_values = {{4.0f / 3.0f, 16.0f / 9.0f, 1.0f}};
std::optional<DisplayAspectRatio> Settings::ParseDisplayAspectRatio(const char* str)
{
int index = 0;
for (const char* name : s_display_aspect_ratio_names)
{
if (StringUtil::Strcasecmp(name, str) == 0)
return static_cast<DisplayAspectRatio>(index);
index++;
}
return std::nullopt;
}
const char* Settings::GetDisplayAspectRatioName(DisplayAspectRatio ar)
{
return s_display_aspect_ratio_names[static_cast<int>(ar)];
}
float Settings::GetDisplayAspectRatioValue(DisplayAspectRatio ar)
{
return s_display_aspect_ratio_values[static_cast<int>(ar)];
}
static std::array<const char*, 3> s_audio_backend_names = {{"Null", "Cubeb", "SDL"}}; static std::array<const char*, 3> s_audio_backend_names = {{"Null", "Cubeb", "SDL"}};
static std::array<const char*, 3> s_audio_backend_display_names = {{"Null (No Output)", "Cubeb", "SDL"}}; static std::array<const char*, 3> s_audio_backend_display_names = {{"Null (No Output)", "Cubeb", "SDL"}};

View file

@ -53,6 +53,7 @@ struct Settings
bool gpu_use_debug_device = false; bool gpu_use_debug_device = false;
bool gpu_force_ntsc_timings = false; bool gpu_force_ntsc_timings = false;
DisplayCropMode display_crop_mode = DisplayCropMode::None; DisplayCropMode display_crop_mode = DisplayCropMode::None;
DisplayAspectRatio display_aspect_ratio = DisplayAspectRatio::R4_3;
bool display_force_progressive_scan = false; bool display_force_progressive_scan = false;
bool display_linear_filtering = true; bool display_linear_filtering = true;
bool display_show_osd_messages = false; bool display_show_osd_messages = false;
@ -114,6 +115,10 @@ struct Settings
static const char* GetDisplayCropModeName(DisplayCropMode crop_mode); static const char* GetDisplayCropModeName(DisplayCropMode crop_mode);
static const char* GetDisplayCropModeDisplayName(DisplayCropMode crop_mode); static const char* GetDisplayCropModeDisplayName(DisplayCropMode crop_mode);
static std::optional<DisplayAspectRatio> ParseDisplayAspectRatio(const char* str);
static const char* GetDisplayAspectRatioName(DisplayAspectRatio ar);
static float GetDisplayAspectRatioValue(DisplayAspectRatio ar);
static std::optional<AudioBackend> ParseAudioBackend(const char* str); static std::optional<AudioBackend> ParseAudioBackend(const char* str);
static const char* GetAudioBackendName(AudioBackend backend); static const char* GetAudioBackendName(AudioBackend backend);
static const char* GetAudioBackendDisplayName(AudioBackend backend); static const char* GetAudioBackendDisplayName(AudioBackend backend);

View file

@ -66,6 +66,14 @@ enum class DisplayCropMode : u8
Count Count
}; };
enum class DisplayAspectRatio : u8
{
R4_3,
R16_9,
R1_1,
Count
};
enum class AudioBackend : u8 enum class AudioBackend : u8
{ {
Null, Null,

View file

@ -12,7 +12,10 @@ GPUSettingsWidget::GPUSettingsWidget(QtHostInterface* host_interface, QWidget* p
SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.renderer, "GPU/Renderer", SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.renderer, "GPU/Renderer",
&Settings::ParseRendererName, &Settings::GetRendererName); &Settings::ParseRendererName, &Settings::GetRendererName);
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.useDebugDevice, "GPU/UseDebugDevice"); SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.useDebugDevice, "GPU/UseDebugDevice");
SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.cropMode, "Display/CropMode", SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.displayAspectRatio, "Display/AspectRatio",
&Settings::ParseDisplayAspectRatio,
&Settings::GetDisplayAspectRatioName);
SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.displayCropMode, "Display/CropMode",
&Settings::ParseDisplayCropMode, &Settings::GetDisplayCropModeName); &Settings::ParseDisplayCropMode, &Settings::GetDisplayCropModeName);
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.forceProgressiveScan, SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.forceProgressiveScan,
"Display/ForceProgressiveScan"); "Display/ForceProgressiveScan");
@ -46,9 +49,15 @@ void GPUSettingsWidget::setupAdditionalUi()
for (u32 i = 0; i < static_cast<u32>(GPURenderer::Count); i++) for (u32 i = 0; i < static_cast<u32>(GPURenderer::Count); i++)
m_ui.renderer->addItem(QString::fromLocal8Bit(Settings::GetRendererDisplayName(static_cast<GPURenderer>(i)))); m_ui.renderer->addItem(QString::fromLocal8Bit(Settings::GetRendererDisplayName(static_cast<GPURenderer>(i))));
for (u32 i = 0; i < static_cast<u32>(DisplayAspectRatio::Count); i++)
{
m_ui.displayAspectRatio->addItem(
QString::fromLocal8Bit(Settings::GetDisplayAspectRatioName(static_cast<DisplayAspectRatio>(i))));
}
for (u32 i = 0; i < static_cast<u32>(DisplayCropMode::Count); i++) for (u32 i = 0; i < static_cast<u32>(DisplayCropMode::Count); i++)
{ {
m_ui.cropMode->addItem( m_ui.displayCropMode->addItem(
QString::fromLocal8Bit(Settings::GetDisplayCropModeDisplayName(static_cast<DisplayCropMode>(i)))); QString::fromLocal8Bit(Settings::GetDisplayCropModeDisplayName(static_cast<DisplayCropMode>(i))));
} }

View file

@ -59,23 +59,33 @@
</property> </property>
<layout class="QFormLayout" name="formLayout_4"> <layout class="QFormLayout" name="formLayout_4">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Aspect Ratio:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="displayAspectRatio"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3"> <widget class="QLabel" name="label_3">
<property name="text"> <property name="text">
<string>Crop:</string> <string>Crop:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="1" column="1">
<widget class="QComboBox" name="cropMode"/> <widget class="QComboBox" name="displayCropMode"/>
</item> </item>
<item row="1" column="0" colspan="2"> <item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="displayLinearFiltering"> <widget class="QCheckBox" name="displayLinearFiltering">
<property name="text"> <property name="text">
<string>Linear Upscaling</string> <string>Linear Upscaling</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0" colspan="2"> <item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="vsync"> <widget class="QCheckBox" name="vsync">
<property name="text"> <property name="text">
<string>VSync</string> <string>VSync</string>

View file

@ -1245,6 +1245,21 @@ void SDLHostInterface::DrawSettingsWindow()
if (DrawSettingsSectionHeader("Display Output")) if (DrawSettingsSectionHeader("Display Output"))
{ {
ImGui::Text("Aspect Ratio:");
ImGui::SameLine(indent);
int display_aspect_ratio = static_cast<int>(m_settings_copy.display_aspect_ratio);
if (ImGui::Combo(
"##display_pixel_aspect_ratio", &display_aspect_ratio,
[](void*, int index, const char** out_text) {
*out_text = Settings::GetDisplayAspectRatioName(static_cast<DisplayAspectRatio>(index));
return true;
},
nullptr, static_cast<int>(DisplayAspectRatio::Count)))
{
m_settings_copy.display_aspect_ratio = static_cast<DisplayAspectRatio>(display_aspect_ratio);
settings_changed = true;
}
ImGui::Text("Crop:"); ImGui::Text("Crop:");
ImGui::SameLine(indent); ImGui::SameLine(indent);