GPU: Properly handle display range config

This commit is contained in:
Connor McLaughlin 2019-10-20 23:19:26 +10:00
parent 7e39dd0935
commit 2e70c22422
3 changed files with 36 additions and 29 deletions

View File

@ -90,10 +90,11 @@ bool GPU::DoState(StateWrapper& sw)
sw.Do(&m_crtc_state.horizontal_resolution); sw.Do(&m_crtc_state.horizontal_resolution);
sw.Do(&m_crtc_state.vertical_resolution); sw.Do(&m_crtc_state.vertical_resolution);
sw.Do(&m_crtc_state.dot_clock_divider); sw.Do(&m_crtc_state.dot_clock_divider);
sw.Do(&m_crtc_state.visible_horizontal_resolution); sw.Do(&m_crtc_state.display_width);
sw.Do(&m_crtc_state.visible_vertical_resolution); sw.Do(&m_crtc_state.display_height);
sw.Do(&m_crtc_state.ticks_per_scanline); sw.Do(&m_crtc_state.ticks_per_scanline);
sw.Do(&m_crtc_state.visible_ticks_per_scanline); sw.Do(&m_crtc_state.visible_ticks_per_scanline);
sw.Do(&m_crtc_state.visible_scanlines_per_frame);
sw.Do(&m_crtc_state.total_scanlines_per_frame); sw.Do(&m_crtc_state.total_scanlines_per_frame);
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);
@ -308,28 +309,11 @@ void GPU::DMAWrite(const u32* words, u32 word_count)
void GPU::UpdateCRTCConfig() void GPU::UpdateCRTCConfig()
{ {
static constexpr std::array<TickCount, 8> dot_clock_dividers = {{8, 4, 10, 5, 7, 7, 7, 7}}; static constexpr std::array<TickCount, 8> dot_clock_dividers = {{10, 8, 5, 4, 7, 7, 7, 7}};
static constexpr std::array<u32, 8> horizontal_resolutions = {{256, 320, 512, 630, 368, 368, 368, 368}}; static constexpr std::array<u32, 8> horizontal_resolutions = {{256, 320, 512, 640, 368, 368, 368, 368}};
static constexpr std::array<u32, 2> vertical_resolutions = {{240, 480}}; static constexpr std::array<u32, 2> vertical_resolutions = {{240, 480}};
CRTCState& cs = m_crtc_state; CRTCState& cs = m_crtc_state;
const u8 horizontal_resolution_index = m_GPUSTAT.horizontal_resolution_1 | (m_GPUSTAT.horizontal_resolution_2 << 2);
cs.dot_clock_divider = dot_clock_dividers[horizontal_resolution_index];
cs.horizontal_resolution = horizontal_resolutions[horizontal_resolution_index];
cs.vertical_resolution =
vertical_resolutions[BoolToUInt8(m_GPUSTAT.vertical_interlace && m_GPUSTAT.vertical_resolution)];
// check for a change in resolution
const u32 old_horizontal_resolution = cs.visible_horizontal_resolution;
const u32 old_vertical_resolution = cs.visible_vertical_resolution;
cs.visible_horizontal_resolution = std::max((cs.regs.X2 - cs.regs.X1) / cs.dot_clock_divider, u32(1));
cs.visible_vertical_resolution = cs.regs.Y2 - cs.regs.Y1 + 1;
if (cs.visible_horizontal_resolution != old_horizontal_resolution ||
cs.visible_vertical_resolution != old_vertical_resolution)
{
Log_InfoPrintf("Visible resolution is now %ux%u", cs.visible_horizontal_resolution, cs.visible_vertical_resolution);
}
if (m_GPUSTAT.pal_mode) if (m_GPUSTAT.pal_mode)
{ {
cs.total_scanlines_per_frame = 314; cs.total_scanlines_per_frame = 314;
@ -341,6 +325,29 @@ void GPU::UpdateCRTCConfig()
cs.ticks_per_scanline = 3413; cs.ticks_per_scanline = 3413;
} }
const u8 horizontal_resolution_index = m_GPUSTAT.horizontal_resolution_1 | (m_GPUSTAT.horizontal_resolution_2 << 2);
cs.dot_clock_divider = dot_clock_dividers[horizontal_resolution_index];
cs.horizontal_resolution = horizontal_resolutions[horizontal_resolution_index];
cs.vertical_resolution =
vertical_resolutions[BoolToUInt8(m_GPUSTAT.vertical_interlace && m_GPUSTAT.vertical_resolution)];
cs.visible_ticks_per_scanline = cs.regs.X2 - cs.regs.X1;
cs.visible_scanlines_per_frame = cs.regs.Y2 - cs.regs.Y1;
// check for a change in resolution
const u32 old_horizontal_resolution = cs.display_width;
const u32 old_vertical_resolution = cs.display_height;
cs.display_width = std::max<u32>(cs.visible_ticks_per_scanline / cs.dot_clock_divider, 1);
cs.display_height = cs.visible_scanlines_per_frame;
if (m_GPUSTAT.vertical_interlace)
{
// Force progressive for now.
cs.display_height *= 2;
}
if (cs.display_width != old_horizontal_resolution || cs.display_height != old_vertical_resolution)
Log_InfoPrintf("Visible resolution is now %ux%u", cs.display_width, cs.display_height);
UpdateSliceTicks(); UpdateSliceTicks();
} }
@ -393,7 +400,7 @@ void GPU::Execute(TickCount ticks)
} }
const bool old_vblank = m_crtc_state.in_vblank; const bool old_vblank = m_crtc_state.in_vblank;
const bool new_vblank = m_crtc_state.current_scanline >= m_crtc_state.visible_vertical_resolution; const bool new_vblank = m_crtc_state.current_scanline >= m_crtc_state.visible_scanlines_per_frame;
if (new_vblank != old_vblank) if (new_vblank != old_vblank)
{ {
m_crtc_state.in_vblank = new_vblank; m_crtc_state.in_vblank = new_vblank;
@ -445,7 +452,6 @@ void GPU::WriteGP0(u32 value)
UpdateGPUSTAT(); UpdateGPUSTAT();
} }
void GPU::WriteGP1(u32 value) void GPU::WriteGP1(u32 value)
{ {
const u8 command = Truncate8(value >> 24); const u8 command = Truncate8(value >> 24);
@ -756,9 +762,9 @@ void GPU::DrawDebugStateWindow()
cs.regs.Y2.GetValue()); cs.regs.Y2.GetValue());
ImGui::NewLine(); ImGui::NewLine();
ImGui::Text("Visible Resolution: %ux%u", cs.visible_horizontal_resolution, cs.visible_vertical_resolution); ImGui::Text("Display Resolution: %ux%u", cs.display_width, cs.display_height);
ImGui::Text("Ticks Per Scanline: %u (%u visible)", cs.ticks_per_scanline, cs.visible_ticks_per_scanline); ImGui::Text("Ticks Per Scanline: %u (%u visible)", cs.ticks_per_scanline, cs.visible_ticks_per_scanline);
ImGui::Text("Scanlines Per Frame: %u", cs.total_scanlines_per_frame); ImGui::Text("Scanlines Per Frame: %u (%u visible)", cs.total_scanlines_per_frame, cs.visible_scanlines_per_frame);
ImGui::Text("Current Scanline: %u (tick %u)", cs.current_scanline, cs.current_tick_in_scanline); ImGui::Text("Current Scanline: %u (tick %u)", cs.current_scanline, cs.current_tick_in_scanline);
ImGui::Text("Horizontal Blank: %s", cs.in_hblank ? "Yes" : "No"); ImGui::Text("Horizontal Blank: %s", cs.in_hblank ? "Yes" : "No");
ImGui::Text("Vertical Blank: %s", cs.in_vblank ? "Yes" : "No"); ImGui::Text("Vertical Blank: %s", cs.in_vblank ? "Yes" : "No");

