snes-refactor bsnes bindings to work via external process. should solve all stability problems. there is much sloppy transitionary code still in this commit; we need to smoke out any killer issues with this approach before committing too heavily. speed is close enough to last release, and can still be improved.

This commit is contained in:
zeromus 2012-12-21 07:23:55 +00:00
parent eec37da5b4
commit 8d7da30681
19 changed files with 1266 additions and 158 deletions

View File

@ -12,11 +12,485 @@ 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
bwPipe.Write(0); //dummy synchronization
brPipe.ReadInt32(); //dummy synchronization
if (audio_sample != null)
{
ushort* audiobuffer = ((ushort*)mmvaPtr);
for (int i = 0; i < nsamples; i++)
{
ushort left = audiobuffer[i++];
ushort right = audiobuffer[i++];
audio_sample(left, right);
}
}
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)]
@ -95,7 +569,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 scanlineStart);
public static extern void snes_set_path_request(snes_path_request_t pathRequest);
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.U1)]
@ -265,6 +739,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
VRAM = 102,
OAM = 103,
CGRAM = 104,
SYSBUS = 200,
LOGICAL_REGS = 201
}
public enum SNES_REGION : byte
@ -354,16 +831,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
disposedSaveRam = ReadSaveRam();
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();
api.snes_unload_cartridge();
api.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
@ -390,8 +862,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
void OnScanlineHooksChanged()
{
if (disposed) return;
if (ScanlineHookManager.HookCount == 0) LibsnesDll.snes_set_scanlineStart(null);
else LibsnesDll.snes_set_scanlineStart(scanlineStart_cb);
if (ScanlineHookManager.HookCount == 0) api.snes_set_scanlineStart(null);
else api.snes_set_scanlineStart(scanlineStart_cb);
}
void snes_scanlineStart(int line)
@ -432,12 +904,16 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
CurrPalette = pal;
int[] tmp = SnesColors.GetLUT(pal);
fixed (int* p = &tmp[0])
BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_color_lut((IntPtr)p);
api.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)
@ -449,27 +925,25 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
ScanlineHookManager = new MyScanlineHookManager(this);
LibsnesDll.snes_init();
//LibsnesDll.snes_set_cartridge_basename(@);
api.snes_init();
vidcb = new LibsnesDll.snes_video_refresh_t(snes_video_refresh);
BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_video_refresh(vidcb);
api.snes_set_video_refresh(vidcb);
pollcb = new LibsnesDll.snes_input_poll_t(snes_input_poll);
BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_input_poll(pollcb);
api.snes_set_input_poll(pollcb);
inputcb = new LibsnesDll.snes_input_state_t(snes_input_state);
BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_input_state(inputcb);
api.snes_set_input_state(inputcb);
notifycb = new LibsnesDll.snes_input_notify_t(snes_input_notify);
BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_input_notify(notifycb);
api.snes_set_input_notify(notifycb);
soundcb = new LibsnesDll.snes_audio_sample_t(snes_audio_sample);
BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_audio_sample(soundcb);
api.snes_set_audio_sample(soundcb);
pathRequest_cb = new LibsnesDll.snes_path_request_t(snes_path_request);
BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_path_request(pathRequest_cb);
api.snes_set_path_request(pathRequest_cb);
scanlineStart_cb = new LibsnesDll.snes_scanlineStart_t(snes_scanlineStart);
@ -500,11 +974,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
else
{
SystemId = "SNES";
if (!LibsnesDll.snes_load_cartridge_normal(null, romData, (uint)romData.Length))
if (!api.snes_load_cartridge_normal(null, romData))
throw new Exception("snes_load_cartridge_normal() failed");
}
if (LibsnesDll.snes_get_region() == LibsnesDll.SNES_REGION.NTSC)
if (api.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;
@ -518,7 +992,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
CoreComm.CpuTraceAvailable = true;
LibsnesDll.snes_power();
api.snes_power();
SetupMemoryDomains(romData);
@ -649,6 +1123,8 @@ 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)
@ -665,55 +1141,58 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
}
if (!nocallbacks && CoreComm.Tracer.Enabled)
LibsnesDll.snes_set_trace_callback(tracecb);
api.snes_set_trace_callback(tracecb);
else
LibsnesDll.snes_set_trace_callback(null);
api.snes_set_trace_callback(null);
// speedup when sound rendering is not needed
if (!rendersound)
LibsnesDll.snes_set_audio_sample(null);
api.snes_set_audio_sample(null);
else
LibsnesDll.snes_set_audio_sample(soundcb);
api.snes_set_audio_sample(soundcb);
bool resetSignal = Controller["Reset"];
if (resetSignal) LibsnesDll.snes_reset();
if (resetSignal) api.snes_reset();
bool powerSignal = Controller["Power"];
if (powerSignal) LibsnesDll.snes_power();
if (powerSignal) api.snes_power();
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);
//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);
// if the input poll callback is called, it will set this to false
IsLagFrame = true;
//apparently this is one frame?
timeFrameCounter++;
LibsnesDll.snes_run();
api.snes_run();
while (LibsnesDll.HasMessage)
Console.WriteLine(LibsnesDll.DequeueMessage());
while (api.HasMessage)
Console.WriteLine(api.DequeueMessage());
if (IsLagFrame)
LagCount++;
//diagnostics for IPC traffic
//Console.WriteLine(api.MessageCounter);
}
public DisplayType DisplayType
{
get
{
if (LibsnesDll.snes_get_region() == LibsnesDll.SNES_REGION.NTSC)
if (api.snes_get_region() == LibsnesDll.SNES_REGION.NTSC)
return BizHawk.DisplayType.NTSC;
else
return BizHawk.DisplayType.PAL;
@ -939,7 +1418,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
}
public void LoadStateBinary(BinaryReader reader)
{
int size = LibsnesDll.snes_serialize_size();
int size = api.snes_serialize_size();
byte[] buf = reader.ReadBytes(size);
CoreLoadState(buf);
@ -990,22 +1469,22 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
/// </summary>
void CoreLoadState(byte[] data)
{
int size = LibsnesDll.snes_serialize_size();
int size = api.snes_serialize_size();
if (data.Length != size)
throw new Exception("Libsnes internal savestate size mismatch!");
LibsnesDll.snes_init();
api.snes_init();
fixed (byte* pbuf = &data[0])
LibsnesDll.snes_unserialize(new IntPtr(pbuf), size);
api.snes_unserialize(new IntPtr(pbuf), size);
}
/// <summary>
/// handle the unmanaged part of savestating
/// </summary>
byte[] CoreSaveState()
{
int size = LibsnesDll.snes_serialize_size();
int size = api.snes_serialize_size();
byte[] buf = new byte[size];
fixed (byte* pbuf = &buf[0])
LibsnesDll.snes_serialize(new IntPtr(pbuf), size);
api.snes_serialize(new IntPtr(pbuf), size);
return buf;
}
@ -1021,36 +1500,50 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
// ----- Client Debugging API stuff -----
unsafe MemoryDomain MakeMemoryDomain(string name, LibsnesDll.SNES_MEMORY id, Endian endian)
{
IntPtr block = LibsnesDll.snes_get_memory_data(id);
int size = LibsnesDll.snes_get_memory_size(id);
int size = api.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
////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
if (Util.IsPowerOfTwo(size))
{
//can &mask for speed
md = new MemoryDomain(name, size, endian,
(addr) => blockptr[addr & mask],
(addr, value) => blockptr[addr & mask] = value);
(addr) => api.peek(id, (uint)(addr & mask)),
(addr, value) => api.poke(id, (uint)(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);
(addr) => api.peek(id, (uint)(addr % size)),
(addr, value) => api.poke(id, (uint)(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)
@ -1071,8 +1564,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
if (!DeterministicEmulation)
MemoryDomains.Add(new MemoryDomain("BUS", 0x1000000, Endian.Little,
(addr) => LibsnesDll.bus_read((uint)addr),
(addr, val) => LibsnesDll.bus_write((uint)addr, val)));
(addr) => api.peek(LibsnesDll.SNES_MEMORY.SYSBUS, (uint)addr),
(addr, val) => api.poke(LibsnesDll.SNES_MEMORY.SYSBUS, (uint)addr, val)));
}
public IList<MemoryDomain> MemoryDomains { get; private set; }
public MemoryDomain MainMemory { get; private set; }

View File

@ -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
public unsafe class SNESGraphicsDecoder : IDisposable
{
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()
public static ScreenInfo GetScreenInfo(LibsnesApi api)
{
var si = new ScreenInfo();
si.Mode1_BG3_Priority = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3_PRIORITY) == 1;
si.Mode1_BG3_Priority = api.snes_peek_logical_register(LibsnesDll.SNES_REG.BG3_PRIORITY) == 1;
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.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.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 = 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.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.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.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.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.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.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.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.Mode.MODE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG_MODE);
si.Mode.MODE = api.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 = 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.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.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.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.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.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.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.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.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;
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;
for (int i = 1; i <= 4; i++)
{
@ -534,7 +534,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
public ScreenInfo ScanScreenInfo()
{
return ScreenInfo.GetScreenInfo();
return ScreenInfo.GetScreenInfo(api);
}
//the same basic color table that libsnes uses to convert from snes 555 to rgba32
@ -558,15 +558,39 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
int[] colortable;
public byte* vram, oam;
public ushort* cgram, vram16;
public SNESGraphicsDecoder(SnesColors.ColorType pal)
LibsnesApi api;
byte[] memVram, memCgram, memOam;
GCHandle gcVram, gcCgram, gcOam;
public void Dispose()
{
gcVram.Free();
gcCgram.Free();
gcOam.Free();
}
public SNESGraphicsDecoder(LibsnesApi api, SnesColors.ColorType pal)
{
this.api = api;
colortable = SnesColors.GetLUT(pal);
IntPtr block = LibsnesDll.snes_get_memory_data(LibsnesDll.SNES_MEMORY.VRAM);
memVram = api.snes_get_memory_data(LibsnesDll.SNES_MEMORY.VRAM);
gcVram = GCHandle.Alloc(memVram, GCHandleType.Pinned);
IntPtr block = gcVram.AddrOfPinnedObject();
vram = (byte*)block;
vram16 = (ushort*)block;
block = LibsnesDll.snes_get_memory_data(LibsnesDll.SNES_MEMORY.CGRAM);
//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();
cgram = (ushort*)block;
block = LibsnesDll.snes_get_memory_data(LibsnesDll.SNES_MEMORY.OAM);
memOam = api.snes_get_memory_data(LibsnesDll.SNES_MEMORY.OAM);
gcOam = GCHandle.Alloc(memOam, GCHandleType.Pinned);
block = gcOam.AddrOfPinnedObject();
oam = (byte*)block;
}
@ -783,7 +807,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
public void CacheTiles()
{
//generate 2bpp tiles
int numtiles = 8192;
int numtiles = 65536/8/2;
int[] tiles = new int[8 * 8 * numtiles];
_tileCache[2] = tiles;
for (int i = 0; i < numtiles; i++)

View File

@ -12,6 +12,14 @@ 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<T, TKey>(this IList<T> list, Func<T, TKey> keySelector, TKey key) where TKey : IComparable<TKey>
{
int min = 0;
@ -491,6 +499,18 @@ 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();
}
/// <summary>
/// conerts bytes to an uppercase string of hex numbers in upper case without any spacing or anything
/// //could be extension method

View File

@ -83,7 +83,6 @@
</Reference>
<Reference Include="System.DirectoryServices" />
<Reference Include="System.Numerics" />
<Reference Include="System.Web" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>

View File

@ -191,7 +191,7 @@ namespace BizHawk.MultiClient
}
}
SNESGraphicsDecoder gd = new SNESGraphicsDecoder(SnesColors.ColorType.BizHawk);
SNESGraphicsDecoder gd;
SNESGraphicsDecoder.ScreenInfo si;
SNESGraphicsDecoder.TileEntry[] map;
byte[,] spriteMap = new byte[256, 224];
@ -199,6 +199,7 @@ namespace BizHawk.MultiClient
void RegenerateData()
{
if (gd != null) gd.Dispose();
gd = null;
if (currentSnesCore == null) return;
gd = NewDecoder();
@ -663,14 +664,15 @@ namespace BizHawk.MultiClient
SNESGraphicsDecoder NewDecoder()
{
//wtf to do? now we need an api all the time
if (currentSnesCore != null)
return new SNESGraphicsDecoder(currentSnesCore.CurrPalette);
else return new SNESGraphicsDecoder(SnesColors.ColorType.BizHawk);
return new SNESGraphicsDecoder(currentSnesCore.api, currentSnesCore.CurrPalette);
else return new SNESGraphicsDecoder(currentSnesCore.api, SnesColors.ColorType.BizHawk);
}
void RenderPalette()
{
var gd = NewDecoder();
//var gd = NewDecoder(); //??
lastPalette = gd.GetPalette();
int pixsize = paletteCellSize * 16 + paletteCellSpacing * 17;
@ -792,7 +794,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);

View File

@ -11,9 +11,11 @@ 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);
//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();
}
/// <summary>

Binary file not shown.

View File

@ -1,9 +1,8 @@
#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 -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 BIZWINCFLAGS="-I. -O3 -masm=intel -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 ..

View File

@ -0,0 +1,11 @@
#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

View File

@ -156,6 +156,7 @@ 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();

View File

@ -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,--out-implib,libsnes.a $(objects) $(TARGET_LIBSNES_LIBDEPS)
$(cpp) -o out/snes.dll -shared -Wl,--output-def,libsneshawk.def,--out-implib,libsnes.a $(objects) $(TARGET_LIBSNES_LIBDEPS)
endif
install:

View File

@ -99,6 +99,7 @@ struct Interface : public SNES::Interface {
pinput_state(0),
pinput_notify(0),
ppath_request(0),
pScanlineStart(0),
backdropColor(-1),
ptrace(0)
{
@ -599,7 +600,7 @@ void bus_write(unsigned addr, uint8_t val) {
int snes_poll_message()
{
if(interface.messages.size() == 0) return -1;
if(interface.messages.empty()) return -1;
return interface.messages.front().length();
}
void snes_dequeue_message(char* buffer)
@ -626,4 +627,4 @@ void snes_set_trace_callback(snes_trace_t callback)
interface.wanttrace = false;
interface.ptrace = 0;
}
}
}

View File

@ -3,6 +3,14 @@
#include <stdint.h>
#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
@ -67,6 +75,9 @@ 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);

View File

@ -0,0 +1,2 @@
gcc libco_win32threads.c -o libco.dll -Wall -shared -O0 -g
mv libco.dll ../../BizHawk.MultiClient/output/dll/libco_msvc_win32.dll

View File

@ -0,0 +1,445 @@
#include <Windows.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#define LIBSNES_IMPORT
#include "../bsnes/target-libsnes/libsnes.hpp"
HANDLE hPipe, hMapFile;
void* hMapFilePtr;
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, //10
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, //16
eMessage_snes_cb_path_request,
eMessage_snes_cb_trace_callback,
eMessage_snes_get_region,
eMessage_snes_get_memory_size, //20
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
};
void ReadPipeBuffer(void* buf, int len)
{
DWORD bytesRead;
BOOL result = ReadFile(hPipe, buf, len, &bytesRead, NULL);
if(!result || bytesRead != len)
exit(1);
}
template<typename T> T ReadPipe()
{
T ret;
ReadPipeBuffer(&ret,sizeof(ret));
return ret;
}
char* ReadPipeSharedPtr()
{
return (char*)hMapFilePtr + ReadPipe<int>();
}
template<> bool ReadPipe<bool>()
{
return !!ReadPipe<char>();
}
FILE* outf = NULL;
void WritePipeBuffer(const void* buf, int len)
{
//if(!outf) outf = fopen("c:\\trace.bin","wb"); fwrite(buf,1,len,outf); fflush(outf);
DWORD bytesWritten;
BOOL result = WriteFile(hPipe, buf, len, &bytesWritten, NULL);
if(!result || bytesWritten != len)
exit(1);
}
template<typename T> void WritePipe(const T& val)
{
WritePipeBuffer(&val, sizeof(val));
}
void WritePipeString(const char* str)
{
//TODO - write string length
int len = strlen(str);
WritePipeBuffer(str,len+1);
}
std::string ReadPipeString()
{
int len = ReadPipe<int>();
std::string ret;
ret.resize(len);
if(len!=0)
ReadPipeBuffer(&ret[0],len);
return ret;
}
typedef std::vector<char> Blob;
void WritePipeBlob(void* buf, int len)
{
WritePipe(len);
WritePipeBuffer(buf,len);
}
Blob ReadPipeBlob()
{
int len = ReadPipe<int>();
Blob ret;
ret.resize(len);
if(len!=0)
ReadPipeBuffer(&ret[0],len);
return ret;
}
void snes_video_refresh(const uint32_t *data, unsigned width, unsigned height)
{
WritePipe(eMessage_snes_cb_video_refresh);
WritePipe(width);
WritePipe(height);
int destOfs = ReadPipe<int>();
char* buf = (char*)hMapFilePtr + destOfs;
int bufsize = 512 * 480 * 4;
memcpy(buf,data,bufsize);
WritePipe((char)0); //dummy synchronization
}
bool audio_en = false;
static const int AUDIOBUFFER_SIZE = 44100*2;
uint16_t audiobuffer[AUDIOBUFFER_SIZE];
int audiobuffer_idx = 0;
void FlushAudio()
{
if(audiobuffer_idx == 0) return;
WritePipe(eMessage_snes_cb_audio_sample);
int nsamples = audiobuffer_idx/2;
WritePipe(nsamples);
int destOfs = ReadPipe<int>();
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
ReadPipe<int>(); //dummy synchronization
WritePipe(0); //dummy synchronization
audiobuffer_idx = 0;
}
void snes_audio_sample(uint16_t left, uint16_t right)
{
if(!audio_en) return;
if(audiobuffer_idx == AUDIOBUFFER_SIZE)
FlushAudio();
audiobuffer[audiobuffer_idx++] = left;
audiobuffer[audiobuffer_idx++] = right;
}
void snes_input_poll(void)
{
WritePipe(eMessage_snes_cb_input_poll);
}
int16_t snes_input_state(unsigned port, unsigned device, unsigned index, unsigned id)
{
WritePipe(eMessage_snes_cb_input_state);
WritePipe(port);
WritePipe(device);
WritePipe(index);
WritePipe(id);
return ReadPipe<int16_t>();
}
void snes_input_notify(int index)
{
WritePipe(eMessage_snes_cb_input_notify);
WritePipe(index);
}
void snes_trace(const char *msg)
{
WritePipe(eMessage_snes_cb_trace_callback);
WritePipeString(msg);
}
const char* snes_path_request(int slot, const char* hint)
{
//yuck
static char ret[MAX_PATH];
WritePipe(eMessage_snes_cb_path_request);
WritePipe(slot);
WritePipeString(hint);
std::string str = ReadPipeString();
strcpy(ret,str.c_str());
return ret;
}
void snes_scanlineStart(int line)
{
WritePipe(eMessage_snes_cb_scanlineStart);
WritePipe(line);
}
void InitBsnes()
{
//setup all hooks to forward messages to the frontend
snes_set_video_refresh(snes_video_refresh);
snes_set_audio_sample(snes_audio_sample);
snes_set_input_poll(snes_input_poll);
snes_set_input_state(snes_input_state);
snes_set_input_notify(snes_input_notify);
snes_set_path_request(snes_path_request);
}
int main(int argc, char** argv)
{
if(argc != 2)
{
printf("This program is run from the libsneshawk emulator core. It is useless to you directly.");
exit(1);
}
if(!strcmp(argv[1],"Bongizong"))
{
fprintf(stderr,"Honga Wongkong");
exit(0x16817);
}
InitBsnes();
char pipename[256];
sprintf(pipename, "\\\\.\\Pipe\\%s",argv[1]);
hPipe = CreateFile(pipename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if(hPipe == INVALID_HANDLE_VALUE)
return 1;
hMapFile = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, argv[1]);
if(hMapFile == INVALID_HANDLE_VALUE)
return 1;
hMapFilePtr = MapViewOfFile(hMapFile, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
for(;;)
{
auto msg = ReadPipe<eMessage>();
switch(msg)
{
case eMessage_snes_library_id: WritePipeString(snes_library_id()); break;
case eMessage_snes_library_revision_major: WritePipe(snes_library_revision_major()); break;
case eMessage_snes_library_revision_minor: WritePipe(snes_library_revision_minor()); break;
case eMessage_snes_init:
snes_init();
break;
case eMessage_snes_power: snes_power(); break;
case eMessage_snes_reset: snes_reset(); break;
case eMessage_snes_run:
FlushAudio();
snes_run();
FlushAudio();
WritePipe(eMessage_Complete);
break;
case eMessage_snes_term: snes_term(); break;
case eMessage_snes_unload_cartridge: snes_unload_cartridge(); break;
case eMessage_snes_load_cartridge_normal:
{
std::string xml = ReadPipeString();
Blob rom_data = ReadPipeBlob();
const char* xmlptr = NULL;
if(xml != "") xmlptr = xml.c_str();
bool ret = snes_load_cartridge_normal(xmlptr,(unsigned char*)&rom_data[0],rom_data.size());
WritePipe(eMessage_Complete);
WritePipe((char)(ret?1:0));
break;
}
case eMessage_snes_get_region:
WritePipe((char)snes_get_region());
break;
case eMessage_snes_get_memory_size:
WritePipe(snes_get_memory_size(ReadPipe<unsigned int>()));
break;
case eMessage_snes_get_memory_data:
{
unsigned int id = ReadPipe<unsigned int>();
char* dstbuf = ReadPipeSharedPtr();
uint8_t* srcbuf = snes_get_memory_data(id);
memcpy(dstbuf,srcbuf,snes_get_memory_size(id));
WritePipe(eMessage_Complete);
break;
}
case eMessage_peek:
{
int id = ReadPipe<int>();
unsigned int addr = ReadPipe<unsigned int>();
uint8_t ret;
if(id == SNES_MEMORY_SYSBUS)
ret = bus_read(addr);
else ret = snes_get_memory_data(id)[addr];
WritePipe(ret);
}
break;
case eMessage_poke:
{
int id = ReadPipe<int>();
unsigned int addr = ReadPipe<unsigned int>();
uint8_t val = ReadPipe<uint8_t>();
if(id == SNES_MEMORY_SYSBUS)
bus_write(addr,val);
else snes_get_memory_data(id)[addr] = val;
break;
}
break;
case eMessage_snes_serialize_size:
WritePipe(snes_serialize_size());
break;
case eMessage_snes_serialize:
{
int size = ReadPipe<int>();
int destOfs = ReadPipe<int>();
char* buf = (char*)hMapFilePtr + destOfs;
bool ret = snes_serialize((uint8_t*)buf,size);
WritePipe(eMessage_Complete);
WritePipe((char)(ret?1:0));
break;
}
case eMessage_snes_unserialize:
{
//auto blob = ReadPipeBlob();
int size = ReadPipe<int>();
int destOfs = ReadPipe<int>();
char* buf = (char*)hMapFilePtr + destOfs;
bool ret = snes_unserialize((uint8_t*)buf ,size);
WritePipe(eMessage_Complete);
WritePipe((char)(ret?1:0));
break;
}
case eMessage_snes_poll_message:
//TBD
WritePipe(-1);
break;
case eMessage_snes_dequeue_message:
//TBD
break;
case eMessage_snes_set_color_lut:
{
auto blob = ReadPipeBlob();
snes_set_color_lut((uint32_t*)&blob[0]);
break;
}
break;
case eMessage_snes_enable_trace:
if(!!ReadPipe<char>())
snes_set_trace_callback(snes_trace);
else snes_set_trace_callback(NULL);
break;
case eMessage_snes_enable_scanline:
if(ReadPipe<bool>())
snes_set_scanlineStart(snes_scanlineStart);
else snes_set_scanlineStart(NULL);
break;
case eMessage_snes_enable_audio:
audio_en = ReadPipe<bool>();
break;
case eMessage_snes_set_layer_enable:
{
int layer = ReadPipe<int>();
int priority = ReadPipe<int>();
bool enable = ReadPipe<bool>();
snes_set_layer_enable(layer,priority,enable);
break;
}
case eMessage_snes_set_backdropColor:
snes_set_backdropColor(ReadPipe<int>());
break;
case eMessage_snes_peek_logical_register:
WritePipe(snes_peek_logical_register(ReadPipe<int>()));
break;
} //switch(msg)
}
return 0;
}
int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
int argc = __argc;
char** argv = __argv;
if(argc != 2)
{
if(IDCANCEL == MessageBox(0,"This program is run from the libsneshawk emulator core. It is useless to you directly. But if you're really, that curious, click cancel.","Whatfor my daddy-o",MB_OKCANCEL))
{
ShellExecute(0,"open","http://www.youtube.com/watch?v=boanuwUMNNQ#t=98s",NULL,NULL,SW_SHOWNORMAL);
}
exit(1);
}
main(argc,argv);
}

View File

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{8D864AC0-4BC2-48EA-8957-53C704F4BC57}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>libsnes_pwrap</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>..\..\Bizhawk.MultiClient\output\dll</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>..\..\Bizhawk.MultiClient\output\dll</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>libsneshawk.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>lib /machine:i386 /def:..\bsnes\libsneshawk.def</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>libsneshawk.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>lib /machine:i386 /def:..\bsnes\libsneshawk.def</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="libsnes_pwrap.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="libsnes_pwrap.cpp" />
</ItemGroup>
</Project>