Update推帧,sms部分指针化

This commit is contained in:
sin365 2025-02-08 00:31:03 +08:00
parent 572aa7d732
commit bf0acee294
12 changed files with 403 additions and 60 deletions

View File

@ -0,0 +1,169 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
namespace Essgee.Utilities
{
internal unsafe static class AxiMemoryEx
{
static HashSet<GCHandle> GCHandles = new HashSet<GCHandle>();
public static void Init()
{
FreeAllGCHandle();
set_TempBuffer = new byte[0x100000];
}
public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref uint* ptr)
{
GetObjectPtr(srcObj, ref handle, out IntPtr intptr);
ptr = (uint*)intptr;
}
public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref short* ptr)
{
GetObjectPtr(srcObj, ref handle, out IntPtr intptr);
ptr = (short*)intptr;
}
public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref ushort* ptr)
{
GetObjectPtr(srcObj, ref handle, out IntPtr intptr);
ptr = (ushort*)intptr;
}
public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref int* ptr)
{
GetObjectPtr(srcObj, ref handle, out IntPtr intptr);
ptr = (int*)intptr;
}
public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref byte* ptr)
{
GetObjectPtr(srcObj, ref handle, out IntPtr intptr);
ptr = (byte*)intptr;
}
static void GetObjectPtr(this object srcObj, ref GCHandle handle, out IntPtr intptr)
{
ReleaseGCHandle(ref handle);
handle = GCHandle.Alloc(srcObj, GCHandleType.Pinned);
GCHandles.Add(handle);
intptr = handle.AddrOfPinnedObject();
}
public static void ReleaseGCHandle(this ref GCHandle handle)
{
if (handle.IsAllocated)
handle.Free();
GCHandles.Remove(handle);
}
public static void FreeAllGCHandle()
{
foreach (var handle in GCHandles)
{
if (handle.IsAllocated)
handle.Free();
}
GCHandles.Clear();
}
#region TempBuffer
static byte[] TempBuffer_src;
static GCHandle TempBuffer_handle;
public static byte* TempBuffer;
public static byte[] set_TempBuffer
{
set
{
TempBuffer_handle.ReleaseGCHandle();
if (value == null)
return;
TempBuffer_src = value;
TempBuffer_src.GetObjectPtr(ref TempBuffer_handle, ref TempBuffer);
}
}
#endregion
public static void Write(this BinaryWriter bw, byte* bufferPtr, int offset, int count)
{
// 使用指针复制数据到临时数组
Buffer.MemoryCopy(bufferPtr + offset, TempBuffer, 0, count);
// 使用BinaryWriter写入临时数组
bw.Write(TempBuffer_src, 0, count);
}
public static void Write(this FileStream fs, byte* bufferPtr, int offset, int count)
{
// 使用指针复制数据到临时数组
Buffer.MemoryCopy(bufferPtr + offset, TempBuffer, 0, count);
// 使用BinaryWriter写入临时数组
fs.Write(TempBuffer_src, 0, count);
}
public static int Read(this FileStream fs, byte* bufferPtr, int offset, int count)
{
// 使用BinaryWriter写入临时数组
count = fs.Read(TempBuffer_src, offset, count);
// 使用指针复制数据到临时数组
Buffer.MemoryCopy(TempBuffer, bufferPtr + offset, 0, count);
return count;
}
}
internal unsafe static class AxiArray
{
public static void Copy(byte* src, int srcindex, byte* target, int targetindex, int count)
{
int singlesize = sizeof(byte);
long totalBytesToCopy = count * singlesize;
Buffer.MemoryCopy(&src[srcindex], &target[targetindex], totalBytesToCopy, totalBytesToCopy);
}
public static void Copy(short* src, int srcindex, short* target, int targetindex, int count)
{
int singlesize = sizeof(short);
long totalBytesToCopy = count * singlesize;
Buffer.MemoryCopy(&src[srcindex], &target[targetindex], totalBytesToCopy, totalBytesToCopy);
}
public static void Copy(ushort* src, int srcindex, ushort* target, int targetindex, int count)
{
int singlesize = sizeof(ushort);
long totalBytesToCopy = count * singlesize;
Buffer.MemoryCopy(&src[srcindex], &target[targetindex], totalBytesToCopy, totalBytesToCopy);
}
public static void Copy(byte* src, byte* target, int index, int count)
{
int singlesize = sizeof(byte);
long totalBytesToCopy = count * singlesize;
Buffer.MemoryCopy(&src[index], &target[index], totalBytesToCopy, totalBytesToCopy);
}
public static void Copy(ushort* src, ushort* target, int index, int count)
{
int singlesize = sizeof(ushort);
long totalBytesToCopy = count * singlesize;
Buffer.MemoryCopy(&src[index], &target[index], totalBytesToCopy, totalBytesToCopy);
}
public static void Copy(ushort* src, ushort* target, int count)
{
int singlesize = sizeof(ushort);
long totalBytesToCopy = count * singlesize;
Buffer.MemoryCopy(src, target, totalBytesToCopy, totalBytesToCopy);
}
public static void Copy(byte* src, byte* target, int count)
{
int singlesize = sizeof(byte);
long totalBytesToCopy = count * singlesize;
Buffer.MemoryCopy(src, target, totalBytesToCopy, totalBytesToCopy);
}
public static void Clear(byte* data, int index, int lenght)
{
for (int i = index; i < lenght; i++, index++)
data[index] = 0;
}
public static void Clear(ushort* data, int index, int lenght)
{
for (int i = index; i < lenght; i++, index++)
data[index] = 0;
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 922bbb45b85e7de4f8bce1c6f407009f

View File

@ -2,6 +2,7 @@
using Essgee.Emulation.Machines; using Essgee.Emulation.Machines;
using Essgee.EventArguments; using Essgee.EventArguments;
using Essgee.Metadata; using Essgee.Metadata;
using Essgee.Utilities;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@ -129,8 +130,10 @@ namespace Essgee.Emulation
emulator.Startup(); emulator.Startup();
emulator.Reset(); emulator.Reset();
emulationThread = new Thread(ThreadMainLoop) { Name = "EssgeeEmulation", Priority = ThreadPriority.Normal }; //不再使用进程推帧
emulationThread.Start();
//emulationThread = new Thread(ThreadMainLoop) { Name = "EssgeeEmulation", Priority = ThreadPriority.Normal };
//emulationThread.Start();
} }
public void Reset() public void Reset()
@ -171,6 +174,9 @@ namespace Essgee.Emulation
public void LoadCartridge(byte[] romData, GameMetadata gameMetadata) public void LoadCartridge(byte[] romData, GameMetadata gameMetadata)
{ {
//初始化AxiMem
AxiMemoryEx.Init();
currentGameMetadata = gameMetadata; currentGameMetadata = gameMetadata;
byte[] ramData = new byte[currentGameMetadata.RamSize]; byte[] ramData = new byte[currentGameMetadata.RamSize];
@ -225,6 +231,30 @@ namespace Essgee.Emulation
public int FramesPerSecond { get; private set; } public int FramesPerSecond { get; private set; }
public void Update_Frame()
{
if (!emulationThreadRunning)
return;
while (pauseStateChangesRequested.Count > 0)
{
var newPauseState = pauseStateChangesRequested.Dequeue();
emulationThreadPaused = newPauseState;
PauseChanged?.Invoke(this, EventArgs.Empty);
}
emulator.RunFrame();
if (configChangeRequested)
{
emulator.SetConfiguration(newConfiguration);
configChangeRequested = false;
}
}
private void ThreadMainLoop() private void ThreadMainLoop()
{ {
// TODO: rework fps limiter/counter - AGAIN - because the counter is inaccurate at sampleTimespan=0.25 and the limiter CAN cause sound crackling at sampleTimespan>0.25 // TODO: rework fps limiter/counter - AGAIN - because the counter is inaccurate at sampleTimespan=0.25 and the limiter CAN cause sound crackling at sampleTimespan>0.25

View File

@ -2,14 +2,22 @@
namespace Essgee.Emulation namespace Essgee.Emulation
{ {
public static class Utilities public unsafe static class Utilities
{ {
public static bool IsBitSet(byte value, int bit) public static bool IsBitSet(byte value, int bit)
{ {
return ((value & (1 << bit)) != 0); return ((value & (1 << bit)) != 0);
} }
public static void RGB222toBGRA8888(int color, ref byte[] buffer, int address) //public static void RGB222toBGRA8888(int color, ref byte[] buffer, int address)
//{
// byte r = (byte)((color >> 0) & 0x3), g = (byte)((color >> 2) & 0x3), b = (byte)((color >> 4) & 0x3);
// buffer[address + 0] = (byte)((b << 6) | (b << 4) | (b << 2) | b);
// buffer[address + 1] = (byte)((g << 6) | (g << 4) | (g << 2) | g);
// buffer[address + 2] = (byte)((r << 6) | (r << 4) | (r << 2) | r);
// buffer[address + 3] = 0xFF;
//}
public static void RGB222toBGRA8888(int color, ref byte* buffer, int address)
{ {
byte r = (byte)((color >> 0) & 0x3), g = (byte)((color >> 2) & 0x3), b = (byte)((color >> 4) & 0x3); byte r = (byte)((color >> 0) & 0x3), g = (byte)((color >> 2) & 0x3), b = (byte)((color >> 4) & 0x3);
buffer[address + 0] = (byte)((b << 6) | (b << 4) | (b << 2) | b); buffer[address + 0] = (byte)((b << 6) | (b << 4) | (b << 2) | b);
@ -18,7 +26,16 @@ namespace Essgee.Emulation
buffer[address + 3] = 0xFF; buffer[address + 3] = 0xFF;
} }
public static void RGB444toBGRA8888(int color, ref byte[] buffer, int address) //public static void RGB444toBGRA8888(int color, ref byte[] buffer, int address)
//{
// byte r = (byte)((color >> 0) & 0xF), g = (byte)((color >> 4) & 0xF), b = (byte)((color >> 8) & 0xF);
// buffer[address + 0] = (byte)((b << 4) | b);
// buffer[address + 1] = (byte)((g << 4) | g);
// buffer[address + 2] = (byte)((r << 4) | r);
// buffer[address + 3] = 0xFF;
//}
public unsafe static void RGB444toBGRA8888(int color, ref byte* buffer, int address)
{ {
byte r = (byte)((color >> 0) & 0xF), g = (byte)((color >> 4) & 0xF), b = (byte)((color >> 8) & 0xF); byte r = (byte)((color >> 0) & 0xF), g = (byte)((color >> 4) & 0xF), b = (byte)((color >> 8) & 0xF);
buffer[address + 0] = (byte)((b << 4) | b); buffer[address + 0] = (byte)((b << 4) | b);

View File

@ -7,7 +7,7 @@ using static Essgee.Emulation.Utilities;
namespace Essgee.Emulation.Video namespace Essgee.Emulation.Video
{ {
/* Sega 315-5378, Game Gear */ /* Sega 315-5378, Game Gear */
public class SegaGGVDP : SegaSMSVDP public unsafe class SegaGGVDP : SegaSMSVDP
{ {
protected override int numTotalScanlines => NumTotalScanlinesNtsc; protected override int numTotalScanlines => NumTotalScanlinesNtsc;
@ -18,7 +18,8 @@ namespace Essgee.Emulation.Video
public SegaGGVDP() : base() public SegaGGVDP() : base()
{ {
cram = new byte[0x40]; //cram = new byte[0x40];
cram_set = new byte[0x40];
} }
public override void Reset() public override void Reset()
@ -41,26 +42,27 @@ namespace Essgee.Emulation.Video
/* Create arrays */ /* Create arrays */
screenUsage = new byte[numVisiblePixels * numVisibleScanlines]; screenUsage = new byte[numVisiblePixels * numVisibleScanlines];
outputFramebuffer = new byte[Viewport.Width * Viewport.Height * 4]; //outputFramebuffer = new byte[Viewport.Width * Viewport.Height * 4];
outputFramebuffer_set = new byte[Viewport.Width * Viewport.Height * 4];
/* Update resolution/display timing */ /* Update resolution/display timing */
UpdateResolution(); UpdateResolution();
} }
GCHandle? lasyRenderHandle; //GCHandle? lasyRenderHandle;
protected override void PrepareRenderScreen() protected override void PrepareRenderScreen()
{ {
// 固定数组,防止垃圾回收器移动它 //// 固定数组,防止垃圾回收器移动它
var bitmapcolorRect_handle = GCHandle.Alloc(outputFramebuffer.Clone() as byte[], GCHandleType.Pinned); //var bitmapcolorRect_handle = GCHandle.Alloc(outputFramebuffer.Clone() as byte[], GCHandleType.Pinned);
// 获取数组的指针 //// 获取数组的指针
IntPtr mFrameDataPtr = bitmapcolorRect_handle.AddrOfPinnedObject(); //IntPtr mFrameDataPtr = bitmapcolorRect_handle.AddrOfPinnedObject();
var eventArgs = RenderScreenEventArgs.Create(numVisiblePixels, numVisibleScanlines, mFrameDataPtr); var eventArgs = RenderScreenEventArgs.Create(numVisiblePixels, numVisibleScanlines, outputFramebuffer_Ptr);
OnRenderScreen(eventArgs); OnRenderScreen(eventArgs);
eventArgs.Release(); eventArgs.Release();
if (lasyRenderHandle != null) //if (lasyRenderHandle != null)
lasyRenderHandle.Value.Free(); // lasyRenderHandle.Value.Free();
lasyRenderHandle = bitmapcolorRect_handle; //lasyRenderHandle = bitmapcolorRect_handle;
//OnRenderScreen(new RenderScreenEventArgs(Viewport.Width, Viewport.Height, outputFramebuffer.Clone() as byte[])); //OnRenderScreen(new RenderScreenEventArgs(Viewport.Width, Viewport.Height, outputFramebuffer.Clone() as byte[]));
} }
@ -92,7 +94,7 @@ namespace Essgee.Emulation.Video
WriteColorToFramebuffer((ushort)(cram[cramAddress + 1] << 8 | cram[cramAddress]), address); WriteColorToFramebuffer((ushort)(cram[cramAddress + 1] << 8 | cram[cramAddress]), address);
} }
protected override void WriteColorToFramebuffer(ushort colorValue, int address) protected unsafe override void WriteColorToFramebuffer(ushort colorValue, int address)
{ {
RGB444toBGRA8888(colorValue, ref outputFramebuffer, address); RGB444toBGRA8888(colorValue, ref outputFramebuffer, address);
} }

View File

@ -8,7 +8,7 @@ using static Essgee.Emulation.Utilities;
namespace Essgee.Emulation.Video namespace Essgee.Emulation.Video
{ {
/* Sega 315-5124 (Mark III, SMS) and 315-5246 (SMS 2); differences see 'VDPDIFF' comments */ /* Sega 315-5124 (Mark III, SMS) and 315-5246 (SMS 2); differences see 'VDPDIFF' comments */
public class SegaSMSVDP : TMS99xxA public unsafe class SegaSMSVDP : TMS99xxA
{ {
/* VDPDIFF: switch for Mk3/SMS1 vs SMS2/GG behavior; configurable via SetRevision, maybe still split into separate classes instead? */ /* VDPDIFF: switch for Mk3/SMS1 vs SMS2/GG behavior; configurable via SetRevision, maybe still split into separate classes instead? */
protected VDPTypes vdpType = VDPTypes.Mk3SMS1; protected VDPTypes vdpType = VDPTypes.Mk3SMS1;
@ -23,8 +23,27 @@ namespace Essgee.Emulation.Video
public const int PortVCounter = 0x40; // 0x7E canonically, but mirrored across bus public const int PortVCounter = 0x40; // 0x7E canonically, but mirrored across bus
public const int PortHCounter = 0x41; // 0x7F canonically, but mirrored across bus public const int PortHCounter = 0x41; // 0x7F canonically, but mirrored across bus
[StateRequired] //[StateRequired]
protected byte[] cram; //protected byte[] cram;
#region //指针化 cram
static byte[] cram_src;
static GCHandle cram_handle;
public static byte* cram;
public static int cramLength;
public static bool cram_IsNull => cram == null;
public static byte[] cram_set
{
set
{
cram_handle.ReleaseGCHandle();
cram_src = value;
cramLength = value.Length;
cram_src.GetObjectPtr(ref cram_handle, ref cram);
}
}
#endregion
[StateRequired] [StateRequired]
protected int vCounter, hCounter; protected int vCounter, hCounter;
@ -330,8 +349,10 @@ namespace Essgee.Emulation.Video
public SegaSMSVDP() : base() public SegaSMSVDP() : base()
{ {
registers = new byte[0x0B]; //registers = new byte[0x0B];
cram = new byte[0x20]; //cram = new byte[0x20];
registers_set = new byte[0x0B];
cram_set = new byte[0x20];
spriteBuffer = new (int Number, int Y, int X, int Pattern, int Attribute)[NumActiveScanlinesHigh][]; spriteBuffer = new (int Number, int Y, int X, int Pattern, int Attribute)[NumActiveScanlinesHigh][];
for (int i = 0; i < spriteBuffer.Length; i++) spriteBuffer[i] = new (int Number, int Y, int X, int Pattern, int Attribute)[NumSpritesPerLineMode4]; for (int i = 0; i < spriteBuffer.Length; i++) spriteBuffer[i] = new (int Number, int Y, int X, int Pattern, int Attribute)[NumSpritesPerLineMode4];
@ -353,7 +374,8 @@ namespace Essgee.Emulation.Video
WriteRegister(0x09, 0x00); WriteRegister(0x09, 0x00);
WriteRegister(0x0A, 0xFF); WriteRegister(0x0A, 0xFF);
for (int i = 0; i < cram.Length; i++) cram[i] = 0; //for (int i = 0; i < cram.Length; i++) cram[i] = 0;
for (int i = 0; i < cramLength; i++) cram[i] = 0;
vCounter = hCounter = 0; vCounter = hCounter = 0;
lineInterruptCounter = registers[0x0A]; lineInterruptCounter = registers[0x0A];
@ -379,7 +401,8 @@ namespace Essgee.Emulation.Video
/* Create arrays */ /* Create arrays */
screenUsage = new byte[numVisiblePixels * numVisibleScanlines]; screenUsage = new byte[numVisiblePixels * numVisibleScanlines];
outputFramebuffer = new byte[(numVisiblePixels * numVisibleScanlines) * 4]; //outputFramebuffer = new byte[(numVisiblePixels * numVisibleScanlines) * 4];
outputFramebuffer_set = new byte[(numVisiblePixels * numVisibleScanlines) * 4];
/* Update resolution/display timing */ /* Update resolution/display timing */
UpdateResolution(); UpdateResolution();
@ -439,20 +462,21 @@ namespace Essgee.Emulation.Video
} }
} }
GCHandle? lasyRenderHandle; //GCHandle? lasyRenderHandle;
protected override void PrepareRenderScreen() protected override void PrepareRenderScreen()
{ {
// 固定数组,防止垃圾回收器移动它 // 固定数组,防止垃圾回收器移动它
var bitmapcolorRect_handle = GCHandle.Alloc(outputFramebuffer.Clone() as byte[], GCHandleType.Pinned); //var bitmapcolorRect_handle = GCHandle.Alloc(outputFramebuffer.Clone() as byte[], GCHandleType.Pinned);
// 获取数组的指针 //var bitmapcolorRect_handle = GCHandle.Alloc(outputFramebuffer, GCHandleType.Pinned);
IntPtr mFrameDataPtr = bitmapcolorRect_handle.AddrOfPinnedObject(); //// 获取数组的指针
//IntPtr mFrameDataPtr = bitmapcolorRect_handle.AddrOfPinnedObject();
var eventArgs = RenderScreenEventArgs.Create(numVisiblePixels, numVisibleScanlines, mFrameDataPtr); var eventArgs = RenderScreenEventArgs.Create(numVisiblePixels, numVisibleScanlines, outputFramebuffer_Ptr);
OnRenderScreen(eventArgs); OnRenderScreen(eventArgs);
eventArgs.Release(); eventArgs.Release();
if (lasyRenderHandle != null) //if (lasyRenderHandle != null)
lasyRenderHandle.Value.Free(); // lasyRenderHandle.Value.Free();
lasyRenderHandle = bitmapcolorRect_handle; //lasyRenderHandle = bitmapcolorRect_handle;
//OnRenderScreen(new RenderScreenEventArgs(numVisiblePixels, numVisibleScanlines, outputFramebuffer.Clone() as byte[])); //OnRenderScreen(new RenderScreenEventArgs(numVisiblePixels, numVisibleScanlines, outputFramebuffer.Clone() as byte[]));
} }
@ -868,7 +892,7 @@ namespace Essgee.Emulation.Video
WriteColorToFramebuffer(cram[((palette * 16) + color)], address); WriteColorToFramebuffer(cram[((palette * 16) + color)], address);
} }
protected override void WriteColorToFramebuffer(ushort colorValue, int address) protected unsafe override void WriteColorToFramebuffer(ushort colorValue, int address)
{ {
/* If not in Master System video mode, color value is index into legacy colormap */ /* If not in Master System video mode, color value is index into legacy colormap */
if (!isBitM4Set) if (!isBitM4Set)
@ -925,7 +949,8 @@ namespace Essgee.Emulation.Video
protected override void WriteRegister(byte register, byte value) protected override void WriteRegister(byte register, byte value)
{ {
if (register < registers.Length) //if (register < registers.Length)
if (register < registersLength)
registers[register] = value; registers[register] = value;
if (register == 0x00 || register == 0x01) if (register == 0x00 || register == 0x01)

View File

@ -8,7 +8,7 @@ using static Essgee.Emulation.Utilities;
namespace Essgee.Emulation.Video namespace Essgee.Emulation.Video
{ {
/* Texas Instruments TMS99xxA family */ /* Texas Instruments TMS99xxA family */
public class TMS99xxA : IVideo public unsafe class TMS99xxA : IVideo
{ {
public const int NumTotalScanlinesPal = 313; public const int NumTotalScanlinesPal = 313;
public const int NumTotalScanlinesNtsc = 262; public const int NumTotalScanlinesNtsc = 262;
@ -48,13 +48,52 @@ namespace Essgee.Emulation.Video
protected double clockRate, refreshRate; protected double clockRate, refreshRate;
protected bool isPalChip; protected bool isPalChip;
[StateRequired] //[StateRequired]
protected byte[] registers, vram; //protected byte[] registers, vram;
#region //指针化 registers
static byte[] registers_src;
static GCHandle registers_handle;
public static byte* registers;
public static int registersLength;
public static bool registers_IsNull => registers == null;
public static byte[] registers_set
{
set
{
registers_handle.ReleaseGCHandle();
registers_src = value;
registersLength = value.Length;
registers_src.GetObjectPtr(ref registers_handle, ref registers);
}
}
#endregion
#region //指针化 vram
static byte[] vram_src;
static GCHandle vram_handle;
public static byte* vram;
public static int vramLength;
public static bool vram_IsNull => vram == null;
public static byte[] vram_set
{
set
{
vram_handle.ReleaseGCHandle();
vram_src = value;
vramLength = value.Length;
vram_src.GetObjectPtr(ref vram_handle, ref vram);
}
}
#endregion
[StateRequired] [StateRequired]
protected (int Number, int Y, int X, int Pattern, int Attribute)[][] spriteBuffer; protected (int Number, int Y, int X, int Pattern, int Attribute)[][] spriteBuffer;
protected ushort vramMask16k => 0x3FFF; //protected ushort vramMask16k => 0x3FFF;
protected ushort vramMask4k => 0x0FFF; //protected ushort vramMask4k => 0x0FFF;
protected const ushort vramMask16k = 0x3FFF;
protected const ushort vramMask4k = 0x0FFF;
[StateRequired] [StateRequired]
protected bool isSecondControlWrite; protected bool isSecondControlWrite;
@ -64,6 +103,7 @@ namespace Essgee.Emulation.Video
protected byte readBuffer; protected byte readBuffer;
protected byte codeRegister => (byte)((controlWord >> 14) & 0x03); protected byte codeRegister => (byte)((controlWord >> 14) & 0x03);
protected ushort addressRegister protected ushort addressRegister
{ {
get { return (ushort)(controlWord & 0x3FFF); } get { return (ushort)(controlWord & 0x3FFF); }
@ -156,7 +196,29 @@ namespace Essgee.Emulation.Video
[StateRequired] [StateRequired]
protected int cycleCount; protected int cycleCount;
protected byte[] outputFramebuffer; //protected byte[] outputFramebuffer;
#region //指针化 outputFramebuffer
static byte[] outputFramebuffer_src;
static GCHandle outputFramebuffer_handle;
public static IntPtr outputFramebuffer_Ptr;
public static byte* outputFramebuffer;
public static int outputFramebufferLength;
public static bool outputFramebuffer_IsNull => outputFramebuffer == null;
public static byte[] outputFramebuffer_set
{
set
{
outputFramebuffer_handle.ReleaseGCHandle();
outputFramebuffer_src = value;
outputFramebufferLength = value.Length;
outputFramebuffer_src.GetObjectPtr(ref outputFramebuffer_handle, ref outputFramebuffer);
outputFramebuffer_Ptr = outputFramebuffer_handle.AddrOfPinnedObject();
}
}
#endregion
protected int clockCyclesPerLine; protected int clockCyclesPerLine;
@ -171,8 +233,10 @@ namespace Essgee.Emulation.Video
public TMS99xxA() public TMS99xxA()
{ {
registers = new byte[0x08]; //registers = new byte[0x08];
vram = new byte[0x4000]; //vram = new byte[0x4000];
registers_set = new byte[0x08];
vram_set = new byte[0x4000];
spriteBuffer = new (int Number, int Y, int X, int Pattern, int Attribute)[NumActiveScanlines][]; spriteBuffer = new (int Number, int Y, int X, int Pattern, int Attribute)[NumActiveScanlines][];
for (int i = 0; i < spriteBuffer.Length; i++) spriteBuffer[i] = new (int Number, int Y, int X, int Pattern, int Attribute)[NumSpritesPerLine]; for (int i = 0; i < spriteBuffer.Length; i++) spriteBuffer[i] = new (int Number, int Y, int X, int Pattern, int Attribute)[NumSpritesPerLine];
@ -218,8 +282,10 @@ namespace Essgee.Emulation.Video
public virtual void Reset() public virtual void Reset()
{ {
for (int i = 0; i < registers.Length; i++) registers[i] = 0; //for (int i = 0; i < registers.Length; i++) registers[i] = 0;
for (int i = 0; i < vram.Length; i++) vram[i] = 0; //for (int i = 0; i < vram.Length; i++) vram[i] = 0;
for (int i = 0; i < registersLength; i++) registers[i] = 0;
for (int i = 0; i < vramLength; i++) vram[i] = 0;
for (int i = 0; i < spriteBuffer.Length; i++) for (int i = 0; i < spriteBuffer.Length; i++)
for (int j = 0; j < spriteBuffer[i].Length; j++) for (int j = 0; j < spriteBuffer[i].Length; j++)
@ -266,7 +332,8 @@ namespace Essgee.Emulation.Video
/* Create arrays */ /* Create arrays */
screenUsage = new byte[numVisiblePixels * numVisibleScanlines]; screenUsage = new byte[numVisiblePixels * numVisibleScanlines];
outputFramebuffer = new byte[(numVisiblePixels * numVisibleScanlines) * 4]; //outputFramebuffer = new byte[(numVisiblePixels * numVisibleScanlines) * 4];
outputFramebuffer_set = new byte[(numVisiblePixels * numVisibleScanlines) * 4];
/* Scanline parameters */ /* Scanline parameters */
if (!isPalChip) if (!isPalChip)
@ -337,19 +404,19 @@ namespace Essgee.Emulation.Video
} }
} }
GCHandle? lasyRenderHandle; //GCHandle? lasyRenderHandle;
protected virtual void PrepareRenderScreen() protected virtual void PrepareRenderScreen()
{ {
// 固定数组,防止垃圾回收器移动它 //// 固定数组,防止垃圾回收器移动它
var bitmapcolorRect_handle = GCHandle.Alloc(outputFramebuffer.Clone() as byte[], GCHandleType.Pinned); //var bitmapcolorRect_handle = GCHandle.Alloc(outputFramebuffer.Clone() as byte[], GCHandleType.Pinned);
// 获取数组的指针 //// 获取数组的指针
IntPtr mFrameDataPtr = bitmapcolorRect_handle.AddrOfPinnedObject(); //IntPtr mFrameDataPtr = bitmapcolorRect_handle.AddrOfPinnedObject();
var eventArgs = RenderScreenEventArgs.Create(numVisiblePixels, numVisibleScanlines, mFrameDataPtr); var eventArgs = RenderScreenEventArgs.Create(numVisiblePixels, numVisibleScanlines, outputFramebuffer_Ptr);
OnRenderScreen(eventArgs); OnRenderScreen(eventArgs);
eventArgs.Release(); eventArgs.Release();
if (lasyRenderHandle != null) //if (lasyRenderHandle != null)
lasyRenderHandle.Value.Free(); // lasyRenderHandle.Value.Free();
lasyRenderHandle = bitmapcolorRect_handle; //lasyRenderHandle = bitmapcolorRect_handle;
//OnRenderScreen(new RenderScreenEventArgs(numVisiblePixels, numVisibleScanlines, outputFramebuffer.Clone() as byte[])); //OnRenderScreen(new RenderScreenEventArgs(numVisiblePixels, numVisibleScanlines, outputFramebuffer.Clone() as byte[]));
} }

View File

@ -44,7 +44,8 @@ public class Essgeeinit : MonoBehaviour
uegResources = new UEGResources(); uegResources = new UEGResources();
uegLog = new UEGLog(); uegLog = new UEGLog();
InitAll(uegResources, Application.persistentDataPath); InitAll(uegResources, Application.persistentDataPath);
LoadAndRunCartridge("G:/Ninja_Gaiden_(UE)_type_A_[!].sms"); LoadAndRunCartridge("G:/psjapa.sms");
//LoadAndRunCartridge("G:/Ninja_Gaiden_(UE)_type_A_[!].sms");
//LoadAndRunCartridge("G:/SML2.gb"); //LoadAndRunCartridge("G:/SML2.gb");
} }
@ -59,6 +60,8 @@ public class Essgeeinit : MonoBehaviour
if (!emulatorHandler.IsRunning) if (!emulatorHandler.IsRunning)
return; return;
mUniKeyboard.UpdateInputKey(); mUniKeyboard.UpdateInputKey();
emulatorHandler.Update_Frame();
} }
void InitAll(IGameMetaReources metaresources,string CustonDataDir) void InitAll(IGameMetaReources metaresources,string CustonDataDir)
@ -343,6 +346,7 @@ public class Essgeeinit : MonoBehaviour
private void LoadAndRunCartridge(string fileName) private void LoadAndRunCartridge(string fileName)
{ {
//Application.targetFrameRate = 60;
try try
{ {
var (machineType, romData) = CartridgeLoader.Load(fileName, "ROM image"); var (machineType, romData) = CartridgeLoader.Load(fileName, "ROM image");

View File

@ -0,0 +1,23 @@
//using MAME.Core;
//using UnityEngine;
//public class UEGMouse : MonoBehaviour, IMouse
//{
// static int mX, mY;
// public byte[] buttons = new byte[2];
// void Update()
// {
// mX = (int)Input.mousePosition.x;
// mY = (int)Input.mousePosition.y;
// buttons[0] = Input.GetMouseButton(0) ? (byte)1 : (byte)0;
// buttons[1] = Input.GetMouseButton(1) ? (byte)1 : (byte)0;
// }
// public void MouseXY(out int X, out int Y, out byte[] MouseButtons)
// {
// X = mX;
// Y = mY * -1;
// MouseButtons = buttons;
// }
//}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 0e566345b50ca464fb8bd492a22c043b

View File

@ -13,8 +13,8 @@ public class UEGSoundPlayer : MonoBehaviour//, ISoundPlayer
void Awake() void Awake()
{ {
//AudioClip dummy = AudioClip.Create("dummy", 1, 2, AudioSettings.outputSampleRate, false); AudioClip dummy = AudioClip.Create("dummy", 1, 2, AudioSettings.outputSampleRate, false);
AudioClip dummy = AudioClip.Create("dummy", 1, 2, 44100, false); //AudioClip dummy = AudioClip.Create("dummy", 1, 2, 44100, false);
dummy.SetData(new float[] { 1, 1 }, 0); dummy.SetData(new float[] { 1, 1 }, 0);
m_as.clip = dummy; m_as.clip = dummy;
m_as.loop = true; m_as.loop = true;
@ -74,7 +74,9 @@ public class UEGSoundPlayer : MonoBehaviour//, ISoundPlayer
for (int i = 0; i < samples_a; i += 2) for (int i = 0; i < samples_a; i += 2)
{ {
_buffer.Write(buffer[i] / 32767.0f); //_buffer.Write(buffer[i] / 32767.0f);
float data = (uint)(buffer[i] + 32767);
_buffer.Write(data / ushort.MaxValue);
//_buffer.Write(buffer[i] / 32767.0f); //_buffer.Write(buffer[i] / 32767.0f);
} }
} }

View File

@ -1,2 +1,2 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 0e566345b50ca464fb8bd492a22c043b guid: d5855fd9c3285e144b7db2b76cf55d77