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:
parent
eec37da5b4
commit
8d7da30681
|
@ -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; }
|
||||
|
|
|
@ -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++)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.
Binary file not shown.
Binary file not shown.
|
@ -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 ..
|
||||
|
|
|
@ -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
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
Loading…
Reference in New Issue