DMA: Decrease slice size when MDEC is active/decoding

Prevents the FIFO getting too large, which causes too large chunks of
CPU time to be stolen and leads to games losing interrupts.

Strangely, this doesn't seem to affect performance in most games, except
the one that it fixes which has a 10-15% hit.

Fixes videos locking up in Cinema Eikaiwa Series Dai-1-dan - Tengoku ni
Ikenai Papa.

Also fixes hangs in Simple 1500 Series Vol. 57 - The Meiro.
pull/3527/head
Stenzek 2 months ago
parent 6bef5a41aa
commit fda28eaea0
No known key found for this signature in database

@ -49,6 +49,7 @@ static constexpr PhysicalMemoryAddress LINKED_LIST_TERMINATOR = UINT32_C(0x00FFF
static constexpr TickCount LINKED_LIST_HEADER_READ_TICKS = 10;
static constexpr TickCount LINKED_LIST_BLOCK_SETUP_TICKS = 5;
static constexpr TickCount SLICE_SIZE_WHEN_TRANSMITTING_PAD = 10;
static constexpr TickCount SLICE_SIZE_WHEN_DECODING_MDEC = 100;
struct ChannelState
{
@ -195,6 +196,7 @@ static TickCount TransferDeviceToMemory(u32 address, u32 increment, u32 word_cou
template<Channel channel>
static TickCount TransferMemoryToDevice(u32 address, u32 increment, u32 word_count);
template<Channel channel>
static TickCount GetMaxSliceTicks(TickCount max_slice_size);
// configuration
@ -533,9 +535,19 @@ ALWAYS_INLINE_RELEASE void DMA::CompleteTransfer(Channel channel, ChannelState&
}
}
template<DMA::Channel channel>
TickCount DMA::GetMaxSliceTicks(TickCount max_slice_size)
{
const TickCount max = Pad::IsTransmitting() ? SLICE_SIZE_WHEN_TRANSMITTING_PAD : max_slice_size;
TickCount max = Pad::IsTransmitting() ? SLICE_SIZE_WHEN_TRANSMITTING_PAD : max_slice_size;
// Prevent the slice size from being too large for MDEC.
// Since we use a larger than real FIFO, this can lead to excessively large chunks of data being
// transferred and queued in the FIFO (multiple kilobytes), which steals a large number of CPU
// cycles and results in other interrupts being missed. I hate it, but unless we do tight sync
// all the time, which has a massive performance penalty, it's really the best option.
if constexpr (channel == Channel::MDECin || channel == Channel::MDECout)
max = MDEC::IsDecodingMacroblock() ? SLICE_SIZE_WHEN_DECODING_MDEC : max;
if (!TimingEvents::IsRunningEvents())
return max;
@ -593,7 +605,7 @@ bool DMA::TransferChannel()
const u8* const ram_ptr = Bus::g_ram;
const u32 mask = Bus::g_ram_mask;
const TickCount slice_ticks = GetMaxSliceTicks(g_settings.dma_max_slice_ticks);
const TickCount slice_ticks = GetMaxSliceTicks<channel>(g_settings.dma_max_slice_ticks);
TickCount remaining_ticks = slice_ticks;
while (cs.request && remaining_ticks > 0)
{
@ -663,7 +675,7 @@ bool DMA::TransferChannel()
const u32 block_size = cs.block_control.request.GetBlockSize();
u32 blocks_remaining = cs.block_control.request.GetBlockCount();
TickCount ticks_remaining = GetMaxSliceTicks(g_settings.dma_max_slice_ticks);
TickCount ticks_remaining = GetMaxSliceTicks<channel>(g_settings.dma_max_slice_ticks);
if (copy_to_device)
{

@ -230,6 +230,11 @@ bool MDEC::IsActive()
return (s_state.active_frame_count > 0);
}
bool MDEC::IsDecodingMacroblock()
{
return (s_state.state == State::DecodingMacroblock);
}
void MDEC::EndFrame()
{
s_state.active_frame_count = (s_state.active_frame_count > 0) ? (s_state.active_frame_count - 1) : 0;

@ -15,6 +15,7 @@ void Reset();
bool DoState(StateWrapper& sw);
bool IsActive();
bool IsDecodingMacroblock();
void EndFrame();
// I/O

@ -401,7 +401,7 @@ void AutoUpdaterWindow::getLatestReleaseComplete(s32 status_code, const Error& e
if (!asset_found)
{
reportError("Asset/asset download not found");
reportError("Asset not found");
return;
}
#endif

Loading…
Cancel
Save