videoProvider增加了cpu计算输出图像的开关

This commit is contained in:
ALIENJACK\alien 2024-12-04 14:25:09 +08:00
parent 075d6c1427
commit 4b855c5695
3 changed files with 409 additions and 1479 deletions

View File

@ -4,44 +4,119 @@ using System.Runtime.InteropServices;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using VirtualNes.Core;
using static UnityEngine.UI.CanvasScaler;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class VideoProvider : MonoBehaviour public class VideoProvider : MonoBehaviour
{ {
#region UI_REF
public NesEmulator NesEmu; public NesEmulator NesEmu;
public Canvas DrawCanvas; public Canvas DrawCanvas;
public RawImage Image; public RawImage Image;
#endregion
private IntPtr wrapTexBufferPointer;
private Texture2D wrapTex;
private int TexBufferSize;
private Texture2D pPal; #region GPU_TURBO
//图像数据字节数
private int TexBufferSize_gpu;
//图像数据指针
private IntPtr wrapTexBufferPointer_gpu;
//Unity 2D纹理对象,用于UI上绘制最终输出画面
private Texture2D wrapTex_gpu;
//nes调色板数据,已转换为unity纹理对象
private Texture2D pPal_gpu;
private Material GPUTurboMat_gpu;
#endregion
#region CPU
//图像数据字节数
private int TexBufferSize_cpu;
//图像数据指针
private GCHandle wrapTexBufferGH;
private IntPtr wrapTexBufferPointer_cpu;
//Unity 2D纹理对象,用于UI上绘制最终输出画面
private Texture2D wrapTex_cpu;
#endregion
public bool GPUTurbo = true;
private void Awake() private void Awake()
{ {
DrawCanvas.worldCamera = Camera.main; DrawCanvas.worldCamera = Camera.main;
GPUTurboMat_gpu = Image.material;
}
private void OnDestroy()
{
if (wrapTexBufferGH.IsAllocated)
wrapTexBufferGH.Free();
} }
public unsafe void SetDrawData(uint* screenData) public unsafe void SetDrawData(uint* screenData)
{ {
if (wrapTex == null) PrepareUI(screenData);
if (GPUTurbo) PrepareForGPU(screenData);
else PrepareForCPU(screenData);
if (GPUTurbo)
{ {
wrapTex = new Texture2D(272, 240, TextureFormat.RGBA32, false); wrapTex_gpu.LoadRawTextureData(wrapTexBufferPointer_gpu, TexBufferSize_gpu);
wrapTex.filterMode = FilterMode.Point; wrapTex_gpu.Apply();
}
else
{
wrapTex_cpu.LoadRawTextureData(wrapTexBufferPointer_cpu, TexBufferSize_cpu);
wrapTex_cpu.Apply();
}
}
wrapTexBufferPointer = (IntPtr)screenData; private unsafe void PrepareUI(uint* screenData)
{
if (GPUTurbo)
{
if (Image.material != GPUTurboMat_gpu) Image.material = GPUTurboMat_gpu;
Image.texture = wrapTex; if (wrapTex_gpu == null)
Image.material.SetTexture("_MainTex", wrapTex); {
wrapTex_gpu = new Texture2D(PPU.SCREEN_WIDTH, PPU.SCREEN_HEIGHT, TextureFormat.RGBA32, false);
wrapTex_gpu.filterMode = FilterMode.Point;
wrapTexBufferPointer_gpu = (IntPtr)screenData;
TexBufferSize = wrapTex.width * wrapTex.height * 4; TexBufferSize_gpu = wrapTex_gpu.width * wrapTex_gpu.height * 4;
}
if (Image.texture != wrapTex_gpu) Image.texture = wrapTex_gpu;
}
else
{
if (Image.material == GPUTurboMat_gpu) Image.material = null;
if (wrapTex_cpu == null)
{
wrapTex_cpu = new Texture2D(PPU.SCREEN_WIDTH - 16, PPU.SCREEN_HEIGHT, TextureFormat.RGBA32, false);
wrapTex_cpu.filterMode = FilterMode.Point;
uint[] cpuTexBuffer = new uint[wrapTex_cpu.width * wrapTex_cpu.height];
wrapTexBufferGH = GCHandle.Alloc(cpuTexBuffer, GCHandleType.Pinned);
wrapTexBufferPointer_cpu = wrapTexBufferGH.AddrOfPinnedObject();
TexBufferSize_cpu = cpuTexBuffer.Length * 4;
}
if (Image.texture != wrapTex_cpu) Image.texture = wrapTex_cpu;
}
}
private unsafe void PrepareForGPU(uint* screenData)
{
if (pPal_gpu == null)
{
var palRaw = PaletteDefine.m_cnPalette[0]; var palRaw = PaletteDefine.m_cnPalette[0];
pPal = new Texture2D(palRaw.Length, 1, TextureFormat.RGBA32, false);
pPal.filterMode = FilterMode.Point; pPal_gpu = new Texture2D(palRaw.Length, 1, TextureFormat.RGBA32, false);
pPal_gpu.filterMode = FilterMode.Point;
for (int i = 0; i < palRaw.Length; i++) for (int i = 0; i < palRaw.Length; i++)
{ {
uint colorRaw = palRaw[i]; uint colorRaw = palRaw[i];
@ -51,14 +126,48 @@ namespace AxibugEmuOnline.Client
temp.g = argbColor[1] / 255f; temp.g = argbColor[1] / 255f;
temp.b = argbColor[0] / 255f; temp.b = argbColor[0] / 255f;
temp.a = 1; temp.a = 1;
pPal.SetPixel(i, 0, temp); pPal_gpu.SetPixel(i, 0, temp);
} }
pPal.Apply(); pPal_gpu.Apply();
Image.material.SetTexture("_PalTex", pPal); GPUTurboMat_gpu.SetTexture("_PalTex", pPal_gpu);
} }
}
wrapTex.LoadRawTextureData(wrapTexBufferPointer, TexBufferSize); private unsafe void PrepareForCPU(uint* screenData)
wrapTex.Apply(); {
int pScn = 0;
int width;
var Dst = (uint*)wrapTexBufferPointer_cpu;
var pDst = 0;
var palRaw = PaletteDefine.m_cnPalette[0];
for (int line = 0; line < PPU.SCREEN_HEIGHT; line++)
{
width = PPU.SCREEN_WIDTH - 16;
while (width > 0)
{
var edx = screenData[pScn + 8];
uint index = edx & 0xFF;
var colorData = palRaw[index];
//dst中颜色排列为abgr,而colorData排列为argb
uint r = (colorData & 0x00FF0000) >> 16; // 提取Red通道
uint g = (colorData & 0x0000FF00) >> 8; // 提取Green通道
uint b = (colorData & 0x000000FF); // 提取Blue通道
uint abgr = 0xFF000000 | (b << 16) | (g << 8) | (r << 0);
Dst[pDst] = abgr;
pScn += 1;
pDst += 1;
width -= 1;
}
pScn += 16;
}
} }
} }
} }

View File

@ -38,7 +38,7 @@ namespace AxibugEmuOnline.Client
m_stepPerformer = new StepPerformer(this); m_stepPerformer = new StepPerformer(this);
menus.Add(new InGameUI_FilterSetting(this)); //menus.Add(new InGameUI_FilterSetting(this));
menus.Add(new InGameUI_Reset(this)); menus.Add(new InGameUI_Reset(this));
menus.Add(new InGameUI_SaveState(this)); menus.Add(new InGameUI_SaveState(this));
menus.Add(new InGameUI_LoadState(this)); menus.Add(new InGameUI_LoadState(this));