IEmuCore 推帧,跳帧抽象,不再需要IEmuCore依赖monobehaviour的update推帧

This commit is contained in:
ALIENJACK\alien 2025-01-26 10:51:06 +08:00
parent 5ae970673a
commit 1090fb4da7
8 changed files with 101 additions and 90 deletions

View File

@ -1,3 +1,7 @@
using AxibugEmuOnline.Client;
using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Network;
using AxibugProtobuf;
using AxiReplay; using AxiReplay;
using MAME.Core; using MAME.Core;
using System; using System;
@ -6,13 +10,6 @@ using System.IO;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using AxibugEmuOnline.Client;
using AxibugEmuOnline.Client.ClientCore;
using AxibugProtobuf;
using static AxibugEmuOnline.Client.NesControllerMapper;
using VirtualNes.Core;
using System.Linq;
using AxibugEmuOnline.Client.Event;
public class UMAME : MonoBehaviour, IEmuCore public class UMAME : MonoBehaviour, IEmuCore
{ {
@ -49,9 +46,9 @@ public class UMAME : MonoBehaviour, IEmuCore
{ {
//设为60帧 //设为60帧
Application.targetFrameRate = 60; Application.targetFrameRate = 120;
// 强制横屏 // 强制横屏
Screen.orientation = ScreenOrientation.LandscapeLeft; Screen.orientation = ScreenOrientation.LandscapeLeft;
instance = this; instance = this;
mFPS = GameObject.Find("FPS").GetComponent<Text>(); mFPS = GameObject.Find("FPS").GetComponent<Text>();
@ -75,7 +72,7 @@ public class UMAME : MonoBehaviour, IEmuCore
{ {
StopGame(); StopGame();
} }
#region #region
public object GetState() public object GetState()
{ {
return SaveState(); return SaveState();
@ -107,7 +104,7 @@ public class UMAME : MonoBehaviour, IEmuCore
if (LoadGame(romFile.FileName, false)) if (LoadGame(romFile.FileName, false))
return true; return true;
else else
return "Rom加载失败"; return "Rom加载失败";
} }
public void Dispose() public void Dispose()
{ {
@ -130,9 +127,9 @@ public class UMAME : MonoBehaviour, IEmuCore
mReplayWriter = new ReplayWriter(mChangeRomName, "fuck", ReplayData.ReplayFormat.FM32IP64, Encoding.UTF8); mReplayWriter = new ReplayWriter(mChangeRomName, "fuck", ReplayData.ReplayFormat.FM32IP64, Encoding.UTF8);
mChangeRomName = loadRom; mChangeRomName = loadRom;
StopGame(); StopGame();
//读取ROM //读取ROM
emu.LoadRom(mChangeRomName); emu.LoadRom(mChangeRomName);
//读取成功 //读取成功
if (emu.bRom) if (emu.bRom)
{ {
if (bReplay) if (bReplay)
@ -142,14 +139,14 @@ public class UMAME : MonoBehaviour, IEmuCore
mUniKeyboard.SetRePlay(true); mUniKeyboard.SetRePlay(true);
} }
//读取ROM之后获得宽高初始化画面 //读取ROM之后获得宽高初始化画面
int _width; int _height; IntPtr _framePtr; int _width; int _height; IntPtr _framePtr;
emu.GetGameScreenSize(out _width, out _height, out _framePtr); emu.GetGameScreenSize(out _width, out _height, out _framePtr);
App.log.Debug($"_width->{_width}, _height->{_height}, _framePtr->{_framePtr}"); App.log.Debug($"_width->{_width}, _height->{_height}, _framePtr->{_framePtr}");
mUniVideoPlayer.Initialize(_width, _height, _framePtr); mUniVideoPlayer.Initialize(_width, _height, _framePtr);
//初始化音频 //初始化音频
mUniSoundPlayer.Initialize(); mUniSoundPlayer.Initialize();
//开始游戏 //开始游戏
emu.StartGame(); emu.StartGame();
bInGame = true; bInGame = true;
bLogicUpdatePause = true; bLogicUpdatePause = true;
@ -157,48 +154,29 @@ public class UMAME : MonoBehaviour, IEmuCore
} }
else else
{ {
App.log.Debug($"ROM加载失败"); App.log.Debug($"ROM加载失败");
return false; return false;
} }
} }
void Update()
{
if (!bInGame)
return;
if (bLogicUpdatePause) public bool PushEmulatorFrame()
{ {
PushEmulatorFrame(); if (!bInGame) return false;
if (InGameUI.Instance.IsNetPlay) if (!bLogicUpdatePause) return false;
FixEmulatorFrame();
} //采集本帧Input
mUniVideoPlayer.ApplyFilterEffect();
mUniVideoPlayer.ApplyScreenScaler();
mFPS.text = ($"fpsv {mUniVideoPlayer.videoFPS.ToString("F2")} fpsa {mUniSoundPlayer.audioFPS.ToString("F2")} ,Idx:{App.roomMgr.netReplay?.mCurrClientFrameIdx},RIdx:{App.roomMgr.netReplay?.mRemoteFrameIdx},RForward:{App.roomMgr.netReplay?.mRemoteForwardCount} ,RD:{App.roomMgr.netReplay?.mRemoteForwardCount} ,D:{App.roomMgr.netReplay?.mDiffFrameCount} ,Q:{App.roomMgr.netReplay?.mNetReplayQueue.Count}");
}
//是否跳帧,单机无效
void FixEmulatorFrame()
{
var skipFrameCount = App.roomMgr.netReplay.GetSkipFrameCount();
if (skipFrameCount > 0) App.log.Debug($"SKIP FRAME : {skipFrameCount} ,CF:{App.roomMgr.netReplay.mCurrClientFrameIdx},RFIdx:{App.roomMgr.netReplay.mRemoteFrameIdx},RForward:{App.roomMgr.netReplay.mRemoteForwardCount} ,queue:{App.roomMgr.netReplay.mNetReplayQueue.Count}");
for (var i = 0; i < skipFrameCount; i++)
if (!PushEmulatorFrame())
break;
}
bool PushEmulatorFrame()
{
//采集本帧Input
bool bhadNext = mUniKeyboard.SampleInput(); bool bhadNext = mUniKeyboard.SampleInput();
//如果未收到Input数据,核心帧不推进 //如果未收到Input数据,核心帧不推进
if (!bhadNext) return false; if (!bhadNext) return false;
//放行下一帧 //放行下一帧
//emu.UnlockNextFreme(); //emu.UnlockNextFreme();
//推帧 //推帧
emu.UpdateFrame(); emu.UpdateFrame();
return true; return true;
}
public void AfterPushFrame()
{
mFPS.text = ($"fpsv {mUniVideoPlayer.videoFPS.ToString("F2")} fpsa {mUniSoundPlayer.audioFPS.ToString("F2")} ,Idx:{App.roomMgr.netReplay?.mCurrClientFrameIdx},RIdx:{App.roomMgr.netReplay?.mRemoteFrameIdx},RForward:{App.roomMgr.netReplay?.mRemoteForwardCount} ,RD:{App.roomMgr.netReplay?.mRemoteForwardCount} ,D:{App.roomMgr.netReplay?.mDiffFrameCount} ,Q:{App.roomMgr.netReplay?.mNetReplayQueue.Count}");
} }
public void SaveReplay() public void SaveReplay()
{ {
@ -245,5 +223,11 @@ public class UMAME : MonoBehaviour, IEmuCore
emu.LoadState(br); emu.LoadState(br);
br.Close(); br.Close();
fs.Close(); fs.Close();
} }
public Texture OutputPixel => mUniVideoPlayer.rawBufferWarper;
public RawImage DrawCanvas => mUniVideoPlayer.DrawCanvas;
} }

