2009-07-28 15:32:10 -06:00
// Copyright (C) 2003 Dolphin Project.
2008-12-07 22:30:24 -07:00
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
2009-10-07 13:54:56 -06:00
# include "VideoConfig.h"
2009-02-22 14:16:12 -07:00
# include "Setup.h"
2008-12-07 22:30:24 -07:00
# include "MemoryUtil.h"
# include "Thread.h"
2009-07-12 23:38:34 -06:00
# include "Atomic.h"
2008-12-07 22:30:24 -07:00
# include "OpcodeDecoding.h"
2009-10-10 15:19:39 -06:00
# include "CommandProcessor.h"
2009-12-16 10:05:30 -07:00
# include "ChunkFile.h"
2008-12-07 22:30:24 -07:00
# include "Fifo.h"
2009-08-07 19:39:56 -06:00
volatile bool g_bSkipCurrentFrame = false ;
2009-07-02 04:16:06 -06:00
volatile bool g_EFBAccessRequested = false ;
2009-08-15 01:33:35 -06:00
extern u8 * g_pVideoData ;
2009-07-02 04:16:06 -06:00
2009-08-15 01:33:35 -06:00
namespace
{
2009-02-22 15:49:42 -07:00
static volatile bool fifoStateRun = false ;
2010-01-07 13:01:41 -07:00
static volatile bool EmuRunning = false ;
2008-12-07 22:30:24 -07:00
static u8 * videoBuffer ;
2010-01-14 03:52:14 -07:00
static Common : : EventEx fifo_run_event ;
2009-02-20 15:04:52 -07:00
// STATE_TO_SAVE
2008-12-07 22:30:24 -07:00
static int size = 0 ;
2009-02-20 15:04:52 -07:00
} // namespace
2008-12-07 22:30:24 -07:00
void Fifo_DoState ( PointerWrap & p )
{
2009-12-16 10:05:30 -07:00
CommandProcessor : : FifoCriticalEnter ( ) ;
2009-07-03 04:00:09 -06:00
2008-12-07 22:30:24 -07:00
p . DoArray ( videoBuffer , FIFO_SIZE ) ;
p . Do ( size ) ;
2009-02-20 15:04:52 -07:00
int pos = ( int ) ( g_pVideoData - videoBuffer ) ; // get offset
2008-12-07 22:30:24 -07:00
p . Do ( pos ) ; // read or write offset (depends on the mode afaik)
g_pVideoData = & videoBuffer [ pos ] ; // overwrite g_pVideoData -> expected no change when load ss and change when save ss
2009-07-03 04:00:09 -06:00
2009-12-16 10:05:30 -07:00
CommandProcessor : : FifoCriticalLeave ( ) ;
2008-12-07 22:30:24 -07:00
}
void Fifo_Init ( )
{
videoBuffer = ( u8 * ) AllocateMemoryPages ( FIFO_SIZE ) ;
2010-01-03 09:04:40 -07:00
fifo_run_event . Init ( ) ;
2009-02-20 17:54:52 -07:00
fifoStateRun = false ;
2008-12-07 22:30:24 -07:00
}
void Fifo_Shutdown ( )
{
2010-01-03 09:04:40 -07:00
if ( fifoStateRun ) PanicAlert ( " Fifo shutting down while active " ) ;
fifo_run_event . Shutdown ( ) ;
2008-12-07 22:30:24 -07:00
FreeMemoryPages ( videoBuffer , FIFO_SIZE ) ;
}
u8 * FAKE_GetFifoStartPtr ( )
{
return videoBuffer ;
}
u8 * FAKE_GetFifoEndPtr ( )
{
return & videoBuffer [ size ] ;
}
2009-08-15 01:33:35 -06:00
void Fifo_SetRendering ( bool enabled )
{
g_bSkipCurrentFrame = ! enabled ;
2009-08-07 19:39:56 -06:00
}
2009-02-22 15:49:42 -07:00
// Executed from another thread, no the graphics thread!
// Basically, all it does is set a flag so that the loop will eventually exit, then
// waits for the event to be set, which happens when the loop does exit.
// If we look stuck in here, then the video thread is stuck in something and won't exit
// the loop. Switch to the video thread and investigate.
2009-02-20 15:04:52 -07:00
void Fifo_ExitLoop ( )
{
2010-01-03 09:04:40 -07:00
Fifo_ExitLoopNonBlocking ( ) ;
2009-02-20 15:04:52 -07:00
}
2009-03-07 16:34:16 -07:00
// May be executed from any thread, even the graphics thread.
// Created to allow for self shutdown.
2009-08-09 05:03:58 -06:00
void Fifo_ExitLoopNonBlocking ( )
{
2010-01-16 15:37:38 -07:00
// This should break the wait loop in CPU thread
CommandProcessor : : fifo . bFF_GPReadEnable = false ;
CommandProcessor : : SetFifoIdleFromVideoPlugin ( ) ;
// Terminate GPU thread loop
2009-03-07 16:34:16 -07:00
fifoStateRun = false ;
2010-01-03 09:04:40 -07:00
fifo_run_event . Set ( ) ;
}
2010-01-07 13:01:41 -07:00
void Fifo_RunLoop ( bool run )
2010-01-03 09:04:40 -07:00
{
2010-01-07 13:01:41 -07:00
EmuRunning = run ;
if ( run )
fifo_run_event . Set ( ) ;
2009-03-07 16:34:16 -07:00
}
2009-06-14 22:30:02 -06:00
// Description: Fifo_EnterLoop() sends data through this function.
2009-07-17 16:57:02 -06:00
void Fifo_SendFifoData ( u8 * _uData , u32 len )
2009-06-14 22:30:02 -06:00
{
if ( size + len > = FIFO_SIZE )
{
int pos = ( int ) ( g_pVideoData - videoBuffer ) ;
2010-06-14 10:32:40 -06:00
size - = pos ;
if ( size + len > FIFO_SIZE )
2009-06-14 22:30:02 -06:00
{
PanicAlert ( " FIFO out of bounds (sz = %i, at %08x) " , size , pos ) ;
}
2010-06-14 10:32:40 -06:00
memmove ( & videoBuffer [ 0 ] , & videoBuffer [ pos ] , size ) ;
2009-12-16 10:05:30 -07:00
g_pVideoData = videoBuffer ;
2009-06-14 22:30:02 -06:00
}
// Copy new video instructions to videoBuffer for future use in rendering the new picture
memcpy ( videoBuffer + size , _uData , len ) ;
size + = len ;
2009-08-09 05:03:58 -06:00
OpcodeDecoder_Run ( g_bSkipCurrentFrame ) ;
2009-06-14 22:30:02 -06:00
}
2010-01-23 14:06:12 -07:00
// Description: Main FIFO update loop
// Purpose: Keep the Core HW updated about the CPU-GPU distance
void Fifo_EnterLoop ( const SVideoInitialize & video_initialize )
2008-12-07 22:30:24 -07:00
{
2010-01-23 14:06:12 -07:00
fifoStateRun = true ;
2009-12-31 13:49:04 -07:00
SCPFifoStruct & _fifo = CommandProcessor : : fifo ;
2009-07-23 16:32:21 -06:00
s32 distToSend ;
2008-12-07 22:30:24 -07:00
2010-01-23 14:06:12 -07:00
while ( fifoStateRun )
2009-12-31 13:49:04 -07:00
{
2010-01-23 14:06:12 -07:00
video_initialize . pPeekMessages ( ) ;
2009-07-17 16:57:02 -06:00
2010-08-04 15:02:32 -06:00
VideoFifo_CheckAsyncRequest ( ) ;
2009-08-15 01:33:35 -06:00
2010-06-24 07:28:54 -06:00
// check if we are able to run this buffer
2010-11-23 23:02:03 -07:00
while ( _fifo . bFF_GPReadEnable & & ( _fifo . CPReadWriteDistance | | ( _fifo . bFF_BPEnable & & ( ( _fifo . CPReadPointer < = _fifo . CPBreakpoint ) & & ( _fifo . CPReadPointer + 32 > _fifo . CPBreakpoint ) ) ) ) )
2010-01-23 05:50:56 -07:00
{
2010-06-24 07:28:54 -06:00
// while the FIFO is processing data we activate this for sync with emulator thread.
CommandProcessor : : isFifoBusy = true ;
2010-01-23 14:06:12 -07:00
if ( ! fifoStateRun )
2010-01-23 05:50:56 -07:00
break ;
2010-06-14 15:55:40 -06:00
_fifo . CPCmdIdle = false ;
2010-01-23 14:06:12 -07:00
CommandProcessor : : FifoCriticalEnter ( ) ;
// Create pointer to video data and send it to the VideoPlugin
u32 readPtr = _fifo . CPReadPointer ;
u8 * uData = video_initialize . pGetMemoryPointer ( readPtr ) ;
2010-06-14 15:55:40 -06:00
// DEBUG_LOG(BOOT, "readPtr: %08x uData %08x", readPtr, uData);
2010-01-23 14:06:12 -07:00
2010-06-13 17:26:22 -06:00
// If we are in BP mode we only send 32B chunks to Video plugin for BP checking
if ( _fifo . bFF_BPEnable )
2009-12-31 09:25:12 -07:00
{
2010-06-15 03:58:43 -06:00
if ( ( readPtr < = _fifo . CPBreakpoint ) & & ( readPtr + 32 > _fifo . CPBreakpoint ) )
2010-06-13 17:26:22 -06:00
{
2010-06-15 08:24:01 -06:00
Common : : AtomicStore ( _fifo . bFF_GPReadEnable , false ) ;
Common : : AtomicStore ( _fifo . bFF_Breakpoint , true ) ;
2010-06-14 15:55:40 -06:00
if ( _fifo . bFF_BPInt )
CommandProcessor : : UpdateInterruptsFromVideoPlugin ( ) ;
2010-06-13 17:26:22 -06:00
CommandProcessor : : FifoCriticalLeave ( ) ;
2010-06-24 07:28:54 -06:00
CommandProcessor : : isFifoBusy = false ;
2010-06-13 17:26:22 -06:00
break ;
}
2010-06-14 15:55:40 -06:00
distToSend = 32 ;
2010-06-15 03:58:43 -06:00
if ( readPtr > = _fifo . CPEnd )
2010-06-13 17:26:22 -06:00
readPtr = _fifo . CPBase ;
else
readPtr + = 32 ;
2009-12-31 09:25:12 -07:00
}
2010-06-13 17:26:22 -06:00
// If we are not in BP mode we send all the chunk we have to speed up
2010-01-23 05:50:56 -07:00
else
2010-06-13 17:26:22 -06:00
{
distToSend = _fifo . CPReadWriteDistance ;
// send 1024B chunk max length to have better control over PeekMessages' period
distToSend = distToSend > 1024 ? 1024 : distToSend ;
2010-06-15 03:58:43 -06:00
if ( readPtr + distToSend > = _fifo . CPEnd + 32 )
2010-06-13 17:26:22 -06:00
{
2010-06-15 03:58:43 -06:00
distToSend = _fifo . CPEnd + 32 - readPtr ;
2010-06-13 17:26:22 -06:00
readPtr = _fifo . CPBase ;
}
else
readPtr + = distToSend ;
}
2009-07-19 19:10:00 -06:00
2010-11-28 13:12:41 -07:00
2010-12-05 08:59:11 -07:00
_assert_msg_ ( COMMANDPROCESSOR , ( s32 ) _fifo . CPReadWriteDistance - distToSend > = 0 ,
2010-11-28 13:12:41 -07:00
" Negative fifo.CPReadWriteDistance = %i in FIFO Loop ! \n That can produce inestabilty in the game. Please report it. " , _fifo . CPReadWriteDistance - distToSend ) ;
2010-11-27 20:20:20 -07:00
Common : : AtomicStore ( _fifo . CPReadPointer , readPtr ) ;
Common : : AtomicAdd ( _fifo . CPReadWriteDistance , - distToSend ) ;
2010-01-23 14:06:12 -07:00
// Execute new instructions found in uData
Fifo_SendFifoData ( uData , distToSend ) ;
2009-12-16 21:01:34 -07:00
2010-11-27 20:20:20 -07:00
2009-12-16 21:01:34 -07:00
2010-01-23 14:06:12 -07:00
CommandProcessor : : FifoCriticalLeave ( ) ;
2010-01-23 05:50:56 -07:00
2010-01-23 14:06:12 -07:00
// Those two are pretty important and must be called in the FIFO Loop.
// If we don't, s_swapRequested (OGL only) or s_efbAccessRequested won't be set to false
// leading the CPU thread to wait in Video_BeginField or Video_AccessEFB thus slowing things down.
2010-06-24 07:28:54 -06:00
2010-08-04 15:02:32 -06:00
VideoFifo_CheckAsyncRequest ( ) ;
2010-06-24 07:28:54 -06:00
CommandProcessor : : isFifoBusy = false ;
2010-01-23 14:06:12 -07:00
}
2010-06-24 07:28:54 -06:00
2010-06-15 03:58:43 -06:00
if ( ! _fifo . CPReadIdle & & _fifo . CPReadWriteDistance < _fifo . CPLoWatermark )
2010-06-14 15:55:40 -06:00
{
Common : : AtomicStore ( _fifo . CPReadIdle , true ) ;
CommandProcessor : : UpdateInterruptsFromVideoPlugin ( ) ;
}
2010-06-24 07:28:54 -06:00
2010-06-14 15:55:40 -06:00
_fifo . CPCmdIdle = true ;
2010-01-23 14:06:12 -07:00
CommandProcessor : : SetFifoIdleFromVideoPlugin ( ) ;
2010-01-07 13:01:41 -07:00
if ( EmuRunning )
2010-01-03 11:58:50 -07:00
Common : : YieldCPU ( ) ;
else
fifo_run_event . MsgWait ( ) ;
2009-12-28 12:13:06 -07:00
}
2008-12-07 22:30:24 -07:00
}
2009-06-15 00:39:26 -06:00