diff --git a/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs b/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs index a4484202f8..3984667641 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs @@ -12,487 +12,11 @@ using System.Linq; using System.Diagnostics; using System.Globalization; using System.IO; -using System.IO.Pipes; using System.Collections.Generic; using System.Runtime.InteropServices; -using System.IO.MemoryMappedFiles; namespace BizHawk.Emulation.Consoles.Nintendo.SNES { - public unsafe class LibsnesApi : IDisposable - { - //this wouldve been the ideal situation to learn protocol buffers, but since the number of messages here is so limited, it took less time to roll it by hand. - //todo - could optimize a lot of the apis once we decide to commit to this. will we? then we wont be able to debug bsnes as well - // well, we could refactor it a lot and let the debuggable static dll version be the one that does annoying workarounds - //todo - more intelligent use of buffers to avoid so many copies (especially framebuffer from bsnes? supply framebuffer to-be-used to libsnes? same for audiobuffer) - //todo - refactor to use a smarter set of pipe reader and pipe writer classes - //todo - combine messages / tracecallbacks into one system with a channel number enum additionally - //todo - consider refactoring bsnes to allocate memory blocks through the interface, and set ours up to allocate from a large arena of shared memory. - // this is a lot of work, but it will be some decent speedups. who wouldve ever thought to make an emulator this way? I will, from now on... - //todo - use a reader/writer ring buffer for communication instead of pipe - //todo - when exe wrapper is fully baked, put it into mingw so we can just have libsneshawk.exe without a separate dll. it hardly needs any debugging presently, it should be easy to maintain. - - Process process; - NamedPipeServerStream pipe; - BinaryWriter bwPipe; - BinaryReader brPipe; - MemoryMappedFile mmf; - MemoryMappedViewAccessor mmva; - byte* mmvaPtr; - - public enum eMessage : int - { - eMessage_Complete, - - eMessage_snes_library_id, - eMessage_snes_library_revision_major, - eMessage_snes_library_revision_minor, - - eMessage_snes_init, - eMessage_snes_power, - eMessage_snes_reset, - eMessage_snes_run, - eMessage_snes_term, - eMessage_snes_unload_cartridge, - - //snes_set_cartridge_basename, //not used - - eMessage_snes_load_cartridge_normal, - - //incoming from bsnes - eMessage_snes_cb_video_refresh, - eMessage_snes_cb_input_poll, - eMessage_snes_cb_input_state, - eMessage_snes_cb_input_notify, - eMessage_snes_cb_audio_sample, - eMessage_snes_cb_scanlineStart, - eMessage_snes_cb_path_request, - eMessage_snes_cb_trace_callback, - - eMessage_snes_get_region, - - eMessage_snes_get_memory_size, - eMessage_snes_get_memory_data, - eMessage_peek, - eMessage_poke, - - eMessage_snes_serialize_size, - - eMessage_snes_serialize, - eMessage_snes_unserialize, - - eMessage_snes_poll_message, - eMessage_snes_dequeue_message, - - eMessage_snes_set_color_lut, - - eMessage_snes_enable_trace, - eMessage_snes_enable_scanline, - eMessage_snes_enable_audio, - eMessage_snes_set_layer_enable, - eMessage_snes_set_backdropColor, - eMessage_snes_peek_logical_register - }; - - static bool DryRun(string exePath) - { - ProcessStartInfo oInfo = new ProcessStartInfo(exePath, "Bongizong"); - oInfo.WorkingDirectory = Path.GetDirectoryName(exePath); - oInfo.UseShellExecute = false; - oInfo.CreateNoWindow = true; - oInfo.RedirectStandardOutput = true; - oInfo.RedirectStandardError = true; - - Process proc = System.Diagnostics.Process.Start(oInfo); - string result = proc.StandardError.ReadToEnd(); - proc.WaitForExit(); - - if (result == "Honga Wongkong" && proc.ExitCode == 0x16817) - return true; - - return false; - } - - static bool Initialized; - static string exePath; - - void StaticInit() - { - if (Initialized) return; - - string thisDir = System.Reflection.Assembly.GetExecutingAssembly().GetDirectory(); - exePath = Path.Combine(thisDir, "libsnes_pwrap.exe"); - if (!File.Exists(exePath)) - exePath = Path.Combine(Path.Combine(thisDir, "dll"), "libsnes_pwrap.exe"); - - if (!File.Exists(exePath)) - throw new InvalidOperationException("Can't find libsnes_pwrap.exe to run libsneshawk core"); - - if (!DryRun(exePath)) - { - throw new InvalidOperationException("Can't launch libsnes_pwrap.exe to run libsneshawk core. Missing a libsneshawk.dll?"); - } - - Initialized = true; - } - - public LibsnesApi() - { - StaticInit(); - - var pipeName = "libsnespwrap_" + Guid.NewGuid().ToString(); - - mmf = MemoryMappedFile.CreateNew(pipeName, 1024 * 1024); - mmva = mmf.CreateViewAccessor(); - mmva.SafeMemoryMappedViewHandle.AcquirePointer(ref mmvaPtr); - - pipe = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.None, 1024 * 1024, 1024); - - process = new Process(); - process.StartInfo.WorkingDirectory = Path.GetDirectoryName(exePath); - process.StartInfo.FileName = exePath; - process.StartInfo.Arguments = pipeName; - process.StartInfo.ErrorDialog = true; - process.Start(); - - //TODO - start a thread to wait for process to exit and gracefully handle errors? how about the pipe? - - pipe.WaitForConnection(); - bwPipe = new BinaryWriter(pipe); - brPipe = new BinaryReader(pipe); - } - - public void Dispose() - { - process.Kill(); - process.Dispose(); - process = null; - pipe.Dispose(); - mmva.Dispose(); - mmf.Dispose(); - } - - void WritePipeString(string str) - { - WritePipeBlob(System.Text.Encoding.ASCII.GetBytes(str)); - } - - byte[] ReadPipeBlob() - { - int len = brPipe.ReadInt32(); - var ret = new byte[len]; - brPipe.Read(ret, 0, len); - return ret; - } - - void WritePipeBlob(byte[] blob) - { - bwPipe.Write(blob.Length); - bwPipe.Write(blob); - } - - public int MessageCounter; - - void WritePipeMessage(eMessage msg) - { - MessageCounter++; - bwPipe.Write((int)msg); - } - - eMessage ReadPipeMessage() - { - return (eMessage)brPipe.ReadInt32(); - } - - public string snes_library_id() - { - WritePipeMessage(eMessage.eMessage_snes_library_id); - return brPipe.ReadStringAsciiZ(); - } - - - public uint snes_library_revision_major() - { - WritePipeMessage(eMessage.eMessage_snes_library_revision_major); - return brPipe.ReadUInt32(); - } - - public uint snes_library_revision_minor() - { - WritePipeMessage(eMessage.eMessage_snes_library_revision_minor); - return brPipe.ReadUInt32(); - } - - public void snes_init() { WritePipeMessage(eMessage.eMessage_snes_init); } - public void snes_power() { WritePipeMessage(eMessage.eMessage_snes_power); } - public void snes_reset() { WritePipeMessage(eMessage.eMessage_snes_reset); } - public void snes_run() - { - WritePipeMessage(eMessage.eMessage_snes_run); - WaitForCompletion(); - } - public void snes_term() { WritePipeMessage(eMessage.eMessage_snes_term); } - public void snes_unload_cartridge() { WritePipeMessage(eMessage.eMessage_snes_unload_cartridge); } - - - public bool snes_load_cartridge_normal(string rom_xml, byte[] rom_data) - { - WritePipeMessage(eMessage.eMessage_snes_load_cartridge_normal); - WritePipeString(rom_xml ?? ""); - WritePipeBlob(rom_data); - WaitForCompletion(); - return brPipe.ReadBoolean(); - } - - public LibsnesDll.SNES_REGION snes_get_region() - { - WritePipeMessage(eMessage.eMessage_snes_get_region); - return (LibsnesDll.SNES_REGION)brPipe.ReadByte(); - } - - public int snes_get_memory_size(LibsnesDll.SNES_MEMORY id) - { - WritePipeMessage(eMessage.eMessage_snes_get_memory_size); - bwPipe.Write((int)id); - return brPipe.ReadInt32(); - } - public byte[] snes_get_memory_data(LibsnesDll.SNES_MEMORY id) - { - int size = snes_get_memory_size(id); - WritePipeMessage(eMessage.eMessage_snes_get_memory_data); - bwPipe.Write((int)id); - bwPipe.Write(0); - var ret = new byte[size]; - WaitForCompletion(); - Marshal.Copy(new IntPtr(mmvaPtr), ret, 0, size); - return ret; - } - - public byte peek(LibsnesDll.SNES_MEMORY id, uint addr) - { - WritePipeMessage(eMessage.eMessage_peek); - bwPipe.Write((uint)id); - bwPipe.Write(addr); - return brPipe.ReadByte(); - } - public void poke(LibsnesDll.SNES_MEMORY id, uint addr, byte val) - { - WritePipeMessage(eMessage.eMessage_poke); - bwPipe.Write((uint)id); - bwPipe.Write(addr); - bwPipe.Write(val); - } - - public int snes_serialize_size() - { - WritePipeMessage(eMessage.eMessage_snes_serialize_size); - return brPipe.ReadInt32(); - } - - [DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)] - public static unsafe extern void* CopyMemory(void* dest, void* src, ulong count); - - - - public bool snes_serialize(IntPtr data, int size) - { - WritePipeMessage(eMessage.eMessage_snes_serialize); - bwPipe.Write(size); - bwPipe.Write(0); //mapped memory location to serialize to - WaitForCompletion(); //serialize/unserialize can cause traces to get called (because serialize can cause execution?) - bool ret = brPipe.ReadBoolean(); - if(ret) - { - CopyMemory(data.ToPointer(), mmvaPtr, (ulong)size); - } - return ret; - } - - public bool snes_unserialize(IntPtr data, int size) - { - WritePipeMessage(eMessage.eMessage_snes_unserialize); - CopyMemory(mmvaPtr, data.ToPointer(), (ulong)size); - bwPipe.Write(size); - bwPipe.Write(0); //mapped memory location to serialize from - WaitForCompletion(); //serialize/unserialize can cause traces to get called (because serialize can cause execution?) - bool ret = brPipe.ReadBoolean(); - return ret; - } - - int snes_poll_message() - { - WritePipeMessage(eMessage.eMessage_snes_poll_message); - return brPipe.ReadInt32(); - } - - public bool HasMessage { get { return snes_poll_message() != -1; } } - - - public string DequeueMessage() - { - WritePipeMessage(eMessage.eMessage_snes_dequeue_message); - return brPipe.ReadStringAsciiZ(); - } - - public void snes_set_color_lut(IntPtr colors) - { - int len = 4 * 16 * 32768; - byte[] buf = new byte[len]; - Marshal.Copy(colors, buf, 0, len); - - WritePipeMessage(eMessage.eMessage_snes_set_color_lut); - WritePipeBlob(buf); - } - - public void snes_set_layer_enable(int layer, int priority, bool enable) - { - WritePipeMessage(eMessage.eMessage_snes_set_layer_enable); - bwPipe.Write(layer); - bwPipe.Write(priority); - bwPipe.Write(enable); - } - - public void snes_set_backdropColor(int backdropColor) - { - WritePipeMessage(eMessage.eMessage_snes_set_backdropColor); - bwPipe.Write(backdropColor); - } - - public int snes_peek_logical_register(LibsnesDll.SNES_REG reg) - { - WritePipeMessage(eMessage.eMessage_snes_peek_logical_register); - bwPipe.Write((int)reg); - return brPipe.ReadInt32(); - } - - void WaitForCompletion() - { - for (; ; ) - { - var msg = ReadPipeMessage(); - MessageCounter++; - switch (msg) - { - case eMessage.eMessage_Complete: - return; - - case eMessage.eMessage_snes_cb_video_refresh: - { - int width = brPipe.ReadInt32(); - int height = brPipe.ReadInt32(); - bwPipe.Write(0); //offset in mapped memory buffer - brPipe.ReadBoolean(); //dummy synchronization - if (video_refresh != null) - { - video_refresh((int*)mmvaPtr, width, height); - } - break; - } - case eMessage.eMessage_snes_cb_input_poll: - break; - case eMessage.eMessage_snes_cb_input_state: - { - int port = brPipe.ReadInt32(); - int device = brPipe.ReadInt32(); - int index = brPipe.ReadInt32(); - int id = brPipe.ReadInt32(); - ushort ret = 0; - if (input_state != null) - ret = input_state(port, device, index, id); - bwPipe.Write(ret); - break; - } - case eMessage.eMessage_snes_cb_input_notify: - { - int index = brPipe.ReadInt32(); - if (input_notify != null) - input_notify(index); - break; - } - case eMessage.eMessage_snes_cb_audio_sample: - { - int nsamples = brPipe.ReadInt32(); - bwPipe.Write(0); //location to store audio buffer in - brPipe.ReadInt32(); //dummy synchronization - - if (audio_sample != null) - { - ushort* audiobuffer = ((ushort*)mmvaPtr); - for (int i = 0; i < nsamples;) - { - ushort left = audiobuffer[i++]; - ushort right = audiobuffer[i++]; - audio_sample(left, right); - } - } - - bwPipe.Write(0); //dummy synchronization - brPipe.ReadInt32(); //dummy synchronization - break; - } - case eMessage.eMessage_snes_cb_scanlineStart: - { - int line = brPipe.ReadInt32(); - if (scanlineStart != null) - scanlineStart(line); - break; - } - case eMessage.eMessage_snes_cb_path_request: - { - int slot = brPipe.ReadInt32(); - string hint = brPipe.ReadStringAsciiZ(); - string ret = hint; - if(pathRequest != null) - hint = pathRequest(slot, hint); - WritePipeString(hint); - break; - } - case eMessage.eMessage_snes_cb_trace_callback: - { - var trace = brPipe.ReadStringAsciiZ(); - if (traceCallback != null) - traceCallback(trace); - break; - } - } - } - } - - - LibsnesDll.snes_video_refresh_t video_refresh; - LibsnesDll.snes_input_poll_t input_poll; - LibsnesDll.snes_input_state_t input_state; - LibsnesDll.snes_input_notify_t input_notify; - LibsnesDll.snes_audio_sample_t audio_sample; - LibsnesDll.snes_scanlineStart_t scanlineStart; - LibsnesDll.snes_path_request_t pathRequest; - LibsnesDll.snes_trace_t traceCallback; - - public void snes_set_video_refresh(LibsnesDll.snes_video_refresh_t video_refresh) { this.video_refresh = video_refresh; } - public void snes_set_input_poll(LibsnesDll.snes_input_poll_t input_poll) { this.input_poll = input_poll; } - public void snes_set_input_state(LibsnesDll.snes_input_state_t input_state) { this.input_state = input_state; } - public void snes_set_input_notify(LibsnesDll.snes_input_notify_t input_notify) { this.input_notify = input_notify; } - public void snes_set_audio_sample(LibsnesDll.snes_audio_sample_t audio_sample) - { - this.audio_sample = audio_sample; - WritePipeMessage(eMessage.eMessage_snes_enable_audio); - bwPipe.Write(audio_sample != null); - } - public void snes_set_path_request(LibsnesDll.snes_path_request_t pathRequest) { this.pathRequest = pathRequest; } - public void snes_set_scanlineStart(LibsnesDll.snes_scanlineStart_t scanlineStart) - { - this.scanlineStart = scanlineStart; - WritePipeMessage(eMessage.eMessage_snes_enable_scanline); - bwPipe.Write(scanlineStart != null); - } - public void snes_set_trace_callback(LibsnesDll.snes_trace_t callback) - { - this.traceCallback = callback; - WritePipeMessage(eMessage.eMessage_snes_enable_trace); - bwPipe.Write(callback != null); - } - } - public unsafe static class LibsnesDll { [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] @@ -571,7 +95,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void snes_set_scanlineStart(snes_scanlineStart_t scanlineStart); [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern void snes_set_path_request(snes_path_request_t pathRequest); + public static extern void snes_set_path_request(snes_path_request_t scanlineStart); [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.U1)] @@ -741,9 +265,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES VRAM = 102, OAM = 103, CGRAM = 104, - - SYSBUS = 200, - LOGICAL_REGS = 201 } public enum SNES_REGION : byte @@ -833,11 +354,16 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES disposedSaveRam = ReadSaveRam(); - api.snes_unload_cartridge(); - api.snes_term(); + BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_video_refresh(null); + BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_input_poll(null); + BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_input_state(null); + BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_audio_sample(null); + BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_scanlineStart(null); + + LibsnesDll.snes_unload_cartridge(); + LibsnesDll.snes_term(); resampler.Dispose(); - api.Dispose(); } //save the save memory before disposing the core, so we can pull from it in the future after the core is terminated //that will be necessary to get it saving to disk @@ -864,8 +390,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES void OnScanlineHooksChanged() { if (disposed) return; - if (ScanlineHookManager.HookCount == 0) api.snes_set_scanlineStart(null); - else api.snes_set_scanlineStart(scanlineStart_cb); + if (ScanlineHookManager.HookCount == 0) LibsnesDll.snes_set_scanlineStart(null); + else LibsnesDll.snes_set_scanlineStart(scanlineStart_cb); } void snes_scanlineStart(int line) @@ -906,16 +432,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES CurrPalette = pal; int[] tmp = SnesColors.GetLUT(pal); fixed (int* p = &tmp[0]) - api.snes_set_color_lut((IntPtr)p); + BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_color_lut((IntPtr)p); } - public LibsnesApi api; - public LibsnesCore(CoreComm comm) { CoreComm = comm; - api = new LibsnesApi(); - api.snes_init(); } public void Load(GameInfo game, byte[] romData, byte[] sgbRomData, bool DeterministicEmulation) @@ -927,25 +449,27 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES ScanlineHookManager = new MyScanlineHookManager(this); - api.snes_init(); + LibsnesDll.snes_init(); + + //LibsnesDll.snes_set_cartridge_basename(@); vidcb = new LibsnesDll.snes_video_refresh_t(snes_video_refresh); - api.snes_set_video_refresh(vidcb); + BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_video_refresh(vidcb); pollcb = new LibsnesDll.snes_input_poll_t(snes_input_poll); - api.snes_set_input_poll(pollcb); + BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_input_poll(pollcb); inputcb = new LibsnesDll.snes_input_state_t(snes_input_state); - api.snes_set_input_state(inputcb); + BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_input_state(inputcb); notifycb = new LibsnesDll.snes_input_notify_t(snes_input_notify); - api.snes_set_input_notify(notifycb); + BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_input_notify(notifycb); soundcb = new LibsnesDll.snes_audio_sample_t(snes_audio_sample); - api.snes_set_audio_sample(soundcb); + BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_audio_sample(soundcb); pathRequest_cb = new LibsnesDll.snes_path_request_t(snes_path_request); - api.snes_set_path_request(pathRequest_cb); + BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_path_request(pathRequest_cb); scanlineStart_cb = new LibsnesDll.snes_scanlineStart_t(snes_scanlineStart); @@ -976,11 +500,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES else { SystemId = "SNES"; - if (!api.snes_load_cartridge_normal(null, romData)) + if (!LibsnesDll.snes_load_cartridge_normal(null, romData, (uint)romData.Length)) throw new Exception("snes_load_cartridge_normal() failed"); } - if (api.snes_get_region() == LibsnesDll.SNES_REGION.NTSC) + if (LibsnesDll.snes_get_region() == LibsnesDll.SNES_REGION.NTSC) { //similar to what aviout reports from snes9x and seems logical from bsnes first principles. bsnes uses that numerator (ntsc master clockrate) for sure. CoreComm.VsyncNum = 21477272; @@ -994,7 +518,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES CoreComm.CpuTraceAvailable = true; - api.snes_power(); + LibsnesDll.snes_power(); SetupMemoryDomains(romData); @@ -1125,8 +649,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES public void FrameAdvance(bool render, bool rendersound) { - api.MessageCounter = 0; - // for deterministic emulation, save the state we're going to use before frame advance // don't do this during nocallbacks though, since it's already been done if (!nocallbacks && DeterministicEmulation) @@ -1143,58 +665,55 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES } if (!nocallbacks && CoreComm.Tracer.Enabled) - api.snes_set_trace_callback(tracecb); + LibsnesDll.snes_set_trace_callback(tracecb); else - api.snes_set_trace_callback(null); + LibsnesDll.snes_set_trace_callback(null); // speedup when sound rendering is not needed if (!rendersound) - api.snes_set_audio_sample(null); + LibsnesDll.snes_set_audio_sample(null); else - api.snes_set_audio_sample(soundcb); + LibsnesDll.snes_set_audio_sample(soundcb); bool resetSignal = Controller["Reset"]; - if (resetSignal) api.snes_reset(); + if (resetSignal) LibsnesDll.snes_reset(); bool powerSignal = Controller["Power"]; - if (powerSignal) api.snes_power(); + if (powerSignal) LibsnesDll.snes_power(); - //too many messages - api.snes_set_layer_enable(0, 0, CoreComm.SNES_ShowBG1_0); - api.snes_set_layer_enable(0, 1, CoreComm.SNES_ShowBG1_1); - api.snes_set_layer_enable(1, 0, CoreComm.SNES_ShowBG2_0); - api.snes_set_layer_enable(1, 1, CoreComm.SNES_ShowBG2_1); - api.snes_set_layer_enable(2, 0, CoreComm.SNES_ShowBG3_0); - api.snes_set_layer_enable(2, 1, CoreComm.SNES_ShowBG3_1); - api.snes_set_layer_enable(3, 0, CoreComm.SNES_ShowBG4_0); - api.snes_set_layer_enable(3, 1, CoreComm.SNES_ShowBG4_1); - api.snes_set_layer_enable(4, 0, CoreComm.SNES_ShowOBJ_0); - api.snes_set_layer_enable(4, 1, CoreComm.SNES_ShowOBJ_1); - api.snes_set_layer_enable(4, 2, CoreComm.SNES_ShowOBJ_2); - api.snes_set_layer_enable(4, 3, CoreComm.SNES_ShowOBJ_3); + LibsnesDll.snes_set_layer_enable(0, 0, CoreComm.SNES_ShowBG1_0); + LibsnesDll.snes_set_layer_enable(0, 1, CoreComm.SNES_ShowBG1_1); + LibsnesDll.snes_set_layer_enable(1, 0, CoreComm.SNES_ShowBG2_0); + LibsnesDll.snes_set_layer_enable(1, 1, CoreComm.SNES_ShowBG2_1); + LibsnesDll.snes_set_layer_enable(2, 0, CoreComm.SNES_ShowBG3_0); + LibsnesDll.snes_set_layer_enable(2, 1, CoreComm.SNES_ShowBG3_1); + LibsnesDll.snes_set_layer_enable(3, 0, CoreComm.SNES_ShowBG4_0); + LibsnesDll.snes_set_layer_enable(3, 1, CoreComm.SNES_ShowBG4_1); + LibsnesDll.snes_set_layer_enable(4, 0, CoreComm.SNES_ShowOBJ_0); + LibsnesDll.snes_set_layer_enable(4, 1, CoreComm.SNES_ShowOBJ_1); + LibsnesDll.snes_set_layer_enable(4, 2, CoreComm.SNES_ShowOBJ_2); + LibsnesDll.snes_set_layer_enable(4, 3, CoreComm.SNES_ShowOBJ_3); // if the input poll callback is called, it will set this to false IsLagFrame = true; //apparently this is one frame? timeFrameCounter++; - api.snes_run(); + LibsnesDll.snes_run(); - while (api.HasMessage) - Console.WriteLine(api.DequeueMessage()); + while (LibsnesDll.HasMessage) + Console.WriteLine(LibsnesDll.DequeueMessage()); if (IsLagFrame) LagCount++; - //diagnostics for IPC traffic - //Console.WriteLine(api.MessageCounter); } public DisplayType DisplayType { get { - if (api.snes_get_region() == LibsnesDll.SNES_REGION.NTSC) + if (LibsnesDll.snes_get_region() == LibsnesDll.SNES_REGION.NTSC) return BizHawk.DisplayType.NTSC; else return BizHawk.DisplayType.PAL; @@ -1420,7 +939,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES } public void LoadStateBinary(BinaryReader reader) { - int size = api.snes_serialize_size(); + int size = LibsnesDll.snes_serialize_size(); byte[] buf = reader.ReadBytes(size); CoreLoadState(buf); @@ -1471,22 +990,22 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES /// void CoreLoadState(byte[] data) { - int size = api.snes_serialize_size(); + int size = LibsnesDll.snes_serialize_size(); if (data.Length != size) throw new Exception("Libsnes internal savestate size mismatch!"); - api.snes_init(); + LibsnesDll.snes_init(); fixed (byte* pbuf = &data[0]) - api.snes_unserialize(new IntPtr(pbuf), size); + LibsnesDll.snes_unserialize(new IntPtr(pbuf), size); } /// /// handle the unmanaged part of savestating /// byte[] CoreSaveState() { - int size = api.snes_serialize_size(); + int size = LibsnesDll.snes_serialize_size(); byte[] buf = new byte[size]; fixed (byte* pbuf = &buf[0]) - api.snes_serialize(new IntPtr(pbuf), size); + LibsnesDll.snes_serialize(new IntPtr(pbuf), size); return buf; } @@ -1502,50 +1021,36 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES // ----- Client Debugging API stuff ----- unsafe MemoryDomain MakeMemoryDomain(string name, LibsnesDll.SNES_MEMORY id, Endian endian) { - int size = api.snes_get_memory_size(id); + IntPtr block = LibsnesDll.snes_get_memory_data(id); + int size = LibsnesDll.snes_get_memory_size(id); int mask = size - 1; + byte* blockptr = (byte*)block.ToPointer(); MemoryDomain md; - ////have to bitmask these somehow because it's unmanaged memory and we would hate to clobber things or make them nondeterministic - //if (Util.IsPowerOfTwo(size)) - //{ - // //can &mask for speed - // md = new MemoryDomain(name, size, endian, - // (addr) => blockptr[addr & mask], - // (addr, value) => blockptr[addr & mask] = value); - //} - //else - //{ - // //have to use % (only OAM needs this, it seems) - // //(OAM is actually two differently sized banks of memory which arent truly considered adjacent. maybe a better way to visualize it would be with an empty bus and adjacent banks) - // md = new MemoryDomain(name, size, endian, - // (addr) => blockptr[addr % size], - // (addr, value) => blockptr[addr % size] = value); - //} - - //EXTERNAL PROCESS CONVERSION: MUST MAKE THIS SAFE - //speed it up later + //have to bitmask these somehow because it's unmanaged memory and we would hate to clobber things or make them nondeterministic if (Util.IsPowerOfTwo(size)) { //can &mask for speed md = new MemoryDomain(name, size, endian, - (addr) => api.peek(id, (uint)(addr & mask)), - (addr, value) => api.poke(id, (uint)(addr & mask), value)); + (addr) => blockptr[addr & mask], + (addr, value) => blockptr[addr & mask] = value); } else { //have to use % (only OAM needs this, it seems) - //(OAM is actually two differently sized banks of memory which arent truly considered adjacent. maybe a better way to visualize it would be with an empty bus and adjacent banks) md = new MemoryDomain(name, size, endian, - (addr) => api.peek(id, (uint)(addr % size)), - (addr, value) => api.poke(id, (uint)(addr % size), value)); + (addr) => blockptr[addr % size], + (addr, value) => blockptr[addr % size] = value); } MemoryDomains.Add(md); return md; - + //doesnt cache the addresses. safer. slower. necessary? don't know + //return new MemoryDomain(name, size, endian, + // (addr) => Peek(LibsnesDll.SNES_MEMORY.WRAM, addr & mask), + // (addr, value) => Poke(LibsnesDll.SNES_MEMORY.WRAM, addr & mask, value)); } void SetupMemoryDomains(byte[] romData) @@ -1566,8 +1071,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES if (!DeterministicEmulation) MemoryDomains.Add(new MemoryDomain("BUS", 0x1000000, Endian.Little, - (addr) => api.peek(LibsnesDll.SNES_MEMORY.SYSBUS, (uint)addr), - (addr, val) => api.poke(LibsnesDll.SNES_MEMORY.SYSBUS, (uint)addr, val))); + (addr) => LibsnesDll.bus_read((uint)addr), + (addr, val) => LibsnesDll.bus_write((uint)addr, val))); } public IList MemoryDomains { get; private set; } public MemoryDomain MainMemory { get; private set; } diff --git a/BizHawk.Emulation/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs b/BizHawk.Emulation/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs index 7953a7bee4..43404a382e 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs @@ -10,14 +10,14 @@ using System.Linq; using System.Diagnostics; using System.Globalization; using System.IO; -using System.Runtime.InteropServices; using System.Collections.Generic; namespace BizHawk.Emulation.Consoles.Nintendo.SNES { - public unsafe class SNESGraphicsDecoder : IDisposable + public unsafe class SNESGraphicsDecoder { + public class PaletteSelection { public PaletteSelection() { } @@ -332,15 +332,15 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES public bool M7SEL_HFLIP { private set; get; } public bool M7SEL_VFLIP { private set; get; } - public static ScreenInfo GetScreenInfo(LibsnesApi api) + public static ScreenInfo GetScreenInfo() { var si = new ScreenInfo(); - si.Mode1_BG3_Priority = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3_PRIORITY) == 1; + si.Mode1_BG3_Priority = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3_PRIORITY) == 1; - si.OBSEL_Size = api.snes_peek_logical_register(LibsnesDll.SNES_REG.OBSEL_SIZE); - si.OBSEL_NameSel = api.snes_peek_logical_register(LibsnesDll.SNES_REG.OBSEL_NAMESEL); - si.OBSEL_NameBase = api.snes_peek_logical_register(LibsnesDll.SNES_REG.OBSEL_NAMEBASE); + si.OBSEL_Size = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.OBSEL_SIZE); + si.OBSEL_NameSel = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.OBSEL_NAMESEL); + si.OBSEL_NameBase = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.OBSEL_NAMEBASE); si.ObjSizeBounds = ObjSizes[si.OBSEL_Size,1]; int square = Math.Max(si.ObjSizeBounds.Width, si.ObjSizeBounds.Height); @@ -350,26 +350,26 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES si.OBJTable0Addr = si.OBSEL_NameBase << 14; si.OBJTable1Addr = (si.OBJTable0Addr + ((si.OBSEL_NameSel + 1) << 13)) & 0xFFFF; - si.SETINI_Mode7ExtBG = api.snes_peek_logical_register(LibsnesDll.SNES_REG.SETINI_MODE7_EXTBG) == 1; - si.SETINI_HiRes = api.snes_peek_logical_register(LibsnesDll.SNES_REG.SETINI_HIRES) == 1; - si.SETINI_Overscan = api.snes_peek_logical_register(LibsnesDll.SNES_REG.SETINI_OVERSCAN) == 1; - si.SETINI_ObjInterlace = api.snes_peek_logical_register(LibsnesDll.SNES_REG.SETINI_OBJ_INTERLACE) == 1; - si.SETINI_ScreenInterlace = api.snes_peek_logical_register(LibsnesDll.SNES_REG.SETINI_SCREEN_INTERLACE) == 1; + si.SETINI_Mode7ExtBG = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.SETINI_MODE7_EXTBG) == 1; + si.SETINI_HiRes = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.SETINI_HIRES) == 1; + si.SETINI_Overscan = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.SETINI_OVERSCAN) == 1; + si.SETINI_ObjInterlace = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.SETINI_OBJ_INTERLACE) == 1; + si.SETINI_ScreenInterlace = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.SETINI_SCREEN_INTERLACE) == 1; - si.CGWSEL_ColorMask = api.snes_peek_logical_register(LibsnesDll.SNES_REG.CGWSEL_COLORMASK); - si.CGWSEL_ColorSubMask = api.snes_peek_logical_register(LibsnesDll.SNES_REG.CGWSEL_COLORSUBMASK); - si.CGWSEL_AddSubMode = api.snes_peek_logical_register(LibsnesDll.SNES_REG.CGWSEL_ADDSUBMODE); - si.CGWSEL_DirectColor = api.snes_peek_logical_register(LibsnesDll.SNES_REG.CGWSEL_DIRECTCOLOR) == 1; + si.CGWSEL_ColorMask = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGWSEL_COLORMASK); + si.CGWSEL_ColorSubMask = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGWSEL_COLORSUBMASK); + si.CGWSEL_AddSubMode = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGWSEL_ADDSUBMODE); + si.CGWSEL_DirectColor = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGWSEL_DIRECTCOLOR) == 1; - si.CGADSUB_AddSub = api.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_MODE); - si.CGADSUB_Half = api.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_HALF) == 1; + si.CGADSUB_AddSub = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_MODE); + si.CGADSUB_Half = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_HALF) == 1; - si.OBJ_MainEnabled = api.snes_peek_logical_register(LibsnesDll.SNES_REG.TM_OBJ) == 1; - si.OBJ_SubEnabled = api.snes_peek_logical_register(LibsnesDll.SNES_REG.TS_OBJ) == 1; - si.OBJ_MathEnabled = api.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_OBJ) == 1; - si.BK_MathEnabled = api.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_BACKDROP) == 1; + si.OBJ_MainEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.TM_OBJ) == 1; + si.OBJ_SubEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.TS_OBJ) == 1; + si.OBJ_MathEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_OBJ) == 1; + si.BK_MathEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_BACKDROP) == 1; - si.Mode.MODE = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG_MODE); + si.Mode.MODE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG_MODE); si.BG.BG1.Bpp = ModeBpps[si.Mode.MODE, 0]; si.BG.BG2.Bpp = ModeBpps[si.Mode.MODE, 1]; si.BG.BG3.Bpp = ModeBpps[si.Mode.MODE, 2]; @@ -379,58 +379,58 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES for(int i=1;i<=4;i++) si.BG[i].BGMode = si.BG[i].Bpp == 0 ? BGMode.Unavailable : BGMode.Text; - si.BG.BG1.TILESIZE = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG1_TILESIZE); - si.BG.BG2.TILESIZE = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2_TILESIZE); - si.BG.BG3.TILESIZE = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3_TILESIZE); - si.BG.BG4.TILESIZE = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG4_TILESIZE); + si.BG.BG1.TILESIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG1_TILESIZE); + si.BG.BG2.TILESIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2_TILESIZE); + si.BG.BG3.TILESIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3_TILESIZE); + si.BG.BG4.TILESIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG4_TILESIZE); - si.BG.BG1.SCSIZE = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG1_SCSIZE); - si.BG.BG2.SCSIZE = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2_SCSIZE); - si.BG.BG3.SCSIZE = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3_SCSIZE); - si.BG.BG4.SCSIZE = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG4_SCSIZE); - si.BG.BG1.SCADDR = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG1_SCADDR); - si.BG.BG2.SCADDR = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2_SCADDR); - si.BG.BG3.SCADDR = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3_SCADDR); - si.BG.BG4.SCADDR = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG4_SCADDR); - si.BG.BG1.TDADDR = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG1_TDADDR); - si.BG.BG2.TDADDR = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2_TDADDR); - si.BG.BG3.TDADDR = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3_TDADDR); - si.BG.BG4.TDADDR = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG4_TDADDR); + si.BG.BG1.SCSIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG1_SCSIZE); + si.BG.BG2.SCSIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2_SCSIZE); + si.BG.BG3.SCSIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3_SCSIZE); + si.BG.BG4.SCSIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG4_SCSIZE); + si.BG.BG1.SCADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG1_SCADDR); + si.BG.BG2.SCADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2_SCADDR); + si.BG.BG3.SCADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3_SCADDR); + si.BG.BG4.SCADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG4_SCADDR); + si.BG.BG1.TDADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG1_TDADDR); + si.BG.BG2.TDADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2_TDADDR); + si.BG.BG3.TDADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3_TDADDR); + si.BG.BG4.TDADDR = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG4_TDADDR); - si.BG.BG1.MainEnabled = api.snes_peek_logical_register(LibsnesDll.SNES_REG.TM_BG1) == 1; - si.BG.BG2.MainEnabled = api.snes_peek_logical_register(LibsnesDll.SNES_REG.TM_BG2) == 1; - si.BG.BG3.MainEnabled = api.snes_peek_logical_register(LibsnesDll.SNES_REG.TM_BG3) == 1; - si.BG.BG4.MainEnabled = api.snes_peek_logical_register(LibsnesDll.SNES_REG.TM_BG4) == 1; - si.BG.BG1.SubEnabled = api.snes_peek_logical_register(LibsnesDll.SNES_REG.TS_BG1) == 1; - si.BG.BG2.SubEnabled = api.snes_peek_logical_register(LibsnesDll.SNES_REG.TS_BG2) == 1; - si.BG.BG3.SubEnabled = api.snes_peek_logical_register(LibsnesDll.SNES_REG.TS_BG3) == 1; - si.BG.BG4.SubEnabled = api.snes_peek_logical_register(LibsnesDll.SNES_REG.TS_BG4) == 1; - si.BG.BG1.MathEnabled = api.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_BG1) == 1; - si.BG.BG2.MathEnabled = api.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_BG2) == 1; - si.BG.BG3.MathEnabled = api.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_BG3) == 1; - si.BG.BG4.MathEnabled = api.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_BG4) == 1; + si.BG.BG1.MainEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.TM_BG1) == 1; + si.BG.BG2.MainEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.TM_BG2) == 1; + si.BG.BG3.MainEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.TM_BG3) == 1; + si.BG.BG4.MainEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.TM_BG4) == 1; + si.BG.BG1.SubEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.TS_BG1) == 1; + si.BG.BG2.SubEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.TS_BG2) == 1; + si.BG.BG3.SubEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.TS_BG3) == 1; + si.BG.BG4.SubEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.TS_BG4) == 1; + si.BG.BG1.MathEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_BG1) == 1; + si.BG.BG2.MathEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_BG2) == 1; + si.BG.BG3.MathEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_BG3) == 1; + si.BG.BG4.MathEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_BG4) == 1; - si.BG.BG1.HOFS = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG1HOFS); - si.BG.BG1.VOFS = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG1VOFS); - si.BG.BG2.HOFS = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2HOFS); - si.BG.BG2.VOFS = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2VOFS); - si.BG.BG3.HOFS = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3HOFS); - si.BG.BG3.VOFS = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3VOFS); - si.BG.BG4.HOFS = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG4HOFS); - si.BG.BG4.VOFS = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG4VOFS); + si.BG.BG1.HOFS = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG1HOFS); + si.BG.BG1.VOFS = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG1VOFS); + si.BG.BG2.HOFS = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2HOFS); + si.BG.BG2.VOFS = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2VOFS); + si.BG.BG3.HOFS = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3HOFS); + si.BG.BG3.VOFS = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3VOFS); + si.BG.BG4.HOFS = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG4HOFS); + si.BG.BG4.VOFS = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG4VOFS); - si.M7HOFS = api.snes_peek_logical_register(LibsnesDll.SNES_REG.M7HOFS); - si.M7VOFS = api.snes_peek_logical_register(LibsnesDll.SNES_REG.M7VOFS); - si.M7A = api.snes_peek_logical_register(LibsnesDll.SNES_REG.M7A); - si.M7B = api.snes_peek_logical_register(LibsnesDll.SNES_REG.M7B); - si.M7C = api.snes_peek_logical_register(LibsnesDll.SNES_REG.M7C); - si.M7D = api.snes_peek_logical_register(LibsnesDll.SNES_REG.M7D); - si.M7X = api.snes_peek_logical_register(LibsnesDll.SNES_REG.M7X); - si.M7Y = api.snes_peek_logical_register(LibsnesDll.SNES_REG.M7Y); - si.M7Y = api.snes_peek_logical_register(LibsnesDll.SNES_REG.M7Y); - si.M7SEL_REPEAT = api.snes_peek_logical_register(LibsnesDll.SNES_REG.M7SEL_REPEAT); - si.M7SEL_HFLIP = api.snes_peek_logical_register(LibsnesDll.SNES_REG.M7SEL_HFLIP)!=0; - si.M7SEL_VFLIP = api.snes_peek_logical_register(LibsnesDll.SNES_REG.M7SEL_VFLIP)!=0; + si.M7HOFS = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7HOFS); + si.M7VOFS = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7VOFS); + si.M7A = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7A); + si.M7B = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7B); + si.M7C = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7C); + si.M7D = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7D); + si.M7X = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7X); + si.M7Y = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7Y); + si.M7Y = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7Y); + si.M7SEL_REPEAT = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7SEL_REPEAT); + si.M7SEL_HFLIP = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7SEL_HFLIP)!=0; + si.M7SEL_VFLIP = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.M7SEL_VFLIP)!=0; for (int i = 1; i <= 4; i++) { @@ -534,7 +534,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES public ScreenInfo ScanScreenInfo() { - return ScreenInfo.GetScreenInfo(api); + return ScreenInfo.GetScreenInfo(); } //the same basic color table that libsnes uses to convert from snes 555 to rgba32 @@ -558,39 +558,15 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES int[] colortable; public byte* vram, oam; public ushort* cgram, vram16; - - LibsnesApi api; - byte[] memVram, memCgram, memOam; - GCHandle gcVram, gcCgram, gcOam; - - public void Dispose() + public SNESGraphicsDecoder(SnesColors.ColorType pal) { - gcVram.Free(); - gcCgram.Free(); - gcOam.Free(); - } - - public SNESGraphicsDecoder(LibsnesApi api, SnesColors.ColorType pal) - { - this.api = api; colortable = SnesColors.GetLUT(pal); - - memVram = api.snes_get_memory_data(LibsnesDll.SNES_MEMORY.VRAM); - gcVram = GCHandle.Alloc(memVram, GCHandleType.Pinned); - IntPtr block = gcVram.AddrOfPinnedObject(); + IntPtr block = LibsnesDll.snes_get_memory_data(LibsnesDll.SNES_MEMORY.VRAM); vram = (byte*)block; vram16 = (ushort*)block; - - //would probably be faster to copy, anyway.. well, its annoying. one day we'll have this memory mapped. - - memCgram = api.snes_get_memory_data(LibsnesDll.SNES_MEMORY.CGRAM); - gcCgram = GCHandle.Alloc(memCgram, GCHandleType.Pinned); - block = gcCgram.AddrOfPinnedObject(); + block = LibsnesDll.snes_get_memory_data(LibsnesDll.SNES_MEMORY.CGRAM); cgram = (ushort*)block; - - memOam = api.snes_get_memory_data(LibsnesDll.SNES_MEMORY.OAM); - gcOam = GCHandle.Alloc(memOam, GCHandleType.Pinned); - block = gcOam.AddrOfPinnedObject(); + block = LibsnesDll.snes_get_memory_data(LibsnesDll.SNES_MEMORY.OAM); oam = (byte*)block; } @@ -807,7 +783,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES public void CacheTiles() { //generate 2bpp tiles - int numtiles = 65536/8/2; + int numtiles = 8192; int[] tiles = new int[8 * 8 * numtiles]; _tileCache[2] = tiles; for (int i = 0; i < numtiles; i++) diff --git a/BizHawk.Emulation/Util.cs b/BizHawk.Emulation/Util.cs index e15c4f47ca..cc97ad68a7 100644 --- a/BizHawk.Emulation/Util.cs +++ b/BizHawk.Emulation/Util.cs @@ -12,14 +12,6 @@ namespace BizHawk { public static class Extensions { - public static string GetDirectory(this Assembly asm) - { - string codeBase = asm.CodeBase; - UriBuilder uri = new UriBuilder(codeBase); - string path = Uri.UnescapeDataString(uri.Path); - return Path.GetDirectoryName(path); - } - public static int LowerBoundBinarySearch(this IList list, Func keySelector, TKey key) where TKey : IComparable { int min = 0; @@ -499,18 +491,6 @@ namespace BizHawk return System.Text.Encoding.UTF8.GetString(read); } - public static string ReadStringAsciiZ(this BinaryReader r) - { - StringBuilder sb = new StringBuilder(); - for(;;) - { - int b = r.ReadByte(); - if(b <= 0) break; - sb.Append((char)b); - } - return sb.ToString(); - } - /// /// conerts bytes to an uppercase string of hex numbers in upper case without any spacing or anything /// //could be extension method diff --git a/BizHawk.MultiClient/BizHawk.MultiClient.csproj b/BizHawk.MultiClient/BizHawk.MultiClient.csproj index 4485008110..1304f7da34 100644 --- a/BizHawk.MultiClient/BizHawk.MultiClient.csproj +++ b/BizHawk.MultiClient/BizHawk.MultiClient.csproj @@ -83,6 +83,7 @@ + 3.5 diff --git a/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.cs b/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.cs index 5f568b0f32..add3dd3138 100644 --- a/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.cs +++ b/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.cs @@ -191,7 +191,7 @@ namespace BizHawk.MultiClient } } - SNESGraphicsDecoder gd; + SNESGraphicsDecoder gd = new SNESGraphicsDecoder(SnesColors.ColorType.BizHawk); SNESGraphicsDecoder.ScreenInfo si; SNESGraphicsDecoder.TileEntry[] map; byte[,] spriteMap = new byte[256, 224]; @@ -199,7 +199,6 @@ namespace BizHawk.MultiClient void RegenerateData() { - if (gd != null) gd.Dispose(); gd = null; if (currentSnesCore == null) return; gd = NewDecoder(); @@ -664,15 +663,14 @@ namespace BizHawk.MultiClient SNESGraphicsDecoder NewDecoder() { - //wtf to do? now we need an api all the time if (currentSnesCore != null) - return new SNESGraphicsDecoder(currentSnesCore.api, currentSnesCore.CurrPalette); - else return new SNESGraphicsDecoder(currentSnesCore.api, SnesColors.ColorType.BizHawk); + return new SNESGraphicsDecoder(currentSnesCore.CurrPalette); + else return new SNESGraphicsDecoder(SnesColors.ColorType.BizHawk); } void RenderPalette() { - //var gd = NewDecoder(); //?? + var gd = NewDecoder(); lastPalette = gd.GetPalette(); int pixsize = paletteCellSize * 16 + paletteCellSpacing * 17; @@ -794,7 +792,7 @@ namespace BizHawk.MultiClient if (lastPalette == null) return; int rgb555 = lastPalette[lastColorNum]; - //var gd = NewDecoder(); //?? + var gd = NewDecoder(); int color = gd.Colorize(rgb555); pnDetailsPaletteColor.BackColor = Color.FromArgb(color); diff --git a/BizHawk.MultiClient/config/PathManager.cs b/BizHawk.MultiClient/config/PathManager.cs index 53d351c581..1dd7e08c3a 100644 --- a/BizHawk.MultiClient/config/PathManager.cs +++ b/BizHawk.MultiClient/config/PathManager.cs @@ -11,19 +11,9 @@ namespace BizHawk.MultiClient { public static string GetExeDirectoryAbsolute() { - //var uri = new Uri(Assembly.GetEntryAssembly().GetName().CodeBase); - //string module = uri.LocalPath + System.Web.HttpUtility.UrlDecode(uri.Fragment); - //return Path.GetDirectoryName(module); - //zero 21-dec-2012 - reuse code elsewhere and remove system.web dependency - //return Assembly.GetEntryAssembly().GetDirectory(); - - // no no no - // this must be available entirely with multiclient code, as it's used to set up the AssemblyResolve event that loads util and emulation - var asm = Assembly.GetEntryAssembly(); - string codeBase = asm.CodeBase; - UriBuilder uri = new UriBuilder(codeBase); - string path = Uri.UnescapeDataString(uri.Path); - return Path.GetDirectoryName(path); + var uri = new Uri(Assembly.GetEntryAssembly().GetName().CodeBase); + string module = uri.LocalPath + System.Web.HttpUtility.UrlDecode(uri.Fragment); + return Path.GetDirectoryName(module); } /// diff --git a/BizHawk.MultiClient/output/dll/libco_msvc_win32.dll b/BizHawk.MultiClient/output/dll/libco_msvc_win32.dll new file mode 100644 index 0000000000..6bd497731e Binary files /dev/null and b/BizHawk.MultiClient/output/dll/libco_msvc_win32.dll differ diff --git a/BizHawk.MultiClient/output/dll/libsnes_pwrap.exe b/BizHawk.MultiClient/output/dll/libsnes_pwrap.exe deleted file mode 100644 index a11d776e9a..0000000000 Binary files a/BizHawk.MultiClient/output/dll/libsnes_pwrap.exe and /dev/null differ diff --git a/BizHawk.MultiClient/output/dll/libsneshawk.dll b/BizHawk.MultiClient/output/dll/libsneshawk.dll index a03fb1021c..dd69137d28 100644 Binary files a/BizHawk.MultiClient/output/dll/libsneshawk.dll and b/BizHawk.MultiClient/output/dll/libsneshawk.dll differ diff --git a/libsnes/bizwinmake.sh b/libsnes/bizwinmake.sh index 70d4948463..cc380379c9 100644 --- a/libsnes/bizwinmake.sh +++ b/libsnes/bizwinmake.sh @@ -1,8 +1,9 @@ -#this is for using the fast libco, hand-coded by byuu. the dll isnt used, and so the threads implementation wont be useful, so it cant be debugged easily cd bsnes mkdir obj mkdir out -export BIZWINCFLAGS="-I. -O3 -masm=intel -static-libgcc -static-libstdc++" +export BIZWINCFLAGS="-I. -O3 -masm=intel -DLIBCO_IMPORT -DLIBCO_MSVC -static-libgcc -static-libstdc++" +#for gdb debugging +#export BIZWINCFLAGS="-I. -O0 -g -masm=intel -DLIBCO_IMPORT -DLIBCO_MSVC -static-libgcc -static-libstdc++" export TARGET_LIBSNES_LIBDEPS="-L ../libco_msvc_win32/release/ -llibco_msvc_win32 -static-libgcc -static-libstdc++" profile=compatibility platform=win target=libsnes make -e -j 4 cd .. diff --git a/libsnes/bizwinmake_debug.sh b/libsnes/bizwinmake_debug.sh deleted file mode 100644 index d592f8ff85..0000000000 --- a/libsnes/bizwinmake_debug.sh +++ /dev/null @@ -1,11 +0,0 @@ -#this is for using the dll libco, and so the threads implementation can be used, for easier debugging -cd bsnes -mkdir obj -mkdir out -export BIZWINCFLAGS="-I. -O3 -masm=intel -DLIBCO_IMPORT -DLIBCO_MSVC -static-libgcc -static-libstdc++" -#for gdb debugging -#export BIZWINCFLAGS="-I. -O0 -g -masm=intel -DLIBCO_IMPORT -DLIBCO_MSVC -static-libgcc -static-libstdc++" -export TARGET_LIBSNES_LIBDEPS="-L ../libco_msvc_win32/release/ -llibco_msvc_win32 -static-libgcc -static-libstdc++" -profile=compatibility platform=win target=libsnes make -e -j 4 -cd .. -cp bsnes/out/snes.dll ../BizHawk.MultiClient/output/dll/libsneshawk.dll diff --git a/libsnes/bsnes/snes/alt/ppu-compatibility/serialization.cpp b/libsnes/bsnes/snes/alt/ppu-compatibility/serialization.cpp index 849c4426f5..d2711e4af4 100644 --- a/libsnes/bsnes/snes/alt/ppu-compatibility/serialization.cpp +++ b/libsnes/bsnes/snes/alt/ppu-compatibility/serialization.cpp @@ -156,7 +156,6 @@ void PPU::serialize(serializer &s) { s.integer(pixel_cache[n].pri_sub); } - //zero TODO - only on load //better to just take a small speed hit than store all of bg_tiledata[3][] ... flush_tiledata_cache(); diff --git a/libsnes/bsnes/target-libsnes/Makefile b/libsnes/bsnes/target-libsnes/Makefile index 48f3b69a07..b799afaa61 100644 --- a/libsnes/bsnes/target-libsnes/Makefile +++ b/libsnes/bsnes/target-libsnes/Makefile @@ -24,7 +24,7 @@ else ifeq ($(platform),osx) ar rcs out/libsnes.a $(objects) $(cpp) -o out/libsnes.dylib -install_name @executable_path/../Libraries/libsnes.dylib -shared -dynamiclib $(objects) else ifeq ($(platform),win) - $(cpp) -o out/snes.dll -shared -Wl,--output-def,libsneshawk.def,--out-implib,libsnes.a $(objects) $(TARGET_LIBSNES_LIBDEPS) + $(cpp) -o out/snes.dll -shared -Wl,--out-implib,libsnes.a $(objects) $(TARGET_LIBSNES_LIBDEPS) endif install: diff --git a/libsnes/bsnes/target-libsnes/libsnes.cpp b/libsnes/bsnes/target-libsnes/libsnes.cpp index a4e6aadaa1..94f7e2d585 100644 --- a/libsnes/bsnes/target-libsnes/libsnes.cpp +++ b/libsnes/bsnes/target-libsnes/libsnes.cpp @@ -99,7 +99,6 @@ struct Interface : public SNES::Interface { pinput_state(0), pinput_notify(0), ppath_request(0), - pScanlineStart(0), backdropColor(-1), ptrace(0) { @@ -600,7 +599,7 @@ void bus_write(unsigned addr, uint8_t val) { int snes_poll_message() { - if(interface.messages.empty()) return -1; + if(interface.messages.size() == 0) return -1; return interface.messages.front().length(); } void snes_dequeue_message(char* buffer) @@ -627,4 +626,4 @@ void snes_set_trace_callback(snes_trace_t callback) interface.wanttrace = false; interface.ptrace = 0; } -} \ No newline at end of file +} diff --git a/libsnes/bsnes/target-libsnes/libsnes.hpp b/libsnes/bsnes/target-libsnes/libsnes.hpp index d8482ebe84..49394f1186 100644 --- a/libsnes/bsnes/target-libsnes/libsnes.hpp +++ b/libsnes/bsnes/target-libsnes/libsnes.hpp @@ -3,14 +3,6 @@ #include -#if defined(LIBSNES_IMPORT) -#define LIBSNES_IMPORTDECL __declspec(dllimport) -#elif defined(LIBSNES_EXPORT) -#define LIBSNES_IMPORTDECL __declspec(dllexport) -#else -#define LIBSNES_IMPORTDECL -#endif - #ifdef __cplusplus extern "C" { #endif @@ -75,9 +67,6 @@ extern "C" { #define SNES_MEMORY_OAM 103 #define SNES_MEMORY_CGRAM 104 -#define SNES_MEMORY_SYSBUS 200 -#define SNES_MEMORY_LOGICAL_REGS 201 - typedef void (*snes_video_refresh_t)(const uint32_t *data, unsigned width, unsigned height); typedef void (*snes_audio_sample_t)(uint16_t left, uint16_t right); typedef void (*snes_input_poll_t)(void); diff --git a/libsnes/libco_debugging/build.sh b/libsnes/libco_debugging/build.sh deleted file mode 100644 index a499104d22..0000000000 --- a/libsnes/libco_debugging/build.sh +++ /dev/null @@ -1,2 +0,0 @@ -gcc libco_win32threads.c -o libco.dll -Wall -shared -O0 -g -mv libco.dll ../../BizHawk.MultiClient/output/dll/libco_msvc_win32.dll \ No newline at end of file diff --git a/libsnes/libsnes_pwrap/libsnes_pwrap.cpp b/libsnes/libsnes_pwrap/libsnes_pwrap.cpp index ccbe99475b..ef7ea216da 100644 --- a/libsnes/libsnes_pwrap/libsnes_pwrap.cpp +++ b/libsnes/libsnes_pwrap/libsnes_pwrap.cpp @@ -164,15 +164,13 @@ void FlushAudio() WritePipe(eMessage_snes_cb_audio_sample); - int nsamples = audiobuffer_idx; + int nsamples = audiobuffer_idx/2; WritePipe(nsamples); - char* buf = ReadPipeSharedPtr(); - memcpy(buf,audiobuffer,nsamples*2); + int destOfs = ReadPipe(); + char* buf = (char*)hMapFilePtr + destOfs; + memcpy(buf,audiobuffer,nsamples*4); //extra just in case we had to unexpectedly flush audio and then carry on with some other process... yeah, its rickety. WritePipe(0); //dummy synchronization - - //wait for frontend to consume data - ReadPipe(); //dummy synchronization WritePipe(0); //dummy synchronization audiobuffer_idx = 0;