mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-23 14:25:37 +00:00
Merge pull request #1227 from ggrtk/auto-aspect-ratio
GPU: Add auto aspect ratio and various fixes
This commit is contained in:
commit
bd8613b120
152
src/core/gpu.cpp
152
src/core/gpu.cpp
|
@ -7,6 +7,7 @@
|
||||||
#include "host_display.h"
|
#include "host_display.h"
|
||||||
#include "host_interface.h"
|
#include "host_interface.h"
|
||||||
#include "interrupt_controller.h"
|
#include "interrupt_controller.h"
|
||||||
|
#include "settings.h"
|
||||||
#include "stb_image_write.h"
|
#include "stb_image_write.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "timers.h"
|
#include "timers.h"
|
||||||
|
@ -161,13 +162,13 @@ bool GPU::DoState(StateWrapper& sw, bool update_display)
|
||||||
sw.Do(&m_crtc_state.display_vram_width);
|
sw.Do(&m_crtc_state.display_vram_width);
|
||||||
sw.Do(&m_crtc_state.display_vram_height);
|
sw.Do(&m_crtc_state.display_vram_height);
|
||||||
sw.Do(&m_crtc_state.horizontal_total);
|
sw.Do(&m_crtc_state.horizontal_total);
|
||||||
sw.Do(&m_crtc_state.horizontal_active_start);
|
sw.Do(&m_crtc_state.horizontal_visible_start);
|
||||||
sw.Do(&m_crtc_state.horizontal_active_end);
|
sw.Do(&m_crtc_state.horizontal_visible_end);
|
||||||
sw.Do(&m_crtc_state.horizontal_display_start);
|
sw.Do(&m_crtc_state.horizontal_display_start);
|
||||||
sw.Do(&m_crtc_state.horizontal_display_end);
|
sw.Do(&m_crtc_state.horizontal_display_end);
|
||||||
sw.Do(&m_crtc_state.vertical_total);
|
sw.Do(&m_crtc_state.vertical_total);
|
||||||
sw.Do(&m_crtc_state.vertical_active_start);
|
sw.Do(&m_crtc_state.vertical_visible_start);
|
||||||
sw.Do(&m_crtc_state.vertical_active_end);
|
sw.Do(&m_crtc_state.vertical_visible_end);
|
||||||
sw.Do(&m_crtc_state.vertical_display_start);
|
sw.Do(&m_crtc_state.vertical_display_start);
|
||||||
sw.Do(&m_crtc_state.vertical_display_end);
|
sw.Do(&m_crtc_state.vertical_display_end);
|
||||||
sw.Do(&m_crtc_state.fractional_ticks);
|
sw.Do(&m_crtc_state.fractional_ticks);
|
||||||
|
@ -448,10 +449,42 @@ float GPU::ComputeVerticalFrequency() const
|
||||||
float GPU::GetDisplayAspectRatio() const
|
float GPU::GetDisplayAspectRatio() const
|
||||||
{
|
{
|
||||||
if (g_settings.display_force_4_3_for_24bit && m_GPUSTAT.display_area_color_depth_24)
|
if (g_settings.display_force_4_3_for_24bit && m_GPUSTAT.display_area_color_depth_24)
|
||||||
|
{
|
||||||
return 4.0f / 3.0f;
|
return 4.0f / 3.0f;
|
||||||
|
}
|
||||||
|
else if (g_settings.display_aspect_ratio == DisplayAspectRatio::Auto)
|
||||||
|
{
|
||||||
|
const CRTCState& cs = m_crtc_state;
|
||||||
|
float relative_width = static_cast<float>(cs.horizontal_visible_end - cs.horizontal_visible_start);
|
||||||
|
float relative_height = static_cast<float>(cs.vertical_visible_end - cs.vertical_visible_start);
|
||||||
|
|
||||||
|
if (relative_width <= 0 || relative_height <= 0)
|
||||||
|
return 4.0f / 3.0f;
|
||||||
|
|
||||||
|
if (m_GPUSTAT.pal_mode)
|
||||||
|
{
|
||||||
|
relative_width /= static_cast<float>(PAL_HORIZONTAL_ACTIVE_END - PAL_HORIZONTAL_ACTIVE_START);
|
||||||
|
relative_height /= static_cast<float>(PAL_VERTICAL_ACTIVE_END - PAL_VERTICAL_ACTIVE_START);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
relative_width /= static_cast<float>(NTSC_HORIZONTAL_ACTIVE_END - NTSC_HORIZONTAL_ACTIVE_START);
|
||||||
|
relative_height /= static_cast<float>(NTSC_VERTICAL_ACTIVE_END - NTSC_VERTICAL_ACTIVE_START);
|
||||||
|
}
|
||||||
|
return (relative_width / relative_height) * (4.0f / 3.0f);
|
||||||
|
}
|
||||||
|
else if (g_settings.display_aspect_ratio == DisplayAspectRatio::PAR1_1)
|
||||||
|
{
|
||||||
|
if (m_crtc_state.display_width == 0 || m_crtc_state.display_height == 0)
|
||||||
|
return 4.0f / 3.0f;
|
||||||
|
|
||||||
|
return static_cast<float>(m_crtc_state.display_width) / static_cast<float>(m_crtc_state.display_height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return Settings::GetDisplayAspectRatioValue(g_settings.display_aspect_ratio);
|
return Settings::GetDisplayAspectRatioValue(g_settings.display_aspect_ratio);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GPU::UpdateCRTCConfig()
|
void GPU::UpdateCRTCConfig()
|
||||||
{
|
{
|
||||||
|
@ -537,54 +570,74 @@ void GPU::UpdateCRTCDisplayParameters()
|
||||||
switch (crop_mode)
|
switch (crop_mode)
|
||||||
{
|
{
|
||||||
case DisplayCropMode::None:
|
case DisplayCropMode::None:
|
||||||
cs.horizontal_active_start = static_cast<u16>(std::max<int>(0, 487 + g_settings.display_active_start_offset));
|
cs.horizontal_visible_start = PAL_HORIZONTAL_ACTIVE_START;
|
||||||
cs.horizontal_active_end = static_cast<u16>(std::max<int>(0, 3282 + g_settings.display_active_end_offset));
|
cs.horizontal_visible_end = PAL_HORIZONTAL_ACTIVE_END;
|
||||||
cs.vertical_active_start = static_cast<u16>(std::max<int>(0, 20 + g_settings.display_line_start_offset));
|
cs.vertical_visible_start = PAL_VERTICAL_ACTIVE_START;
|
||||||
cs.vertical_active_end = static_cast<u16>(std::max<int>(0, 308 + g_settings.display_line_end_offset));
|
cs.vertical_visible_end = PAL_VERTICAL_ACTIVE_END;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DisplayCropMode::Overscan:
|
case DisplayCropMode::Overscan:
|
||||||
cs.horizontal_active_start = static_cast<u16>(std::max<int>(0, 628 + g_settings.display_active_start_offset));
|
cs.horizontal_visible_start = static_cast<u16>(std::max<int>(0, 628 + g_settings.display_active_start_offset));
|
||||||
cs.horizontal_active_end = static_cast<u16>(std::max<int>(0, 3188 + g_settings.display_active_end_offset));
|
cs.horizontal_visible_end =
|
||||||
cs.vertical_active_start = static_cast<u16>(std::max<int>(0, 30 + g_settings.display_line_start_offset));
|
static_cast<u16>(std::max<int>(cs.horizontal_visible_start, 3188 + g_settings.display_active_end_offset));
|
||||||
cs.vertical_active_end = static_cast<u16>(std::max<int>(0, 298 + g_settings.display_line_end_offset));
|
cs.vertical_visible_start = static_cast<u16>(std::max<int>(0, 30 + g_settings.display_line_start_offset));
|
||||||
|
cs.vertical_visible_end =
|
||||||
|
static_cast<u16>(std::max<int>(cs.vertical_visible_start, 298 + g_settings.display_line_end_offset));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DisplayCropMode::Borders:
|
case DisplayCropMode::Borders:
|
||||||
default:
|
default:
|
||||||
cs.horizontal_active_start = horizontal_display_start;
|
cs.horizontal_visible_start = horizontal_display_start;
|
||||||
cs.horizontal_active_end = horizontal_display_end;
|
cs.horizontal_visible_end = horizontal_display_end;
|
||||||
cs.vertical_active_start = vertical_display_start;
|
cs.vertical_visible_start = vertical_display_start;
|
||||||
cs.vertical_active_end = vertical_display_end;
|
cs.vertical_visible_end = vertical_display_end;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
cs.horizontal_visible_start =
|
||||||
|
std::clamp<u16>(cs.horizontal_visible_start, PAL_HORIZONTAL_ACTIVE_START, PAL_HORIZONTAL_ACTIVE_END);
|
||||||
|
cs.horizontal_visible_end =
|
||||||
|
std::clamp<u16>(cs.horizontal_visible_end, cs.horizontal_visible_start, PAL_HORIZONTAL_ACTIVE_END);
|
||||||
|
cs.vertical_visible_start =
|
||||||
|
std::clamp<u16>(cs.vertical_visible_start, PAL_VERTICAL_ACTIVE_START, PAL_VERTICAL_ACTIVE_END);
|
||||||
|
cs.vertical_visible_end =
|
||||||
|
std::clamp<u16>(cs.vertical_visible_end, cs.vertical_visible_start, PAL_VERTICAL_ACTIVE_END);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch (crop_mode)
|
switch (crop_mode)
|
||||||
{
|
{
|
||||||
case DisplayCropMode::None:
|
case DisplayCropMode::None:
|
||||||
cs.horizontal_active_start = static_cast<u16>(std::max<int>(0, 488 + g_settings.display_active_start_offset));
|
cs.horizontal_visible_start = NTSC_HORIZONTAL_ACTIVE_START;
|
||||||
cs.horizontal_active_end = static_cast<u16>(std::max<int>(0, 3288 + g_settings.display_active_end_offset));
|
cs.horizontal_visible_end = NTSC_HORIZONTAL_ACTIVE_END;
|
||||||
cs.vertical_active_start = static_cast<u16>(std::max<int>(0, 16 + g_settings.display_line_start_offset));
|
cs.vertical_visible_start = NTSC_VERTICAL_ACTIVE_START;
|
||||||
cs.vertical_active_end = static_cast<u16>(std::max<int>(0, 256 + g_settings.display_line_end_offset));
|
cs.vertical_visible_end = NTSC_VERTICAL_ACTIVE_END;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DisplayCropMode::Overscan:
|
case DisplayCropMode::Overscan:
|
||||||
cs.horizontal_active_start = static_cast<u16>(std::max<int>(0, 608 + g_settings.display_active_start_offset));
|
cs.horizontal_visible_start = static_cast<u16>(std::max<int>(0, 608 + g_settings.display_active_start_offset));
|
||||||
cs.horizontal_active_end = static_cast<u16>(std::max<int>(0, 3168 + g_settings.display_active_end_offset));
|
cs.horizontal_visible_end =
|
||||||
cs.vertical_active_start = static_cast<u16>(std::max<int>(0, 24 + g_settings.display_line_start_offset));
|
static_cast<u16>(std::max<int>(cs.horizontal_visible_start, 3168 + g_settings.display_active_end_offset));
|
||||||
cs.vertical_active_end = static_cast<u16>(std::max<int>(0, 248 + g_settings.display_line_end_offset));
|
cs.vertical_visible_start = static_cast<u16>(std::max<int>(0, 24 + g_settings.display_line_start_offset));
|
||||||
|
cs.vertical_visible_end =
|
||||||
|
static_cast<u16>(std::max<int>(cs.vertical_visible_start, 248 + g_settings.display_line_end_offset));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DisplayCropMode::Borders:
|
case DisplayCropMode::Borders:
|
||||||
default:
|
default:
|
||||||
cs.horizontal_active_start = horizontal_display_start;
|
cs.horizontal_visible_start = horizontal_display_start;
|
||||||
cs.horizontal_active_end = horizontal_display_end;
|
cs.horizontal_visible_end = horizontal_display_end;
|
||||||
cs.vertical_active_start = vertical_display_start;
|
cs.vertical_visible_start = vertical_display_start;
|
||||||
cs.vertical_active_end = vertical_display_end;
|
cs.vertical_visible_end = vertical_display_end;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
cs.horizontal_visible_start =
|
||||||
|
std::clamp<u16>(cs.horizontal_visible_start, NTSC_HORIZONTAL_ACTIVE_START, NTSC_HORIZONTAL_ACTIVE_END);
|
||||||
|
cs.horizontal_visible_end =
|
||||||
|
std::clamp<u16>(cs.horizontal_visible_end, cs.horizontal_visible_start, NTSC_HORIZONTAL_ACTIVE_END);
|
||||||
|
cs.vertical_visible_start =
|
||||||
|
std::clamp<u16>(cs.vertical_visible_start, NTSC_VERTICAL_ACTIVE_START, NTSC_VERTICAL_ACTIVE_END);
|
||||||
|
cs.vertical_visible_end =
|
||||||
|
std::clamp<u16>(cs.vertical_visible_end, cs.vertical_visible_start, NTSC_VERTICAL_ACTIVE_END);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If force-progressive is enabled, we only double the height in 480i mode. This way non-interleaved 480i framebuffers
|
// If force-progressive is enabled, we only double the height in 480i mode. This way non-interleaved 480i framebuffers
|
||||||
|
@ -593,8 +646,8 @@ void GPU::UpdateCRTCDisplayParameters()
|
||||||
const u8 height_shift = m_force_progressive_scan ? y_shift : BoolToUInt8(m_GPUSTAT.vertical_interlace);
|
const u8 height_shift = m_force_progressive_scan ? y_shift : BoolToUInt8(m_GPUSTAT.vertical_interlace);
|
||||||
|
|
||||||
// Determine screen size.
|
// Determine screen size.
|
||||||
cs.display_width = (cs.horizontal_active_end - cs.horizontal_active_start) / cs.dot_clock_divider;
|
cs.display_width = (cs.horizontal_visible_end - cs.horizontal_visible_start) / cs.dot_clock_divider;
|
||||||
cs.display_height = (cs.vertical_active_end - cs.vertical_active_start) << height_shift;
|
cs.display_height = (cs.vertical_visible_end - cs.vertical_visible_start) << height_shift;
|
||||||
|
|
||||||
// Determine number of pixels outputted from VRAM (in general, round to 4-pixel multiple).
|
// Determine number of pixels outputted from VRAM (in general, round to 4-pixel multiple).
|
||||||
// TODO: Verify behavior if values are outside of the active video portion of scanline.
|
// TODO: Verify behavior if values are outside of the active video portion of scanline.
|
||||||
|
@ -610,17 +663,17 @@ void GPU::UpdateCRTCDisplayParameters()
|
||||||
// Determine if we need to adjust the VRAM rectangle (because the display is starting outside the visible area) or add
|
// Determine if we need to adjust the VRAM rectangle (because the display is starting outside the visible area) or add
|
||||||
// padding.
|
// padding.
|
||||||
u16 horizontal_skip_pixels;
|
u16 horizontal_skip_pixels;
|
||||||
if (horizontal_display_start >= cs.horizontal_active_start)
|
if (horizontal_display_start >= cs.horizontal_visible_start)
|
||||||
{
|
{
|
||||||
cs.display_origin_left = (horizontal_display_start - cs.horizontal_active_start) / cs.dot_clock_divider;
|
cs.display_origin_left = (horizontal_display_start - cs.horizontal_visible_start) / cs.dot_clock_divider;
|
||||||
cs.display_vram_left = std::min<u16>(m_crtc_state.regs.X, VRAM_WIDTH - 1);
|
cs.display_vram_left = cs.regs.X;
|
||||||
horizontal_skip_pixels = 0;
|
horizontal_skip_pixels = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
horizontal_skip_pixels = (cs.horizontal_active_start - horizontal_display_start) / cs.dot_clock_divider;
|
horizontal_skip_pixels = (cs.horizontal_visible_start - horizontal_display_start) / cs.dot_clock_divider;
|
||||||
cs.display_origin_left = 0;
|
cs.display_origin_left = 0;
|
||||||
cs.display_vram_left = std::min<u16>(m_crtc_state.regs.X + horizontal_skip_pixels, VRAM_WIDTH - 1);
|
cs.display_vram_left = (cs.regs.X + horizontal_skip_pixels) % VRAM_WIDTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply the crop from the start (usually overscan)
|
// apply the crop from the start (usually overscan)
|
||||||
|
@ -629,28 +682,29 @@ void GPU::UpdateCRTCDisplayParameters()
|
||||||
// Apply crop from the end by shrinking VRAM rectangle width if display would end outside the visible area.
|
// Apply crop from the end by shrinking VRAM rectangle width if display would end outside the visible area.
|
||||||
cs.display_vram_width = std::min<u16>(cs.display_vram_width, cs.display_width - cs.display_origin_left);
|
cs.display_vram_width = std::min<u16>(cs.display_vram_width, cs.display_width - cs.display_origin_left);
|
||||||
|
|
||||||
if (vertical_display_start >= cs.vertical_active_start)
|
if (vertical_display_start >= cs.vertical_visible_start)
|
||||||
{
|
{
|
||||||
cs.display_origin_top = (vertical_display_start - cs.vertical_active_start) << y_shift;
|
cs.display_origin_top = (vertical_display_start - cs.vertical_visible_start) << y_shift;
|
||||||
cs.display_vram_top = m_crtc_state.regs.Y;
|
cs.display_vram_top = cs.regs.Y;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cs.display_origin_top = 0;
|
cs.display_origin_top = 0;
|
||||||
cs.display_vram_top = m_crtc_state.regs.Y + ((cs.vertical_active_start - vertical_display_start) << y_shift);
|
cs.display_vram_top = (cs.regs.Y + ((cs.vertical_visible_start - vertical_display_start) << y_shift)) % VRAM_HEIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vertical_display_end <= cs.vertical_active_end)
|
if (vertical_display_end <= cs.vertical_visible_end)
|
||||||
{
|
{
|
||||||
cs.display_vram_height = (vertical_display_end - std::min(vertical_display_end, std::max(vertical_display_start,
|
cs.display_vram_height =
|
||||||
cs.vertical_active_start)))
|
(vertical_display_end -
|
||||||
|
std::min(vertical_display_end, std::max(vertical_display_start, cs.vertical_visible_start)))
|
||||||
<< height_shift;
|
<< height_shift;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cs.display_vram_height =
|
cs.display_vram_height =
|
||||||
(cs.vertical_active_end -
|
(cs.vertical_visible_end -
|
||||||
std::min(cs.vertical_active_end, std::max(vertical_display_start, cs.vertical_active_start)))
|
std::min(cs.vertical_visible_end, std::max(vertical_display_start, cs.vertical_visible_start)))
|
||||||
<< height_shift;
|
<< height_shift;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -887,8 +941,8 @@ bool GPU::ConvertScreenCoordinatesToBeamTicksAndLines(s32 window_x, s32 window_y
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_line =
|
*out_line =
|
||||||
(static_cast<u32>(display_y) >> BoolToUInt8(m_GPUSTAT.vertical_interlace)) + m_crtc_state.vertical_active_start;
|
(static_cast<u32>(display_y) >> BoolToUInt8(m_GPUSTAT.vertical_interlace)) + m_crtc_state.vertical_visible_start;
|
||||||
*out_tick = (static_cast<u32>(display_x) * m_crtc_state.dot_clock_divider) + m_crtc_state.horizontal_active_start;
|
*out_tick = (static_cast<u32>(display_x) * m_crtc_state.dot_clock_divider) + m_crtc_state.horizontal_visible_start;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1532,9 +1586,9 @@ void GPU::DrawDebugStateWindow()
|
||||||
cs.horizontal_display_start / cs.dot_clock_divider, cs.horizontal_display_end / cs.dot_clock_divider,
|
cs.horizontal_display_start / cs.dot_clock_divider, cs.horizontal_display_end / cs.dot_clock_divider,
|
||||||
cs.vertical_display_start, cs.vertical_display_end);
|
cs.vertical_display_start, cs.vertical_display_end);
|
||||||
ImGui::Text("Cropping: %s", Settings::GetDisplayCropModeName(g_settings.display_crop_mode));
|
ImGui::Text("Cropping: %s", Settings::GetDisplayCropModeName(g_settings.display_crop_mode));
|
||||||
ImGui::Text("Visible Display Range: %u-%u (%u-%u), %u-%u", cs.horizontal_active_start, cs.horizontal_active_end,
|
ImGui::Text("Visible Display Range: %u-%u (%u-%u), %u-%u", cs.horizontal_visible_start, cs.horizontal_visible_end,
|
||||||
cs.horizontal_active_start / cs.dot_clock_divider, cs.horizontal_active_end / cs.dot_clock_divider,
|
cs.horizontal_visible_start / cs.dot_clock_divider, cs.horizontal_visible_end / cs.dot_clock_divider,
|
||||||
cs.vertical_active_start, cs.vertical_active_end);
|
cs.vertical_visible_start, cs.vertical_visible_end);
|
||||||
ImGui::Text("Display Resolution: %ux%u", cs.display_width, cs.display_height);
|
ImGui::Text("Display Resolution: %ux%u", cs.display_width, cs.display_height);
|
||||||
ImGui::Text("Display Origin: %u, %u", cs.display_origin_left, cs.display_origin_top);
|
ImGui::Text("Display Origin: %u, %u", cs.display_origin_left, cs.display_origin_top);
|
||||||
ImGui::Text("Displayed/Visible VRAM Portion: %ux%u @ (%u, %u)", cs.display_vram_width, cs.display_vram_height,
|
ImGui::Text("Displayed/Visible VRAM Portion: %ux%u @ (%u, %u)", cs.display_vram_width, cs.display_vram_height,
|
||||||
|
|
|
@ -56,6 +56,18 @@ public:
|
||||||
PAL_TOTAL_LINES = 314,
|
PAL_TOTAL_LINES = 314,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum : u16
|
||||||
|
{
|
||||||
|
NTSC_HORIZONTAL_ACTIVE_START = 488,
|
||||||
|
NTSC_HORIZONTAL_ACTIVE_END = 3288,
|
||||||
|
NTSC_VERTICAL_ACTIVE_START = 16,
|
||||||
|
NTSC_VERTICAL_ACTIVE_END = 256,
|
||||||
|
PAL_HORIZONTAL_ACTIVE_START = 487,
|
||||||
|
PAL_HORIZONTAL_ACTIVE_END = 3282,
|
||||||
|
PAL_VERTICAL_ACTIVE_START = 20,
|
||||||
|
PAL_VERTICAL_ACTIVE_END = 308,
|
||||||
|
};
|
||||||
|
|
||||||
// Base class constructor.
|
// Base class constructor.
|
||||||
GPU();
|
GPU();
|
||||||
virtual ~GPU();
|
virtual ~GPU();
|
||||||
|
@ -89,7 +101,7 @@ public:
|
||||||
}
|
}
|
||||||
void EndDMAWrite();
|
void EndDMAWrite();
|
||||||
|
|
||||||
/// Returns false if the DAC is loading any data from VRAM.
|
/// Returns true if no data is being sent from VRAM to the DAC or that no portion of VRAM would be visible on screen.
|
||||||
ALWAYS_INLINE bool IsDisplayDisabled() const
|
ALWAYS_INLINE bool IsDisplayDisabled() const
|
||||||
{
|
{
|
||||||
return m_GPUSTAT.display_disable || m_crtc_state.display_vram_width == 0 || m_crtc_state.display_vram_height == 0;
|
return m_GPUSTAT.display_disable || m_crtc_state.display_vram_width == 0 || m_crtc_state.display_vram_height == 0;
|
||||||
|
@ -98,13 +110,13 @@ public:
|
||||||
/// Returns true if scanout should be interlaced.
|
/// Returns true if scanout should be interlaced.
|
||||||
ALWAYS_INLINE bool IsInterlacedDisplayEnabled() const
|
ALWAYS_INLINE bool IsInterlacedDisplayEnabled() const
|
||||||
{
|
{
|
||||||
return (!m_force_progressive_scan) & m_GPUSTAT.vertical_interlace;
|
return (!m_force_progressive_scan) && m_GPUSTAT.vertical_interlace;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if interlaced rendering is enabled and force progressive scan is disabled.
|
/// Returns true if interlaced rendering is enabled and force progressive scan is disabled.
|
||||||
ALWAYS_INLINE bool IsInterlacedRenderingEnabled() const
|
ALWAYS_INLINE bool IsInterlacedRenderingEnabled() const
|
||||||
{
|
{
|
||||||
return (!m_force_progressive_scan) & m_GPUSTAT.SkipDrawingToActiveField();
|
return (!m_force_progressive_scan) && m_GPUSTAT.SkipDrawingToActiveField();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of pending GPU ticks.
|
/// Returns the number of pending GPU ticks.
|
||||||
|
@ -475,28 +487,31 @@ protected:
|
||||||
u16 display_width;
|
u16 display_width;
|
||||||
u16 display_height;
|
u16 display_height;
|
||||||
|
|
||||||
// Top-left corner where the VRAM is displayed. Depending on the CRTC config, this may indicate padding.
|
// Top-left corner in screen coordinates where the outputted portion of VRAM is first visible.
|
||||||
u16 display_origin_left;
|
u16 display_origin_left;
|
||||||
u16 display_origin_top;
|
u16 display_origin_top;
|
||||||
|
|
||||||
// Rectangle describing the displayed area of VRAM, in coordinates.
|
// Rectangle in VRAM coordinates describing the area of VRAM that is visible on screen.
|
||||||
u16 display_vram_left;
|
u16 display_vram_left;
|
||||||
u16 display_vram_top;
|
u16 display_vram_top;
|
||||||
u16 display_vram_width;
|
u16 display_vram_width;
|
||||||
u16 display_vram_height;
|
u16 display_vram_height;
|
||||||
|
|
||||||
u16 horizontal_total;
|
// Visible range of the screen, in GPU ticks/lines. Clamped to lie within the active video region.
|
||||||
u16 horizontal_sync_start; // <- not currently saved to state, so we don't have to bump the version
|
u16 horizontal_visible_start;
|
||||||
u16 horizontal_active_start;
|
u16 horizontal_visible_end;
|
||||||
u16 horizontal_active_end;
|
u16 vertical_visible_start;
|
||||||
|
u16 vertical_visible_end;
|
||||||
|
|
||||||
u16 horizontal_display_start;
|
u16 horizontal_display_start;
|
||||||
u16 horizontal_display_end;
|
u16 horizontal_display_end;
|
||||||
u16 vertical_total;
|
|
||||||
u16 vertical_active_start;
|
|
||||||
u16 vertical_active_end;
|
|
||||||
u16 vertical_display_start;
|
u16 vertical_display_start;
|
||||||
u16 vertical_display_end;
|
u16 vertical_display_end;
|
||||||
|
|
||||||
|
u16 horizontal_total;
|
||||||
|
u16 horizontal_sync_start; // <- not currently saved to state, so we don't have to bump the version
|
||||||
|
u16 vertical_total;
|
||||||
|
|
||||||
TickCount fractional_ticks;
|
TickCount fractional_ticks;
|
||||||
TickCount current_tick_in_scanline;
|
TickCount current_tick_in_scanline;
|
||||||
u32 current_scanline;
|
u32 current_scanline;
|
||||||
|
|
|
@ -655,6 +655,7 @@ static void RTPS(const s16 V[3], u8 shift, bool lm, bool last)
|
||||||
Sx = ((((s64(result) * s64(REGS.IR1)) * s64(7)) / s64(6)) + s64(REGS.OFX));
|
Sx = ((((s64(result) * s64(REGS.IR1)) * s64(7)) / s64(6)) + s64(REGS.OFX));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DisplayAspectRatio::Auto:
|
||||||
case DisplayAspectRatio::R4_3:
|
case DisplayAspectRatio::R4_3:
|
||||||
case DisplayAspectRatio::PAR1_1:
|
case DisplayAspectRatio::PAR1_1:
|
||||||
default:
|
default:
|
||||||
|
@ -747,6 +748,7 @@ static void RTPS(const s16 V[3], u8 shift, bool lm, bool last)
|
||||||
precise_x = (precise_x * 7.0f) / 6.0f;
|
precise_x = (precise_x * 7.0f) / 6.0f;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DisplayAspectRatio::Auto:
|
||||||
case DisplayAspectRatio::R4_3:
|
case DisplayAspectRatio::R4_3:
|
||||||
case DisplayAspectRatio::PAR1_1:
|
case DisplayAspectRatio::PAR1_1:
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -138,7 +138,6 @@ void HostDisplay::CalculateDrawRect(s32 window_width, s32 window_height, s32* ou
|
||||||
s32* out_height, s32* out_left_padding, s32* out_top_padding, float* out_scale,
|
s32* out_height, s32* out_left_padding, s32* out_top_padding, float* out_scale,
|
||||||
float* out_y_scale, bool apply_aspect_ratio) const
|
float* out_y_scale, bool apply_aspect_ratio) const
|
||||||
{
|
{
|
||||||
apply_aspect_ratio = (m_display_aspect_ratio > 0) ? apply_aspect_ratio : false;
|
|
||||||
const float y_scale =
|
const float y_scale =
|
||||||
apply_aspect_ratio ?
|
apply_aspect_ratio ?
|
||||||
((static_cast<float>(m_display_width) / static_cast<float>(m_display_height)) / m_display_aspect_ratio) :
|
((static_cast<float>(m_display_width) / static_cast<float>(m_display_height)) / m_display_aspect_ratio) :
|
||||||
|
|
|
@ -625,10 +625,11 @@ 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*, 11> s_display_aspect_ratio_names = {
|
static std::array<const char*, 12> s_display_aspect_ratio_names = {{"Auto (Game Native)", "4:3", "16:9", "16:10",
|
||||||
{"4:3", "16:9", "16:10", "19:9", "21:9", "8:7", "5:4", "3:2", "2:1 (VRAM 1:1)", "1:1", "PAR 1:1"}};
|
"19:9", "21:9", "8:7", "5:4", "3:2",
|
||||||
static constexpr std::array<float, 11> s_display_aspect_ratio_values = {
|
"2:1 (VRAM 1:1)", "1:1", "PAR 1:1"}};
|
||||||
{4.0f / 3.0f, 16.0f / 9.0f, 16.0f / 10.0f, 19.0f / 9.0f, 21.0f / 9.0f, 8.0f / 7.0f, 5.0f / 4.0f, 3.0f / 2.0f,
|
static constexpr std::array<float, 12> s_display_aspect_ratio_values = {
|
||||||
|
{-1.0f, 4.0f / 3.0f, 16.0f / 9.0f, 16.0f / 10.0f, 19.0f / 9.0f, 21.0f / 9.0f, 8.0f / 7.0f, 5.0f / 4.0f, 3.0f / 2.0f,
|
||||||
2.0f / 1.0f, 1.0f, -1.0f}};
|
2.0f / 1.0f, 1.0f, -1.0f}};
|
||||||
|
|
||||||
std::optional<DisplayAspectRatio> Settings::ParseDisplayAspectRatio(const char* str)
|
std::optional<DisplayAspectRatio> Settings::ParseDisplayAspectRatio(const char* str)
|
||||||
|
|
|
@ -111,15 +111,11 @@ struct Settings
|
||||||
bool gpu_pgxp_cpu = false;
|
bool gpu_pgxp_cpu = false;
|
||||||
bool gpu_pgxp_preserve_proj_fp = false;
|
bool gpu_pgxp_preserve_proj_fp = false;
|
||||||
DisplayCropMode display_crop_mode = DisplayCropMode::None;
|
DisplayCropMode display_crop_mode = DisplayCropMode::None;
|
||||||
DisplayAspectRatio display_aspect_ratio = DisplayAspectRatio::R4_3;
|
DisplayAspectRatio display_aspect_ratio = DisplayAspectRatio::Auto;
|
||||||
s16 display_active_start_offset = 0;
|
s16 display_active_start_offset = 0;
|
||||||
s16 display_active_end_offset = 0;
|
s16 display_active_end_offset = 0;
|
||||||
s8 display_line_start_offset = 0;
|
s8 display_line_start_offset = 0;
|
||||||
s8 display_line_end_offset = 0;
|
s8 display_line_end_offset = 0;
|
||||||
s8 display_crop_left = 0;
|
|
||||||
s8 display_crop_right = 0;
|
|
||||||
s8 display_crop_top = 0;
|
|
||||||
s8 display_crop_bottom = 0;
|
|
||||||
bool display_force_4_3_for_24bit = false;
|
bool display_force_4_3_for_24bit = false;
|
||||||
bool gpu_24bit_chroma_smoothing = false;
|
bool gpu_24bit_chroma_smoothing = false;
|
||||||
bool display_linear_filtering = true;
|
bool display_linear_filtering = true;
|
||||||
|
@ -304,7 +300,7 @@ struct Settings
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static constexpr DisplayCropMode DEFAULT_DISPLAY_CROP_MODE = DisplayCropMode::Overscan;
|
static constexpr DisplayCropMode DEFAULT_DISPLAY_CROP_MODE = DisplayCropMode::Overscan;
|
||||||
static constexpr DisplayAspectRatio DEFAULT_DISPLAY_ASPECT_RATIO = DisplayAspectRatio::R4_3;
|
static constexpr DisplayAspectRatio DEFAULT_DISPLAY_ASPECT_RATIO = DisplayAspectRatio::Auto;
|
||||||
static constexpr ControllerType DEFAULT_CONTROLLER_1_TYPE = ControllerType::DigitalController;
|
static constexpr ControllerType DEFAULT_CONTROLLER_1_TYPE = ControllerType::DigitalController;
|
||||||
static constexpr ControllerType DEFAULT_CONTROLLER_2_TYPE = ControllerType::None;
|
static constexpr ControllerType DEFAULT_CONTROLLER_2_TYPE = ControllerType::None;
|
||||||
static constexpr MemoryCardType DEFAULT_MEMORY_CARD_1_TYPE = MemoryCardType::PerGameTitle;
|
static constexpr MemoryCardType DEFAULT_MEMORY_CARD_1_TYPE = MemoryCardType::PerGameTitle;
|
||||||
|
|
|
@ -85,6 +85,7 @@ enum class DisplayCropMode : u8
|
||||||
|
|
||||||
enum class DisplayAspectRatio : u8
|
enum class DisplayAspectRatio : u8
|
||||||
{
|
{
|
||||||
|
Auto,
|
||||||
R4_3,
|
R4_3,
|
||||||
R16_9,
|
R16_9,
|
||||||
R16_10,
|
R16_10,
|
||||||
|
|
|
@ -704,7 +704,8 @@ static std::array<retro_core_option_definition, 49> s_option_definitions = {{
|
||||||
{"duckstation_Display.AspectRatio",
|
{"duckstation_Display.AspectRatio",
|
||||||
"Aspect Ratio",
|
"Aspect Ratio",
|
||||||
"Sets the core-provided aspect ratio.",
|
"Sets the core-provided aspect ratio.",
|
||||||
{{"4:3", "4:3"},
|
{{"Auto", "Auto (Game Native)"},
|
||||||
|
{"4:3", "4:3"},
|
||||||
{"16:9", "16:9"},
|
{"16:9", "16:9"},
|
||||||
{"16:10", "16:10"},
|
{"16:10", "16:10"},
|
||||||
{"19:9", "19:9"},
|
{"19:9", "19:9"},
|
||||||
|
@ -715,7 +716,7 @@ static std::array<retro_core_option_definition, 49> s_option_definitions = {{
|
||||||
{"2:1 (VRAM 1:1)", "2:1 (VRAM 1:1)"},
|
{"2:1 (VRAM 1:1)", "2:1 (VRAM 1:1)"},
|
||||||
{"1:1", "1:1"},
|
{"1:1", "1:1"},
|
||||||
{"PAR 1:1", "PAR 1:1"}},
|
{"PAR 1:1", "PAR 1:1"}},
|
||||||
"4:3"},
|
"Auto"},
|
||||||
{"duckstation_Main.LoadDevicesFromSaveStates",
|
{"duckstation_Main.LoadDevicesFromSaveStates",
|
||||||
"Load Devices From Save States",
|
"Load Devices From Save States",
|
||||||
"Sets whether the contents of devices and memory cards will be loaded when a save state is loaded.",
|
"Sets whether the contents of devices and memory cards will be loaded when a save state is loaded.",
|
||||||
|
|
|
@ -62,9 +62,9 @@ DisplaySettingsWidget::DisplaySettingsWidget(QtHostInterface* host_interface, QW
|
||||||
"renderers. <br>This option is only supported in Direct3D and Vulkan. OpenGL will always use the default "
|
"renderers. <br>This option is only supported in Direct3D and Vulkan. OpenGL will always use the default "
|
||||||
"device."));
|
"device."));
|
||||||
dialog->registerWidgetHelp(
|
dialog->registerWidgetHelp(
|
||||||
m_ui.displayAspectRatio, tr("Aspect Ratio"), QStringLiteral("4:3"),
|
m_ui.displayAspectRatio, tr("Aspect Ratio"), QStringLiteral("Auto (Game Native)"),
|
||||||
tr("Changes the aspect ratio used to display the console's output to the screen. The default "
|
tr("Changes the aspect ratio used to display the console's output to the screen. The default is Auto (Game Native) "
|
||||||
"is 4:3 which matches a typical TV of the era."));
|
"which automatically adjusts the aspect ratio to match how a game would be shown on a typical TV of the era."));
|
||||||
dialog->registerWidgetHelp(
|
dialog->registerWidgetHelp(
|
||||||
m_ui.displayCropMode, tr("Crop Mode"), tr("Only Overscan Area"),
|
m_ui.displayCropMode, tr("Crop Mode"), tr("Only Overscan Area"),
|
||||||
tr("Determines how much of the area typically not visible on a consumer TV set to crop/hide. <br>"
|
tr("Determines how much of the area typically not visible on a consumer TV set to crop/hide. <br>"
|
||||||
|
|
Loading…
Reference in a new issue