GPU: Tweaks to ODE handling
Fixes Team Buddies and The Next Tetris.
This commit is contained in:
parent
a8699d9908
commit
d4665e8b22
|
@ -162,6 +162,7 @@ bool GPU::DoState(StateWrapper& sw)
|
||||||
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.interlaced_field);
|
sw.Do(&m_crtc_state.interlaced_field);
|
||||||
|
sw.Do(&m_crtc_state.interlaced_display_field);
|
||||||
sw.Do(&m_crtc_state.active_line_lsb);
|
sw.Do(&m_crtc_state.active_line_lsb);
|
||||||
|
|
||||||
sw.Do(&m_blitter_state);
|
sw.Do(&m_blitter_state);
|
||||||
|
@ -734,10 +735,10 @@ void GPU::CRTCTickEvent(TickCount ticks)
|
||||||
System::FrameDone();
|
System::FrameDone();
|
||||||
|
|
||||||
// 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.InInterleaved480iMode())
|
||||||
m_crtc_state.interlaced_field ^= 1u;
|
m_crtc_state.interlaced_display_field = m_crtc_state.interlaced_field ^ 1u;
|
||||||
else
|
else
|
||||||
m_crtc_state.interlaced_field = 0;
|
m_crtc_state.interlaced_display_field = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_timers.SetGate(HBLANK_TIMER_INDEX, new_vblank);
|
g_timers.SetGate(HBLANK_TIMER_INDEX, new_vblank);
|
||||||
|
@ -749,15 +750,20 @@ void GPU::CRTCTickEvent(TickCount ticks)
|
||||||
{
|
{
|
||||||
// start the new frame
|
// start the new frame
|
||||||
m_crtc_state.current_scanline = 0;
|
m_crtc_state.current_scanline = 0;
|
||||||
|
if (m_GPUSTAT.vertical_interlace)
|
||||||
|
m_crtc_state.interlaced_field ^= 1u;
|
||||||
|
else
|
||||||
|
m_crtc_state.interlaced_field = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// alternating even line bit in 240-line mode
|
// alternating even line bit in 240-line mode
|
||||||
if (m_GPUSTAT.vertical_interlace)
|
if (m_GPUSTAT.InInterleaved480iMode())
|
||||||
{
|
{
|
||||||
m_crtc_state.active_line_lsb =
|
m_crtc_state.active_line_lsb =
|
||||||
ConvertToBoolUnchecked((m_crtc_state.regs.Y + BoolToUInt32(m_crtc_state.interlaced_field)) & u32(1));
|
Truncate8((m_crtc_state.regs.Y + BoolToUInt32(m_crtc_state.interlaced_display_field)) & u32(1));
|
||||||
m_GPUSTAT.display_line_lsb = m_crtc_state.active_line_lsb && !m_crtc_state.in_vblank;
|
m_GPUSTAT.display_line_lsb = ConvertToBoolUnchecked(
|
||||||
|
(m_crtc_state.regs.Y + (BoolToUInt8(m_crtc_state.in_vblank) ^ m_crtc_state.interlaced_display_field)) & u32(1));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -513,6 +513,11 @@ protected:
|
||||||
static constexpr u32 ACTIVE = (1 << 19) | (1 << 22);
|
static constexpr u32 ACTIVE = (1 << 19) | (1 << 22);
|
||||||
return ((bits & MASK) == ACTIVE);
|
return ((bits & MASK) == ACTIVE);
|
||||||
}
|
}
|
||||||
|
bool InInterleaved480iMode() const
|
||||||
|
{
|
||||||
|
static constexpr u32 ACTIVE = (1 << 19) | (1 << 22);
|
||||||
|
return ((bits & ACTIVE) == ACTIVE);
|
||||||
|
}
|
||||||
|
|
||||||
// During transfer/render operations, if ((dst_pixel & mask_and) == 0) { pixel = src_pixel | mask_or }
|
// During transfer/render operations, if ((dst_pixel & mask_and) == 0) { pixel = src_pixel | mask_or }
|
||||||
u16 GetMaskAND() const
|
u16 GetMaskAND() const
|
||||||
|
@ -694,6 +699,7 @@ protected:
|
||||||
bool in_vblank;
|
bool in_vblank;
|
||||||
|
|
||||||
u8 interlaced_field; // 0 = odd, 1 = even
|
u8 interlaced_field; // 0 = odd, 1 = even
|
||||||
|
u8 interlaced_display_field;
|
||||||
u8 active_line_lsb;
|
u8 active_line_lsb;
|
||||||
} m_crtc_state = {};
|
} m_crtc_state = {};
|
||||||
|
|
||||||
|
|
|
@ -227,7 +227,7 @@ bool RecreateGPU(GPURenderer renderer)
|
||||||
// save current state
|
// save current state
|
||||||
std::unique_ptr<ByteStream> state_stream = ByteStream_CreateGrowableMemoryStream();
|
std::unique_ptr<ByteStream> state_stream = ByteStream_CreateGrowableMemoryStream();
|
||||||
StateWrapper sw(state_stream.get(), StateWrapper::Mode::Write);
|
StateWrapper sw(state_stream.get(), StateWrapper::Mode::Write);
|
||||||
const bool state_valid = g_gpu->DoState(sw) && TimingEvents::DoState(sw, TimingEvents::GetGlobalTickCounter());
|
const bool state_valid = g_gpu->DoState(sw) && TimingEvents::DoState(sw);
|
||||||
if (!state_valid)
|
if (!state_valid)
|
||||||
Log_ErrorPrintf("Failed to save old GPU state when switching renderers");
|
Log_ErrorPrintf("Failed to save old GPU state when switching renderers");
|
||||||
|
|
||||||
|
@ -247,7 +247,7 @@ bool RecreateGPU(GPURenderer renderer)
|
||||||
sw.SetMode(StateWrapper::Mode::Read);
|
sw.SetMode(StateWrapper::Mode::Read);
|
||||||
g_gpu->RestoreGraphicsAPIState();
|
g_gpu->RestoreGraphicsAPIState();
|
||||||
g_gpu->DoState(sw);
|
g_gpu->DoState(sw);
|
||||||
TimingEvents::DoState(sw, TimingEvents::GetGlobalTickCounter());
|
TimingEvents::DoState(sw);
|
||||||
g_gpu->ResetGraphicsAPIState();
|
g_gpu->ResetGraphicsAPIState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,13 +540,9 @@ bool DoState(StateWrapper& sw)
|
||||||
if (!sw.DoMarker("System"))
|
if (!sw.DoMarker("System"))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// TODO: Move this into timing state
|
|
||||||
u32 global_tick_counter = TimingEvents::GetGlobalTickCounter();
|
|
||||||
|
|
||||||
sw.Do(&s_region);
|
sw.Do(&s_region);
|
||||||
sw.Do(&s_frame_number);
|
sw.Do(&s_frame_number);
|
||||||
sw.Do(&s_internal_frame_number);
|
sw.Do(&s_internal_frame_number);
|
||||||
sw.Do(&global_tick_counter);
|
|
||||||
|
|
||||||
if (!sw.DoMarker("CPU") || !CPU::DoState(sw))
|
if (!sw.DoMarker("CPU") || !CPU::DoState(sw))
|
||||||
return false;
|
return false;
|
||||||
|
@ -584,7 +580,7 @@ bool DoState(StateWrapper& sw)
|
||||||
if (!sw.DoMarker("SIO") || !g_sio.DoState(sw))
|
if (!sw.DoMarker("SIO") || !g_sio.DoState(sw))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!sw.DoMarker("Events") || !TimingEvents::DoState(sw, global_tick_counter))
|
if (!sw.DoMarker("Events") || !TimingEvents::DoState(sw))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return !sw.HasError();
|
return !sw.HasError();
|
||||||
|
|
|
@ -172,12 +172,12 @@ void RunEvents()
|
||||||
UpdateCPUDowncount();
|
UpdateCPUDowncount();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DoState(StateWrapper& sw, u32 global_tick_counter)
|
bool DoState(StateWrapper& sw)
|
||||||
{
|
{
|
||||||
|
sw.Do(&s_global_tick_counter);
|
||||||
|
|
||||||
if (sw.IsReading())
|
if (sw.IsReading())
|
||||||
{
|
{
|
||||||
s_global_tick_counter = global_tick_counter;
|
|
||||||
|
|
||||||
// Load timestamps for the clock events.
|
// Load timestamps for the clock events.
|
||||||
// Any oneshot events should be recreated by the load state method, so we can fix up their times here.
|
// Any oneshot events should be recreated by the load state method, so we can fix up their times here.
|
||||||
u32 event_count = 0;
|
u32 event_count = 0;
|
||||||
|
|
|
@ -79,7 +79,7 @@ std::unique_ptr<TimingEvent> CreateTimingEvent(std::string name, TickCount perio
|
||||||
TimingEventCallback callback, bool activate);
|
TimingEventCallback callback, bool activate);
|
||||||
|
|
||||||
/// Serialization.
|
/// Serialization.
|
||||||
bool DoState(StateWrapper& sw, u32 global_tick_counter);
|
bool DoState(StateWrapper& sw);
|
||||||
|
|
||||||
void RunEvents();
|
void RunEvents();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue