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