ppu lpScreen改为指针版本

This commit is contained in:
ALIENJACK\alien 2024-11-14 11:17:17 +08:00
parent 3913595b18
commit 43e7ba8332
4 changed files with 259 additions and 275 deletions

View File

@ -51,7 +51,7 @@ namespace AxibugEmuOnline.Client
NesCore = null; NesCore = null;
} }
private void Update() private unsafe void Update()
{ {
if (m_bPause) return; if (m_bPause) return;
@ -63,7 +63,7 @@ namespace AxibugEmuOnline.Client
var screenBuffer = NesCore.ppu.GetScreenPtr(); var screenBuffer = NesCore.ppu.GetScreenPtr();
var lineColorMode = NesCore.ppu.GetLineColorMode(); var lineColorMode = NesCore.ppu.GetLineColorMode();
VideoProvider.SetDrawData(screenBuffer, lineColorMode, 256, 240); VideoProvider.SetDrawData(screenBuffer, lineColorMode, 277, 240);
} }
} }

View File

@ -24,15 +24,15 @@ namespace AxibugEmuOnline.Client
DrawCanvas.worldCamera = Camera.main; DrawCanvas.worldCamera = Camera.main;
} }
public void SetDrawData(uint[] screenData, byte[] lineColorMode, int screenWidth, int screenHeight) public unsafe void SetDrawData(byte* screenData, byte[] lineColorMode, int screenWidth, int screenHeight)
{ {
if (wrapTex == null) if (wrapTex == null)
{ {
//wrapTex = new Texture2D(272, 240, TextureFormat.BGRA32, false); //wrapTex = new Texture2D(272, 240, TextureFormat.BGRA32, false);
wrapTex = new Texture2D(272, 240, TextureFormat.RGBA32, false); wrapTex = new Texture2D(272, 240, TextureFormat.RGBA32, false);
wrapTex.filterMode = FilterMode.Point; wrapTex.filterMode = FilterMode.Point;
wrapTexBuffer = screenData;
wrapTexBuffer = new uint[screenWidth * screenHeight];
// 固定数组,防止垃圾回收器移动它 // 固定数组,防止垃圾回收器移动它
GCHandle handle = GCHandle.Alloc(wrapTexBuffer, GCHandleType.Pinned); GCHandle handle = GCHandle.Alloc(wrapTexBuffer, GCHandleType.Pinned);
// 获取数组的指针 // 获取数组的指针
@ -44,7 +44,6 @@ namespace AxibugEmuOnline.Client
TexBufferSize = wrapTexBuffer.Length * 4; TexBufferSize = wrapTexBuffer.Length * 4;
var palRaw = PaletteDefine.m_cnPalette[0]; var palRaw = PaletteDefine.m_cnPalette[0];
//pPal = new Texture2D(palRaw.Length, 1, TextureFormat.BGRA32, 1, true);
pPal = new Texture2D(palRaw.Length, 1, TextureFormat.RGBA32, false); pPal = new Texture2D(palRaw.Length, 1, TextureFormat.RGBA32, false);
pPal.filterMode = FilterMode.Point; pPal.filterMode = FilterMode.Point;
for (int i = 0; i < palRaw.Length; i++) for (int i = 0; i < palRaw.Length; i++)
@ -62,6 +61,11 @@ namespace AxibugEmuOnline.Client
Image.material.SetTexture("_PalTex", pPal); Image.material.SetTexture("_PalTex", pPal);
} }
for (int i = 0; i < wrapTexBuffer.Length; i++)
{
wrapTexBuffer[i] = screenData[i];
}
wrapTex.LoadRawTextureData(wrapTexBufferPointer, TexBufferSize); wrapTex.LoadRawTextureData(wrapTexBufferPointer, TexBufferSize);
wrapTex.Apply(); wrapTex.Apply();
} }

View File