View File

@ -1,4 +1,4 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugProtobuf; using AxibugProtobuf;
using MAME.Core; using MAME.Core;
using System; using System;
@ -24,6 +24,9 @@ public class UniVideoPlayer : MonoBehaviour, IVideoPlayer
public ulong mFrame { get; private set; } public ulong mFrame { get; private set; }
bool bInit = false; bool bInit = false;
public Texture2D rawBufferWarper => m_rawBufferWarper;
public RawImage DrawCanvas => m_drawCanvas;
private void Awake() private void Awake()
{ {
mFrame = 0; mFrame = 0;
@ -31,7 +34,7 @@ public class UniVideoPlayer : MonoBehaviour, IVideoPlayer
m_drawCanvasrect = m_drawCanvas.GetComponent<RectTransform>(); m_drawCanvasrect = m_drawCanvas.GetComponent<RectTransform>();
} }
public void Initialize(int width, int height,IntPtr framePtr) public void Initialize(int width, int height, IntPtr framePtr)
{ {
m_drawCanvas.color = Color.white; m_drawCanvas.color = Color.white;
@ -40,7 +43,7 @@ public class UniVideoPlayer : MonoBehaviour, IVideoPlayer
mScreenSize = new Vector2Int(width, height); mScreenSize = new Vector2Int(width, height);
mDataLenght = width * height * 4; mDataLenght = width * height * 4;
//mFrameData = new int[mWidth * mHeight]; //mFrameData = new int[mWidth * mHeight];
//MAME来的是BGRA32好好好 BGRA->RGBA //MAME来的是BGRA32好好好 BGRA->RGBA
m_rawBufferWarper = new Texture2D(mScreenSize.x, mScreenSize.y, TextureFormat.RGBA32, false); m_rawBufferWarper = new Texture2D(mScreenSize.x, mScreenSize.y, TextureFormat.RGBA32, false);
m_rawBufferWarper.filterMode = FilterMode.Point; m_rawBufferWarper.filterMode = FilterMode.Point;
} }
@ -56,7 +59,7 @@ public class UniVideoPlayer : MonoBehaviour, IVideoPlayer
public void StopVideo() public void StopVideo()
{ {
bInit = false; bInit = false;
m_drawCanvas.color = new Color(0,0,0,0); m_drawCanvas.color = new Color(0, 0, 0, 0);
} }
//void Update() //void Update()

