More accurate audio interrupts (preparation for homebrew audio support). some minor cleanup in gl plugin.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@226 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
hrydgard 2008-08-16 10:49:08 +00:00
parent 7962ab4713
commit dcd5ffeb7a
16 changed files with 177 additions and 101 deletions

View File

@ -15,6 +15,13 @@
// Official SVN repository and contact information can be found at // Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/ // http://code.google.com/p/dolphin-emu/
// This file is ONLY about disc streaming. It's a bit unfortunately named.
// For the rest of the audio stuff, including the "real" AI, see DSP.cpp/h.
// AI disc streaming is handled completely separately from the rest of the
// audio processing. In short, it simply streams audio directly from disc
// out through the speakers.
#include "Common.h" #include "Common.h"
#include "StreamADPCM.H" #include "StreamADPCM.H"
@ -125,13 +132,15 @@ void Read32(u32& _rReturnValue, const u32 _Address)
return; return;
case AI_INTERRUPT_TIMING: case AI_INTERRUPT_TIMING:
// When sample counter reaches the value of this register, the interrupt AIINT should
// fire.
LOG(AUDIO_INTERFACE, "AudioInterface(R) 0x%08x", _Address); LOG(AUDIO_INTERFACE, "AudioInterface(R) 0x%08x", _Address);
_rReturnValue = g_AudioRegister.m_InterruptTiming; _rReturnValue = g_AudioRegister.m_InterruptTiming;
return; return;
default: default:
LOG(AUDIO_INTERFACE, "AudioInterface(R) 0x%08x", _Address); LOG(AUDIO_INTERFACE, "AudioInterface(R) 0x%08x", _Address);
_dbg_assert_msg_(AUDIO_INTERFACE,0,"AudioInterface - Read from ???"); _dbg_assert_msg_(AUDIO_INTERFACE, 0, "AudioInterface - Read from ???");
_rReturnValue = 0; _rReturnValue = 0;
return; return;
} }
@ -196,7 +205,8 @@ void Write32(const u32 _Value, const u32 _Address)
break; break;
case AI_SAMPLE_COUNTER: case AI_SAMPLE_COUNTER:
_dbg_assert_msg_(AUDIO_INTERFACE,0,"AudioInterface - m_SampleCounter is Read only"); // _dbg_assert_msg_(AUDIO_INTERFACE, 0, "AudioInterface - m_SampleCounter is Read only");
g_AudioRegister.m_SampleCounter = _Value;
break; break;
case AI_INTERRUPT_TIMING: case AI_INTERRUPT_TIMING:
@ -229,7 +239,7 @@ void GenerateAudioInterrupt()
UpdateInterrupts(); UpdateInterrupts();
} }
// Callback for the DSP streaming // Callback for the disc streaming
// WARNING - called from audio thread // WARNING - called from audio thread
unsigned __int32 Callback_GetStreaming(short* _pDestBuffer, unsigned __int32 _numSamples) unsigned __int32 Callback_GetStreaming(short* _pDestBuffer, unsigned __int32 _numSamples)
{ {
@ -240,9 +250,9 @@ unsigned __int32 Callback_GetStreaming(short* _pDestBuffer, unsigned __int32 _nu
const int lvolume = g_AudioRegister.m_Volume.leftVolume; const int lvolume = g_AudioRegister.m_Volume.leftVolume;
const int rvolume = g_AudioRegister.m_Volume.rightVolume; const int rvolume = g_AudioRegister.m_Volume.rightVolume;
for (unsigned int i=0; i<_numSamples; i++) for (unsigned int i = 0; i < _numSamples; i++)
{ {
if (pos==0) if (pos == 0)
{ {
ReadStreamBlock(pcm); ReadStreamBlock(pcm);
} }
@ -253,13 +263,13 @@ unsigned __int32 Callback_GetStreaming(short* _pDestBuffer, unsigned __int32 _nu
pos++; pos++;
if (pos == 28) if (pos == 28)
{ {
pos=0; pos = 0;
} }
} }
} }
else else
{ {
for (unsigned int i=0; i<_numSamples*2; i++) for (unsigned int i = 0; i < _numSamples * 2; i++)
{ {
_pDestBuffer[i] = 0; //silence! _pDestBuffer[i] = 0; //silence!
} }
@ -269,7 +279,7 @@ unsigned __int32 Callback_GetStreaming(short* _pDestBuffer, unsigned __int32 _nu
} }
// WARNING - called from audio thread // WARNING - called from audio thread
void ReadStreamBlock(short* _pPCM) void ReadStreamBlock(short *_pPCM)
{ {
char tempADPCM[32]; char tempADPCM[32];
if (DVDInterface::DVDReadADPCM((u8*)tempADPCM, 32)) if (DVDInterface::DVDReadADPCM((u8*)tempADPCM, 32))
@ -289,6 +299,7 @@ void ReadStreamBlock(short* _pPCM)
// our whole streaming code is "faked" ... so it shouldn't increase the sample counter // our whole streaming code is "faked" ... so it shouldn't increase the sample counter
// streaming will never work correctly this way, but at least the program will think all is alright. // streaming will never work correctly this way, but at least the program will think all is alright.
// This call must not be done wihout going through CoreTiming's threadsafe option.
// IncreaseSampleCount(28); // IncreaseSampleCount(28);
} }
@ -298,7 +309,7 @@ void IncreaseSampleCount(const u32 _iAmount)
{ {
g_AudioRegister.m_SampleCounter += _iAmount; g_AudioRegister.m_SampleCounter += _iAmount;
if (g_AudioRegister.m_Control.AIINTVLD && if (g_AudioRegister.m_Control.AIINTVLD &&
(g_AudioRegister.m_SampleCounter > g_AudioRegister.m_InterruptTiming)) (g_AudioRegister.m_SampleCounter >= g_AudioRegister.m_InterruptTiming))
{ {
GenerateAudioInterrupt(); GenerateAudioInterrupt();
} }

View File

@ -14,6 +14,9 @@
// Official SVN repository and contact information can be found at // Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/ // http://code.google.com/p/dolphin-emu/
// See CPP file for comments.
#ifndef _AUDIOINTERFACE_H #ifndef _AUDIOINTERFACE_H
#define _AUDIOINTERFACE_H #define _AUDIOINTERFACE_H

View File

@ -15,6 +15,22 @@
// Official SVN repository and contact information can be found at // Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/ // http://code.google.com/p/dolphin-emu/
// AID / AUDIO_DMA controls pushing audio out to the SRC and then the speakers.
// The audio DMA pushes audio through a small FIFO 32 bytes at a time, as needed.
// Since the SRC behind the fifo eats stereo 16-bit data at a sample rate of 32khz,
// that is, 4 bytes at 32 khz, which is 32 bytes at 4 khz. We should thus schedule an
// event that runs at 4khz, that eats audio from the fifo, and all the rest will follow.
// Then we will have homebrew audio.
// The AID interrupt is set when the fifo STARTS a transfer. It latches address and count
// into internal registers and starts copying. This means that the interrupt handler can simply
// set the registers to where the next buffer is, and start filling it. When the DMA is complete,
// it will automatically relatch and fire a new interrupt.
// Then there's the DSP... what likely happens is that the fifo-latched-interrupt handler
// kicks off the DSP, requesting it to fill up the just used buffer through the AXList (or
// whatever it might be called in Nintendo games).
#include "DSP.h" #include "DSP.h"
#include "../CoreTiming.h" #include "../CoreTiming.h"
@ -80,8 +96,8 @@ union UDSPControl
unsigned DSPAssertInt : 1; unsigned DSPAssertInt : 1;
unsigned DSPHalt : 1; unsigned DSPHalt : 1;
unsigned AI : 1; unsigned AID : 1;
unsigned AI_mask : 1; unsigned AID_mask : 1;
unsigned ARAM : 1; unsigned ARAM : 1;
unsigned ARAM_mask : 1; unsigned ARAM_mask : 1;
unsigned DSP : 1; unsigned DSP : 1;
@ -107,14 +123,14 @@ struct DSPState
} }
}; };
// UDSPControl // Blocks are 32 bytes.
union UAudioDMAControl union UAudioDMAControl
{ {
u16 Hex; u16 Hex;
struct struct
{ {
unsigned NumSamples : 15; unsigned NumBlocks : 15;
unsigned Enabled : 1; unsigned Enabled : 1;
}; };
UAudioDMAControl(u16 _Hex = 0) : Hex(_Hex) UAudioDMAControl(u16 _Hex = 0) : Hex(_Hex)
@ -125,8 +141,9 @@ union UAudioDMAControl
struct AudioDMA struct AudioDMA
{ {
u32 SourceAddress; u32 SourceAddress;
u32 ReadAddress;
UAudioDMAControl AudioDMAControl; UAudioDMAControl AudioDMAControl;
u32 SamplesLeft; int BlocksLeft;
}; };
// ARDMA // ARDMA
@ -162,6 +179,11 @@ void WriteARAM(u8 _iValue, u32 _iAddress);
bool Update_DSP_ReadRegister(); bool Update_DSP_ReadRegister();
void Update_DSP_WriteRegister(); void Update_DSP_WriteRegister();
int GetDSPSampleRate()
{
return 32000; // TODO - can also be 48000
}
void Init() void Init()
{ {
g_ARAM = (u8 *)AllocateMemoryPages(ARAM_SIZE); g_ARAM = (u8 *)AllocateMemoryPages(ARAM_SIZE);
@ -236,7 +258,8 @@ void Read16(u16& _uReturnValue, const u32 _iAddress)
// DMA_REGS 0x5030+ // DMA_REGS 0x5030+
// ================================================================================== // ==================================================================================
case AUDIO_DMA_BYTES_LEFT: case AUDIO_DMA_BYTES_LEFT:
_uReturnValue = g_audioDMA.SamplesLeft; // Hmm. Would be stupid to ask for bytes left. Assume it wants blocks left.
_uReturnValue = g_audioDMA.BlocksLeft;
return; return;
case AUDIO_DMA_START_LO: case AUDIO_DMA_START_LO:
@ -305,12 +328,12 @@ void Write16(const u16 _Value, const u32 _Address)
g_dspState.DSPControl.DSPInit = tmpControl.DSPInit; g_dspState.DSPControl.DSPInit = tmpControl.DSPInit;
// Interrupt (mask) // Interrupt (mask)
g_dspState.DSPControl.AI_mask = tmpControl.AI_mask; g_dspState.DSPControl.AID_mask = tmpControl.AID_mask;
g_dspState.DSPControl.ARAM_mask = tmpControl.ARAM_mask; g_dspState.DSPControl.ARAM_mask = tmpControl.ARAM_mask;
g_dspState.DSPControl.DSP_mask = tmpControl.DSP_mask; g_dspState.DSPControl.DSP_mask = tmpControl.DSP_mask;
// Interrupt // Interrupt
if (tmpControl.AI) g_dspState.DSPControl.AI = 0; if (tmpControl.AID) g_dspState.DSPControl.AID = 0;
if (tmpControl.ARAM) g_dspState.DSPControl.ARAM = 0; if (tmpControl.ARAM) g_dspState.DSPControl.ARAM = 0;
if (tmpControl.DSP) g_dspState.DSPControl.DSP = 0; if (tmpControl.DSP) g_dspState.DSPControl.DSP = 0;
@ -332,6 +355,7 @@ void Write16(const u16 _Value, const u32 _Address)
// ================================================================================== // ==================================================================================
// AR_REGS 0x501x+ // AR_REGS 0x501x+
// DMA back and forth between ARAM and RAM
// ================================================================================== // ==================================================================================
case 0x5012: case 0x5012:
@ -369,6 +393,7 @@ void Write16(const u16 _Value, const u32 _Address)
// ================================================================================== // ==================================================================================
// Audio DMA_REGS 0x5030+ // Audio DMA_REGS 0x5030+
// This is the DMA that goes straight out the speaker.
// ================================================================================== // ==================================================================================
case AUDIO_DMA_START_HI: case AUDIO_DMA_START_HI:
g_audioDMA.SourceAddress = (g_audioDMA.SourceAddress & 0xFFFF) | (_Value<<16); g_audioDMA.SourceAddress = (g_audioDMA.SourceAddress & 0xFFFF) | (_Value<<16);
@ -379,16 +404,20 @@ void Write16(const u16 _Value, const u32 _Address)
break; break;
case AUDIO_DMA_CONTROL_LEN: // called by AIStartDMA() case AUDIO_DMA_CONTROL_LEN: // called by AIStartDMA()
g_audioDMA.AudioDMAControl.Hex = _Value;
g_audioDMA.SamplesLeft = g_audioDMA.AudioDMAControl.NumSamples;
if (g_audioDMA.AudioDMAControl.Enabled)
{ {
PluginDSP::DSP_SendAIBuffer(g_audioDMA.SourceAddress, g_audioDMA.AudioDMAControl.NumSamples); UAudioDMAControl old_control = g_audioDMA.AudioDMAControl;
g_audioDMA.SamplesLeft = 0; g_audioDMA.AudioDMAControl.Hex = _Value;
if (!old_control.Enabled && g_audioDMA.AudioDMAControl.Enabled)
{
// Enabled bit was flipped to true, let's latch address & length and call the interrupt.
g_audioDMA.BlocksLeft = g_audioDMA.AudioDMAControl.NumBlocks;
g_audioDMA.ReadAddress = g_audioDMA.SourceAddress;
GenerateDSPInterrupt(DSP::INT_AID);
LOG(DSP, "AID DMA started - source address %08x, length %i blocks", g_audioDMA.SourceAddress, g_audioDMA.AudioDMAControl.NumBlocks);
} }
break; break;
}
case AUDIO_DMA_BYTES_LEFT: case AUDIO_DMA_BYTES_LEFT:
_dbg_assert_(DSPINTERFACE,0); _dbg_assert_(DSPINTERFACE,0);
break; break;
@ -399,6 +428,25 @@ void Write16(const u16 _Value, const u32 _Address)
} }
} }
// This happens at 4 khz, since 32 bytes at 4khz = 4 bytes at 32 khz (16bit stereo pcm)
void UpdateAudioDMA()
{
if (g_audioDMA.AudioDMAControl.Enabled && g_audioDMA.BlocksLeft) {
// TODO : Read audio at g_audioDMA.ReadAddress in RAM and push onto an external audio fifo in the emulator,
// to be mixed with the disc streaming output. If that audio queue fills up, we have to delay the emulator.
g_audioDMA.ReadAddress += 32;
g_audioDMA.BlocksLeft--;
if (!g_audioDMA.BlocksLeft) {
// No need to turn off the DMA - we can only get here if we had blocks left when we
// entered this function, and no longer have any.
// Latch new parameters
g_audioDMA.BlocksLeft = g_audioDMA.AudioDMAControl.NumBlocks;
g_audioDMA.ReadAddress = g_audioDMA.SourceAddress;
GenerateDSPInterrupt(DSP::INT_AID);
}
}
}
void Read32(u32& _uReturnValue, const u32 _iAddress) void Read32(u32& _uReturnValue, const u32 _iAddress)
{ {
LOG(DSPINTERFACE, "DSPInterface(r) 0x%08x", _iAddress); LOG(DSPINTERFACE, "DSPInterface(r) 0x%08x", _iAddress);
@ -450,7 +498,7 @@ void Write32(const u32 _iValue, const u32 _iAddress)
// //
void UpdateInterrupts() void UpdateInterrupts()
{ {
if ((g_dspState.DSPControl.AI & g_dspState.DSPControl.AI_mask) || if ((g_dspState.DSPControl.AID & g_dspState.DSPControl.AID_mask) ||
(g_dspState.DSPControl.ARAM & g_dspState.DSPControl.ARAM_mask) || (g_dspState.DSPControl.ARAM & g_dspState.DSPControl.ARAM_mask) ||
(g_dspState.DSPControl.DSP & g_dspState.DSPControl.DSP_mask)) (g_dspState.DSPControl.DSP & g_dspState.DSPControl.DSP_mask))
{ {
@ -468,7 +516,7 @@ void GenerateDSPInterrupt(DSPInterruptType type, bool _bSet)
{ {
case INT_DSP: g_dspState.DSPControl.DSP = _bSet ? 1 : 0; break; case INT_DSP: g_dspState.DSPControl.DSP = _bSet ? 1 : 0; break;
case INT_ARAM: g_dspState.DSPControl.ARAM = _bSet ? 1 : 0; break; case INT_ARAM: g_dspState.DSPControl.ARAM = _bSet ? 1 : 0; break;
case INT_AI: g_dspState.DSPControl.AI = _bSet ? 1 : 0; break; case INT_AID: g_dspState.DSPControl.AID = _bSet ? 1 : 0; break;
} }
UpdateInterrupts(); UpdateInterrupts();
@ -504,7 +552,7 @@ void Update_ARAM_DMA()
u32 iARAMAddress = g_arDMA.ARAddr; u32 iARAMAddress = g_arDMA.ARAddr;
// TODO(??): sanity check instead of writing bogus data? // TODO(??): sanity check instead of writing bogus data?
for (u32 i=0; i<g_arDMA.Cnt.count; i++) for (u32 i = 0; i < g_arDMA.Cnt.count; i++)
{ {
u32 tmp = (iARAMAddress < ARAM_SIZE) ? g_ARAM[iARAMAddress] : 0x05050505; u32 tmp = (iARAMAddress < ARAM_SIZE) ? g_ARAM[iARAMAddress] : 0x05050505;
Memory::Write_U8(tmp, iMemAddress); Memory::Write_U8(tmp, iMemAddress);
@ -520,7 +568,7 @@ void Update_ARAM_DMA()
//write to g_ARAM //write to g_ARAM
LOG(DSPINTERFACE,"g_ARAM DMA write %08x bytes from %08x to Aram: %08x",g_arDMA.Cnt.count, g_arDMA.MMAddr, g_arDMA.ARAddr); LOG(DSPINTERFACE,"g_ARAM DMA write %08x bytes from %08x to Aram: %08x",g_arDMA.Cnt.count, g_arDMA.MMAddr, g_arDMA.ARAddr);
for (u32 i=0; i<g_arDMA.Cnt.count; i++) for (u32 i = 0; i < g_arDMA.Cnt.count; i++)
{ {
if (iARAMAddress < ARAM_SIZE) if (iARAMAddress < ARAM_SIZE)
g_ARAM[iARAMAddress] = Memory::Read_U8(iMemAddress); g_ARAM[iARAMAddress] = Memory::Read_U8(iMemAddress);

View File

@ -27,7 +27,7 @@ enum DSPInterruptType
{ {
INT_DSP = 0, INT_DSP = 0,
INT_ARAM = 1, INT_ARAM = 1,
INT_AI = 2 INT_AID = 2
}; };
void Init(); void Init();
@ -49,8 +49,8 @@ u8 ReadARAM(const u32 _uAddress);
// Debugger Helper // Debugger Helper
u8* GetARAMPtr(); u8* GetARAMPtr();
void UpdateAudioDMA(); void UpdateAudioDMA();
int GetDSPSampleRate();
}// end of namespace DSP }// end of namespace DSP

View File

@ -47,6 +47,10 @@ void Init()
ResetGatherPipe(); ResetGatherPipe();
} }
bool IsEmpty() {
return m_gatherPipeCount == 0;
}
void ResetGatherPipe() void ResetGatherPipe()
{ {
m_gatherPipeCount = 0; m_gatherPipeCount = 0;

View File

@ -40,6 +40,8 @@ void Init();
void ResetGatherPipe(); void ResetGatherPipe();
void CheckGatherPipe(); void CheckGatherPipe();
bool IsEmpty();
// Write // Write
void HWCALL Write8(const u8 _iValue, const u32 _iAddress); void HWCALL Write8(const u8 _iValue, const u32 _iAddress);
void HWCALL Write16(const u16 _iValue, const u32 _iAddress); void HWCALL Write16(const u16 _iValue, const u32 _iAddress);

View File

@ -54,13 +54,22 @@ int
// VideoInterface::Update is stupid! // VideoInterface::Update is stupid!
VI_PERIOD = GetTicksPerSecond() / (60*120), VI_PERIOD = GetTicksPerSecond() / (60*120),
// TODO: The SI interfact actually has a register that determines the polling frequency.
// We should obey that instead of arbitrarly checking at 60fps.
SI_PERIOD = GetTicksPerSecond() / 60, //once a frame is good for controllers SI_PERIOD = GetTicksPerSecond() / 60, //once a frame is good for controllers
// These are the big question marks IMHO :) // These are the big question marks IMHO :)
// This one should simply be determined by the increasing counter in AI.
AI_PERIOD = GetTicksPerSecond() / 80, AI_PERIOD = GetTicksPerSecond() / 80,
// These shouldn't be period controlled either, most likely.
DSP_PERIOD = GetTicksPerSecond() / 250, DSP_PERIOD = GetTicksPerSecond() / 250,
DSPINT_PERIOD = GetTicksPerSecond() / 230,
// This is completely arbitrary. If we find that we need lower latency, we can just
// increase this number.
HLE_IPC_PERIOD = GetTicksPerSecond() / 250, HLE_IPC_PERIOD = GetTicksPerSecond() / 250,
// This one is also fairly arbitrary. Every N cycles, run the GPU until it starves (in single core mode only).
GPU_PERIOD = 10000; GPU_PERIOD = 10000;
u32 GetTicksPerSecond() u32 GetTicksPerSecond()
@ -75,10 +84,28 @@ u32 ConvertMillisecondsToTicks(u32 _Milliseconds)
void AICallback(u64 userdata, int cyclesLate) void AICallback(u64 userdata, int cyclesLate)
{ {
// Update disk streaming. All that code really needs a revamp, including replacing the codec with the one
// from in_cube.
AudioInterface::Update(); AudioInterface::Update();
CoreTiming::ScheduleEvent(AI_PERIOD-cyclesLate, &AICallback, "AICallback"); CoreTiming::ScheduleEvent(AI_PERIOD-cyclesLate, &AICallback, "AICallback");
} }
void DSPCallback(u64 userdata, int cyclesLate)
{
// Poke the DSP, make it do stuff. This should eventually be replaced with dsp->RunCycles(1000) or whatever,
// ~1/6th as many cycles as the period PPC-side.
PluginDSP::DSP_Update();
CoreTiming::ScheduleEvent(DSP_PERIOD-cyclesLate, &DSPCallback, "DSPCallback");
}
void AudioFifoCallback(u64 userdata, int cyclesLate)
{
int period = CPU_CORE_CLOCK / (DSP::GetDSPSampleRate() * 4 / 32);
DSP::UpdateAudioDMA(); // Push audio to speakers.
CoreTiming::ScheduleEvent(period - cyclesLate, &AudioFifoCallback, "AudioFifoCallback");
}
void IPC_HLE_UpdateCallback(u64 userdata, int cyclesLate) void IPC_HLE_UpdateCallback(u64 userdata, int cyclesLate)
{ {
WII_IPC_HLE_Interface::Update(); WII_IPC_HLE_Interface::Update();
@ -100,18 +127,6 @@ void SICallback(u64 userdata, int cyclesLate)
CoreTiming::ScheduleEvent(SI_PERIOD-cyclesLate, &SICallback, "SICallback"); CoreTiming::ScheduleEvent(SI_PERIOD-cyclesLate, &SICallback, "SICallback");
} }
void DSPCallback(u64 userdata, int cyclesLate)
{
PluginDSP::DSP_Update();
CoreTiming::ScheduleEvent(DSP_PERIOD-cyclesLate, &DSPCallback, "DSPCallback");
}
void DSPInterruptCallback(u64 userdata, int cyclesLate)
{
DSP::GenerateDSPInterrupt(DSP::INT_AI);
CoreTiming::ScheduleEvent(DSPINT_PERIOD-cyclesLate, &DSPInterruptCallback, "DSPInterruptCallback");
}
void DecrementerCallback(u64 userdata, int cyclesLate) void DecrementerCallback(u64 userdata, int cyclesLate)
{ {
//Why is fakeDec too big here? //Why is fakeDec too big here?
@ -122,7 +137,6 @@ void DecrementerCallback(u64 userdata, int cyclesLate)
void DecrementerSet() void DecrementerSet()
{ {
// MessageBox(0, "dec set",0,0);
u32 decValue = PowerPC::ppcState.spr[SPR_DEC]; u32 decValue = PowerPC::ppcState.spr[SPR_DEC];
fakeDec = decValue*TIMER_RATIO; fakeDec = decValue*TIMER_RATIO;
CoreTiming::RemoveEvent(DecrementerCallback); CoreTiming::RemoveEvent(DecrementerCallback);
@ -131,10 +145,7 @@ void DecrementerSet()
void AdvanceCallback(int cyclesExecuted) void AdvanceCallback(int cyclesExecuted)
{ {
//int oldFakeDec = fakeDec;
fakeDec -= cyclesExecuted; fakeDec -= cyclesExecuted;
//if (fakeDec < 0 && oldFakeDec > 0)
// fakeDec = TIMER_RATIO;
u64 timebase_ticks = CoreTiming::GetTicks() / TIMER_RATIO; //works since we are little endian and TL comes first :) u64 timebase_ticks = CoreTiming::GetTicks() / TIMER_RATIO; //works since we are little endian and TL comes first :)
*(u64*)&TL = timebase_ticks; *(u64*)&TL = timebase_ticks;
if (fakeDec >= 0) if (fakeDec >= 0)
@ -185,26 +196,24 @@ void Init()
if (Core::GetStartupParameter().bWii) if (Core::GetStartupParameter().bWii)
{ {
CPU_CORE_CLOCK = 721000000; CPU_CORE_CLOCK = 721000000;
VI_PERIOD = GetTicksPerSecond() / (60*120), VI_PERIOD = GetTicksPerSecond() / (60*120);
SI_PERIOD = GetTicksPerSecond() / 60, //once a frame is good for controllers SI_PERIOD = GetTicksPerSecond() / 60; // once a frame is good for controllers
// These are the big question marks IMHO :) // These are the big question marks IMHO :)
AI_PERIOD = GetTicksPerSecond() / 80, AI_PERIOD = GetTicksPerSecond() / 80;
DSP_PERIOD = (int)(GetTicksPerSecond() * 0.003f), DSP_PERIOD = (int)(GetTicksPerSecond() * 0.003f);
DSPINT_PERIOD = (int)(GetTicksPerSecond() * 0.003f);
HLE_IPC_PERIOD = (int)(GetTicksPerSecond() * 0.003f); HLE_IPC_PERIOD = (int)(GetTicksPerSecond() * 0.003f);
} }
else else
{ {
CPU_CORE_CLOCK = 486000000; CPU_CORE_CLOCK = 486000000;
VI_PERIOD = GetTicksPerSecond() / (60*120), VI_PERIOD = GetTicksPerSecond() / (60*120);
SI_PERIOD = GetTicksPerSecond() / 60, //once a frame is good for controllers SI_PERIOD = GetTicksPerSecond() / 60; // once a frame is good for controllers
// These are the big question marks IMHO :) // These are the big question marks IMHO :)
AI_PERIOD = GetTicksPerSecond() / 80, AI_PERIOD = GetTicksPerSecond() / 80;
DSP_PERIOD = (int)(GetTicksPerSecond() * 0.005f), DSP_PERIOD = (int)(GetTicksPerSecond() * 0.005f);
DSPINT_PERIOD = (int)(GetTicksPerSecond() *0.005f);
} }
Common::Timer::IncreaseResolution(); Common::Timer::IncreaseResolution();
memset(timeHistory, 0, sizeof(timeHistory)); memset(timeHistory, 0, sizeof(timeHistory));
@ -216,7 +225,7 @@ void Init()
CoreTiming::ScheduleEvent(VI_PERIOD, &VICallback, "VICallback"); CoreTiming::ScheduleEvent(VI_PERIOD, &VICallback, "VICallback");
CoreTiming::ScheduleEvent(DSP_PERIOD, &DSPCallback, "DSPCallback"); CoreTiming::ScheduleEvent(DSP_PERIOD, &DSPCallback, "DSPCallback");
CoreTiming::ScheduleEvent(SI_PERIOD, &SICallback, "SICallback"); CoreTiming::ScheduleEvent(SI_PERIOD, &SICallback, "SICallback");
CoreTiming::ScheduleEvent(DSPINT_PERIOD, &DSPInterruptCallback, "DSPInterruptCallback"); CoreTiming::ScheduleEvent(CPU_CORE_CLOCK / (32000 * 4 / 32), &AudioFifoCallback, "AudioFifoCallback");
if (!Core::GetStartupParameter().bUseDualCore) if (!Core::GetStartupParameter().bUseDualCore)
CoreTiming::ScheduleEvent(GPU_PERIOD, &RunGPUCallback, "RunGPUCallback"); CoreTiming::ScheduleEvent(GPU_PERIOD, &RunGPUCallback, "RunGPUCallback");

View File

@ -234,11 +234,11 @@ void CInterpreter::mftb(UGeckoInstruction _inst)
void CInterpreter::mfspr(UGeckoInstruction _inst) void CInterpreter::mfspr(UGeckoInstruction _inst)
{ {
u32 iIndex = ((_inst.SPR & 0x1F) << 5) + ((_inst.SPR >> 5)&0x1F); u32 iIndex = ((_inst.SPR & 0x1F) << 5) + ((_inst.SPR >> 5) & 0x1F);
//TODO - check processor privilege level - many of these require privilege //TODO - check processor privilege level - many of these require privilege
//XER LR CTR are the only ones available in user mode, time base can be read too. //XER LR CTR are the only ones available in user mode, time base can be read too.
//Not that gamecube games usually run user mode, but hey.... //Gamecube games always run in superuser mode, but hey....
switch (iIndex) switch (iIndex)
{ {
@ -247,11 +247,8 @@ void CInterpreter::mfspr(UGeckoInstruction _inst)
// break; // break;
case SPR_WPAR: case SPR_WPAR:
{ {
//There's supposed to be a bit here that indicates whether there is any data in the wp // If wpar_empty ever is false, Paper Mario hangs. Strange.
//(or if it's full, not sure) bool wpar_empty = true; //GPFifo::IsEmpty();
//MessageBox(NULL, "Read from SPR_WPAR", "????", MB_OK);
//Paper Mario reads here, this should be investigated ... TODO(ector)
bool wpar_empty = true;
if (!wpar_empty) if (!wpar_empty)
rSPR(iIndex) |= 1; // BNE = buffer not empty rSPR(iIndex) |= 1; // BNE = buffer not empty
else else
@ -268,9 +265,9 @@ void CInterpreter::mtspr(UGeckoInstruction _inst)
u32 oldValue = rSPR(iIndex); u32 oldValue = rSPR(iIndex);
rSPR(iIndex) = m_GPR[_inst.RD]; rSPR(iIndex) = m_GPR[_inst.RD];
//TODO(ector) - check processor privilege level - many of these require privilege //TODO - check processor privilege level - many of these require privilege
//XER LR CTR are the only ones available in user mode //XER LR CTR are the only ones available in user mode, time base can be read too.
//Not that gamecube games usually run user mode, but hey.... //Gamecube games always run in superuser mode, but hey....
//Our DMA emulation is highly inaccurate - instead of properly emulating the queue //Our DMA emulation is highly inaccurate - instead of properly emulating the queue
//and so on, we simply make all DMA:s complete instantaneously. //and so on, we simply make all DMA:s complete instantaneously.
@ -306,7 +303,6 @@ void CInterpreter::mtspr(UGeckoInstruction _inst)
//TODO(ector): Protect LC memory if LCE is false. //TODO(ector): Protect LC memory if LCE is false.
//TODO(ector): Honor PSE. //TODO(ector): Honor PSE.
//
//_assert_msg_(GEKKO, WriteGatherPipeEnable, "Write gather pipe not enabled!"); //_assert_msg_(GEKKO, WriteGatherPipeEnable, "Write gather pipe not enabled!");
//if ((HID2.PSE == 0)) //if ((HID2.PSE == 0))
// MessageBox(NULL, "PSE in HID2 is set", "Warning", MB_OK); // MessageBox(NULL, "PSE in HID2 is set", "Warning", MB_OK);

View File

@ -77,7 +77,9 @@ namespace Jit64
int d = inst.RD; int d = inst.RD;
switch (iIndex) switch (iIndex)
{ {
case SPR_WPAR:
Default(inst);
return;
// case SPR_DEC: // case SPR_DEC:
//MessageBox(NULL, "Read from DEC", "????", MB_OK); //MessageBox(NULL, "Read from DEC", "????", MB_OK);
//break; //break;

View File

@ -1048,6 +1048,10 @@
RelativePath=".\Src\Render.h" RelativePath=".\Src\Render.h"
> >
</File> </File>
<File
RelativePath=".\Src\SConscript"
>
</File>
<File <File
RelativePath=".\Src\XFB.cpp" RelativePath=".\Src\XFB.cpp"
> >

View File

@ -15,6 +15,13 @@
// Official SVN repository and contact information can be found at // Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/ // http://code.google.com/p/dolphin-emu/
#include <wx/wx.h>
#include <wx/filepicker.h>
#include <wx/notebook.h>
#include <wx/dialog.h>
#include <wx/aboutdlg.h>
#include "Globals.h" #include "Globals.h"
#include "pluginspecs_video.h" #include "pluginspecs_video.h"

View File

@ -19,12 +19,6 @@
#ifndef _GLOBALS_H #ifndef _GLOBALS_H
#define _GLOBALS_H #define _GLOBALS_H
#include <wx/wx.h>
#include <wx/filepicker.h>
#include <wx/notebook.h>
#include <wx/dialog.h>
#include <wx/aboutdlg.h>
#define LOGGING #define LOGGING
#include "Common.h" #include "Common.h"
@ -32,13 +26,6 @@
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
void OpenConsole();
void CloseConsole();
#define GLEW_STATIC #define GLEW_STATIC
#include "GLew/glew.h" #include "GLew/glew.h"
@ -97,16 +84,8 @@ struct RECT
#define GL_DEPTH24_STENCIL8_EXT 0x88F0 #define GL_DEPTH24_STENCIL8_EXT 0x88F0
#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 #define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1
#endif #endif
extern float MValue;
// several macros
// PLEASE DO NOT USE THE FOLLOWING SAFE*
// They only encourage sloppy coding, and hide bugs.
#define SAFE_RELEASE_CGPROG(x) { if( (x) != NULL ) { cgDestroyProgram(x); x = NULL; } }
#define SAFE_RELEASE_PROG(x) { if( (x) != 0 ) { glDeleteProgramsARB(1, &(x)); x = 0; } }
#define SAFE_RELEASE_TEX(x) { if( (x) != 0 ) { glDeleteTextures(1, &(x)); x = 0; } }
#define SAFE_RELEASE_BUF(x) { if( (x) != 0 ) { glDeleteBuffers(1, &(x)); x = 0; } }
#define FORIT(it, v) for(it = (v).begin(); it != (v).end(); ++(it)) extern float MValue;
#define ERROR_LOG __Log #define ERROR_LOG __Log

View File

@ -18,11 +18,20 @@
#include <windows.h> #include <windows.h>
#include <wx/wx.h>
#include <wx/filepicker.h>
#include <wx/notebook.h>
#include <wx/dialog.h>
#include <wx/aboutdlg.h>
#include "../Globals.h" #include "../Globals.h"
#include "../../Core/Src/Core.h" #include "../../Core/Src/Core.h"
#include "Win32.h" #include "Win32.h"
void OpenConsole();
void CloseConsole();
HINSTANCE g_hInstance; HINSTANCE g_hInstance;
class wxDLLApp : public wxApp class wxDLLApp : public wxApp

View File

@ -94,16 +94,17 @@ void PixelShaderMngr::Init()
GL_REPORT_ERROR(); GL_REPORT_ERROR();
if( err != GL_NO_ERROR ) { if( err != GL_NO_ERROR ) {
ERROR_LOG("Failed to create color matrix fragment program\n"); ERROR_LOG("Failed to create color matrix fragment program\n");
glDeleteProgramsARB(1, &s_ColorMatrixProgram);
SAFE_RELEASE_PROG(s_ColorMatrixProgram); s_ColorMatrixProgram = 0;
} }
} }
void PixelShaderMngr::Shutdown() void PixelShaderMngr::Shutdown()
{ {
SAFE_RELEASE_PROG(s_ColorMatrixProgram); glDeleteProgramsARB(1, &s_ColorMatrixProgram);
s_ColorMatrixProgram = 0;
PSCache::iterator iter = pshaders.begin(); PSCache::iterator iter = pshaders.begin();
for (;iter!=pshaders.end();iter++) for (; iter != pshaders.end(); iter++)
iter->second.Destroy(); iter->second.Destroy();
pshaders.clear(); pshaders.clear();
} }

View File

@ -80,14 +80,15 @@ void TextureMngr::TCacheEntry::SetTextureParameters(TexMode0& newmode)
void TextureMngr::TCacheEntry::Destroy() void TextureMngr::TCacheEntry::Destroy()
{ {
SAFE_RELEASE_TEX(texture); glDeleteTextures(1, &texture);
texture = 0;
} }
void TextureMngr::Init() void TextureMngr::Init()
{ {
temp = (u8*)AllocateMemoryPages(TEMP_SIZE); temp = (u8*)AllocateMemoryPages(TEMP_SIZE);
nTex2DEnabled = nTexRECTEnabled = 0; nTex2DEnabled = nTexRECTEnabled = 0;
TexDecoder_SetTexFmtOverlayOptions(g_Config.bTexFmtOverlayEnable,g_Config.bTexFmtOverlayCenter); TexDecoder_SetTexFmtOverlayOptions(g_Config.bTexFmtOverlayEnable, g_Config.bTexFmtOverlayCenter);
} }
void TextureMngr::Invalidate() void TextureMngr::Invalidate()
@ -96,7 +97,7 @@ void TextureMngr::Invalidate()
for (;iter!=textures.end();iter++) for (;iter!=textures.end();iter++)
iter->second.Destroy(); iter->second.Destroy();
textures.clear(); textures.clear();
TexDecoder_SetTexFmtOverlayOptions(g_Config.bTexFmtOverlayEnable,g_Config.bTexFmtOverlayCenter); TexDecoder_SetTexFmtOverlayOptions(g_Config.bTexFmtOverlayEnable, g_Config.bTexFmtOverlayCenter);
} }
void TextureMngr::Shutdown() void TextureMngr::Shutdown()

View File

@ -1087,7 +1087,7 @@ void VertexManager::Flush()
int offset = 0; int offset = 0;
vector< pair<int, int> >::iterator it; vector< pair<int, int> >::iterator it;
FORIT (it, s_vStoredPrimitives) { for (it = s_vStoredPrimitives.begin(); it != s_vStoredPrimitives.end(); ++it) {
glDrawArrays(it->first, offset, it->second); glDrawArrays(it->first, offset, it->second);
offset += it->second; offset += it->second;
} }