mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2025-03-06 14:27:44 +00:00
- Added function-based interface Audio for OSD sound output, together with SDL implementation
- Added object interface CThread for OSD threading and synchronization, together with SDL implementation - Added multi-threading to CModel3 so that separate CPUs (PPC of main board, 68K of sound board and Z80 of drive board) can be run in separate threads if requested to improve performance on multi-core PCs - Added -multi-threaded command line option (default is to run single-threaded still)
This commit is contained in:
parent
1f73280282
commit
03fa9532eb
|
@ -191,7 +191,6 @@
|
|||
#include <string.h>
|
||||
#include "Supermodel.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
Model 3 Inputs
|
||||
|
||||
|
@ -1226,7 +1225,7 @@ void CModel3::Write16(UINT32 addr, UINT16 data)
|
|||
break;
|
||||
}
|
||||
|
||||
DebugLog("PC=%08X\twrite8 : %08X=%02X\n", ppc_get_pc(), addr, data);
|
||||
DebugLog("PC=%08X\twrite16 : %08X=%04X\n", ppc_get_pc(), addr, data);
|
||||
break;
|
||||
|
||||
// MPC105/106
|
||||
|
@ -1238,7 +1237,7 @@ void CModel3::Write16(UINT32 addr, UINT16 data)
|
|||
|
||||
// Unknown
|
||||
default:
|
||||
DebugLog("PC=%08X\twrite32: %08X=%08X\n", ppc_get_pc(), addr, data);
|
||||
DebugLog("PC=%08X\twrite16: %08X=%04X\n", ppc_get_pc(), addr, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1865,6 +1864,244 @@ void CModel3::ClearNVRAM(void)
|
|||
|
||||
void CModel3::RunFrame(void)
|
||||
{
|
||||
// See if currently running multi-threaded
|
||||
if (multiThreaded)
|
||||
{
|
||||
// If so, check all threads are up and running
|
||||
if (!StartThreads())
|
||||
goto ThreadError;
|
||||
|
||||
// Wake sound board and drive board threads so they can process a frame
|
||||
#ifdef SUPERMODEL_DRIVEBOARD
|
||||
if (!sndBrdThreadSync->Post() || !drvBrdThreadSync->Post())
|
||||
#else
|
||||
if (!sndBrdThreadSync->Post())
|
||||
#endif
|
||||
goto ThreadError;
|
||||
|
||||
// At the same time, process a single frame for main board (PPC) in this thread
|
||||
RunMainBoardFrame();
|
||||
|
||||
// Enter notify wait critical section
|
||||
if (!notifyLock->Lock())
|
||||
goto ThreadError;
|
||||
|
||||
// Wait for sound board and drive board threads to finish their work (if they haven't done so already)
|
||||
#ifdef SUPERMODEL_DRIVEBOARD
|
||||
while (!sndBrdThreadDone || !drvBrdThreadDone)
|
||||
#else
|
||||
while (!sndBrdThreadDone)
|
||||
#endif
|
||||
{
|
||||
if (!notifySync->Wait(notifyLock))
|
||||
goto ThreadError;
|
||||
}
|
||||
sndBrdThreadDone = false;
|
||||
#ifdef SUPERMODEL_DRIVEBOARD
|
||||
drvBrdThreadDone = false;
|
||||
#endif
|
||||
|
||||
// Leave notify wait critical section
|
||||
if (!notifyLock->Unlock())
|
||||
goto ThreadError;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If not multi-threaded, then just process a single frame for main board, sound board and drive board in turn in this thread
|
||||
RunMainBoardFrame();
|
||||
SoundBoard.RunFrame();
|
||||
#ifdef SUPERMODEL_DRIVEBOARD
|
||||
DriveBoard.RunFrame();
|
||||
#endif
|
||||
}
|
||||
|
||||
// End frame
|
||||
GPU.EndFrame();
|
||||
TileGen.EndFrame();
|
||||
IRQ.Assert(0x0D);
|
||||
return;
|
||||
|
||||
ThreadError:
|
||||
ErrorLog("Threading error in CModel3::RunFrame: %s\nSwitching back to single-threaded mode.\n", CThread::GetLastError());
|
||||
multiThreaded = false;
|
||||
}
|
||||
|
||||
bool CModel3::StartThreads()
|
||||
{
|
||||
if (startedThreads)
|
||||
return true;
|
||||
|
||||
// Create synchronization objects
|
||||
sndBrdThreadSync = CThread::CreateSemaphore(1);
|
||||
if (sndBrdThreadSync == NULL)
|
||||
goto ThreadError;
|
||||
#ifdef SUPERMODEL_DRIVEBOARD
|
||||
drvBrdThreadSync = CThread::CreateSemaphore(1);
|
||||
if (drvBrdThreadSync == NULL)
|
||||
goto ThreadError;
|
||||
#endif
|
||||
notifyLock = CThread::CreateMutex();
|
||||
if (notifyLock == NULL)
|
||||
goto ThreadError;
|
||||
notifySync = CThread::CreateCondVar();
|
||||
if (notifySync == NULL)
|
||||
goto ThreadError;
|
||||
|
||||
// Create sound board thread
|
||||
sndBrdThread = CThread::CreateThread(StartSoundBoardThread, this);
|
||||
if (sndBrdThread == NULL)
|
||||
goto ThreadError;
|
||||
|
||||
#ifdef SUPERMODEL_DRIVEBOARD
|
||||
// Create drive board thread
|
||||
drvBrdThread = CThread::CreateThread(StartDriveBoardThread, this);
|
||||
if (drvBrdThread == NULL)
|
||||
goto ThreadError;
|
||||
#endif
|
||||
|
||||
startedThreads = true;
|
||||
return true;
|
||||
|
||||
ThreadError:
|
||||
ErrorLog("Unable to create threads and/or synchronization objects: %s\nSwitching back to single-threaded mode.\n", CThread::GetLastError());
|
||||
DeleteThreadObjects();
|
||||
multiThreaded = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
void CModel3::StopThreads()
|
||||
{
|
||||
if (!startedThreads)
|
||||
return;
|
||||
|
||||
DeleteThreadObjects();
|
||||
startedThreads = false;
|
||||
}
|
||||
|
||||
void CModel3::DeleteThreadObjects()
|
||||
{
|
||||
// Delete (which in turn kills) sound board and drive board threads
|
||||
// Note that can do so here safely because threads will always be waiting on their semaphores when this method is called
|
||||
if (sndBrdThread != NULL)
|
||||
{
|
||||
delete sndBrdThread;
|
||||
sndBrdThread = NULL;
|
||||
}
|
||||
#ifdef SUPERMODEL_DRIVEBOARD
|
||||
if (drvBrdThread != NULL)
|
||||
{
|
||||
delete drvBrdThread;
|
||||
drvBrdThread = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Delete synchronization objects
|
||||
if (sndBrdThreadSync != NULL)
|
||||
{
|
||||
delete sndBrdThreadSync;
|
||||
sndBrdThreadSync = NULL;
|
||||
}
|
||||
#ifdef SUPERMODEL_DRIVEBOARD
|
||||
if (drvBrdThreadSync != NULL)
|
||||
{
|
||||
delete drvBrdThreadSync;
|
||||
drvBrdThreadSync = NULL;
|
||||
}
|
||||
#endif
|
||||
if (notifyLock != NULL)
|
||||
{
|
||||
delete notifyLock;
|
||||
notifyLock = NULL;
|
||||
}
|
||||
if (notifySync != NULL)
|
||||
{
|
||||
delete notifySync;
|
||||
notifySync = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int CModel3::StartSoundBoardThread(void *data)
|
||||
{
|
||||
// Call sound board thread method on CModel3
|
||||
CModel3 *model3 = (CModel3*)data;
|
||||
model3->RunSoundBoardThread();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef SUPERMODEL_DRIVEBOARD
|
||||
int CModel3::StartDriveBoardThread(void *data)
|
||||
{
|
||||
// Call drive board thread method on CModel3
|
||||
CModel3 *model3 = (CModel3*)data;
|
||||
model3->RunDriveBoardThread();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void CModel3::RunSoundBoardThread()
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
// Wait on sound board thread semaphore
|
||||
if (!sndBrdThreadSync->Wait())
|
||||
goto ThreadError;
|
||||
|
||||
// Process a single frame for sound board
|
||||
SoundBoard.RunFrame();
|
||||
|
||||
// Enter notify critical section
|
||||
if (!notifyLock->Lock())
|
||||
goto ThreadError;
|
||||
|
||||
// Let main thread know processing has finished
|
||||
sndBrdThreadDone = true;
|
||||
if (!notifySync->Signal())
|
||||
goto ThreadError;
|
||||
|
||||
// Leave notify critical section
|
||||
if (!notifyLock->Unlock())
|
||||
goto ThreadError;
|
||||
}
|
||||
|
||||
ThreadError:
|
||||
ErrorLog("Threading error in sound board thread: %s\nSwitching back to single-threaded mode.\n", CThread::GetLastError());
|
||||
multiThreaded = false;
|
||||
}
|
||||
|
||||
#ifdef SUPERMODEL_DRIVEBOARD
|
||||
void CModel3::RunDriveBoardThread()
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
// Wait on drive board thread semaphore
|
||||
if (!drvBrdThreadSync->Wait())
|
||||
goto ThreadError;
|
||||
|
||||
// Process a single frame for drive board
|
||||
//DriveBoard.RunFrame();
|
||||
|
||||
// Enter notify critical section
|
||||
if (!notifyLock->Lock())
|
||||
goto ThreadError;
|
||||
|
||||
// Let main thread know processing has finished
|
||||
drvBrdThreadDone = true;
|
||||
if (!notifySync->Signal())
|
||||
goto ThreadError;
|
||||
|
||||
// Leave notify critical section
|
||||
if (!notifyLock->Unlock())
|
||||
goto ThreadError;
|
||||
}
|
||||
|
||||
ThreadError:
|
||||
ErrorLog("Threading error in drive board thread: %s\nSwitching back to single-threaded mode.\n", CThread::GetLastError());
|
||||
multiThreaded = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void CModel3::RunMainBoardFrame(void)
|
||||
{
|
||||
// Run the PowerPC for a frame
|
||||
ppc_execute(ppcFrequency/60-10000);
|
||||
|
||||
|
@ -1891,14 +2128,7 @@ void CModel3::RunFrame(void)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
IRQ.Deassert(0x40);
|
||||
SoundBoard.RunFrame();
|
||||
|
||||
// End frame
|
||||
GPU.EndFrame();
|
||||
TileGen.EndFrame();
|
||||
IRQ.Assert(0x0D);
|
||||
}
|
||||
|
||||
void CModel3::Reset(void)
|
||||
|
@ -1932,6 +2162,9 @@ void CModel3::Reset(void)
|
|||
TileGen.Reset();
|
||||
GPU.Reset();
|
||||
SoundBoard.Reset();
|
||||
#ifdef SUPERMODEL_DRIVEBOARD
|
||||
DriveBoard.Reset();
|
||||
#endif
|
||||
|
||||
DebugLog("Model 3 reset\n");
|
||||
}
|
||||
|
@ -2289,7 +2522,7 @@ void CModel3::AttachInputs(CInputs *InputsPtr)
|
|||
DebugLog("Model 3 attached inputs\n");
|
||||
}
|
||||
|
||||
BOOL CModel3::Init(unsigned ppcFrequencyParam)
|
||||
BOOL CModel3::Init(unsigned ppcFrequencyParam, BOOL multiThreadedParam)
|
||||
{
|
||||
float memSizeMB = (float)MEMORY_POOL_SIZE/(float)0x100000;
|
||||
|
||||
|
@ -2297,6 +2530,7 @@ BOOL CModel3::Init(unsigned ppcFrequencyParam)
|
|||
ppcFrequency = ppcFrequencyParam;
|
||||
if (ppcFrequency < 1000000)
|
||||
ppcFrequency = 1000000;
|
||||
multiThreaded = !!multiThreadedParam;
|
||||
|
||||
// Allocate all memory for ROMs and PPC RAM
|
||||
memoryPool = new(std::nothrow) UINT8[MEMORY_POOL_SIZE];
|
||||
|
@ -2326,6 +2560,9 @@ BOOL CModel3::Init(unsigned ppcFrequencyParam)
|
|||
return FAIL;
|
||||
if (OKAY != SoundBoard.Init(soundROM,sampleROM,&IRQ,0x40))
|
||||
return FAIL;
|
||||
#ifdef SUPERMODEL_DRIVEBOARD
|
||||
DriveBoard.Init();
|
||||
#endif
|
||||
|
||||
PCIBridge.AttachPCIBus(&PCIBus);
|
||||
PCIBus.AttachDevice(13,&GPU);
|
||||
|
@ -2333,6 +2570,7 @@ BOOL CModel3::Init(unsigned ppcFrequencyParam)
|
|||
PCIBus.AttachDevice(16,this);
|
||||
|
||||
DebugLog("Initialized Model 3 (allocated %1.1f MB)\n", memSizeMB);
|
||||
|
||||
return OKAY;
|
||||
}
|
||||
|
||||
|
@ -2354,6 +2592,23 @@ CModel3::CModel3(void)
|
|||
|
||||
securityPtr = 0;
|
||||
|
||||
multiThreaded = true;
|
||||
startedThreads = false;
|
||||
sndBrdThread = NULL;
|
||||
#ifdef SUPERMODEL_DRIVEBOARD
|
||||
drvBrdThread = NULL;
|
||||
#endif
|
||||
sndBrdThreadDone = false;
|
||||
#ifdef SUPERMODEL_DRIVEBOARD
|
||||
drvBrdThreadDone = false;
|
||||
#endif
|
||||
sndBrdThreadSync = NULL;
|
||||
#ifdef SUPERMODEL_DRIVEBOARD
|
||||
drvBrdThreadSync = NULL;
|
||||
#endif
|
||||
notifyLock = NULL;
|
||||
notifySync = NULL;
|
||||
|
||||
DebugLog("Built Model 3\n");
|
||||
}
|
||||
|
||||
|
@ -2369,6 +2624,9 @@ CModel3::~CModel3(void)
|
|||
//Dump("sampleROM", sampleROM, 0x800000, FALSE, TRUE);
|
||||
#endif
|
||||
|
||||
// Stop all threads
|
||||
StopThreads();
|
||||
|
||||
if (memoryPool != NULL)
|
||||
{
|
||||
delete [] memoryPool;
|
||||
|
|
|
@ -171,7 +171,7 @@ public:
|
|||
* Runs one frame (assuming 60 Hz video refresh rate).
|
||||
*/
|
||||
void RunFrame(void);
|
||||
|
||||
|
||||
/*
|
||||
* Reset(void):
|
||||
*
|
||||
|
@ -224,7 +224,7 @@ public:
|
|||
void AttachInputs(CInputs *InputsPtr);
|
||||
|
||||
/*
|
||||
* Init(ppcFrequencyParam):
|
||||
* Init(ppcFrequencyParam, multiThreadedParam):
|
||||
*
|
||||
* One-time initialization of the context. Must be called prior to all
|
||||
* other members. Allocates memory and initializes device states.
|
||||
|
@ -237,7 +237,7 @@ public:
|
|||
* OKAY is successful, otherwise FAILED if a non-recoverable error
|
||||
* occurred. Prints own error messages.
|
||||
*/
|
||||
BOOL Init(unsigned ppcFrequencyParam);
|
||||
BOOL Init(unsigned ppcFrequencyParam, BOOL multiThreadedParam);
|
||||
|
||||
/*
|
||||
* CModel3(void):
|
||||
|
@ -250,13 +250,12 @@ public:
|
|||
*/
|
||||
CModel3(void);
|
||||
~CModel3(void);
|
||||
|
||||
|
||||
/*
|
||||
* Private Property.
|
||||
* Tresspassers will be shot! ;)
|
||||
*/
|
||||
private:
|
||||
|
||||
// Private member functions
|
||||
UINT8 ReadInputs(unsigned reg);
|
||||
void WriteInputs(unsigned reg, UINT8 data);
|
||||
|
@ -266,12 +265,27 @@ private:
|
|||
UINT8 ReadSystemRegister(unsigned reg);
|
||||
void WriteSystemRegister(unsigned reg, UINT8 data);
|
||||
void Patch(void);
|
||||
|
||||
void RunMainBoardFrame(); // Runs the main board (PPC) for a frame
|
||||
bool StartThreads(); // Starts all threads
|
||||
void StopThreads(); // Stops all threads
|
||||
void DeleteThreadObjects(); // Deletes all threads and synchronization objects
|
||||
|
||||
static int StartSoundBoardThread(void *data); // Callback to start sound board thread
|
||||
#ifdef SUPERMODEL_DRIVEBOARD
|
||||
static int StartDriveBoardThread(void *data); // Callback to start drive board thread
|
||||
#endif
|
||||
|
||||
void RunSoundBoardThread(); // Runs sound board thread
|
||||
#ifdef SUPERMODEL_DRIVEBOARD
|
||||
void RunDriveBoardThread(); // Runs drive board thread
|
||||
#endif
|
||||
|
||||
// Game and hardware information
|
||||
const struct GameInfo *Game;
|
||||
|
||||
// Game inputs
|
||||
CInputs *Inputs;
|
||||
CInputs *Inputs;
|
||||
|
||||
// Input registers (game controls)
|
||||
UINT8 inputBank;
|
||||
|
@ -302,6 +316,26 @@ private:
|
|||
// PowerPC
|
||||
PPC_FETCH_REGION PPCFetchRegions[3];
|
||||
unsigned ppcFrequency; // clock frequency (Hz)
|
||||
|
||||
// Multiple threading
|
||||
bool multiThreaded; // True if should run CPUs in multiple threads, otherwise everything is run in a single thread
|
||||
bool startedThreads; // True if threads have been created and started
|
||||
CThread *sndBrdThread; // Sound board thread
|
||||
#ifdef SUPERMODEL_DRIVEBOARD
|
||||
CThread *drvBrdThread; // Drive board thread
|
||||
#endif
|
||||
bool sndBrdThreadDone; // Flag to indicate sound board thread has finished processing for current frame
|
||||
#ifdef SUPERMODEL_DRIVEBOARD
|
||||
bool drvBrdThreadDone; // Flag to indicate drive board thread has finished processing for current frame
|
||||
#endif
|
||||
|
||||
// Thread synchronization objects
|
||||
CSemaphore *sndBrdThreadSync;
|
||||
#ifdef SUPERMODEL_DRIVEBOARD
|
||||
CSemaphore *drvBrdThreadSync;
|
||||
#endif
|
||||
CMutex *notifyLock;
|
||||
CCondVar *notifySync;
|
||||
|
||||
// Other devices
|
||||
CIRQ IRQ; // Model 3 IRQ controller
|
||||
|
@ -312,7 +346,10 @@ private:
|
|||
C93C46 EEPROM; // 93C46 EEPROM
|
||||
CTileGen TileGen; // Sega 2D tile generator
|
||||
CReal3D GPU; // Real3D graphics hardware
|
||||
CSoundBoard SoundBoard; // sound board
|
||||
CSoundBoard SoundBoard; // Sound board
|
||||
#ifdef SUPERMODEL_DRIVEBOARD
|
||||
CDriveBoard DriveBoard; // Drive board
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -346,7 +346,10 @@ void CSoundBoard::RunFrame(void)
|
|||
{
|
||||
#ifdef SUPERMODEL_SOUND
|
||||
SCSP_Update();
|
||||
|
||||
|
||||
// Output the audio buffers
|
||||
OutputAudio(44100/60, leftBuffer, rightBuffer);
|
||||
|
||||
// Output to binary file
|
||||
INT16 s;
|
||||
for (int i = 0; i < 44100/60; i++)
|
||||
|
|
31
Src/OSD/Audio.h
Executable file
31
Src/OSD/Audio.h
Executable file
|
@ -0,0 +1,31 @@
|
|||
#ifndef INCLUDED_AUDIO_H
|
||||
#define INCLUDED_AUDIO_H
|
||||
|
||||
/*
|
||||
* Audio.h
|
||||
*
|
||||
* Function-based interface for audio output.
|
||||
*/
|
||||
|
||||
/*
|
||||
* OpenAudio()
|
||||
*
|
||||
* Initializes the audio system.
|
||||
*/
|
||||
extern BOOL OpenAudio();
|
||||
|
||||
/*
|
||||
* OutputAudio(unsigned numSamples, *INT16 leftBuffer, *INT16 rightBuffer)
|
||||
*
|
||||
* Sends a chunk of two-channel audio with the given number of samples to the audio system.
|
||||
*/
|
||||
extern void OutputAudio(unsigned numSamples, INT16 *leftBuffer, INT16 *rightBuffer);
|
||||
|
||||
/*
|
||||
* CloseAudio()
|
||||
*
|
||||
* Shuts down the audio system.
|
||||
*/
|
||||
extern void CloseAudio();
|
||||
|
||||
#endif // INCLUDED_AUDIO_H
|
294
Src/OSD/SDL/Audio.cpp
Executable file
294
Src/OSD/SDL/Audio.cpp
Executable file
|
@ -0,0 +1,294 @@
|
|||
#include "Supermodel.h"
|
||||
|
||||
#ifdef SUPERMODEL_OSX
|
||||
#include <SDL/SDL.h>
|
||||
#include <SDL/SDL_audio.h>
|
||||
#else
|
||||
#include <SDL.h>
|
||||
#include <SDL_audio.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
// Model3 audio output is 44.1KHz 2-channel sound and frame rate is 60fps
|
||||
#define SAMPLE_RATE 44100
|
||||
#define NUM_CHANNELS 2
|
||||
#define SUPERMODEL_FPS 60
|
||||
|
||||
#define BYTES_PER_SAMPLE (NUM_CHANNELS * sizeof(INT16))
|
||||
#define SAMPLES_PER_FRAME (SAMPLE_RATE / SUPERMODEL_FPS)
|
||||
#define BYTES_PER_FRAME (SAMPLES_PER_FRAME * BYTES_PER_SAMPLE)
|
||||
|
||||
#define MAX_LATENCY 100
|
||||
|
||||
static bool enabled = true; // True if sound output is enabled
|
||||
static unsigned latency = 20; // Audio latency to use (ie size of audio buffer) as percentage of max buffer size
|
||||
|
||||
static unsigned playSamples = 512; // Size (in samples) of callback play buffer
|
||||
|
||||
static UINT32 audioBufferSize = 0; // Size (in bytes) of audio buffer
|
||||
static INT8 *audioBuffer = NULL; // Audio buffer
|
||||
|
||||
static UINT32 writePos = 0; // Current position at which writing into buffer
|
||||
static UINT32 playPos = 0; // Current position at which playing data in buffer via callback
|
||||
|
||||
static bool writeWrapped = false; // True if write position has wrapped around at end of buffer but play position has not done so yet
|
||||
|
||||
static unsigned underRuns = 0; // Number of buffer under-runs that have occured
|
||||
static unsigned overRuns = 0; // Number of buffer over-runs that have occured
|
||||
|
||||
static void PlayCallback(void *data, Uint8 *stream, int len)
|
||||
{
|
||||
//printf("PlayCallback(%d)\n", len);
|
||||
|
||||
// Get current write position and adjust it if write has wrapped
|
||||
UINT32 adjWritePos = writePos;
|
||||
if (writeWrapped)
|
||||
adjWritePos += audioBufferSize;
|
||||
|
||||
// Check if play position overlaps write position (ie buffer under-run)
|
||||
if (adjWritePos < playPos + len)
|
||||
{
|
||||
// If so, just copy silence to audio output stream and exit
|
||||
memset(stream, 0, len);
|
||||
|
||||
//printf("Audio buffer under-run in PlayCallback\n");
|
||||
underRuns++;
|
||||
return;
|
||||
}
|
||||
|
||||
INT8* src1;
|
||||
INT8* src2;
|
||||
UINT32 len1;
|
||||
UINT32 len2;
|
||||
|
||||
// Check if play region extends past end of buffer
|
||||
if (playPos + len > audioBufferSize)
|
||||
{
|
||||
// If so, split play region into two
|
||||
src1 = audioBuffer + playPos;
|
||||
src2 = audioBuffer;
|
||||
len1 = audioBufferSize - playPos;
|
||||
len2 = len - len1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, just copy whole region
|
||||
src1 = audioBuffer + playPos;
|
||||
src2 = 0;
|
||||
len1 = len;
|
||||
len2 = 0;
|
||||
}
|
||||
|
||||
// Check if audio is enabled
|
||||
if (enabled)
|
||||
{
|
||||
// If so, copy play region into audio output stream and blank region out afterwards
|
||||
memcpy(stream, src1, len1);
|
||||
memset(src1, 0, len1);
|
||||
|
||||
if (len2)
|
||||
{
|
||||
// If region was split into two, copy second half into audio output stream as well and blank region out afterwards
|
||||
memcpy(stream + len1, src2, len2);
|
||||
memset(src2, 0, len2);
|
||||
}
|
||||
}
|
||||
else
|
||||
// Otherwise, just copy silence to audio output stream
|
||||
memset(stream, 0, len);
|
||||
|
||||
// Move play position forward for next time
|
||||
playPos += len;
|
||||
|
||||
// Check if play position has moved past end of buffer
|
||||
if (playPos >= audioBufferSize)
|
||||
{
|
||||
// If so, wrap it around to beginning again and reset write wrap flag
|
||||
playPos -= audioBufferSize;
|
||||
writeWrapped = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void MixChannels(unsigned numSamples, INT16 *leftBuffer, INT16 *rightBuffer, void *dest)
|
||||
{
|
||||
INT16 *p = (INT16*)dest;
|
||||
for (unsigned i = 0; i < numSamples; i++)
|
||||
{
|
||||
#if (NUM_CHANNELS == 1)
|
||||
*p++ = leftBuffer[i] + rightBuffer[i];
|
||||
#else
|
||||
*p++ = rightBuffer[i];
|
||||
*p++ = leftBuffer[i];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
BOOL OpenAudio()
|
||||
{
|
||||
// Initialize SDL audio sub-system
|
||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO) != 0)
|
||||
{
|
||||
ErrorLog("Unable to initialize SDL audio sub-system: %s\n", SDL_GetError());
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
// Set up audio specification
|
||||
SDL_AudioSpec fmt;
|
||||
memset(&fmt, 0, sizeof(SDL_AudioSpec));
|
||||
fmt.freq = SAMPLE_RATE;
|
||||
fmt.channels = NUM_CHANNELS;
|
||||
fmt.format = AUDIO_S16SYS;
|
||||
fmt.samples = playSamples;
|
||||
fmt.callback = PlayCallback;
|
||||
|
||||
// Try opening SDL audio output with that specification
|
||||
SDL_AudioSpec obtained;
|
||||
if (SDL_OpenAudio(&fmt, &obtained) < 0)
|
||||
{
|
||||
ErrorLog("Unable to open 44.1KHz 2-channel audio with SDL: %s\n", SDL_GetError());
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
// Check what buffer sample size was actually obtained, and use that
|
||||
playSamples = obtained.samples;
|
||||
|
||||
// Create audio buffer
|
||||
audioBufferSize = SAMPLE_RATE * BYTES_PER_SAMPLE * latency / MAX_LATENCY;
|
||||
int roundBuffer = 2 * playSamples;
|
||||
audioBufferSize = max<int>(roundBuffer, (audioBufferSize / roundBuffer) * roundBuffer);
|
||||
audioBuffer = new INT8[audioBufferSize];
|
||||
memset(audioBuffer, 0, sizeof(INT8) * audioBufferSize);
|
||||
|
||||
// Set initial play position to be beginning of buffer and initial write position to be half-way into buffer
|
||||
playPos = 0;
|
||||
writePos = (BYTES_PER_FRAME + audioBufferSize) / 2;
|
||||
writeWrapped = false;
|
||||
|
||||
// Reset counters
|
||||
underRuns = 0;
|
||||
overRuns = 0;
|
||||
|
||||
// Start audio playing
|
||||
SDL_PauseAudio(0);
|
||||
return OKAY;
|
||||
}
|
||||
|
||||
void OutputAudio(unsigned numSamples, INT16 *leftBuffer, INT16 *rightBuffer)
|
||||
{
|
||||
//printf("OutputAudio(%u)\n", numSamples);
|
||||
|
||||
// Number of samples should never be more than max number of samples per frame
|
||||
if (numSamples > SAMPLES_PER_FRAME)
|
||||
numSamples = SAMPLES_PER_FRAME;
|
||||
|
||||
// Mix together left and right channels into single chunk of data
|
||||
INT16 mixBuffer[NUM_CHANNELS * SAMPLES_PER_FRAME];
|
||||
MixChannels(numSamples, leftBuffer, rightBuffer, mixBuffer);
|
||||
|
||||
// Lock SDL audio callback so that it doesn't interfere with following code
|
||||
SDL_LockAudio();
|
||||
|
||||
// Calculate number of bytes for current sound chunk
|
||||
UINT32 numBytes = numSamples * BYTES_PER_SAMPLE;
|
||||
|
||||
// Get end of current play region (writing must occur past this point)
|
||||
UINT32 playEndPos = playPos + BYTES_PER_FRAME;
|
||||
|
||||
// Undo any wrap-around of the write position that may have occured to create following ordering: playPos < playEndPos < writePos
|
||||
if (writePos < playEndPos && writeWrapped)
|
||||
writePos += audioBufferSize;
|
||||
|
||||
// If play region has caught up with write position and now overlaps it (ie buffer under-run), then bump write position forward in chunks
|
||||
// until it is past end of play region
|
||||
while (writePos < playEndPos)
|
||||
{
|
||||
//printf("Audio buffer under-run in OutputAudio\n");
|
||||
underRuns++;
|
||||
writePos += numBytes;
|
||||
}
|
||||
|
||||
// If write position has caught up with play region and now overlaps it (ie buffer over-run), then discard current chunk of data
|
||||
if (writePos + numBytes > playPos + audioBufferSize)
|
||||
{
|
||||
//printf("Audio buffer over-run in OutputAudio\n");
|
||||
overRuns++;
|
||||
goto Finish;
|
||||
}
|
||||
|
||||
// Check if write position has moved past end of buffer
|
||||
if (writePos >= audioBufferSize)
|
||||
{
|
||||
// If so, wrap it around to beginning again and set write wrap flag
|
||||
writePos -= audioBufferSize;
|
||||
writeWrapped = true;
|
||||
}
|
||||
|
||||
INT16 *src = mixBuffer;
|
||||
INT8 *dst1;
|
||||
INT8 *dst2;
|
||||
UINT32 len1;
|
||||
UINT32 len2;
|
||||
|
||||
// Check if write region extends past end of buffer
|
||||
if (writePos + numBytes > audioBufferSize)
|
||||
{
|
||||
// If so, split write region into two
|
||||
dst1 = audioBuffer + writePos;
|
||||
dst2 = audioBuffer;
|
||||
len1 = audioBufferSize - writePos;
|
||||
len2 = numBytes - len1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, just copy whole region
|
||||
dst1 = audioBuffer + writePos;
|
||||
dst2 = 0;
|
||||
len1 = numBytes;
|
||||
len2 = 0;
|
||||
}
|
||||
|
||||
// Copy chunk to write position in buffer
|
||||
UINT32 bytesRemaining = numBytes;
|
||||
UINT32 bytesToCopy = (bytesRemaining > len1 ? len1 : bytesRemaining);
|
||||
memcpy(dst1, src, bytesToCopy);
|
||||
|
||||
// Adjust for number of bytes copied
|
||||
bytesRemaining -= bytesToCopy;
|
||||
src = (INT16*)((UINT8*)src + bytesToCopy);
|
||||
|
||||
if (bytesRemaining)
|
||||
{
|
||||
// If write region was split into two, copy second half of chunk into buffer as well
|
||||
bytesToCopy = (bytesRemaining > len2 ? len2 : bytesRemaining);
|
||||
memcpy(dst2, src, bytesToCopy);
|
||||
}
|
||||
|
||||
// Move write position forward for next time
|
||||
writePos += numBytes;
|
||||
|
||||
// Check if write position has moved past end of buffer
|
||||
if (writePos >= audioBufferSize)
|
||||
{
|
||||
// If so wrap it around to beginning again and set write wrap flag
|
||||
writePos -= audioBufferSize;
|
||||
writeWrapped = true;
|
||||
}
|
||||
|
||||
Finish:
|
||||
// Unlock SDL audio callback
|
||||
SDL_UnlockAudio();
|
||||
}
|
||||
|
||||
void CloseAudio()
|
||||
{
|
||||
// Close SDL audio output
|
||||
SDL_CloseAudio();
|
||||
|
||||
// Delete audio buffer
|
||||
if (audioBuffer != NULL)
|
||||
{
|
||||
delete[] audioBuffer;
|
||||
audioBuffer = NULL;
|
||||
}
|
||||
}
|
|
@ -54,7 +54,7 @@
|
|||
#include "Supermodel.h"
|
||||
#include "SDLInputSystem.h"
|
||||
#ifdef SUPERMODEL_WIN32
|
||||
#include "OSD/Windows/DirectInputSystem.h"
|
||||
#include "DirectInputSystem.h"
|
||||
#endif
|
||||
|
||||
CLogger *GetLogger();
|
||||
|
@ -361,12 +361,12 @@ static void LoadNVRAM(CModel3 *Model3)
|
|||
******************************************************************************/
|
||||
|
||||
#ifdef SUPERMODEL_DEBUGGER
|
||||
int Supermodel(const char *zipFile, CModel3 *Model3, CInputs *Inputs, Debugger::CDebugger *Debugger, unsigned ppcFrequency,
|
||||
int Supermodel(const char *zipFile, CModel3 *Model3, CInputs *Inputs, Debugger::CDebugger *Debugger, unsigned ppcFrequency, BOOL multiThreaded,
|
||||
unsigned xResParam, unsigned yResParam, BOOL keepAspectRatio, BOOL fullScreen, BOOL noThrottle, BOOL showFPS,
|
||||
const char *vsFile, const char *fsFile)
|
||||
{
|
||||
#else
|
||||
int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequency, unsigned xResParam, unsigned yResParam,
|
||||
int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequency, BOOL multiThreaded, unsigned xResParam, unsigned yResParam,
|
||||
BOOL keepAspectRatio, BOOL fullScreen, BOOL noThrottle, BOOL showFPS, const char *vsFile, const char *fsFile)
|
||||
{
|
||||
CModel3 *Model3 = new CModel3();
|
||||
|
@ -386,7 +386,7 @@ int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequency, unsi
|
|||
InfoLog("Frame rate limiting: %s", noThrottle?"Disabled":"Enabled");
|
||||
|
||||
// Initialize and load ROMs
|
||||
Model3->Init(ppcFrequency);
|
||||
Model3->Init(ppcFrequency, multiThreaded);
|
||||
if (OKAY != Model3->LoadROMSet(Model3GameList, zipFile))
|
||||
return 1;
|
||||
|
||||
|
@ -399,7 +399,11 @@ int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequency, unsi
|
|||
sprintf(titleStr, "Supermodel - %s", Model3->GetGameInfo()->title);
|
||||
if (OKAY != CreateGLScreen(titleStr,&xOffset,&yOffset,&xRes,&yRes,keepAspectRatio,fullScreen))
|
||||
return 1;
|
||||
|
||||
|
||||
// Initialize audio system
|
||||
if (OKAY != OpenAudio())
|
||||
return 1;
|
||||
|
||||
// Hide mouse if fullscreen
|
||||
Inputs->GetInputSystem()->SetMouseVisibility(!fullScreen);
|
||||
|
||||
|
@ -606,6 +610,9 @@ int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequency, unsi
|
|||
// Save NVRAM
|
||||
SaveNVRAM(Model3);
|
||||
|
||||
// Close audio
|
||||
CloseAudio();
|
||||
|
||||
// Shut down
|
||||
#ifndef SUPERMODEL_DEBUGGER
|
||||
delete Model3;
|
||||
|
@ -1002,6 +1009,7 @@ static void Help(void)
|
|||
puts("");
|
||||
puts("Emulation Options:");
|
||||
puts(" -ppc-frequency=<f> Set PowerPC frequency in MHz [Default: 25]");
|
||||
puts(" -multi-threaded Enable multi-threading");
|
||||
#ifdef SUPERMODEL_DEBUGGER
|
||||
puts(" -disable-debugger Completely disable debugger functionality");
|
||||
puts(" -enter-debugger Enter debugger at start of emulation");
|
||||
|
@ -1055,7 +1063,7 @@ static void PrintGameList(void)
|
|||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, ret;
|
||||
int cmd=0, fileIdx=0, cmdFullScreen=0, cmdNoThrottle=0, cmdShowFPS=0, cmdPrintInputs=0, cmdConfigInputs=0, cmdPrintGames=0, cmdDis=0, cmdPrintGLInfo=0;
|
||||
int cmd=0, fileIdx=0, cmdMultiThreaded=0, cmdFullScreen=0, cmdNoThrottle=0, cmdShowFPS=0, cmdPrintInputs=0, cmdConfigInputs=0, cmdPrintGames=0, cmdDis=0, cmdPrintGLInfo=0;
|
||||
#ifdef SUPERMODEL_DEBUGGER
|
||||
int cmdDisableDebugger = 0, cmdEnterDebugger=0;
|
||||
#endif // SUPERMODEL_DEBUGGER
|
||||
|
@ -1099,6 +1107,8 @@ int main(int argc, char **argv)
|
|||
ppcFrequency = f*1000000;
|
||||
}
|
||||
}
|
||||
else if (!strncmp(argv[i],"-multi-threaded", 16))
|
||||
cmd = cmdMultiThreaded = 1;
|
||||
#ifdef SUPERMODEL_DEBUGGER
|
||||
else if (!strncmp(argv[i],"-disable-debugger",17))
|
||||
cmd = cmdDisableDebugger = 1;
|
||||
|
@ -1268,13 +1278,13 @@ int main(int argc, char **argv)
|
|||
Debugger->ForceBreak(true);
|
||||
}
|
||||
// Fire up Supermodel with debugger
|
||||
exitCode = Supermodel(argv[fileIdx],Model3,Inputs,Debugger,ppcFrequency,xRes,yRes,TRUE,cmdFullScreen,cmdNoThrottle,cmdShowFPS,vsFile,fsFile);
|
||||
exitCode = Supermodel(argv[fileIdx],Model3,Inputs,Debugger,ppcFrequency,cmdMultiThreaded,xRes,yRes,TRUE,cmdFullScreen,cmdNoThrottle,cmdShowFPS,vsFile,fsFile);
|
||||
if (Debugger != NULL)
|
||||
delete Debugger;
|
||||
delete Model3;
|
||||
#else
|
||||
// Fire up Supermodel
|
||||
exitCode = Supermodel(argv[fileIdx],Inputs,ppcFrequency,xRes,yRes,TRUE,cmdFullScreen,cmdNoThrottle,cmdShowFPS,vsFile,fsFile);
|
||||
exitCode = Supermodel(argv[fileIdx],Inputs,ppcFrequency,cmdMultiThreaded,xRes,yRes,TRUE,cmdFullScreen,cmdNoThrottle,cmdShowFPS,vsFile,fsFile);
|
||||
#endif // SUPERMODEL_DEBUGGER
|
||||
|
||||
Exit:
|
||||
|
|
143
Src/OSD/SDL/Thread.cpp
Executable file
143
Src/OSD/SDL/Thread.cpp
Executable file
|
@ -0,0 +1,143 @@
|
|||
#include "Supermodel.h"
|
||||
|
||||
#ifdef SUPERMODEL_OSX
|
||||
#include <SDL/SDL.h>
|
||||
#include <SDL/SDL_thread.h>
|
||||
#else
|
||||
#include <SDL.h>
|
||||
#include <SDL_thread.h>
|
||||
#endif
|
||||
|
||||
CThread *CThread::CreateThread(ThreadStart start, void *startParam)
|
||||
{
|
||||
SDL_Thread *impl = SDL_CreateThread(start, startParam);
|
||||
if (impl == NULL)
|
||||
return NULL;
|
||||
return new CThread(impl);
|
||||
}
|
||||
|
||||
CSemaphore *CThread::CreateSemaphore(UINT32 initVal)
|
||||
{
|
||||
SDL_sem *impl = SDL_CreateSemaphore(initVal);
|
||||
if (impl == NULL)
|
||||
return NULL;
|
||||
return new CSemaphore(impl);
|
||||
}
|
||||
|
||||
CCondVar *CThread::CreateCondVar()
|
||||
{
|
||||
SDL_cond *impl = SDL_CreateCond();
|
||||
if (impl == NULL)
|
||||
return NULL;
|
||||
return new CCondVar(impl);
|
||||
}
|
||||
|
||||
CMutex *CThread::CreateMutex()
|
||||
{
|
||||
SDL_mutex *impl = SDL_CreateMutex();
|
||||
if (impl == NULL)
|
||||
return NULL;
|
||||
return new CMutex(impl);
|
||||
}
|
||||
|
||||
const char *CThread::GetLastError()
|
||||
{
|
||||
return SDL_GetError();
|
||||
}
|
||||
|
||||
CThread::CThread(void *impl) : m_impl(impl)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
CThread::~CThread()
|
||||
{
|
||||
Kill();
|
||||
}
|
||||
|
||||
UINT32 CThread::GetId()
|
||||
{
|
||||
return SDL_GetThreadID((SDL_Thread*)m_impl);
|
||||
}
|
||||
|
||||
void CThread::Kill()
|
||||
{
|
||||
if (m_impl != NULL)
|
||||
SDL_KillThread((SDL_Thread*)m_impl);
|
||||
m_impl = NULL;
|
||||
}
|
||||
|
||||
int CThread::Wait()
|
||||
{
|
||||
int status;
|
||||
if (m_impl == NULL)
|
||||
return -1;
|
||||
SDL_WaitThread((SDL_Thread*)m_impl, &status);
|
||||
m_impl = NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
CSemaphore::CSemaphore(void *impl) : m_impl(impl)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
CSemaphore::~CSemaphore()
|
||||
{
|
||||
SDL_DestroySemaphore((SDL_sem*)m_impl);
|
||||
}
|
||||
|
||||
UINT32 CSemaphore::GetValue()
|
||||
{
|
||||
return SDL_SemValue((SDL_sem*)m_impl);
|
||||
}
|
||||
|
||||
bool CSemaphore::Wait()
|
||||
{
|
||||
return SDL_SemWait((SDL_sem*)m_impl) == 0;
|
||||
}
|
||||
|
||||
bool CSemaphore::Post()
|
||||
{
|
||||
return SDL_SemPost((SDL_sem*)m_impl) == 0;
|
||||
}
|
||||
|
||||
CCondVar::CCondVar(void *impl) : m_impl(impl)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
CCondVar::~CCondVar()
|
||||
{
|
||||
SDL_DestroyCond((SDL_cond*)m_impl);
|
||||
}
|
||||
|
||||
bool CCondVar::Wait(CMutex *mutex)
|
||||
{
|
||||
return SDL_CondWait((SDL_cond*)m_impl, (SDL_mutex*)mutex->m_impl) == 0;
|
||||
}
|
||||
|
||||
bool CCondVar::Signal()
|
||||
{
|
||||
return SDL_CondSignal((SDL_cond*)m_impl) == 0;
|
||||
}
|
||||
|
||||
CMutex::CMutex(void *impl) : m_impl(impl)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
CMutex::~CMutex()
|
||||
{
|
||||
SDL_DestroyMutex((SDL_mutex*)m_impl);
|
||||
}
|
||||
|
||||
bool CMutex::Lock()
|
||||
{
|
||||
return SDL_mutexP((SDL_mutex*)m_impl) == 0;
|
||||
}
|
||||
|
||||
bool CMutex::Unlock()
|
||||
{
|
||||
return SDL_mutexV((SDL_mutex*)m_impl) == 0;
|
||||
}
|
196
Src/OSD/Thread.h
Executable file
196
Src/OSD/Thread.h
Executable file
|
@ -0,0 +1,196 @@
|
|||
#ifndef INCLUDED_THREADS_H
|
||||
#define INCLUDED_THREADS_H
|
||||
|
||||
class CSemaphore;
|
||||
class CMutex;
|
||||
class CCondVar;
|
||||
|
||||
typedef int (*ThreadStart)(void *startParam);
|
||||
|
||||
/*
|
||||
* CThread
|
||||
*
|
||||
* Class that represents an O/S thread.
|
||||
*/
|
||||
class CThread
|
||||
{
|
||||
private:
|
||||
void *m_impl;
|
||||
|
||||
CThread(void *impl);
|
||||
|
||||
public:
|
||||
/*
|
||||
* CreateThread
|
||||
*
|
||||
* Creates a new thread with the given ThreadStart callback and start parameter. The thread starts running immediately.
|
||||
*/
|
||||
static CThread *CreateThread(ThreadStart start, void *startParam);
|
||||
|
||||
/*
|
||||
* CreateSemaphore
|
||||
*
|
||||
* Creates a new semaphore with the given initial starting value.
|
||||
*/
|
||||
static CSemaphore *CreateSemaphore(UINT32 initVal);
|
||||
|
||||
/*
|
||||
* CreateCondVar
|
||||
*
|
||||
* Creates a new condition variable.
|
||||
*/
|
||||
static CCondVar *CreateCondVar();
|
||||
|
||||
/*
|
||||
* CreateMutex
|
||||
*
|
||||
* Creates a new mutex.
|
||||
*/
|
||||
static CMutex *CreateMutex();
|
||||
|
||||
/*
|
||||
* GetLastError
|
||||
*
|
||||
* Returns the error message for the last error.
|
||||
*/
|
||||
static const char *GetLastError();
|
||||
|
||||
/*
|
||||
* Thread destructor.
|
||||
*/
|
||||
~CThread();
|
||||
|
||||
/*
|
||||
* GetId
|
||||
*
|
||||
* Returns the id of this thread.
|
||||
*/
|
||||
UINT32 GetId();
|
||||
|
||||
/*
|
||||
* Kill
|
||||
*
|
||||
* Kills this thread.
|
||||
*/
|
||||
void Kill();
|
||||
|
||||
/*
|
||||
* Wait
|
||||
*
|
||||
* Waits until this thread has exited.
|
||||
*/
|
||||
int Wait();
|
||||
};
|
||||
|
||||
/*
|
||||
* CSemaphore
|
||||
*
|
||||
* Class that represents a semaphore.
|
||||
*/
|
||||
class CSemaphore
|
||||
{
|
||||
friend class CThread;
|
||||
|
||||
private:
|
||||
void *m_impl;
|
||||
|
||||
CSemaphore(void *impl);
|
||||
|
||||
public:
|
||||
~CSemaphore();
|
||||
|
||||
/*
|
||||
* GetValue
|
||||
*
|
||||
* Returns the current value of this semaphore.
|
||||
*/
|
||||
UINT32 GetValue();
|
||||
|
||||
/*
|
||||
* Wait
|
||||
*
|
||||
* Locks this semaphore and suspends the calling thread if its value is zero.
|
||||
*/
|
||||
bool Wait();
|
||||
|
||||
/*
|
||||
* Post
|
||||
*
|
||||
* Unlocks this semaphore and resumes any threads that were blocked on it.
|
||||
*/
|
||||
bool Post();
|
||||
};
|
||||
|
||||
/*
|
||||
* CSemaphore
|
||||
*
|
||||
* Class that represents a condition variable.
|
||||
*/
|
||||
class CCondVar
|
||||
{
|
||||
friend class CThread;
|
||||
|
||||
private:
|
||||
void *m_impl;
|
||||
|
||||
CCondVar(void *impl);
|
||||
|
||||
public:
|
||||
~CCondVar();
|
||||
|
||||
/*
|
||||
* Wait
|
||||
*
|
||||
* Waits on this condition variable and unlocks the provided mutex (which must be locked before calling this method).
|
||||
*/
|
||||
bool Wait(CMutex *mutex);
|
||||
|
||||
/*
|
||||
* Signal
|
||||
*
|
||||
* Restarts a single thread that is waiting on this condition variable.
|
||||
*/
|
||||
bool Signal();
|
||||
|
||||
/*
|
||||
* SignalAll
|
||||
*
|
||||
* Restarts all threads that are waiting on this condition variable.
|
||||
*/
|
||||
bool SignalAll();
|
||||
};
|
||||
|
||||
/*
|
||||
* CSemaphore
|
||||
*
|
||||
* Class that represents a mutex.
|
||||
*/
|
||||
class CMutex
|
||||
{
|
||||
friend class CThread;
|
||||
friend class CCondVar;
|
||||
|
||||
private:
|
||||
void *m_impl;
|
||||
|
||||
CMutex(void *impl);
|
||||
|
||||
public:
|
||||
~CMutex();
|
||||
|
||||
/*
|
||||
* Lock
|
||||
*
|
||||
* Locks this mutex. If it is already locked then the calling thread will suspend until it is unlocked.
|
||||
*/
|
||||
bool Lock();
|
||||
|
||||
/*
|
||||
* Unlock
|
||||
*
|
||||
* Unlocks this mutex.
|
||||
*/
|
||||
bool Unlock();
|
||||
};
|
||||
|
||||
#endif // INCLUDED_THREADS_H
|
|
@ -173,23 +173,23 @@ bool IsXInputDevice(const GUID &devProdGUID)
|
|||
bool isXInpDev = false;
|
||||
HRESULT hr = CoCreateInstance(__uuidof(WbemLocator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IWbemLocator), (LPVOID*)&pIWbemLocator);
|
||||
if (FAILED(hr) || pIWbemLocator == NULL)
|
||||
goto exit;
|
||||
goto Finish;
|
||||
|
||||
if ((bstrNamespace = SysAllocString(L"\\\\.\\root\\cimv2")) == NULL) goto exit;
|
||||
if ((bstrClassName = SysAllocString(L"Win32_PNPEntity")) == NULL) goto exit;
|
||||
if ((bstrDeviceID = SysAllocString(L"DeviceID")) == NULL) goto exit;
|
||||
if ((bstrNamespace = SysAllocString(L"\\\\.\\root\\cimv2")) == NULL) goto Finish;
|
||||
if ((bstrClassName = SysAllocString(L"Win32_PNPEntity")) == NULL) goto Finish;
|
||||
if ((bstrDeviceID = SysAllocString(L"DeviceID")) == NULL) goto Finish;
|
||||
|
||||
// Connect to WMI
|
||||
hr = pIWbemLocator->ConnectServer(bstrNamespace, NULL, NULL, 0L, 0L, NULL, NULL, &pIWbemServices);
|
||||
if (FAILED(hr) || pIWbemServices == NULL)
|
||||
goto exit;
|
||||
goto Finish;
|
||||
|
||||
// Switch security level to IMPERSONATE
|
||||
CoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
|
||||
|
||||
hr = pIWbemServices->CreateInstanceEnum(bstrClassName, 0, NULL, &pEnumDevices);
|
||||
if (FAILED(hr) || pEnumDevices == NULL)
|
||||
goto exit;
|
||||
goto Finish;
|
||||
|
||||
// Loop over all devices
|
||||
for (;;)
|
||||
|
@ -198,7 +198,7 @@ bool IsXInputDevice(const GUID &devProdGUID)
|
|||
DWORD uReturned;
|
||||
hr = pEnumDevices->Next(10000, 20, pDevices, &uReturned);
|
||||
if (FAILED(hr) || uReturned == 0)
|
||||
goto exit;
|
||||
goto Finish;
|
||||
|
||||
for (unsigned devNum = 0; devNum < uReturned; devNum++)
|
||||
{
|
||||
|
@ -224,7 +224,7 @@ bool IsXInputDevice(const GUID &devProdGUID)
|
|||
if (dwVidPid == devProdGUID.Data1)
|
||||
{
|
||||
isXInpDev = true;
|
||||
goto exit;
|
||||
goto Finish;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -236,7 +236,7 @@ bool IsXInputDevice(const GUID &devProdGUID)
|
|||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
Finish:
|
||||
if (bstrNamespace)
|
||||
SysFreeString(bstrNamespace);
|
||||
if (bstrDeviceID)
|
||||
|
|
|
@ -70,6 +70,10 @@
|
|||
*/
|
||||
#include "Types.h"
|
||||
|
||||
// OSD Interfaces
|
||||
#include "Thread.h"
|
||||
#include "Audio.h"
|
||||
|
||||
/*
|
||||
* Error and Debug Logging
|
||||
*/
|
||||
|
@ -139,9 +143,6 @@ extern void InfoLog(const char *fmt, ...);
|
|||
#ifdef SUPERMODEL_DEBUGGER
|
||||
#include "Debugger/SupermodelDebugger.h"
|
||||
#include "Debugger/CPU/PPCDebug.h"
|
||||
#ifdef SUPERMODEL_SOUND
|
||||
#include "Debugger/CPU/68KDebug.h"
|
||||
#endif // SUPERMODEL_SOUND
|
||||
#endif // SUPERMODEL_DEBUGGER
|
||||
#include "CPU/Bus.h"
|
||||
#include "CPU/PowerPC/PPCDisasm.h"
|
||||
|
|
Loading…
Reference in a new issue