diff --git a/BizHawk.Common/IPC/IPCRingBuffer.cs b/BizHawk.Common/IPC/IPCRingBuffer.cs
index 40df4140b0..6239d0fb9e 100644
--- a/BizHawk.Common/IPC/IPCRingBuffer.cs
+++ b/BizHawk.Common/IPC/IPCRingBuffer.cs
@@ -4,13 +4,14 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.MemoryMappedFiles;
+using System.Threading;
namespace BizHawk.Common
{
///
/// a ring buffer suitable for IPC. It uses a spinlock to control access, so overhead can be kept to a minimum.
- /// you'll probably need to use this in pairs, so it will occupy two threads and degrade entirely if there is less than one processor.
+ /// you'll probably need to use this in pairs, so it will occupy two threads.
///
public unsafe class IPCRingBuffer : IDisposable
{
@@ -80,6 +81,7 @@ namespace BizHawk.Common
if (Available > amt)
return;
//this is a greedy spinlock.
+ Thread.Yield();
}
}
@@ -119,6 +121,7 @@ namespace BizHawk.Common
if (available > 0)
return available;
//this is a greedy spinlock.
+ Thread.Yield();
}
}
diff --git a/libsnes/bsnes/target-libsnes/libsnes_pwrap.cpp b/libsnes/bsnes/target-libsnes/libsnes_pwrap.cpp
index 0a5b260ea8..ad0e09e094 100644
--- a/libsnes/bsnes/target-libsnes/libsnes_pwrap.cpp
+++ b/libsnes/bsnes/target-libsnes/libsnes_pwrap.cpp
@@ -231,6 +231,7 @@ private:
if (Available() > amt)
return;
//this is a greedy spinlock.
+ SwitchToThread();
}
}
@@ -284,6 +285,7 @@ public:
if (available > 0)
return available;
//this is a greedy spinlock.
+ SwitchToThread();
//NOTE: it's annoying right now because libsnes processes die and eat a whole core.
//we need to gracefully exit somehow
}
@@ -504,71 +506,71 @@ Blob ReadPipeBlob()
return ret;
}
-void snes_video_refresh(const uint32_t *data, unsigned width, unsigned height)
-{
+void snes_video_refresh(const uint32_t *data, unsigned width, unsigned height)
+{
s_EmulationControl.exitReason = eEmulationExitReason_SIG;
s_EmulationControl.exitCallbackType = eEmulationCallback_snes_video_refresh;
s_EmulationControl.cb_video_refresh_params.data = data;
s_EmulationControl.cb_video_refresh_params.width = width;
s_EmulationControl.cb_video_refresh_params.height = height;
- SETCONTROL;
-}
-
-bool audio_en = false;
-static const int AUDIOBUFFER_SIZE = 44100*2;
-uint16_t audiobuffer[AUDIOBUFFER_SIZE];
-int audiobuffer_idx = 0;
-
-void SIG_FlushAudio()
-{
+ SETCONTROL;
+}
+
+bool audio_en = false;
+static const int AUDIOBUFFER_SIZE = 44100*2;
+uint16_t audiobuffer[AUDIOBUFFER_SIZE];
+int audiobuffer_idx = 0;
+
+void SIG_FlushAudio()
+{
s_EmulationControl.exitReason = eEmulationExitReason_SIG;
s_EmulationControl.exitCallbackType = eEmulationCallback_snes_audio_flush;
SETCONTROL;
-}
-
-//this is the raw callback from the emulator internals when a new audio sample is available
-void snes_audio_sample(uint16_t left, uint16_t right)
-{
- if(!audio_en) return;
-
- //if theres no room in the audio buffer, we need to send a flush signal
- if(audiobuffer_idx == AUDIOBUFFER_SIZE)
- SIG_FlushAudio();
-
- audiobuffer[audiobuffer_idx++] = left;
+}
+
+//this is the raw callback from the emulator internals when a new audio sample is available
+void snes_audio_sample(uint16_t left, uint16_t right)
+{
+ if(!audio_en) return;
+
+ //if theres no room in the audio buffer, we need to send a flush signal
+ if(audiobuffer_idx == AUDIOBUFFER_SIZE)
+ SIG_FlushAudio();
+
+ audiobuffer[audiobuffer_idx++] = left;
audiobuffer[audiobuffer_idx++] = right;
-}
-
-void snes_input_poll(void)
-{
+}
+
+void snes_input_poll(void)
+{
s_EmulationControl.exitReason = eEmulationExitReason_SIG;
- s_EmulationControl.exitCallbackType = eEmulationCallback_snes_input_poll;
- SETCONTROL;
-}
-int16_t snes_input_state(unsigned port, unsigned device, unsigned index, unsigned id)
-{
+ s_EmulationControl.exitCallbackType = eEmulationCallback_snes_input_poll;
+ SETCONTROL;
+}
+int16_t snes_input_state(unsigned port, unsigned device, unsigned index, unsigned id)
+{
s_EmulationControl.exitReason = eEmulationExitReason_SIG;
- s_EmulationControl.exitCallbackType = eEmulationCallback_snes_input_state;
- s_EmulationControl.cb_input_state_params.port = port;
- s_EmulationControl.cb_input_state_params.device = device;
- s_EmulationControl.cb_input_state_params.index = index;
- s_EmulationControl.cb_input_state_params.id = id;
- SETCONTROL;
- return s_EmulationControl.cb_input_state_params.result;
-}
-void snes_input_notify(int index)
-{
+ s_EmulationControl.exitCallbackType = eEmulationCallback_snes_input_state;
+ s_EmulationControl.cb_input_state_params.port = port;
+ s_EmulationControl.cb_input_state_params.device = device;
+ s_EmulationControl.cb_input_state_params.index = index;
+ s_EmulationControl.cb_input_state_params.id = id;
+ SETCONTROL;
+ return s_EmulationControl.cb_input_state_params.result;
+}
+void snes_input_notify(int index)
+{
s_EmulationControl.exitReason = eEmulationExitReason_SIG;
- s_EmulationControl.exitCallbackType = eEmulationCallback_snes_input_notify;
- s_EmulationControl.cb_input_notify_params.index = index;
- SETCONTROL;
-}
-
+ s_EmulationControl.exitCallbackType = eEmulationCallback_snes_input_notify;
+ s_EmulationControl.cb_input_notify_params.index = index;
+ SETCONTROL;
+}
+
void snes_trace(const char *msg)
{
s_EmulationControl.exitReason = eEmulationExitReason_SIG;
- s_EmulationControl.exitCallbackType = eEmulationCallback_snes_trace;
+ s_EmulationControl.exitCallbackType = eEmulationCallback_snes_trace;
s_EmulationControl.cb_trace_params.msg = msg;
SETCONTROL;
}
@@ -606,24 +608,24 @@ public:
static std::map memHandleTable;
-void* implementation_snes_allocSharedMemory()
-{
- const char* memtype = s_EmulationControl.cb_allocSharedMemory_params.memtype;
- size_t amt = s_EmulationControl.cb_allocSharedMemory_params.amt;
-
- if(!running)
- {
- s_EmulationControl.cb_allocSharedMemory_params.result = NULL;
- return NULL;
- }
-
- //printf("WritePipe(eMessage_SIG_allocSharedMemory)\n");
- WritePipe(eMessage_SIG_allocSharedMemory);
- WritePipeString(memtype);
- WritePipe(amt);
-
- std::string blockname = ReadPipeString();
-
+void* implementation_snes_allocSharedMemory()
+{
+ const char* memtype = s_EmulationControl.cb_allocSharedMemory_params.memtype;
+ size_t amt = s_EmulationControl.cb_allocSharedMemory_params.amt;
+
+ if(!running)
+ {
+ s_EmulationControl.cb_allocSharedMemory_params.result = NULL;
+ return NULL;
+ }
+
+ //printf("WritePipe(eMessage_SIG_allocSharedMemory)\n");
+ WritePipe(eMessage_SIG_allocSharedMemory);
+ WritePipeString(memtype);
+ WritePipe(amt);
+
+ std::string blockname = ReadPipeString();
+
auto mapfile = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, blockname.c_str());
if(mapfile == INVALID_HANDLE_VALUE)
@@ -636,36 +638,36 @@ void* implementation_snes_allocSharedMemory()
smb->handle = mapfile;
memHandleTable[ptr] = smb;
-
- s_EmulationControl.cb_allocSharedMemory_params.result = ptr;
+
+ s_EmulationControl.cb_allocSharedMemory_params.result = ptr;
}
-void* snes_allocSharedMemory(const char* memtype, size_t amt)
-{
- //its important that this happen before the message marshaling because allocation/free attempts can happen before the marshaling is setup (or at shutdown time, in case of errors?)
- if(!running) return NULL;
-
+void* snes_allocSharedMemory(const char* memtype, size_t amt)
+{
+ //its important that this happen before the message marshaling because allocation/free attempts can happen before the marshaling is setup (or at shutdown time, in case of errors?)
+ if(!running) return NULL;
+
s_EmulationControl.exitReason = eEmulationExitReason_SIG;
s_EmulationControl.exitCallbackType = eEmulationCallback_snes_allocSharedMemory;
s_EmulationControl.cb_allocSharedMemory_params.memtype = memtype;
s_EmulationControl.cb_allocSharedMemory_params.amt = amt;
SETCONTROL;
-
- return s_EmulationControl.cb_allocSharedMemory_params.result;
-}
-
-void implementation_snes_freeSharedMemory()
-{
- void* ptr = s_EmulationControl.cb_freeSharedMemory_params.ptr;
+
+ return s_EmulationControl.cb_allocSharedMemory_params.result;
+}
+
+void implementation_snes_freeSharedMemory()
+{
+ void* ptr = s_EmulationControl.cb_freeSharedMemory_params.ptr;
if(!ptr) return;
auto smb = memHandleTable.find(ptr)->second;
UnmapViewOfFile(ptr);
CloseHandle(smb->handle);
//printf("WritePipe(eMessage_SIG_freeSharedMemory);\n");
- WritePipe(eMessage_SIG_freeSharedMemory);
- WritePipeString(smb->memtype.c_str());
-}
-
+ WritePipe(eMessage_SIG_freeSharedMemory);
+ WritePipeString(smb->memtype.c_str());
+}
+
void snes_freeSharedMemory(void* ptr)
{
//its important that this happen before the message marshaling because allocation/free attempts can happen before the marshaling is setup (or at shutdown time, in case of errors?)
@@ -997,7 +999,7 @@ TOP:
break;
}
case eEmulationCallback_snes_audio_flush:
- Handle_SIG_audio_flush();
+ Handle_SIG_audio_flush();
break;
case eEmulationCallback_snes_input_poll:
WritePipe(eMessage_SIG_input_poll);
@@ -1203,13 +1205,13 @@ void emuthread()
//EDIT - well, we changed that, but.. we still want this probably, for debugging and stuff
for(;;)
{
- SNES::scheduler.sync = SNES::Scheduler::SynchronizeMode::None;
- SNES::scheduler.clearExitReason();
- SNES::scheduler.enter();
- if(SNES::scheduler.exit_reason() == SNES::Scheduler::ExitReason::FrameEvent)
- {
- SNES::video.update();
- break;
+ SNES::scheduler.sync = SNES::Scheduler::SynchronizeMode::None;
+ SNES::scheduler.clearExitReason();
+ SNES::scheduler.enter();
+ if(SNES::scheduler.exit_reason() == SNES::Scheduler::ExitReason::FrameEvent)
+ {
+ SNES::video.update();
+ break;
}
//not used yet
if(SNES::scheduler.exit_reason() == SNES::Scheduler::ExitReason::DebuggerEvent)
@@ -1273,7 +1275,7 @@ int xmain(int argc, char** argv)
printf("running\n");
RunControlMessageLoop();
-
+
return 0;
}
diff --git a/output/dll/libsneshawk-32-compatibility.exe b/output/dll/libsneshawk-32-compatibility.exe
index a7b40091c6..abfd4b1c79 100644
Binary files a/output/dll/libsneshawk-32-compatibility.exe and b/output/dll/libsneshawk-32-compatibility.exe differ
diff --git a/output/dll/libsneshawk-32-performance.exe b/output/dll/libsneshawk-32-performance.exe
index ac844d10ef..8a69243ef7 100644
Binary files a/output/dll/libsneshawk-32-performance.exe and b/output/dll/libsneshawk-32-performance.exe differ