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:
parent
7962ab4713
commit
dcd5ffeb7a
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,10 @@ void Init()
|
||||||
ResetGatherPipe();
|
ResetGatherPipe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsEmpty() {
|
||||||
|
return m_gatherPipeCount == 0;
|
||||||
|
}
|
||||||
|
|
||||||
void ResetGatherPipe()
|
void ResetGatherPipe()
|
||||||
{
|
{
|
||||||
m_gatherPipeCount = 0;
|
m_gatherPipeCount = 0;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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"
|
||||||
>
|
>
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue