GPU/HW: More improvements to GPUSTAT.31

Fixes True Pinball without breaking intros to Final Fantasy 7/8.
This commit is contained in:
Connor McLaughlin 2020-05-26 22:57:56 +10:00
parent 04f131f979
commit 23436f08ba
7 changed files with 34 additions and 30 deletions

View File

@ -158,8 +158,8 @@ bool GPU::DoState(StateWrapper& sw)
sw.Do(&m_crtc_state.current_scanline); sw.Do(&m_crtc_state.current_scanline);
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);
sw.Do(&m_crtc_state.displaying_odd_field); sw.Do(&m_crtc_state.interlaced_field);
sw.Do(&m_crtc_state.displaying_odd_lines); sw.Do(&m_crtc_state.active_line_lsb);
sw.Do(&m_blitter_state); sw.Do(&m_blitter_state);
sw.Do(&m_command_ticks); sw.Do(&m_command_ticks);
@ -693,9 +693,9 @@ void GPU::Execute(TickCount ticks)
// switch fields early. this is needed so we draw to the correct one. // switch fields early. this is needed so we draw to the correct one.
if (m_GPUSTAT.vertical_interlace) if (m_GPUSTAT.vertical_interlace)
m_crtc_state.displaying_odd_field ^= true; m_crtc_state.interlaced_field ^= 1u;
else else
m_crtc_state.displaying_odd_field = false; m_crtc_state.interlaced_field = 0;
} }
m_timers->SetGate(HBLANK_TIMER_INDEX, new_vblank); m_timers->SetGate(HBLANK_TIMER_INDEX, new_vblank);
@ -713,15 +713,14 @@ void GPU::Execute(TickCount ticks)
// alternating even line bit in 240-line mode // alternating even line bit in 240-line mode
if (m_GPUSTAT.vertical_interlace) if (m_GPUSTAT.vertical_interlace)
{ {
m_crtc_state.displaying_odd_lines = m_crtc_state.active_line_lsb =
ConvertToBoolUnchecked((m_crtc_state.regs.Y + BoolToUInt32(m_crtc_state.displaying_odd_field)) & u32(1)); ConvertToBoolUnchecked((m_crtc_state.regs.Y + BoolToUInt32(m_crtc_state.interlaced_field)) & u32(1));
m_GPUSTAT.drawing_odd_lines = !m_crtc_state.displaying_odd_lines && !m_crtc_state.in_vblank; m_GPUSTAT.display_line_lsb = m_crtc_state.active_line_lsb && !m_crtc_state.in_vblank;
} }
else else
{ {
m_crtc_state.displaying_odd_lines = false; m_crtc_state.active_line_lsb = 0;
m_GPUSTAT.drawing_odd_lines = m_GPUSTAT.display_line_lsb = ConvertToBoolUnchecked((m_crtc_state.regs.Y + m_crtc_state.current_scanline) & u32(1));
ConvertToBoolUnchecked((m_crtc_state.regs.Y + m_crtc_state.current_scanline) & u32(1));
} }
UpdateSliceTicks(); UpdateSliceTicks();
@ -1018,7 +1017,7 @@ void GPU::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)
if (IsRasterScanlinePending()) if (IsRasterScanlinePending())
Synchronize(); Synchronize();
const u32 active_field = GetInterlacedDisplayLineOffset(); const u32 active_field = GetActiveLineLSB();
for (u32 yoffs = 0; yoffs < height; yoffs++) for (u32 yoffs = 0; yoffs < height; yoffs++)
{ {
const u32 row = (y + yoffs) % VRAM_HEIGHT; const u32 row = (y + yoffs) % VRAM_HEIGHT;
@ -1326,9 +1325,9 @@ void GPU::DrawDebugStateWindow()
const auto& cs = m_crtc_state; const auto& cs = m_crtc_state;
ImGui::Text("Dot Clock Divider: %u", cs.dot_clock_divider); ImGui::Text("Dot Clock Divider: %u", cs.dot_clock_divider);
ImGui::Text("Vertical Interlace: %s (%s field)", m_GPUSTAT.vertical_interlace ? "Yes" : "No", ImGui::Text("Vertical Interlace: %s (%s field)", m_GPUSTAT.vertical_interlace ? "Yes" : "No",
m_crtc_state.displaying_odd_field ? "odd" : "even"); m_crtc_state.interlaced_field ? "odd" : "even");
ImGui::Text("Display Disable: %s", m_GPUSTAT.display_disable ? "Yes" : "No"); ImGui::Text("Display Disable: %s", m_GPUSTAT.display_disable ? "Yes" : "No");
ImGui::Text("Displaying Odd Lines: %s", m_crtc_state.displaying_odd_lines ? "Yes" : "No"); ImGui::Text("Displaying Odd Lines: %s", m_crtc_state.active_line_lsb ? "Yes" : "No");
ImGui::Text("Color Depth: %u-bit", m_GPUSTAT.display_area_color_depth_24 ? 24 : 15); ImGui::Text("Color Depth: %u-bit", m_GPUSTAT.display_area_color_depth_24 ? 24 : 15);
ImGui::Text("Start Offset: (%u, %u)", cs.regs.X.GetValue(), cs.regs.Y.GetValue()); ImGui::Text("Start Offset: (%u, %u)", cs.regs.X.GetValue(), cs.regs.Y.GetValue());
ImGui::Text("Display Total: %u (%u) horizontal, %u vertical", cs.horizontal_total, ImGui::Text("Display Total: %u (%u) horizontal, %u vertical", cs.horizontal_total,

View File

@ -356,8 +356,11 @@ protected:
return (!m_force_progressive_scan) & m_GPUSTAT.SkipDrawingToActiveField(); return (!m_force_progressive_scan) & m_GPUSTAT.SkipDrawingToActiveField();
} }
/// Returns 0 if the currently-displayed field is on an even line, otherwise 1. /// Returns 0 if the currently-displayed field is on odd lines (1,3,5,...) or 1 if even (2,4,6,...).
ALWAYS_INLINE u32 GetInterlacedDisplayLineOffset() const { return BoolToUInt32(m_crtc_state.displaying_odd_lines); } ALWAYS_INLINE u32 GetInterlacedDisplayField() const { return ZeroExtend32(m_crtc_state.interlaced_field); }
/// Returns 0 if the currently-displayed field is on an even line in VRAM, otherwise 1.
ALWAYS_INLINE u32 GetActiveLineLSB() const { return ZeroExtend32(m_crtc_state.active_line_lsb); }
/// Sets/decodes GP0(E1h) (set draw mode). /// Sets/decodes GP0(E1h) (set draw mode).
void SetDrawMode(u16 bits); void SetDrawMode(u16 bits);
@ -446,7 +449,7 @@ protected:
BitField<u32, bool, 27, 1> ready_to_send_vram; BitField<u32, bool, 27, 1> ready_to_send_vram;
BitField<u32, bool, 28, 1> ready_to_recieve_dma; BitField<u32, bool, 28, 1> ready_to_recieve_dma;
BitField<u32, DMADirection, 29, 2> dma_direction; BitField<u32, DMADirection, 29, 2> dma_direction;
BitField<u32, bool, 31, 1> drawing_odd_lines; BitField<u32, bool, 31, 1> display_line_lsb;
bool IsMaskingEnabled() const bool IsMaskingEnabled() const
{ {
@ -638,8 +641,8 @@ protected:
bool in_hblank; bool in_hblank;
bool in_vblank; bool in_vblank;
bool displaying_odd_field; u8 interlaced_field; // 0 = odd, 1 = even
bool displaying_odd_lines; u8 active_line_lsb;
} m_crtc_state = {}; } m_crtc_state = {};
BlitterState m_blitter_state = BlitterState::Idle; BlitterState m_blitter_state = BlitterState::Idle;

View File

@ -713,7 +713,7 @@ void GPU_HW::DispatchRenderCommand()
m_batch.interlacing = IsInterlacedRenderingEnabled(); m_batch.interlacing = IsInterlacedRenderingEnabled();
if (m_batch.interlacing) if (m_batch.interlacing)
{ {
const u32 displayed_field = GetInterlacedDisplayLineOffset(); const u32 displayed_field = GetActiveLineLSB();
m_batch_ubo_dirty |= (m_batch_ubo_data.u_interlaced_displayed_field != displayed_field); m_batch_ubo_dirty |= (m_batch_ubo_data.u_interlaced_displayed_field != displayed_field);
m_batch_ubo_data.u_interlaced_displayed_field = displayed_field; m_batch_ubo_data.u_interlaced_displayed_field = displayed_field;
} }

View File

@ -583,7 +583,7 @@ void GPU_HW_D3D11::UpdateDisplay()
else else
{ {
const u32 vram_offset_x = m_crtc_state.display_vram_left; const u32 vram_offset_x = m_crtc_state.display_vram_left;
const u32 vram_offset_y = m_crtc_state.display_vram_top; const u32 vram_offset_y = m_crtc_state.display_vram_top + GetActiveLineLSB();
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 = m_crtc_state.display_vram_width; const u32 display_width = m_crtc_state.display_vram_width;
@ -610,7 +610,7 @@ void GPU_HW_D3D11::UpdateDisplay()
m_context->OMSetDepthStencilState(m_depth_disabled_state.Get(), 0); m_context->OMSetDepthStencilState(m_depth_disabled_state.Get(), 0);
m_context->PSSetShaderResources(0, 1, m_vram_texture.GetD3DSRVArray()); m_context->PSSetShaderResources(0, 1, m_vram_texture.GetD3DSRVArray());
const u32 reinterpret_field_offset = GetInterlacedDisplayLineOffset(); const u32 reinterpret_field_offset = GetInterlacedDisplayField();
const u32 reinterpret_start_x = m_crtc_state.regs.X * m_resolution_scale; const u32 reinterpret_start_x = m_crtc_state.regs.X * m_resolution_scale;
const u32 reinterpret_crop_left = (m_crtc_state.display_vram_left - m_crtc_state.regs.X) * m_resolution_scale; const u32 reinterpret_crop_left = (m_crtc_state.display_vram_left - m_crtc_state.regs.X) * m_resolution_scale;
const u32 uniforms[4] = {reinterpret_start_x, scaled_vram_offset_y, reinterpret_crop_left, const u32 uniforms[4] = {reinterpret_start_x, scaled_vram_offset_y, reinterpret_crop_left,
@ -694,7 +694,7 @@ void GPU_HW_D3D11::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)
Uniforms uniforms; Uniforms uniforms;
std::tie(uniforms.u_fill_color[0], uniforms.u_fill_color[1], uniforms.u_fill_color[2], uniforms.u_fill_color[3]) = std::tie(uniforms.u_fill_color[0], uniforms.u_fill_color[1], uniforms.u_fill_color[2], uniforms.u_fill_color[3]) =
RGBA8ToFloat(color); RGBA8ToFloat(color);
uniforms.u_interlaced_displayed_field = GetInterlacedDisplayLineOffset(); uniforms.u_interlaced_displayed_field = GetActiveLineLSB();
m_context->OMSetDepthStencilState(m_depth_test_always_state.Get(), 0); m_context->OMSetDepthStencilState(m_depth_test_always_state.Get(), 0);

View File

@ -580,7 +580,7 @@ void GPU_HW_OpenGL::UpdateDisplay()
else else
{ {
const u32 vram_offset_x = m_crtc_state.display_vram_left; const u32 vram_offset_x = m_crtc_state.display_vram_left;
const u32 vram_offset_y = m_crtc_state.display_vram_top; const u32 vram_offset_y = m_crtc_state.display_vram_top + GetActiveLineLSB();
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 = m_crtc_state.display_vram_width; const u32 display_width = m_crtc_state.display_vram_width;
@ -616,7 +616,7 @@ void GPU_HW_OpenGL::UpdateDisplay()
const u32 flipped_vram_offset_y = VRAM_HEIGHT - vram_offset_y - (display_height >> height_div2); const u32 flipped_vram_offset_y = VRAM_HEIGHT - vram_offset_y - (display_height >> height_div2);
const u32 scaled_flipped_vram_offset_y = const u32 scaled_flipped_vram_offset_y =
m_vram_texture.GetHeight() - scaled_vram_offset_y - (scaled_display_height >> height_div2); m_vram_texture.GetHeight() - scaled_vram_offset_y - (scaled_display_height >> height_div2);
const u32 reinterpret_field_offset = GetInterlacedDisplayLineOffset(); const u32 reinterpret_field_offset = GetInterlacedDisplayField();
const u32 reinterpret_start_x = m_crtc_state.regs.X * m_resolution_scale; const u32 reinterpret_start_x = m_crtc_state.regs.X * m_resolution_scale;
const u32 reinterpret_crop_left = (m_crtc_state.display_vram_left - m_crtc_state.regs.X) * m_resolution_scale; const u32 reinterpret_crop_left = (m_crtc_state.display_vram_left - m_crtc_state.regs.X) * m_resolution_scale;
const u32 uniforms[4] = {reinterpret_start_x, scaled_flipped_vram_offset_y, reinterpret_crop_left, const u32 uniforms[4] = {reinterpret_start_x, scaled_flipped_vram_offset_y, reinterpret_crop_left,
@ -724,7 +724,7 @@ void GPU_HW_OpenGL::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)
Uniforms uniforms; Uniforms uniforms;
std::tie(uniforms.u_fill_color[0], uniforms.u_fill_color[1], uniforms.u_fill_color[2], uniforms.u_fill_color[3]) = std::tie(uniforms.u_fill_color[0], uniforms.u_fill_color[1], uniforms.u_fill_color[2], uniforms.u_fill_color[3]) =
RGBA8ToFloat(color); RGBA8ToFloat(color);
uniforms.u_interlaced_displayed_field = GetInterlacedDisplayLineOffset(); uniforms.u_interlaced_displayed_field = GetActiveLineLSB();
m_vram_interlaced_fill_program.Bind(); m_vram_interlaced_fill_program.Bind();
UploadUniformBuffer(&uniforms, sizeof(uniforms)); UploadUniformBuffer(&uniforms, sizeof(uniforms));

View File

@ -1031,6 +1031,8 @@ std::string GPU_HW_ShaderGen::GenerateDisplayFragmentShader(bool depth_24bit, GP
#if !INTERLEAVED #if !INTERLEAVED
icoords.y /= 2u; icoords.y /= 2u;
#else
icoords.y &= ~1u;
#endif #endif
#endif #endif

View File

@ -157,22 +157,22 @@ void GPU_SW::UpdateDisplay()
} }
const u32 vram_offset_x = m_crtc_state.display_vram_left; const u32 vram_offset_x = m_crtc_state.display_vram_left;
const u32 vram_offset_y = m_crtc_state.display_vram_top; const u32 vram_offset_y = m_crtc_state.display_vram_top + GetActiveLineLSB();
const u32 display_width = m_crtc_state.display_vram_width; const u32 display_width = m_crtc_state.display_vram_width;
const u32 display_height = m_crtc_state.display_vram_height; const u32 display_height = m_crtc_state.display_vram_height;
const u32 texture_offset_x = m_crtc_state.display_vram_left - m_crtc_state.regs.X; const u32 texture_offset_x = m_crtc_state.display_vram_left - m_crtc_state.regs.X;
if (IsInterlacedDisplayEnabled()) if (IsInterlacedDisplayEnabled())
{ {
const u32 field = GetInterlacedDisplayLineOffset(); const u32 field = GetInterlacedDisplayField();
if (m_GPUSTAT.display_area_color_depth_24) if (m_GPUSTAT.display_area_color_depth_24)
{ {
CopyOut24Bit(m_crtc_state.regs.X, vram_offset_y + (m_GPUSTAT.vertical_resolution ? field : 0u), CopyOut24Bit(m_crtc_state.regs.X, vram_offset_y,
m_display_texture_buffer.data() + field * VRAM_WIDTH, VRAM_WIDTH, display_width + texture_offset_x, m_display_texture_buffer.data() + field * VRAM_WIDTH, VRAM_WIDTH, display_width + texture_offset_x,
display_height, true, m_GPUSTAT.vertical_resolution); display_height, true, m_GPUSTAT.vertical_resolution);
} }
else else
{ {
CopyOut15Bit(m_crtc_state.regs.X, vram_offset_y + (m_GPUSTAT.vertical_resolution ? field : 0u), CopyOut15Bit(m_crtc_state.regs.X, vram_offset_y,
m_display_texture_buffer.data() + field * VRAM_WIDTH, VRAM_WIDTH, display_width + texture_offset_x, m_display_texture_buffer.data() + field * VRAM_WIDTH, VRAM_WIDTH, display_width + texture_offset_x,
display_height, true, m_GPUSTAT.vertical_resolution); display_height, true, m_GPUSTAT.vertical_resolution);
} }
@ -716,7 +716,7 @@ void GPU_SW::ShadePixel(u32 x, u32 y, u8 color_r, u8 color_g, u8 color_b, u8 tex
if ((bg_color.bits & mask_and) != 0) if ((bg_color.bits & mask_and) != 0)
return; return;
if (IsInterlacedRenderingEnabled() && GetInterlacedDisplayLineOffset() == (static_cast<u32>(y) & 1u)) if (IsInterlacedRenderingEnabled() && GetActiveLineLSB() == (static_cast<u32>(y) & 1u))
return; return;
SetPixel(static_cast<u32>(x), static_cast<u32>(y), color.bits | m_GPUSTAT.GetMaskOR()); SetPixel(static_cast<u32>(x), static_cast<u32>(y), color.bits | m_GPUSTAT.GetMaskOR());