View File

@ -330,11 +330,12 @@ protected:
u32 vertical_resolution; u32 vertical_resolution;
TickCount dot_clock_divider; TickCount dot_clock_divider;
u32 visible_horizontal_resolution; u32 display_width;
u32 visible_vertical_resolution; u32 display_height;
TickCount ticks_per_scanline; TickCount ticks_per_scanline;
TickCount visible_ticks_per_scanline; TickCount visible_ticks_per_scanline;
u32 visible_scanlines_per_frame;
u32 total_scanlines_per_frame; u32 total_scanlines_per_frame;
TickCount fractional_ticks; TickCount fractional_ticks;

View File

@ -452,8 +452,8 @@ void GPU_HW_OpenGL::UpdateDisplay()
const u32 vram_offset_y = m_crtc_state.regs.Y; const u32 vram_offset_y = m_crtc_state.regs.Y;
const u32 scaled_vram_offset_x = vram_offset_x * m_resolution_scale; const u32 scaled_vram_offset_x = vram_offset_x * m_resolution_scale;
const u32 scaled_vram_offset_y = vram_offset_y * m_resolution_scale; const u32 scaled_vram_offset_y = vram_offset_y * m_resolution_scale;
const u32 display_width = std::min<u32>(m_crtc_state.horizontal_resolution, VRAM_WIDTH - vram_offset_x); const u32 display_width = std::min<u32>(m_crtc_state.display_width, VRAM_WIDTH - vram_offset_x);
const u32 display_height = std::min<u32>(m_crtc_state.vertical_resolution, VRAM_HEIGHT - vram_offset_y); const u32 display_height = std::min<u32>(m_crtc_state.display_height, VRAM_HEIGHT - vram_offset_y);
const u32 scaled_display_width = display_width * m_resolution_scale; const u32 scaled_display_width = display_width * m_resolution_scale;
const u32 scaled_display_height = display_height * m_resolution_scale; const u32 scaled_display_height = display_height * m_resolution_scale;
const u32 flipped_vram_offset_y = VRAM_HEIGHT - vram_offset_y - display_height; const u32 flipped_vram_offset_y = VRAM_HEIGHT - vram_offset_y - display_height;