@ -221,7 +221,7 @@ namespace VirtualNes.Core
Debuger.Log("Allocating PPU..."); Debuger.Log("Allocating PPU...");
ppu = new PPU(this); ppu = new PPU(this);
var screenBuffer = new uint[PPU.SCREEN_WIDTH * PPU.SCREEN_HEIGHT]; var screenBuffer = new byte[PPU.SCREEN_WIDTH * PPU.SCREEN_HEIGHT];
var colormode = new byte[PPU.SCREEN_HEIGHT]; var colormode = new byte[PPU.SCREEN_HEIGHT];
ppu.SetScreenPtr(screenBuffer, colormode); ppu.SetScreenPtr(screenBuffer, colormode);
@ -840,7 +840,7 @@ namespace VirtualNes.Core
} }
} }
internal void DrawFont(int x, int y, byte chr, byte col) internal unsafe void DrawFont(int x, int y, byte chr, byte col)
{ {
int i; int i;
int pFnt; int pFnt;
@ -866,7 +866,7 @@ namespace VirtualNes.Core
} }
} }
private void DrawBitmap(int x, int y, byte[] bitMap) private unsafe void DrawBitmap(int x, int y, byte[] bitMap)
{ {
int i, j; int i, j;
int h, v; int h, v;

View File

@ -1,10 +1,24 @@
namespace VirtualNes.Core using Codice.CM.Client.Differences;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using UnityEngine.UIElements;
namespace VirtualNes.Core
{ {
public class PPU public unsafe class PPU
{ {
public const int SCREEN_WIDTH = 256 + 16; public const int SCREEN_WIDTH = 272;
public const int SCREEN_HEIGHT = 240; public const int SCREEN_HEIGHT = 240;
private GCHandle BGwriteGCH;
private GCHandle BGmonoGCH;
private GCHandle SPwriteGCH;
private byte* BGwrite;
private byte* BGmono;
private byte* SPwrite;
private static byte[][] CreateCOLORMAP() private static byte[][] CreateCOLORMAP()
{ {
byte[][] res = new byte[5][]; byte[][] res = new byte[5][];
@ -104,9 +118,10 @@
private ushort loopy_y; private ushort loopy_y;
private ushort loopy_shift; private ushort loopy_shift;
private uint[] lpScreen; private GCHandle lpScreenGCH;
private byte* lpScreen;
/// <summary> 作为lpScreen数组的索引 </summary> /// <summary> 作为lpScreen数组的索引 </summary>
private int lpScanline; private byte* lpScanline;
private int ScanlineNo; private int ScanlineNo;
private byte[] lpColormode; private byte[] lpColormode;
@ -137,9 +152,22 @@
} }
Bit2Rev[i] = c; Bit2Rev[i] = c;
} }
BGwriteGCH = GCHandle.Alloc(new byte[33 + 1], GCHandleType.Pinned);
BGmonoGCH = GCHandle.Alloc(new byte[33 + 1], GCHandleType.Pinned);
SPwriteGCH = GCHandle.Alloc(new byte[33 + 1], GCHandleType.Pinned);
BGwrite = (byte*)BGwriteGCH.AddrOfPinnedObject();
BGmono = (byte*)BGmonoGCH.AddrOfPinnedObject();
SPwrite = (byte*)SPwriteGCH.AddrOfPinnedObject();
} }
public void Dispose() { } public void Dispose()
{
lpScreenGCH.Free();
BGwriteGCH.Free();
BGmonoGCH.Free();
SPwriteGCH.Free();
}
internal byte Read(ushort addr) internal byte Read(ushort addr)
{ {
@ -199,7 +227,7 @@
ScanlineNo = scanline; ScanlineNo = scanline;
if (scanline < 240) if (scanline < 240)
{ {
lpScanline = (SCREEN_WIDTH) * scanline; lpScanline = lpScreen + SCREEN_WIDTH * scanline;
} }
} }
@ -358,7 +386,7 @@
loopy_shift = 0; loopy_shift = 0;
if (lpScreen != null) if (lpScreen != null)
MemoryUtility.memset(lpScreen, 0, 0x3F, SCREEN_WIDTH * SCREEN_HEIGHT); Unsafe.InitBlockUnaligned(lpScreen, 0, SCREEN_WIDTH * SCREEN_HEIGHT);
if (lpColormode != null) if (lpColormode != null)
MemoryUtility.memset(lpColormode, 0, SCREEN_HEIGHT); MemoryUtility.memset(lpColormode, 0, SCREEN_HEIGHT);
} }
@ -374,7 +402,7 @@
if (lpScreen != null) if (lpScreen != null)
{ {
MemoryUtility.memset(lpScreen, 0, 0x3F, SCREEN_WIDTH); Unsafe.InitBlockUnaligned(lpScreen, 0x3F, SCREEN_WIDTH);
} }
if (lpColormode != null) if (lpColormode != null)
{ {
@ -425,18 +453,12 @@
} }
} }
private byte[] BGwrite = new byte[33 + 1];
private byte[] BGmono = new byte[33 + 1];
private byte[] SPwrite = new byte[33 + 1];
internal void Scanline(int scanline, bool bMax, bool bLeftClip) internal void Scanline(int scanline, bool bMax, bool bLeftClip)
{ {
int pScn = 0;
int pBGw = 0;
byte chr_h = 0, chr_l = 0, attr = 0; byte chr_h = 0, chr_l = 0, attr = 0;
MemoryUtility.ZEROMEMORY(BGwrite, BGwrite.Length); Unsafe.InitBlockUnaligned(BGwrite, 0, 34);
MemoryUtility.ZEROMEMORY(BGmono, BGmono.Length); Unsafe.InitBlockUnaligned(BGmono, 0, 34);
// Linecolor mode // Linecolor mode
lpColormode[scanline] = (byte)(((MMU.PPUREG[1] & PPU_BGCOLOR_BIT) >> 5) | ((MMU.PPUREG[1] & PPU_COLORMODE_BIT) << 7)); lpColormode[scanline] = (byte)(((MMU.PPUREG[1] & PPU_BGCOLOR_BIT) >> 5) | ((MMU.PPUREG[1] & PPU_COLORMODE_BIT) << 7));
@ -444,7 +466,7 @@
// Render BG // Render BG
if ((MMU.PPUREG[1] & PPU_BGDISP_BIT) == 0) if ((MMU.PPUREG[1] & PPU_BGDISP_BIT) == 0)
{ {
MemoryUtility.memset(lpScreen, lpScanline, MMU.BGPAL[0], SCREEN_WIDTH); Unsafe.InitBlockUnaligned(lpScanline, MMU.BGPAL[0], SCREEN_WIDTH);
if (nes.GetRenderMethod() == EnumRenderMethod.TILE_RENDER) if (nes.GetRenderMethod() == EnumRenderMethod.TILE_RENDER)
{ {
nes.EmulationCPU(NES.FETCH_CYCLES * 4 * 32); nes.EmulationCPU(NES.FETCH_CYCLES * 4 * 32);
@ -457,9 +479,8 @@
if (!bExtLatch) if (!bExtLatch)
{ {
// Without Extension Latch // Without Extension Latch
pScn = lpScanline + (8 - loopy_shift); byte* pScn = lpScanline + (8 - loopy_shift);
pBGw = 0; byte* pBGw = BGwrite;
int tileofs = (MMU.PPUREG[0] & PPU_BGTBL_BIT) << 8; int tileofs = (MMU.PPUREG[0] & PPU_BGTBL_BIT) << 8;
int ntbladr = 0x2000 + (MMU.loopy_v & 0x0FFF); int ntbladr = 0x2000 + (MMU.loopy_v & 0x0FFF);
int attradr = 0x23C0 + (MMU.loopy_v & 0x0C00) + ((MMU.loopy_v & 0x0380) >> 4); int attradr = 0x23C0 + (MMU.loopy_v & 0x0C00) + ((MMU.loopy_v & 0x0380) >> 4);
@ -475,7 +496,6 @@
attradr &= 0x3FF; attradr &= 0x3FF;
for (int i = 0; i < 33; i++) for (int i = 0; i < 33; i++)
{ {
tileadr = tileofs + pNTBL[ntbladr & 0x03FF] * 0x10 + loopy_y; tileadr = tileofs + pNTBL[ntbladr & 0x03FF] * 0x10 + loopy_y;
@ -483,17 +503,9 @@
if (cache_tile == tileadr && cache_attr == attr) if (cache_tile == tileadr && cache_attr == attr)
{ {
lpScreen[pScn + 0] = lpScreen[pScn - 8]; *(uint*)(pScn + 0) = *(uint*)(pScn - 8);
lpScreen[pScn + 0 + 1] = lpScreen[pScn - 8 + 1]; *(uint*)(pScn + 4) = *(uint*)(pScn - 4);
lpScreen[pScn + 0 + 2] = lpScreen[pScn - 8 + 2]; *(pBGw + 0) = *(pBGw - 1);
lpScreen[pScn + 0 + 3] = lpScreen[pScn - 8 + 3];
lpScreen[pScn + 4] = lpScreen[pScn - 4];
lpScreen[pScn + 4 + 1] = lpScreen[pScn - 4 + 1];
lpScreen[pScn + 4 + 2] = lpScreen[pScn - 4 + 2];
lpScreen[pScn + 4 + 3] = lpScreen[pScn - 4 + 3];
BGwrite[pBGw + 0] = BGwrite[pBGw - 1];
} }
else else
{ {
@ -501,20 +513,20 @@
cache_attr = attr; cache_attr = attr;
chr_l = MMU.PPU_MEM_BANK[tileadr >> 10][tileadr & 0x03FF]; chr_l = MMU.PPU_MEM_BANK[tileadr >> 10][tileadr & 0x03FF];
chr_h = MMU.PPU_MEM_BANK[tileadr >> 10][(tileadr & 0x03FF) + 8]; chr_h = MMU.PPU_MEM_BANK[tileadr >> 10][(tileadr & 0x03FF) + 8];
BGwrite[pBGw] = (byte)(chr_h | chr_l); *pBGw = (byte)(chr_h | chr_l);
int pBGPAL = attr; fixed (byte* pBGPAL = &MMU.BGPAL[attr])
{ {
int c1 = ((chr_l >> 1) & 0x55) | (chr_h & 0xAA); int c1 = ((chr_l >> 1) & 0x55) | (chr_h & 0xAA);
int c2 = (chr_l & 0x55) | ((chr_h << 1) & 0xAA); int c2 = (chr_l & 0x55) | ((chr_h << 1) & 0xAA);
lpScreen[pScn + 0] = MMU.BGPAL[pBGPAL + (c1 >> 6)]; pScn[0] = pBGPAL[(c1 >> 6)];
lpScreen[pScn + 4] = MMU.BGPAL[pBGPAL + ((c1 >> 2) & 3)]; pScn[4] = pBGPAL[(c1 >> 2) & 3];
lpScreen[pScn + 1] = MMU.BGPAL[pBGPAL + ((c1 >> 6))]; pScn[1] = pBGPAL[(c2 >> 6)];
lpScreen[pScn + 5] = MMU.BGPAL[pBGPAL + ((c2 >> 2) & 3)]; pScn[5] = pBGPAL[(c2 >> 2) & 3];
lpScreen[pScn + 2] = MMU.BGPAL[pBGPAL + ((c1 >> 4) & 3)]; pScn[2] = pBGPAL[(c1 >> 4) & 3];
lpScreen[pScn + 6] = MMU.BGPAL[pBGPAL + (c1 & 3)]; pScn[6] = pBGPAL[c1 & 3];
lpScreen[pScn + 3] = MMU.BGPAL[pBGPAL + ((c2 >> 4) & 3)]; pScn[3] = pBGPAL[(c2 >> 4) & 3];
lpScreen[pScn + 7] = MMU.BGPAL[pBGPAL + (c2 & 3)]; pScn[7] = pBGPAL[c2 & 3];
} }
} }
pScn += 8; pScn += 8;
@ -542,8 +554,8 @@
else else
{ {
// With Extension Latch(For MMC5) // With Extension Latch(For MMC5)
pScn = lpScanline + (8 - loopy_shift); byte* pScn = lpScanline + (8 - loopy_shift);
pBGw = 0; byte* pBGw = BGwrite;
int ntbladr = 0x2000 + (MMU.loopy_v & 0x0FFF); int ntbladr = 0x2000 + (MMU.loopy_v & 0x0FFF);
int ntbl_x = ntbladr & 0x1F; int ntbl_x = ntbladr & 0x1F;
@ -564,35 +576,27 @@
{ {
cache_tile = ((chr_h << 8) + chr_l); cache_tile = ((chr_h << 8) + chr_l);
cache_attr = attr; cache_attr = attr;
BGwrite[pBGw] = (byte)(chr_h | chr_l); *pBGw = (byte)(chr_h | chr_l);
int pBGPAL = attr; fixed (byte* pBGPAL = &MMU.BGPAL[attr])
{ {
int c1 = ((chr_l >> 1) & 0x55) | (chr_h & 0xAA); int c1 = ((chr_l >> 1) & 0x55) | (chr_h & 0xAA);
int c2 = (chr_l & 0x55) | ((chr_h << 1) & 0xAA); int c2 = (chr_l & 0x55) | ((chr_h << 1) & 0xAA);
lpScreen[pScn + 0] = MMU.BGPAL[pBGPAL + (c1 >> 6)]; pScn[0] = pBGPAL[(c1 >> 6)];
lpScreen[pScn + 4] = MMU.BGPAL[pBGPAL + ((c1 >> 2) & 3)]; pScn[4] = pBGPAL[(c1 >> 2) & 3];
lpScreen[pScn + 1] = MMU.BGPAL[pBGPAL + (c2 >> 6)]; pScn[1] = pBGPAL[(c2 >> 6)];
lpScreen[pScn + 5] = MMU.BGPAL[pBGPAL + ((c2 >> 2) & 3)]; pScn[5] = pBGPAL[(c2 >> 2) & 3];
lpScreen[pScn + 2] = MMU.BGPAL[pBGPAL + ((c1 >> 4) & 3)]; pScn[2] = pBGPAL[(c1 >> 4) & 3];
lpScreen[pScn + 6] = MMU.BGPAL[pBGPAL + (c1 & 3)]; pScn[6] = pBGPAL[c1 & 3];
lpScreen[pScn + 3] = MMU.BGPAL[pBGPAL + ((c2 >> 4) & 3)]; pScn[3] = pBGPAL[(c2 >> 4) & 3];
lpScreen[pScn + 7] = MMU.BGPAL[pBGPAL + (c2 & 3)]; pScn[7] = pBGPAL[c2 & 3];
} }
} }
else else
{ {
lpScreen[pScn + 0] = lpScreen[pScn - 8]; *(uint*)(pScn + 0) = *(uint*)(pScn - 8);
lpScreen[pScn + 0 + 1] = lpScreen[pScn - 8 + 1]; *(uint*)(pScn + 4) = *(uint*)(pScn - 4);
lpScreen[pScn + 0 + 2] = lpScreen[pScn - 8 + 2]; *(pBGw + 0) = *(pBGw - 1);
lpScreen[pScn + 0 + 3] = lpScreen[pScn - 8 + 3];
lpScreen[pScn + 4] = lpScreen[pScn - 4];
lpScreen[pScn + 4 + 1] = lpScreen[pScn - 4 + 1];
lpScreen[pScn + 4 + 2] = lpScreen[pScn - 4 + 2];
lpScreen[pScn + 4 + 3] = lpScreen[pScn - 4 + 3];
BGwrite[pBGw + 0] = BGwrite[pBGw - 1];
} }
pScn += 8; pScn += 8;
pBGw++; pBGw++;
@ -616,8 +620,8 @@
// Without Extension Latch // Without Extension Latch
if (!bExtNameTable) if (!bExtNameTable)
{ {
pScn = lpScanline + (8 - loopy_shift); byte* pScn = lpScanline + (8 - loopy_shift);
pBGw = 0; byte* pBGw = BGwrite;
int ntbladr = 0x2000 + (MMU.loopy_v & 0x0FFF); int ntbladr = 0x2000 + (MMU.loopy_v & 0x0FFF);
int attradr = 0x03C0 + ((MMU.loopy_v & 0x0380) >> 4); int attradr = 0x03C0 + ((MMU.loopy_v & 0x0380) >> 4);
@ -649,35 +653,27 @@
chr_l = MMU.PPU_MEM_BANK[tileadr >> 10][tileadr & 0x03FF]; chr_l = MMU.PPU_MEM_BANK[tileadr >> 10][tileadr & 0x03FF];
chr_h = MMU.PPU_MEM_BANK[tileadr >> 10][(tileadr & 0x03FF) + 8]; chr_h = MMU.PPU_MEM_BANK[tileadr >> 10][(tileadr & 0x03FF) + 8];
lpScreen[pBGw] = (byte)(chr_l | chr_h); *pBGw = (byte)(chr_l | chr_h);
int pBGPAL = attr; fixed (byte* pBGPAL = &MMU.BGPAL[attr])
{ {
int c1 = ((chr_l >> 1) & 0x55) | (chr_h & 0xAA); int c1 = ((chr_l >> 1) & 0x55) | (chr_h & 0xAA);
int c2 = (chr_l & 0x55) | ((chr_h << 1) & 0xAA); int c2 = (chr_l & 0x55) | ((chr_h << 1) & 0xAA);
lpScreen[pScn + 0] = MMU.BGPAL[pBGPAL + (c1 >> 6)]; pScn[0] = pBGPAL[(c1 >> 6)];
lpScreen[pScn + 4] = MMU.BGPAL[pBGPAL + ((c1 >> 2) & 3)]; pScn[4] = pBGPAL[(c1 >> 2) & 3];
lpScreen[pScn + 1] = MMU.BGPAL[pBGPAL + ((c2 >> 6))]; pScn[1] = pBGPAL[(c2 >> 6)];
lpScreen[pScn + 5] = MMU.BGPAL[pBGPAL + ((c2 >> 2) & 3)]; pScn[5] = pBGPAL[(c2 >> 2) & 3];
lpScreen[pScn + 2] = MMU.BGPAL[pBGPAL + ((c1 >> 4) & 3)]; pScn[2] = pBGPAL[(c1 >> 4) & 3];
lpScreen[pScn + 6] = MMU.BGPAL[pBGPAL + (c1 & 3)]; pScn[6] = pBGPAL[c1 & 3];
lpScreen[pScn + 3] = MMU.BGPAL[pBGPAL + ((c2 >> 4) & 3)]; pScn[3] = pBGPAL[(c2 >> 4) & 3];
lpScreen[pScn + 7] = MMU.BGPAL[pBGPAL + (c2 & 3)]; pScn[7] = pBGPAL[c2 & 3];
} }
} }
else else
{ {
lpScreen[pScn + 0] = lpScreen[pScn - 8]; *(uint*)(pScn + 0) = *(uint*)(pScn - 8);
lpScreen[pScn + 0 + 1] = lpScreen[pScn - 8 + 1]; *(uint*)(pScn + 4) = *(uint*)(pScn - 4);
lpScreen[pScn + 0 + 2] = lpScreen[pScn - 8 + 2]; *(pBGw + 0) = *(pBGw - 1);
lpScreen[pScn + 0 + 3] = lpScreen[pScn - 8 + 3];
lpScreen[pScn + 4] = lpScreen[pScn - 4];
lpScreen[pScn + 4 + 1] = lpScreen[pScn - 4 + 1];
lpScreen[pScn + 4 + 2] = lpScreen[pScn - 4 + 2];
lpScreen[pScn + 4 + 3] = lpScreen[pScn - 4 + 3];
BGwrite[pBGw + 0] = BGwrite[pBGw - 1];
} }
pScn += 8; pScn += 8;
pBGw++; pBGw++;
@ -703,8 +699,8 @@
} }
else else
{ {
pScn = lpScanline + (8 - loopy_shift); byte* pScn = lpScanline + (8 - loopy_shift);
pBGw = 0; byte* pBGw = BGwrite;
int ntbladr; int ntbladr;
int tileadr; int tileadr;
@ -733,35 +729,27 @@
chr_l = MMU.PPU_MEM_BANK[tileadr >> 10][tileadr & 0x03FF]; chr_l = MMU.PPU_MEM_BANK[tileadr >> 10][tileadr & 0x03FF];
chr_h = MMU.PPU_MEM_BANK[tileadr >> 10][(tileadr & 0x03FF) + 8]; chr_h = MMU.PPU_MEM_BANK[tileadr >> 10][(tileadr & 0x03FF) + 8];
BGwrite[pBGw] = (byte)(chr_l | chr_h); *pBGw = (byte)(chr_l | chr_h);
int pBGPAL = attr; fixed (byte* pBGPAL = &MMU.BGPAL[attr])
{ {
int c1 = ((chr_l >> 1) & 0x55) | (chr_h & 0xAA); int c1 = ((chr_l >> 1) & 0x55) | (chr_h & 0xAA);
int c2 = (chr_l & 0x55) | ((chr_h << 1) & 0xAA); int c2 = (chr_l & 0x55) | ((chr_h << 1) & 0xAA);
lpScreen[pScn + 0] = MMU.BGPAL[pBGPAL + (c1 >> 6)]; pScn[0] = pBGPAL[(c1 >> 6)];
lpScreen[pScn + 4] = MMU.BGPAL[pBGPAL + ((c1 >> 2) & 3)]; pScn[4] = pBGPAL[(c1 >> 2) & 3];
lpScreen[pScn + 1] = MMU.BGPAL[pBGPAL + (c2 >> 6)]; pScn[1] = pBGPAL[(c2 >> 6)];
lpScreen[pScn + 5] = MMU.BGPAL[pBGPAL + ((c2 >> 2) & 3)]; pScn[5] = pBGPAL[(c2 >> 2) & 3];
lpScreen[pScn + 2] = MMU.BGPAL[pBGPAL + ((c1 >> 4) & 3)]; pScn[2] = pBGPAL[(c1 >> 4) & 3];
lpScreen[pScn + 6] = MMU.BGPAL[pBGPAL + (c1 & 3)]; pScn[6] = pBGPAL[c1 & 3];
lpScreen[pScn + 3] = MMU.BGPAL[pBGPAL + ((c2 >> 4) & 3)]; pScn[3] = pBGPAL[(c2 >> 4) & 3];
lpScreen[pScn + 7] = MMU.BGPAL[pBGPAL + (c2 & 3)]; pScn[7] = pBGPAL[c2 & 3];
} }
} }
else else
{ {
lpScreen[pScn + 0] = lpScreen[pScn - 8]; *(uint*)(pScn + 0) = *(uint*)(pScn - 8);
lpScreen[pScn + 0 + 1] = lpScreen[pScn - 8 + 1]; *(uint*)(pScn + 4) = *(uint*)(pScn - 4);
lpScreen[pScn + 0 + 2] = lpScreen[pScn - 8 + 2]; *(pBGw + 0) = *(pBGw - 1);
lpScreen[pScn + 0 + 3] = lpScreen[pScn - 8 + 3];
lpScreen[pScn + 4] = lpScreen[pScn - 4];
lpScreen[pScn + 4 + 1] = lpScreen[pScn - 4 + 1];
lpScreen[pScn + 4 + 2] = lpScreen[pScn - 4 + 2];
lpScreen[pScn + 4 + 3] = lpScreen[pScn - 4 + 3];
BGwrite[pBGw + 0] = BGwrite[pBGw - 1];
} }
pScn += 8; pScn += 8;
pBGw++; pBGw++;
@ -787,8 +775,8 @@
else else
{ {
// With Extension Latch(For MMC5) // With Extension Latch(For MMC5)
pScn = lpScanline + (8 - loopy_shift); byte* pScn = lpScanline + (8 - loopy_shift);
pBGw = 0; byte* pBGw = BGwrite;
int ntbladr = 0x2000 + (MMU.loopy_v & 0x0FFF); int ntbladr = 0x2000 + (MMU.loopy_v & 0x0FFF);
int ntbl_x = ntbladr & 0x1F; int ntbl_x = ntbladr & 0x1F;
@ -813,35 +801,27 @@
{ {
cache_tile = ((chr_h << 8) + chr_l); cache_tile = ((chr_h << 8) + chr_l);
cache_attr = attr; cache_attr = attr;
BGwrite[pBGw] = (byte)(chr_l | chr_h); *pBGw = (byte)(chr_l | chr_h);
int pBGPAL = attr; fixed (byte* pBGPAL = &MMU.BGPAL[attr])
{ {
int c1 = ((chr_l >> 1) & 0x55) | (chr_h & 0xAA); int c1 = ((chr_l >> 1) & 0x55) | (chr_h & 0xAA);
int c2 = (chr_l & 0x55) | ((chr_h << 1) & 0xAA); int c2 = (chr_l & 0x55) | ((chr_h << 1) & 0xAA);
lpScreen[pScn + 0] = MMU.BGPAL[pBGPAL + ((c1 >> 6))]; pScn[0] = pBGPAL[(c1 >> 6)];
lpScreen[pScn + 4] = MMU.BGPAL[pBGPAL + ((c1 >> 2) & 3)]; pScn[4] = pBGPAL[(c1 >> 2) & 3];
lpScreen[pScn + 1] = MMU.BGPAL[pBGPAL + ((c2 >> 6))]; pScn[1] = pBGPAL[(c2 >> 6)];
lpScreen[pScn + 5] = MMU.BGPAL[pBGPAL + ((c2 >> 2) & 3)]; pScn[5] = pBGPAL[(c2 >> 2) & 3];
lpScreen[pScn + 2] = MMU.BGPAL[pBGPAL + ((c1 >> 4) & 3)]; pScn[2] = pBGPAL[(c1 >> 4) & 3];
lpScreen[pScn + 6] = MMU.BGPAL[pBGPAL + (c1 & 3)]; pScn[6] = pBGPAL[c1 & 3];
lpScreen[pScn + 3] = MMU.BGPAL[pBGPAL + ((c2 >> 4) & 3)]; pScn[3] = pBGPAL[(c2 >> 4) & 3];
lpScreen[pScn + 7] = MMU.BGPAL[pBGPAL + (c2 & 3)]; pScn[7] = pBGPAL[c2 & 3];
} }
} }
else else
{ {
lpScreen[pScn + 0] = lpScreen[pScn - 8]; *(uint*)(pScn + 0) = *(uint*)(pScn - 8);
lpScreen[pScn + 0 + 1] = lpScreen[pScn - 8 + 1]; *(uint*)(pScn + 4) = *(uint*)(pScn - 4);
lpScreen[pScn + 0 + 2] = lpScreen[pScn - 8 + 2]; *(pBGw + 0) = *(pBGw - 1);
lpScreen[pScn + 0 + 3] = lpScreen[pScn - 8 + 3];
lpScreen[pScn + 4] = lpScreen[pScn - 4];
lpScreen[pScn + 4 + 1] = lpScreen[pScn - 4 + 1];
lpScreen[pScn + 4 + 2] = lpScreen[pScn - 4 + 2];
lpScreen[pScn + 4 + 3] = lpScreen[pScn - 4 + 3];
BGwrite[pBGw + 0] = BGwrite[pBGw - 1];
} }
pScn += 8; pScn += 8;
pBGw++; pBGw++;
@ -860,17 +840,17 @@
} }
if ((MMU.PPUREG[1] & PPU_BGCLIP_BIT) == 0 && bLeftClip) if ((MMU.PPUREG[1] & PPU_BGCLIP_BIT) == 0 && bLeftClip)
{ {
pScn = lpScanline + 8; byte* pScn = lpScanline + 8;
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
lpScreen[i] = MMU.BGPAL[0]; pScn[i] = MMU.BGPAL[0];
} }
} }
} }
// Render sprites // Render sprites
var temp = ~PPU_SPMAX_FLAG; var temp = ~PPU_SPMAX_FLAG;
MMU.PPUREG[2] = (byte)(MMU.PPUREG[2] & temp); MMU.PPUREG[2] &= (byte)(MMU.PPUREG[2] & temp);
// 昞帵婜娫奜偱偁傟偽僉儍儞僙儖 // 昞帵婜娫奜偱偁傟偽僉儍儞僙儖
if (scanline > 239) if (scanline > 239)
@ -885,12 +865,11 @@
int spraddr = 0, sp_y = 0, sp_h = 0; int spraddr = 0, sp_y = 0, sp_h = 0;
chr_h = chr_l = 0; chr_h = chr_l = 0;
fixed (byte* pBit2Rev = &Bit2Rev[0])
pBGw = 0; {
int pSPw = 0; byte* pBGw = BGwrite;
int pBit2Rev = 0; byte* pSPw = SPwrite;
Unsafe.InitBlockUnaligned(pSPw, 0, 34);
MemoryUtility.ZEROMEMORY(SPwrite, SPwrite.Length);
spmax = 0; spmax = 0;
Sprite sp = new Sprite(MMU.SPRAM, 0); Sprite sp = new Sprite(MMU.SPRAM, 0);
@ -940,8 +919,8 @@
// pattern mask // pattern mask
if ((sp.attr & SP_HMIRROR_BIT) != 0) if ((sp.attr & SP_HMIRROR_BIT) != 0)
{ {
chr_l = Bit2Rev[pBit2Rev + chr_l]; chr_l = pBit2Rev[chr_l];
chr_h = Bit2Rev[pBit2Rev + chr_h]; chr_h = pBit2Rev[chr_h];
} }
byte SPpat = (byte)(chr_l | chr_h); byte SPpat = (byte)(chr_l | chr_h);
@ -950,10 +929,7 @@
{ {
int BGpos = ((sp.x & 0xF8) + ((loopy_shift + (sp.x & 7)) & 8)) >> 3; int BGpos = ((sp.x & 0xF8) + ((loopy_shift + (sp.x & 7)) & 8)) >> 3;
int BGsft = 8 - ((loopy_shift + sp.x) & 7); int BGsft = 8 - ((loopy_shift + sp.x) & 7);
byte BGmsk = (byte)(((pBGw[BGpos + 0] << 8) | pBGw[BGpos + 1]) >> BGsft);
var temp1 = BGwrite[pBGw + BGpos + 0] << 8;
var temp2 = BGwrite[pBGw + BGpos + 1];
byte BGmsk = (byte)((temp1 | temp2) >> BGsft);
if ((SPpat & BGmsk) != 0) if ((SPpat & BGmsk) != 0)
{ {
@ -964,10 +940,10 @@
// Sprite mask // Sprite mask
int SPpos = sp.x / 8; int SPpos = sp.x / 8;
int SPsft = 8 - (sp.x & 7); int SPsft = 8 - (sp.x & 7);
byte SPmsk = (byte)((SPwrite[pSPw + SPpos + 0] << 8 | SPwrite[pSPw + SPpos + 1]) >> SPsft); byte SPmsk = (byte)(((pSPw[SPpos + 0] << 8) | pSPw[SPpos + 1]) >> SPsft);
ushort SPwrt = (ushort)(SPpat << SPsft); ushort SPwrt = (ushort)(SPpat << SPsft);
SPwrite[pSPw + SPpos + 0] = (byte)(SPwrite[pSPw + SPpos + 0] | SPwrt >> 8); pSPw[SPpos + 0] = (byte)((pSPw[SPpos + 0]) | (SPwrt >> 8));
SPwrite[pSPw + SPpos + 1] = (byte)(SPwrite[pSPw + SPpos + 1] | SPwrt & 0xFF); pSPw[SPpos + 1] = (byte)((pSPw[SPpos + 1]) | (SPwrt & 0xFF));
SPpat = (byte)(SPpat & ~SPmsk); SPpat = (byte)(SPpat & ~SPmsk);
if ((sp.attr & SP_PRIORITY_BIT) != 0) if ((sp.attr & SP_PRIORITY_BIT) != 0)
@ -975,28 +951,29 @@
// BG > SP priority // BG > SP priority
int BGpos = ((sp.x & 0xF8) + ((loopy_shift + (sp.x & 7)) & 8)) >> 3; int BGpos = ((sp.x & 0xF8) + ((loopy_shift + (sp.x & 7)) & 8)) >> 3;
int BGsft = 8 - ((loopy_shift + sp.x) & 7); int BGsft = 8 - ((loopy_shift + sp.x) & 7);
byte BGmsk = (byte)(((BGwrite[pBGw + BGpos + 0] << 8) | BGwrite[pBGw + BGpos + 1]) >> BGsft); byte BGmsk = (byte)(((pBGw[BGpos + 0] << 8) | pBGw[BGpos + 1]) >> BGsft);
SPpat = (byte)(SPpat & ~BGmsk); SPpat = (byte)(SPpat & ~BGmsk);
} }
// Attribute // Attribute
int pSPPAL = (sp.attr & SP_COLOR_BIT) << 2; fixed (byte* pSPPAL = &MMU.SPPAL[(sp.attr & SP_COLOR_BIT) << 2])
{
// Ptr // Ptr
pScn = lpScanline + sp.x + 8; byte* pScn = lpScanline + sp.x + 8;
if (!bExtMono) if (!bExtMono)
{ {
int c1 = ((chr_l >> 1) & 0x55) | (chr_h & 0xAA); int c1 = ((chr_l >> 1) & 0x55) | (chr_h & 0xAA);
int c2 = (chr_l & 0x55) | ((chr_h << 1) & 0xAA); int c2 = (chr_l & 0x55) | ((chr_h << 1) & 0xAA);
if ((SPpat & 0x80) != 0) lpScreen[pScn + 0] = MMU.SPPAL[pSPPAL + (c1 >> 6)]; if ((SPpat & 0x80) != 0) pScn[0] = pSPPAL[(c1 >> 6)];
if ((SPpat & 0x08) != 0) lpScreen[pScn + 4] = MMU.SPPAL[pSPPAL + ((c1 >> 2) & 3)]; if ((SPpat & 0x08) != 0) pScn[4] = pSPPAL[(c1 >> 2) & 3];
if ((SPpat & 0x40) != 0) lpScreen[pScn + 1] = MMU.SPPAL[pSPPAL + ((c2 >> 6))]; if ((SPpat & 0x40) != 0) pScn[1] = pSPPAL[(c2 >> 6)];
if ((SPpat & 0x04) != 0) lpScreen[pScn + 5] = MMU.SPPAL[pSPPAL + ((c2 >> 2) & 3)]; if ((SPpat & 0x04) != 0) pScn[5] = pSPPAL[(c2 >> 2) & 3];
if ((SPpat & 0x20) != 0) lpScreen[pScn + 2] = MMU.SPPAL[pSPPAL + ((c1 >> 4) & 3)]; if ((SPpat & 0x20) != 0) pScn[2] = pSPPAL[(c1 >> 4) & 3];
if ((SPpat & 0x02) != 0) lpScreen[pScn + 6] = MMU.SPPAL[pSPPAL + (c1 & 3)]; if ((SPpat & 0x02) != 0) pScn[6] = pSPPAL[c1 & 3];
if ((SPpat & 0x10) != 0) lpScreen[pScn + 3] = MMU.SPPAL[pSPPAL + ((c2 >> 4) & 3)]; if ((SPpat & 0x10) != 0) pScn[3] = pSPPAL[(c2 >> 4) & 3];
if ((SPpat & 0x01) != 0) lpScreen[pScn + 7] = MMU.SPPAL[pSPPAL + (c2 & 3)]; if ((SPpat & 0x01) != 0) pScn[7] = pSPPAL[c2 & 3];
} }
else else
{ {
@ -1005,14 +982,15 @@
int c1 = ((chr_l >> 1) & 0x55) | (chr_h & 0xAA); int c1 = ((chr_l >> 1) & 0x55) | (chr_h & 0xAA);
int c2 = (chr_l & 0x55) | ((chr_h << 1) & 0xAA); int c2 = (chr_l & 0x55) | ((chr_h << 1) & 0xAA);
if ((SPpat & 0x80) != 0) lpScreen[pScn + 0] = (byte)(MMU.SPPAL[pSPPAL + (c1 >> 6)] | mono); if ((SPpat & 0x80) != 0) pScn[0] = (byte)(pSPPAL[c1>>6] |mono);
if ((SPpat & 0x08) != 0) lpScreen[pScn + 4] = (byte)(MMU.SPPAL[pSPPAL + ((c1 >> 2) & 3)] | mono); if ((SPpat & 0x08) != 0) pScn[4] = (byte)(pSPPAL[(c1>>2)&3] |mono);
if ((SPpat & 0x40) != 0) lpScreen[pScn + 1] = (byte)(MMU.SPPAL[pSPPAL + (c2 >> 6)] | mono); if ((SPpat & 0x40) != 0) pScn[1] = (byte)(pSPPAL[c2>>6] |mono);
if ((SPpat & 0x04) != 0) lpScreen[pScn + 5] = (byte)(MMU.SPPAL[pSPPAL + ((c2 >> 2) & 3)] | mono); if ((SPpat & 0x04) != 0) pScn[5] = (byte)(pSPPAL[(c2>>2)&3] |mono);
if ((SPpat & 0x20) != 0) lpScreen[pScn + 2] = (byte)(MMU.SPPAL[pSPPAL + ((c1 >> 4) & 3)] | mono); if ((SPpat & 0x20) != 0) pScn[2] = (byte)(pSPPAL[(c1>>4)&3] |mono);
if ((SPpat & 0x02) != 0) lpScreen[pScn + 6] = (byte)(MMU.SPPAL[pSPPAL + (c1 & 3)] | mono); if ((SPpat & 0x02) != 0) pScn[6] = (byte)(pSPPAL[c1&3] |mono);
if ((SPpat & 0x10) != 0) lpScreen[pScn + 3] = (byte)(MMU.SPPAL[pSPPAL + ((c2 >> 4) & 3)] | mono); if ((SPpat & 0x10) != 0) pScn[3] = (byte)(pSPPAL[(c2>>4)&3] |mono);
if ((SPpat & 0x01) != 0) lpScreen[pScn + 7] = (byte)(MMU.SPPAL[pSPPAL + (c2 & 3)] | mono); if ((SPpat & 0x01) != 0) pScn[7] = (byte)(pSPPAL[c2 & 3] | mono);
}
} }
if (++spmax > 8 - 1) if (++spmax > 8 - 1)
@ -1026,6 +1004,7 @@
MMU.PPUREG[2] |= PPU_SPMAX_FLAG; MMU.PPUREG[2] |= PPU_SPMAX_FLAG;
} }
} }
}
internal bool IsSprite0(int scanline) internal bool IsSprite0(int scanline)
{ {
@ -1103,7 +1082,7 @@
MMU.PPUREG[2] |= PPU_VBLANK_FLAG; MMU.PPUREG[2] |= PPU_VBLANK_FLAG;
} }
public uint[] GetScreenPtr() public byte* GetScreenPtr()
{ {
return lpScreen; return lpScreen;
} }
@ -1113,9 +1092,10 @@
return lpColormode; return lpColormode;
} }
internal void SetScreenPtr(uint[] screenBuffer, byte[] colormode) internal void SetScreenPtr(byte[] screenBuffer, byte[] colormode)
{ {
lpScreen = screenBuffer; lpScreenGCH = GCHandle.Alloc(screenBuffer, GCHandleType.Pinned);
lpScreen = (byte*)lpScreenGCH.AddrOfPinnedObject();
lpColormode = colormode; lpColormode = colormode;
} }