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
// 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 "StreamADPCM.H"
@ -125,13 +132,15 @@ void Read32(u32& _rReturnValue, const u32 _Address)
return;
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);
_rReturnValue = g_AudioRegister.m_InterruptTiming;
return;
default:
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;
return;
}
@ -196,7 +205,8 @@ void Write32(const u32 _Value, const u32 _Address)
break;
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;
case AI_INTERRUPT_TIMING:
@ -229,7 +239,7 @@ void GenerateAudioInterrupt()
UpdateInterrupts();
}
// Callback for the DSP streaming
// Callback for the disc streaming
// WARNING - called from audio thread
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 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);
}
@ -253,13 +263,13 @@ unsigned __int32 Callback_GetStreaming(short* _pDestBuffer, unsigned __int32 _nu
pos++;
if (pos == 28)
{
pos=0;
pos = 0;
}
}
}
else
{
for (unsigned int i=0; i<_numSamples*2; i++)
for (unsigned int i = 0; i < _numSamples * 2; i++)
{
_pDestBuffer[i] = 0; //silence!
}
@ -269,7 +279,7 @@ unsigned __int32 Callback_GetStreaming(short* _pDestBuffer, unsigned __int32 _nu
}
// WARNING - called from audio thread
void ReadStreamBlock(short* _pPCM)
void ReadStreamBlock(short *_pPCM)
{
char 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
// 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);
}
@ -298,7 +309,7 @@ void IncreaseSampleCount(const u32 _iAmount)
{
g_AudioRegister.m_SampleCounter += _iAmount;
if (g_AudioRegister.m_Control.AIINTVLD &&
(g_AudioRegister.m_SampleCounter > g_AudioRegister.m_InterruptTiming))
(g_AudioRegister.m_SampleCounter >= g_AudioRegister.m_InterruptTiming))
{
GenerateAudioInterrupt();
}

View File

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

View File

@ -15,6 +15,22 @@
// Official SVN repository and contact information can be found at
// 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 "../CoreTiming.h"
@ -80,8 +96,8 @@ union UDSPControl
unsigned DSPAssertInt : 1;
unsigned DSPHalt : 1;
unsigned AI : 1;
unsigned AI_mask : 1;
unsigned AID : 1;
unsigned AID_mask : 1;
unsigned ARAM : 1;
unsigned ARAM_mask : 1;
unsigned DSP : 1;
@ -107,14 +123,14 @@ struct DSPState
}
};
// UDSPControl
// Blocks are 32 bytes.
union UAudioDMAControl
{
u16 Hex;
struct
{
unsigned NumSamples : 15;
unsigned Enabled : 1;
unsigned NumBlocks : 15;
unsigned Enabled : 1;
};
UAudioDMAControl(u16 _Hex = 0) : Hex(_Hex)
@ -125,8 +141,9 @@ union UAudioDMAControl
struct AudioDMA
{
u32 SourceAddress;
u32 ReadAddress;
UAudioDMAControl AudioDMAControl;
u32 SamplesLeft;
int BlocksLeft;
};
// ARDMA
@ -162,6 +179,11 @@ void WriteARAM(u8 _iValue, u32 _iAddress);
bool Update_DSP_ReadRegister();
void Update_DSP_WriteRegister();
int GetDSPSampleRate()
{
return 32000; // TODO - can also be 48000
}
void Init()
{
g_ARAM = (u8 *)AllocateMemoryPages(ARAM_SIZE);
@ -236,7 +258,8 @@ void Read16(u16& _uReturnValue, const u32 _iAddress)
// DMA_REGS 0x5030+
// ==================================================================================
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;
case AUDIO_DMA_START_LO:
@ -305,12 +328,12 @@ void Write16(const u16 _Value, const u32 _Address)
g_dspState.DSPControl.DSPInit = tmpControl.DSPInit;
// 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.DSP_mask = tmpControl.DSP_mask;
// 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.DSP) g_dspState.DSPControl.DSP = 0;
@ -332,6 +355,7 @@ void Write16(const u16 _Value, const u32 _Address)
// ==================================================================================
// AR_REGS 0x501x+
// DMA back and forth between ARAM and RAM
// ==================================================================================
case 0x5012:
@ -369,6 +393,7 @@ void Write16(const u16 _Value, const u32 _Address)
// ==================================================================================
// Audio DMA_REGS 0x5030+
// This is the DMA that goes straight out the speaker.
// ==================================================================================
case AUDIO_DMA_START_HI:
g_audioDMA.SourceAddress = (g_audioDMA.SourceAddress & 0xFFFF) | (_Value<<16);
@ -379,16 +404,20 @@ void Write16(const u16 _Value, const u32 _Address)
break;
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);
g_audioDMA.SamplesLeft = 0;
UAudioDMAControl old_control = g_audioDMA.AudioDMAControl;
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;
}
case AUDIO_DMA_BYTES_LEFT:
_dbg_assert_(DSPINTERFACE,0);
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)
{
LOG(DSPINTERFACE, "DSPInterface(r) 0x%08x", _iAddress);
@ -450,7 +498,7 @@ void Write32(const u32 _iValue, const u32 _iAddress)
//
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.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_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();
@ -504,7 +552,7 @@ void Update_ARAM_DMA()
u32 iARAMAddress = g_arDMA.ARAddr;
// 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;
Memory::Write_U8(tmp, iMemAddress);
@ -520,7 +568,7 @@ void Update_ARAM_DMA()
//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);
for (u32 i=0; i<g_arDMA.Cnt.count; i++)
for (u32 i = 0; i < g_arDMA.Cnt.count; i++)
{
if (iARAMAddress < ARAM_SIZE)
g_ARAM[iARAMAddress] = Memory::Read_U8(iMemAddress);

View File

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

View File

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

View File

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

View File

@ -54,13 +54,22 @@ int
// VideoInterface::Update is stupid!
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
// These are the big question marks IMHO :)
// This one should simply be determined by the increasing counter in AI.
AI_PERIOD = GetTicksPerSecond() / 80,
// These shouldn't be period controlled either, most likely.
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,
// This one is also fairly arbitrary. Every N cycles, run the GPU until it starves (in single core mode only).
GPU_PERIOD = 10000;
u32 GetTicksPerSecond()
@ -75,10 +84,28 @@ u32 ConvertMillisecondsToTicks(u32 _Milliseconds)
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();
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)
{
WII_IPC_HLE_Interface::Update();
@ -100,18 +127,6 @@ void SICallback(u64 userdata, int cyclesLate)
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)
{
//Why is fakeDec too big here?
@ -122,7 +137,6 @@ void DecrementerCallback(u64 userdata, int cyclesLate)
void DecrementerSet()
{
// MessageBox(0, "dec set",0,0);
u32 decValue = PowerPC::ppcState.spr[SPR_DEC];
fakeDec = decValue*TIMER_RATIO;
CoreTiming::RemoveEvent(DecrementerCallback);
@ -131,10 +145,7 @@ void DecrementerSet()
void AdvanceCallback(int cyclesExecuted)
{
//int oldFakeDec = fakeDec;
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*)&TL = timebase_ticks;
if (fakeDec >= 0)
@ -185,26 +196,24 @@ void Init()
if (Core::GetStartupParameter().bWii)
{
CPU_CORE_CLOCK = 721000000;
VI_PERIOD = GetTicksPerSecond() / (60*120),
SI_PERIOD = GetTicksPerSecond() / 60, //once a frame is good for controllers
VI_PERIOD = GetTicksPerSecond() / (60*120);
SI_PERIOD = GetTicksPerSecond() / 60; // once a frame is good for controllers
// These are the big question marks IMHO :)
AI_PERIOD = GetTicksPerSecond() / 80,
DSP_PERIOD = (int)(GetTicksPerSecond() * 0.003f),
DSPINT_PERIOD = (int)(GetTicksPerSecond() * 0.003f);
AI_PERIOD = GetTicksPerSecond() / 80;
DSP_PERIOD = (int)(GetTicksPerSecond() * 0.003f);
HLE_IPC_PERIOD = (int)(GetTicksPerSecond() * 0.003f);
}
else
{
CPU_CORE_CLOCK = 486000000;
VI_PERIOD = GetTicksPerSecond() / (60*120),
SI_PERIOD = GetTicksPerSecond() / 60, //once a frame is good for controllers
VI_PERIOD = GetTicksPerSecond() / (60*120);
SI_PERIOD = GetTicksPerSecond() / 60; // once a frame is good for controllers
// These are the big question marks IMHO :)
AI_PERIOD = GetTicksPerSecond() / 80,
DSP_PERIOD = (int)(GetTicksPerSecond() * 0.005f),
DSPINT_PERIOD = (int)(GetTicksPerSecond() *0.005f);
AI_PERIOD = GetTicksPerSecond() / 80;
DSP_PERIOD = (int)(GetTicksPerSecond() * 0.005f);
}
Common::Timer::IncreaseResolution();
memset(timeHistory, 0, sizeof(timeHistory));
@ -216,7 +225,7 @@ void Init()
CoreTiming::ScheduleEvent(VI_PERIOD, &VICallback, "VICallback");
CoreTiming::ScheduleEvent(DSP_PERIOD, &DSPCallback, "DSPCallback");
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)
CoreTiming::ScheduleEvent(GPU_PERIOD, &RunGPUCallback, "RunGPUCallback");

View File

@ -234,11 +234,11 @@ void CInterpreter::mftb(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
//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)
{
@ -247,11 +247,8 @@ void CInterpreter::mfspr(UGeckoInstruction _inst)
// break;
case SPR_WPAR:
{
//There's supposed to be a bit here that indicates whether there is any data in the wp
//(or if it's full, not sure)
//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 ever is false, Paper Mario hangs. Strange.
bool wpar_empty = true; //GPFifo::IsEmpty();
if (!wpar_empty)
rSPR(iIndex) |= 1; // BNE = buffer not empty
else
@ -268,9 +265,9 @@ void CInterpreter::mtspr(UGeckoInstruction _inst)
u32 oldValue = rSPR(iIndex);
rSPR(iIndex) = m_GPR[_inst.RD];
//TODO(ector) - check processor privilege level - many of these require privilege
//XER LR CTR are the only ones available in user mode
//Not that gamecube games usually run user mode, but hey....
//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.
//Gamecube games always run in superuser mode, but hey....
//Our DMA emulation is highly inaccurate - instead of properly emulating the queue
//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): Honor PSE.
//
//_assert_msg_(GEKKO, WriteGatherPipeEnable, "Write gather pipe not enabled!");
//if ((HID2.PSE == 0))
// MessageBox(NULL, "PSE in HID2 is set", "Warning", MB_OK);

View File

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

View File

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

View File

@ -15,6 +15,13 @@
// Official SVN repository and contact information can be found at
// 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 "pluginspecs_video.h"

View File

@ -19,12 +19,6 @@
#ifndef _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
#include "Common.h"
@ -32,13 +26,6 @@
#ifdef _WIN32
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
void OpenConsole();
void CloseConsole();
#define GLEW_STATIC
#include "GLew/glew.h"
@ -97,16 +84,8 @@ struct RECT
#define GL_DEPTH24_STENCIL8_EXT 0x88F0
#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1
#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

View File

@ -18,11 +18,20 @@
#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 "../../Core/Src/Core.h"
#include "Win32.h"
void OpenConsole();
void CloseConsole();
HINSTANCE g_hInstance;
class wxDLLApp : public wxApp

View File

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

View File

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

View File

@ -1087,7 +1087,7 @@ void VertexManager::Flush()
int offset = 0;
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);
offset += it->second;
}