View File

@ -6,6 +6,7 @@ using System.Globalization;
using System.IO; using System.IO;
using System.Xml.Linq; using System.Xml.Linq;
using UnityEngine; using UnityEngine;
using UnityEngine.UI;
using VirtualNes.Core; using VirtualNes.Core;
using VirtualNes.Core.Debug; using VirtualNes.Core.Debug;
@ -38,25 +39,6 @@ namespace AxibugEmuOnline.Client
AudioProvider.NesEmu = this; AudioProvider.NesEmu = this;
} }
/// <summary>
/// Unity的逐帧驱动
/// </summary>
private unsafe void Update()
{
if (NesCore != null && !IsPause)
{
PushEmulatorFrame();
if (InGameUI.Instance.IsNetPlay)
FixEmulatorFrame();
var screenBuffer = NesCore.ppu.GetScreenPtr();
VideoProvider.SetDrawData(screenBuffer);
}
VideoProvider.ApplyScreenScaler();
VideoProvider.ApplyFilterEffect();
}
public RomPlatformType Platform => RomPlatformType.Nes; public RomPlatformType Platform => RomPlatformType.Nes;
private CoreSupporter m_coreSupporter; private CoreSupporter m_coreSupporter;
/// <summary> /// <summary>
@ -148,20 +130,11 @@ namespace AxibugEmuOnline.Client
#if UNITY_EDITOR #if UNITY_EDITOR
private ControllerState m_lastState; private ControllerState m_lastState;
#endif #endif
//是否跳帧,单机无效
private void FixEmulatorFrame()
{
var skipFrameCount = App.roomMgr.netReplay.GetSkipFrameCount();
if (skipFrameCount > 0) App.log.Debug($"SKIP FRAME : {skipFrameCount}");
for (var i = 0; i < skipFrameCount; i++)
if (!PushEmulatorFrame())
break;
}
//推进帧 //推进帧
private bool PushEmulatorFrame() public bool PushEmulatorFrame()
{ {
if (NesCore == null || IsPause) return false;
m_coreSupporter.SampleInput(NesCore.FrameCount); m_coreSupporter.SampleInput(NesCore.FrameCount);
var controlState = m_coreSupporter.GetControllerState(); var controlState = m_coreSupporter.GetControllerState();
@ -178,9 +151,15 @@ namespace AxibugEmuOnline.Client
return true; return true;
}
public unsafe void AfterPushFrame()
{
var screenBuffer = NesCore.ppu.GetScreenPtr();
VideoProvider.SetDrawData(screenBuffer);
} }
public IControllerSetuper GetControllerSetuper() public IControllerSetuper GetControllerSetuper()
{ {
return ControllerMapper; return ControllerMapper;
@ -219,7 +198,11 @@ namespace AxibugEmuOnline.Client
UnityEditor.EditorUtility.SetDirty(db); UnityEditor.EditorUtility.SetDirty(db);
UnityEditor.AssetDatabase.SaveAssets(); UnityEditor.AssetDatabase.SaveAssets();
} }
public Texture OutputPixel => VideoProvider.OutputPixel;
public RawImage DrawCanvas => VideoProvider.Drawer;
#endif #endif
} }
} }

View File

@ -10,6 +10,9 @@ namespace AxibugEmuOnline.Client
{ {
public class VideoProvider : MonoBehaviour public class VideoProvider : MonoBehaviour
{ {
public RenderTexture OutputPixel => rt_gpu;
public RawImage Drawer => Image;
#region UI_REF #region UI_REF
public NesEmulator NesEmu; public NesEmulator NesEmu;
public Canvas DrawCanvas; public Canvas DrawCanvas;

View File

@ -1,5 +1,6 @@
using AxibugProtobuf; using AxibugProtobuf;
using UnityEngine; using UnityEngine;
using UnityEngine.UI;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
@ -34,6 +35,12 @@ namespace AxibugEmuOnline.Client
RomPlatformType Platform { get; } RomPlatformType Platform { get; }
/// <summary> 获取当前模拟器帧序号,在加载快照和Reset后,应当重置为0 </summary> /// <summary> 获取当前模拟器帧序号,在加载快照和Reset后,应当重置为0 </summary>
uint Frame { get; } uint Frame { get; }
/// <summary> 模拟器核心推帧 </summary>
bool PushEmulatorFrame();
/// <summary> 模拟器核心推帧结束 </summary>
void AfterPushFrame();
Texture OutputPixel { get; }
RawImage DrawCanvas { get; }
} }
public static class IEnumCoreTool public static class IEnumCoreTool

View File

@ -1,4 +1,4 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Common; using AxibugEmuOnline.Client.Common;
using AxibugEmuOnline.Client.Network; using AxibugEmuOnline.Client.Network;
using AxibugProtobuf; using AxibugProtobuf;

View File

@ -2,6 +2,7 @@
using AxibugProtobuf; using AxibugProtobuf;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine;
namespace AxibugEmuOnline.Client.Network namespace AxibugEmuOnline.Client.Network
{ {
@ -76,7 +77,6 @@ namespace AxibugEmuOnline.Client.Network
{ {
while (queueNetMsg.Count > 0) while (queueNetMsg.Count > 0)
{ {
var msgData = queueNetMsg.Dequeue(); var msgData = queueNetMsg.Dequeue();
PostNetMsgEvent(msgData.Item1, msgData.Item2, msgData.Item3); PostNetMsgEvent(msgData.Item1, msgData.Item2, msgData.Item3);
} }

View File

@ -1,5 +1,6 @@
using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Event; using AxibugEmuOnline.Client.Event;
using AxibugEmuOnline.Client.Network;
using AxibugProtobuf; using AxibugProtobuf;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -51,6 +52,36 @@ namespace AxibugEmuOnline.Client
base.Awake(); base.Awake();
} }
protected override void Update()
{
base.Update();
PushCoreFrame();
App.settings.Filter.ExecuteFilterRender(Core.OutputPixel, Core.DrawCanvas);
App.settings.ScreenScaler.CalcScale(Core.DrawCanvas, Core.Platform);
}
void PushCoreFrame()
{
if (Core.IsNull()) return;
//fluash netMsg
NetMsg.Instance.DequeueNesMsg();
if (!Core.PushEmulatorFrame()) return;
if (IsNetPlay) //skip frame handle
{
var skipFrameCount = App.roomMgr.netReplay.GetSkipFrameCount();
if (skipFrameCount > 0) App.log.Debug($"SKIP FRAME : {skipFrameCount} ,CF:{App.roomMgr.netReplay.mCurrClientFrameIdx},RFIdx:{App.roomMgr.netReplay.mRemoteFrameIdx},RForward:{App.roomMgr.netReplay.mRemoteForwardCount} ,queue:{App.roomMgr.netReplay.mNetReplayQueue.Count}");
for (var i = 0; i < skipFrameCount; i++)
if (!Core.PushEmulatorFrame())
break;
}
Core.AfterPushFrame();
}
protected override void OnDestroy() protected override void OnDestroy()
{ {
Instance = null; Instance = null;