AxibugEmuOnline/AxibugEmuOnline.Client/Assets/Plugins/Mame.Core/emu/Video.cs

1128 lines
53 KiB
C#
Raw Normal View History

using MAME.Core;
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace MAME.Core
{
public struct screen_state
{
public int width; /* current width (HTOTAL) */
public int height; /* current height (VTOTAL) */
public RECT visarea; /* current visible area (HBLANK end/start, VBLANK end/start) */
public int last_partial_scan; /* scanline of last partial update */
public long frame_period; /* attoseconds per frame */
public long vblank_period; /* attoseconds per VBLANK period */
public long scantime; /* attoseconds per scanline */
public long pixeltime; /* attoseconds per pixel */
public Atime vblank_start_time;
public Atime vblank_end_time;
public long frame_number;
};
unsafe partial class Video
{
public static bool flip_screen_x, flip_screen_y;
public static long frame_number_obj;
public static Atime frame_update_time;
public static screen_state screenstate;
public static int video_attributes;
private static int PAUSED_REFRESH_RATE = 30, VIDEO_UPDATE_AFTER_VBLANK = 4;
public static EmuTimer.emu_timer vblank_begin_timer, vblank_end_timer;
public static EmuTimer.emu_timer scanline0_timer, scanline_timer;
private static Atime speed_last_emutime, overall_emutime;
private static long speed_last_realtime, overall_real_ticks;
private static double speed_percent;
private static uint throttle_history, overall_valid_counter, overall_real_seconds;
private static int[] popcount;
//public static ushort[][] bitmapbase;
//public static int[][] bitmapbaseN;
//public static int[] bitmapcolor;
/** bitmapcolor的指针管理 **/
public static ushort[][] bitmapbase; //还有 部分 Array.Copy 在引用
static GCHandle[] bitmapbase_handles;
public static ushort*[] bitmapbase_Ptrs;
/** end **/
/** bitmapbaseN的指针管理 **/
public static int[][] bitmapbaseN; //还有 部分 Array.Copy 在引用
static GCHandle[] bitmapbaseN_handles;
public static int*[] bitmapbaseN_Ptrs;
/** end **/
/** bitmapcolor的指针管理 **/
//不再拷贝完整画布
//public static int[] bitmapcolor;
//static GCHandle bitmapcolor_handle;
//public static IntPtr bitmapcolor_Ptr;
public static int[] bitmapcolorRect;
static GCHandle bitmapcolorRect_handle;
public static IntPtr bitmapcolorRect_Ptr;
public static int* bitmapcolorRect_Ptrunsafe;
/** end **/
public static int fullwidth, fullheight;
public static bool global_throttle;
public static int scanline_param;
public static RECT new_clip;
public static int curbitmap;
public static string sDrawText;
public static long popup_text_end;
public static int iMode, nMode;
//private static BitmapData bitmapData;
public static int offsetx, offsety, width, height;
public delegate void video_delegate();
public static video_delegate video_update_callback, video_eof_callback;
private static int NEOGEO_HBEND = 0x01e;//30 /* this should really be 29.5 */
private static int NEOGEO_HBSTART = 0x15e;//350 /* this should really be 349.5 */
private static int NEOGEO_VTOTAL = 0x108;//264
private static int NEOGEO_VBEND = 0x010;
private static int NEOGEO_VBSTART = 0x0f0;//240
private static int NEOGEO_VBLANK_RELOAD_HPOS = 0x11f;//287
#region
static Action<int[], long> Act_SubmitVideo;
public static void BindFunc(IVideoPlayer Ivp)
{
Act_SubmitVideo -= Act_SubmitVideo;
Act_SubmitVideo += Ivp.SubmitVideo;
}
static void SubmitVideo(int[] Bitmap, long frame_number)
{
Act_SubmitVideo.Invoke(Bitmap, frame_number);
}
#endregion
public static void video_init()
{
Wintime.wintime_init();
global_throttle = true;
Motion.motion_handler_callback = Motion.handler_ingame;
sDrawText = "";
popup_text_end = 0;
popcount = new int[256]{
0,1,1,2,1,2,2,3, 1,2,2,3,2,3,3,4, 1,2,2,3,2,3,3,4, 2,3,3,4,3,4,4,5,
1,2,2,3,2,3,3,4, 2,3,3,4,3,4,4,5, 2,3,3,4,3,4,4,5, 3,4,4,5,4,5,5,6,
1,2,2,3,2,3,3,4, 2,3,3,4,3,4,4,5, 2,3,3,4,3,4,4,5, 3,4,4,5,4,5,5,6,
2,3,3,4,3,4,4,5, 3,4,4,5,4,5,5,6, 3,4,4,5,4,5,5,6, 4,5,5,6,5,6,6,7,
1,2,2,3,2,3,3,4, 2,3,3,4,3,4,4,5, 2,3,3,4,3,4,4,5, 3,4,4,5,4,5,5,6,
2,3,3,4,3,4,4,5, 3,4,4,5,4,5,5,6, 3,4,4,5,4,5,5,6, 4,5,5,6,5,6,6,7,
2,3,3,4,3,4,4,5, 3,4,4,5,4,5,5,6, 3,4,4,5,4,5,5,6, 4,5,5,6,5,6,6,7,
3,4,4,5,4,5,5,6, 4,5,5,6,5,6,6,7, 4,5,5,6,5,6,6,7, 5,6,6,7,6,7,7,8
};
switch (Machine.sBoard)
{
case "CPS-1":
case "CPS-1(QSound)":
screenstate.width = 0x200;
screenstate.height = 0x100;
screenstate.visarea.min_x = 0;
screenstate.visarea.max_x = 0x1ff;
screenstate.visarea.min_y = 0;
screenstate.visarea.max_y = 0x1ff;
fullwidth = 0x200;
fullheight = 0x200;
frame_update_time = new Atime(0, (long)(1e18 / 59.61));//59.61Hz
screenstate.vblank_period = 0;
video_attributes = 0;
Motion.motion_update_callback = Motion.ui_updateC;
bitmapbase = new ushort[2][];
bitmapbase[0] = new ushort[0x200 * 0x200];
bitmapbase[1] = new ushort[0x200 * 0x200];
video_update_callback = CPS.video_update_cps1;
video_eof_callback = CPS.video_eof_cps1;
break;
case "CPS2":
screenstate.width = 0x200;
screenstate.height = 0x100;
screenstate.visarea.min_x = 0;
screenstate.visarea.max_x = 0x1ff;
screenstate.visarea.min_y = 0;
screenstate.visarea.max_y = 0x1ff;
fullwidth = 0x200;
fullheight = 0x200;
frame_update_time = new Atime(0, (long)(1e18 / 8000000) * 512 * 262);//59.637404580152669Hz
screenstate.vblank_period = 0;
video_attributes = 0;
Motion.motion_update_callback = Motion.ui_updateC;
bitmapbase = new ushort[2][];
bitmapbase[0] = new ushort[0x200 * 0x200];
bitmapbase[1] = new ushort[0x200 * 0x200];
video_update_callback = CPS.video_update_cps1;
video_eof_callback = CPS.video_eof_cps1;
break;
case "Data East":
screenstate.width = 0x100;
screenstate.height = 0x100;
screenstate.visarea.min_x = 0;
screenstate.visarea.max_x = 0xff;
screenstate.visarea.min_y = 0x10;
screenstate.visarea.max_y = 0xef;
fullwidth = 0x100;
fullheight = 0x100;
frame_update_time = new Atime(0, (long)(1e18 / 60));
screenstate.vblank_period = 0;
video_attributes = 0;
Motion.motion_update_callback = Motion.ui_updateC;
bitmapbase = new ushort[2][];
bitmapbase[0] = new ushort[0x100 * 0x100];
bitmapbase[1] = new ushort[0x100 * 0x100];
video_update_callback = Dataeast.video_update_pcktgal;
video_eof_callback = Dataeast.video_eof_pcktgal;
switch (Machine.sName)
{
case "pcktgal":
case "pcktgalb":
case "pcktgal2":
case "pcktgal2j":
case "spool3":
case "spool3i":
Dataeast.palette_init_pcktgal(Dataeast.prom);
break;
}
break;
case "Tehkan":
screenstate.width = 0x100;
screenstate.height = 0x100;
screenstate.visarea.min_x = 0;
screenstate.visarea.max_x = 0xff;
screenstate.visarea.min_y = 0x10;
screenstate.visarea.max_y = 0xef;
fullwidth = 0x100;
fullheight = 0x100;
frame_update_time = new Atime(0, (long)(1e18 / 60));
screenstate.vblank_period = 0;
video_attributes = 0;
Motion.motion_update_callback = Motion.ui_updateTehkan;
bitmapbase = new ushort[2][];
bitmapbase[0] = new ushort[0x100 * 0x100];
bitmapbase[1] = new ushort[0x100 * 0x100];
video_update_callback = Tehkan.video_update_pbaction;
video_eof_callback = Tehkan.video_eof_pbaction;
break;
case "Neo Geo":
screenstate.width = 384;
screenstate.height = 264;
screenstate.visarea.min_x = NEOGEO_HBEND;//30
screenstate.visarea.max_x = NEOGEO_HBSTART - 1;//349
screenstate.visarea.min_y = NEOGEO_VBEND;//16
screenstate.visarea.max_y = NEOGEO_VBSTART - 1;//239
fullwidth = 384;
fullheight = 264;
frame_update_time = new Atime(0, (long)(1e18 / 6000000) * screenstate.width * screenstate.height);//59.1856060608428Hz
screenstate.vblank_period = (long)(1e18 / 6000000) * 384 * (264 - 224);
video_attributes = 0;
Motion.motion_update_callback = Motion.ui_updateN;
bitmapbaseN = new int[2][];
bitmapbaseN[0] = new int[384 * 264];
bitmapbaseN[1] = new int[384 * 264];
video_update_callback = Neogeo.video_update_neogeo;
video_eof_callback = Neogeo.video_eof_neogeo;
break;
case "SunA8":
screenstate.width = 0x100;
screenstate.height = 0x100;
screenstate.visarea.min_x = 0;
screenstate.visarea.min_x = 0xff;
screenstate.visarea.min_y = 0x10;
screenstate.visarea.max_y = 0xef;
fullwidth = 0x100;
fullheight = 0x100;
frame_update_time = new Atime(0, (long)(1e18 / 60));
screenstate.vblank_period = (long)(1e12 * 2500);
video_attributes = 0;
Motion.motion_update_callback = Motion.ui_updatePGM;
bitmapbase = new ushort[2][];
bitmapbase[0] = new ushort[0x100 * 0x100];
bitmapbase[1] = new ushort[0x100 * 0x100];
video_update_callback = SunA8.video_update_suna8;
video_eof_callback = SunA8.video_eof_suna8;
break;
case "Namco System 1":
screenstate.width = 0x200;
screenstate.height = 0x200;
screenstate.visarea.min_x = 0;
screenstate.visarea.max_x = 0x1ff;
screenstate.visarea.min_y = 0;
screenstate.visarea.max_y = 0x1ff;
fullwidth = 0x200;
fullheight = 0x200;
frame_update_time = new Atime(0, (long)(1e18 / 60.606060));
screenstate.vblank_period = 0;
video_attributes = 0;
Motion.motion_update_callback = Motion.ui_updateNa;
bitmapbase = new ushort[2][];
bitmapbase[0] = new ushort[0x200 * 0x200];
bitmapbase[1] = new ushort[0x200 * 0x200];
video_update_callback = Namcos1.video_update_namcos1;
video_eof_callback = Namcos1.video_eof_namcos1;
break;
case "IGS011":
screenstate.width = 0x200;
screenstate.height = 0x100;
screenstate.visarea.min_x = 0;
screenstate.visarea.max_x = 0x1ff;
screenstate.visarea.min_y = 0;
screenstate.visarea.max_y = 0xef;
fullwidth = 0x200;
fullheight = 0x200;
frame_update_time = new Atime(0, (long)(1e18 / 60));
screenstate.vblank_period = 0;
video_attributes = 0;
Motion.motion_update_callback = Motion.ui_updateIGS011;
bitmapbase = new ushort[2][];
bitmapbase[0] = new ushort[0x200 * 0x200];
bitmapbase[1] = new ushort[0x200 * 0x200];
video_update_callback = IGS011.video_update_igs011;
video_eof_callback = IGS011.video_eof_igs011;
break;
case "PGM":
screenstate.width = 0x200;
screenstate.height = 0x200;
screenstate.visarea.min_x = 0;
screenstate.visarea.max_x = 0x1bf;
screenstate.visarea.min_y = 0;
screenstate.visarea.max_y = 0xdf;
fullwidth = 0x200;
fullheight = 0x200;
frame_update_time = new Atime(0, (long)(1e18 / 60));
screenstate.vblank_period = 0;
video_attributes = 0;
Motion.motion_update_callback = Motion.ui_updatePGM;
bitmapbase = new ushort[2][];
bitmapbase[0] = new ushort[0x200 * 0x200];
bitmapbase[1] = new ushort[0x200 * 0x200];
video_update_callback = PGM.video_update_pgm;
video_eof_callback = PGM.video_eof_pgm;
break;
case "M72":
screenstate.width = 0x200;
screenstate.height = 0x11c;
screenstate.visarea.min_x = 0x40;
screenstate.visarea.max_x = 0x1bf;
screenstate.visarea.min_y = 0;
screenstate.visarea.max_y = 0xff;
fullwidth = 0x200;
fullheight = 0x200;
frame_update_time = new Atime(0, (long)(1e18 / 8000000) * screenstate.width * screenstate.height);
screenstate.vblank_period = (long)(1e18 / 8000000) * 512 * (284 - 256);
video_attributes = 0;
Motion.motion_update_callback = Motion.ui_updatePGM;
bitmapbase = new ushort[2][];
bitmapbase[0] = new ushort[0x200 * 0x200];//0x11c
bitmapbase[1] = new ushort[0x200 * 0x200];//0x11c
video_update_callback = M72.video_update_m72;
video_eof_callback = M72.video_eof_m72;
break;
case "M92":
screenstate.width = 0x200;
screenstate.height = 0x100;
screenstate.visarea.min_x = 0x50;
screenstate.visarea.max_x = 0x18f;
screenstate.visarea.min_y = 0x8;
screenstate.visarea.max_y = 0xf7;
fullwidth = 0x200;
fullheight = 0x200;
frame_update_time = new Atime(0, (long)(1e18 / 60));
screenstate.vblank_period = 0;
video_attributes = 0;
Motion.motion_update_callback = Motion.ui_updatePGM;
bitmapbase = new ushort[2][];
bitmapbase[0] = new ushort[0x200 * 0x200];
bitmapbase[1] = new ushort[0x200 * 0x200];
video_update_callback = M92.video_update_m92;
video_eof_callback = M92.video_eof_m92;
break;
case "Taito":
video_attributes = 0;
Motion.motion_update_callback = Motion.ui_updatePGM;
switch (Machine.sName)
{
case "tokio":
case "tokioo":
case "tokiou":
case "tokiob":
case "bublbobl":
case "bublbobl1":
case "bublboblr":
case "bublboblr1":
case "boblbobl":
case "sboblbobl":
case "sboblbobla":
case "sboblboblb":
case "sboblbobld":
case "sboblboblc":
case "bub68705":
case "dland":
case "bbredux":
case "bublboblb":
case "bublcave":
case "boblcave":
case "bublcave11":
case "bublcave10":
screenstate.width = 0x100;
screenstate.height = 0x100;
screenstate.visarea.min_x = 0;
screenstate.visarea.max_x = 255;
screenstate.visarea.min_y = 16;
screenstate.visarea.max_y = 240 - 1;
fullwidth = 0x100;
fullheight = 0x100;
frame_update_time = new Atime(0, 0x003c372a18883411);
screenstate.vblank_period = 0;// (long)(1e18 * 0.00256);
bitmapbase = new ushort[2][];
bitmapbase[0] = new ushort[0x100 * 0x100];
bitmapbase[1] = new ushort[0x100 * 0x100];
video_update_callback = Taito.video_update_bublbobl;
video_eof_callback = Taito.video_eof_taito;
break;
case "opwolf":
case "opwolfa":
case "opwolfj":
case "opwolfu":
case "opwolfb":
case "opwolfp":
screenstate.width = 0x140;
screenstate.height = 0x100;
screenstate.visarea.min_x = 0;
screenstate.visarea.max_x = 0x13f;
screenstate.visarea.min_y = 8;
screenstate.visarea.max_y = 0xf7;
fullwidth = 0x140;
fullheight = 0x100;
frame_update_time = new Atime(0, (long)(1e18 / 60));
screenstate.vblank_period = 0;// (long)(1e18 * 0.00256);
bitmapbase = new ushort[2][];
bitmapbase[0] = new ushort[0x140 * 0x100];
bitmapbase[1] = new ushort[0x140 * 0x100];
video_update_callback = Taito.video_update_opwolf;
video_eof_callback = Taito.video_eof_taito;
break;
}
break;
case "Taito B":
screenstate.width = 0x200;
screenstate.height = 0x100;
screenstate.visarea.min_x = 0;//0
screenstate.visarea.max_x = 320 - 1;//319
screenstate.visarea.min_y = 16;//16
screenstate.visarea.max_y = 240 - 1;//239
fullwidth = 0x200;
fullheight = 0x100;
frame_update_time = new Atime(0, (long)(1e18 / 60));
screenstate.vblank_period = 0;
video_attributes = 0;
Motion.motion_update_callback = Motion.ui_updatePGM;
bitmapbase = new ushort[2][];
bitmapbase[0] = new ushort[0x200 * 0x100];
bitmapbase[1] = new ushort[0x200 * 0x100];
video_update_callback = Taitob.video_update_taitob;
video_eof_callback = Taitob.video_eof_taitob;
break;
case "Konami 68000":
screenstate.width = 0x200;
screenstate.height = 0x100;
fullwidth = 0x200;
fullheight = 0x100;
frame_update_time = new Atime(0, (long)(1e18 / 60));
screenstate.vblank_period = (long)(1e12 * 2500);
video_attributes = 0x34;
Motion.motion_update_callback = Motion.ui_updatePGM;
bitmapbase = new ushort[2][];
bitmapbase[0] = new ushort[0x200 * 0x100];
bitmapbase[1] = new ushort[0x200 * 0x100];
video_eof_callback = Konami68000.video_eof;
switch (Machine.sName)
{
case "cuebrick":
screenstate.visarea.min_x = 0x68;
screenstate.visarea.max_x = 0x197;
screenstate.visarea.min_y = 0x10;
screenstate.visarea.max_y = 0xef;
video_update_callback = Konami68000.video_update_mia;
break;
case "mia":
case "mia2":
screenstate.visarea.min_x = 0x68;
screenstate.visarea.max_x = 0x197;
screenstate.visarea.min_y = 0x10;
screenstate.visarea.max_y = 0xef;
video_attributes = 0x30;
video_update_callback = Konami68000.video_update_mia;
break;
case "tmnt":
case "tmntu":
case "tmntua":
case "tmntub":
case "tmht":
case "tmhta":
case "tmhtb":
case "tmntj":
case "tmnta":
case "tmht2p":
case "tmht2pa":
case "tmnt2pj":
case "tmnt2po":
screenstate.visarea.min_x = 0x60;
screenstate.visarea.max_x = 0x19f;
screenstate.visarea.min_y = 0x10;
screenstate.visarea.max_y = 0xef;
video_attributes = 0x30;
video_update_callback = Konami68000.video_update_mia;
break;
case "punkshot":
case "punkshot2":
case "punkshotj":
screenstate.visarea.min_x = 0x70;
screenstate.visarea.max_x = 0x18f;
screenstate.visarea.min_y = 0x10;
screenstate.visarea.max_y = 0xef;
video_update_callback = Konami68000.video_update_punkshot;
break;
case "lgtnfght":
case "lgtnfghta":
case "lgtnfghtu":
case "trigon":
screenstate.visarea.min_x = 0x60;
screenstate.visarea.max_x = 0x19f;
screenstate.visarea.min_y = 0x10;
screenstate.visarea.max_y = 0xef;
video_update_callback = Konami68000.video_update_lgtnfght;
break;
case "blswhstl":
case "blswhstla":
case "detatwin":
screenstate.visarea.min_x = 0x60;
screenstate.visarea.max_x = 0x19f;
screenstate.visarea.min_y = 0x10;
screenstate.visarea.max_y = 0xef;
video_update_callback = Konami68000.video_update_lgtnfght;
video_eof_callback = Konami68000.video_eof_blswhstl;
break;
case "glfgreat":
case "glfgreatj":
case "prmrsocr":
case "prmrsocrj":
screenstate.visarea.min_x = 0x70;
screenstate.visarea.max_x = 0x18f;
screenstate.visarea.min_y = 0x10;
screenstate.visarea.max_y = 0xef;
video_update_callback = Konami68000.video_update_glfgreat;
break;
case "tmnt2":
case "tmnt2a":
case "tmht22pe":
case "tmht24pe":
case "tmnt22pu":
case "qgakumon":
screenstate.visarea.min_x = 0x68;
screenstate.visarea.max_x = 0x197;
screenstate.visarea.min_y = 0x10;
screenstate.visarea.max_y = 0xef;
video_update_callback = Konami68000.video_update_tmnt2;
break;
case "ssriders":
case "ssriderseaa":
case "ssridersebd":
case "ssridersebc":
case "ssridersuda":
case "ssridersuac":
case "ssridersuab":
case "ssridersubc":
case "ssridersadd":
case "ssridersabd":
case "ssridersjad":
case "ssridersjac":
case "ssridersjbd":
screenstate.visarea.min_x = 0x70;
screenstate.visarea.max_x = 0x18f;
screenstate.visarea.min_y = 0x10;
screenstate.visarea.max_y = 0xef;
video_update_callback = Konami68000.video_update_tmnt2;
break;
case "thndrx2":
case "thndrx2a":
case "thndrx2j":
screenstate.visarea.min_x = 0x70;
screenstate.visarea.max_x = 0x18f;
screenstate.visarea.min_y = 0x10;
screenstate.visarea.max_y = 0xef;
video_attributes = 0x30;
video_update_callback = Konami68000.video_update_thndrx2;
break;
}
break;
case "Capcom":
switch (Machine.sName)
{
case "gng":
case "gnga":
case "gngbl":
case "gngprot":
case "gngblita":
case "gngc":
case "gngt":
case "makaimur":
case "makaimurc":
case "makaimurg":
case "diamond":
screenstate.width = 0x100;
screenstate.height = 0x100;
screenstate.visarea.min_x = 0;
screenstate.visarea.max_x = 0xff;
screenstate.visarea.min_y = 0x10;
screenstate.visarea.max_y = 0xef;
fullwidth = 0x100;
fullheight = 0x100;
frame_update_time = new Atime(0, (long)(1e18 / 60));
screenstate.vblank_period = 0;
video_attributes = 0;
Motion.motion_update_callback = Motion.ui_updatePGM;
bitmapbase = new ushort[2][];
bitmapbase[0] = new ushort[0x100 * 0x100];
bitmapbase[1] = new ushort[0x100 * 0x100];
video_update_callback = Capcom.video_update_gng;
video_eof_callback = Capcom.video_eof_gng;
break;
case "sf":
case "sfua":
case "sfj":
case "sfjan":
case "sfan":
case "sfp":
screenstate.width = 0x200;
screenstate.height = 0x100;
screenstate.visarea.min_x = 0x40;
screenstate.visarea.max_x = 0x1bf;
screenstate.visarea.min_y = 0x10;
screenstate.visarea.max_y = 0xef;
fullwidth = 0x200;
fullheight = 0x100;
frame_update_time = new Atime(0, (long)(1e18 / 60));
screenstate.vblank_period = 0;
video_attributes = 0;
Motion.motion_update_callback = Motion.ui_updatePGM;
bitmapbase = new ushort[2][];
bitmapbase[0] = new ushort[0x200 * 0x100];
bitmapbase[1] = new ushort[0x200 * 0x100];
video_update_callback = Capcom.video_update_sf;
video_eof_callback = Capcom.video_eof;
break;
}
break;
}
screenstate.frame_period = frame_update_time.attoseconds;
screenstate.scantime = screenstate.frame_period / screenstate.height;
screenstate.pixeltime = screenstate.frame_period / (screenstate.height * screenstate.width);
screenstate.frame_number = 0;
/** bitmapbase的指针管理 **/
// 释放句柄
if (bitmapbase_handles != null)
{
for (int i = 0; i < bitmapbase_handles.Length; i++)
{
if (bitmapbase_handles[i].IsAllocated)
bitmapbase_handles[i].Free();
}
bitmapbase_handles = null;
bitmapbase_Ptrs = null;
}
if (bitmapbase != null)
{
bitmapbase_handles = new GCHandle[bitmapbase.Length];
bitmapbase_Ptrs = new ushort*[bitmapbase.Length];
for (int i = 0; i < bitmapbase.Length; i++)
{
bitmapbase_handles[i] = GCHandle.Alloc(bitmapbase[i], GCHandleType.Pinned);
bitmapbase_Ptrs[i] = (ushort*)bitmapbase_handles[i].AddrOfPinnedObject();
}
}
if (bitmapbaseN_handles != null)
{
for (int i = 0; i < bitmapbaseN_handles.Length; i++)
{
if (bitmapbaseN_handles[i].IsAllocated)
bitmapbaseN_handles[i].Free();
}
bitmapbaseN_handles = null;
bitmapbaseN_Ptrs = null;
}
if (bitmapbaseN != null)
{
bitmapbaseN_handles = new GCHandle[bitmapbaseN.Length];
bitmapbaseN_Ptrs = new int*[bitmapbaseN.Length];
for (int i = 0; i < bitmapbaseN.Length; i++)
{
bitmapbaseN_handles[i] = GCHandle.Alloc(bitmapbaseN[i], GCHandleType.Pinned);
bitmapbaseN_Ptrs[i] = (int*)bitmapbaseN_handles[i].AddrOfPinnedObject();
}
}
/** end **/
//bitmapcolor = new int[Video.fullwidth * Video.fullheight];
/** bitmapcolor的指针管理 **/
//不再拷贝完整画布
//if (bitmapcolor != null)
//{
// // 释放句柄
// if (bitmapcolor_handle.IsAllocated)
// {
// bitmapcolor_handle.Free();
// }
//}
//bitmapcolor = new int[Video.fullwidth * Video.fullheight];
//// 固定数组,防止垃圾回收器移动它
//bitmapcolor_handle = GCHandle.Alloc(bitmapcolor, GCHandleType.Pinned);
//// 获取数组的指针
//bitmapcolor_Ptr = bitmapcolor_handle.AddrOfPinnedObject();
// 释放句柄
if (bitmapcolorRect != null && bitmapcolorRect_handle.IsAllocated)
bitmapcolorRect_handle.Free();
bitmapcolorRect = new int[width * height];
// 固定数组,防止垃圾回收器移动它
bitmapcolorRect_handle = GCHandle.Alloc(bitmapcolorRect, GCHandleType.Pinned);
// 获取数组的指针
bitmapcolorRect_Ptr = bitmapcolorRect_handle.AddrOfPinnedObject();
bitmapcolorRect_Ptrunsafe = (int*)bitmapcolorRect_Ptr;
/** end **/
vblank_begin_timer = EmuTimer.timer_alloc_common(EmuTimer.TIME_ACT.Video_vblank_begin_callback, false);
EmuTimer.timer_adjust_periodic(vblank_begin_timer, video_screen_get_time_until_vblank_start(), Attotime.ATTOTIME_NEVER);
scanline0_timer = EmuTimer.timer_alloc_common(EmuTimer.TIME_ACT.Video_scanline0_callback, false);
EmuTimer.timer_adjust_periodic(scanline0_timer, video_screen_get_time_until_pos(0, 0), Attotime.ATTOTIME_NEVER);
vblank_end_timer = EmuTimer.timer_alloc_common(EmuTimer.TIME_ACT.Video_vblank_end_callback, false);
switch (Machine.sBoard)
{
case "CPS-1":
case "CPS-1(QSound)":
case "Namco System 1":
case "M92":
case "Taito B":
break;
case "CPS2":
Cpuexec.cpu[0].partial_frame_period = Attotime.attotime_div(Video.frame_update_time, 262);
Cpuexec.cpu[0].partial_frame_timer = EmuTimer.timer_alloc_common(EmuTimer.TIME_ACT.Cpuexec_trigger_partial_frame_interrupt, false);
break;
case "Tehkan":
Cpuexec.cpu[1].partial_frame_period = Attotime.attotime_div(Video.frame_update_time, 2);
Cpuexec.cpu[1].partial_frame_timer = EmuTimer.timer_alloc_common(EmuTimer.TIME_ACT.Cpuexec_trigger_partial_frame_interrupt, false);
break;
case "Neo Geo":
break;
case "SunA8":
Cpuexec.cpu[0].partial_frame_period = Attotime.attotime_div(Video.frame_update_time, 0x100);
Cpuexec.cpu[0].partial_frame_timer = EmuTimer.timer_alloc_common(EmuTimer.TIME_ACT.Cpuexec_trigger_partial_frame_interrupt, false);
Cpuexec.cpu[1].partial_frame_period = Attotime.attotime_div(Video.frame_update_time, 4);
Cpuexec.cpu[1].partial_frame_timer = EmuTimer.timer_alloc_common(EmuTimer.TIME_ACT.Cpuexec_trigger2, false);
break;
case "IGS011":
switch (Machine.sName)
{
case "drgnwrld":
case "drgnwrldv30":
case "drgnwrldv21":
case "drgnwrldv21j":
case "drgnwrldv20j":
case "drgnwrldv10c":
case "drgnwrldv11h":
case "drgnwrldv40k":
case "lhb2":
Cpuexec.cpu[0].partial_frame_period = Attotime.attotime_div(Video.frame_update_time, 5);
Cpuexec.cpu[0].partial_frame_timer = EmuTimer.timer_alloc_common(EmuTimer.TIME_ACT.Cpuexec_trigger_partial_frame_interrupt, false);
break;
case "lhb":
case "lhbv33c":
case "dbc":
case "ryukobou":
Cpuexec.cpu[0].partial_frame_period = Attotime.attotime_div(Video.frame_update_time, 4);
Cpuexec.cpu[0].partial_frame_timer = EmuTimer.timer_alloc_common(EmuTimer.TIME_ACT.Cpuexec_trigger_partial_frame_interrupt, false);
break;
}
break;
case "M72":
Cpuexec.cpu[1].partial_frame_period = Attotime.attotime_div(Video.frame_update_time, 128);
Cpuexec.cpu[1].partial_frame_timer = EmuTimer.timer_alloc_common(EmuTimer.TIME_ACT.Cpuexec_trigger_partial_frame_interrupt, false);
break;
case "Taito":
switch (Machine.sName)
{
case "bub68705":
Cpuexec.cpu[3].partial_frame_period = Attotime.attotime_div(Video.frame_update_time, 2);
Cpuexec.cpu[3].partial_frame_timer = EmuTimer.timer_alloc_common(EmuTimer.TIME_ACT.Cpuexec_trigger_partial_frame_interrupt, false);
break;
}
break;
case "Konami 68000":
switch (Machine.sName)
{
case "cuebrick":
Cpuexec.cpu[0].partial_frame_period = Attotime.attotime_div(Video.frame_update_time, 10);
Cpuexec.cpu[0].partial_frame_timer = EmuTimer.timer_alloc_common(EmuTimer.TIME_ACT.Cpuexec_trigger_partial_frame_interrupt, false);
break;
}
break;
case "Capcom":
switch (Machine.sName)
{
case "gng":
case "gnga":
case "gngbl":
case "gngprot":
case "gngblita":
case "gngc":
case "gngt":
case "makaimur":
case "makaimurc":
case "makaimurg":
case "diamond":
Cpuexec.cpu[1].partial_frame_period = Attotime.attotime_div(Video.frame_update_time, 4);
Cpuexec.cpu[1].partial_frame_timer = EmuTimer.timer_alloc_common(EmuTimer.TIME_ACT.Cpuexec_trigger_partial_frame_interrupt, false);
break;
}
break;
}
screenstate.vblank_start_time = Attotime.ATTOTIME_ZERO;
screenstate.vblank_end_time = new Atime(0, screenstate.vblank_period);
}
public static void video_screen_configure(int width, int height, RECT visarea, long frame_period)
{
screenstate.width = width;
screenstate.height = height;
screenstate.visarea = visarea;
//realloc_screen_bitmaps(screen);
screenstate.frame_period = frame_period;
screenstate.scantime = frame_period / height;
screenstate.pixeltime = frame_period / (height * width);
/*if (config->vblank == 0 && !config->oldstyle_vblank_supplied)
state->vblank_period = state->scantime * (height - (visarea->max_y + 1 - visarea->min_y));
else
state->vblank_period = config->vblank;
if (video_screen_get_vpos(screen) == 0)
timer_adjust_oneshot(state->scanline0_timer, attotime_zero, 0);
else
timer_adjust_oneshot(state->scanline0_timer, video_screen_get_time_until_pos(screen, 0, 0), 0);
timer_adjust_oneshot(state->vblank_begin_timer, video_screen_get_time_until_vblank_start(screen), 0);
update_refresh_speed(screen->machine);*/
}
public static bool video_screen_update_partial(int scanline)
{
new_clip = screenstate.visarea;
bool result = false;
if (screenstate.last_partial_scan > new_clip.min_y)
{
new_clip.min_y = screenstate.last_partial_scan;
}
if (scanline < new_clip.max_y)
{
new_clip.max_y = scanline;
}
if (new_clip.min_y <= new_clip.max_y)
{
video_update_callback();
result = true;
}
screenstate.last_partial_scan = scanline + 1;
return result;
}
public static int video_screen_get_vpos()
{
long delta = Attotime.attotime_to_attoseconds(Attotime.attotime_sub(EmuTimer.get_current_time(), screenstate.vblank_start_time));
int vpos;
delta += screenstate.pixeltime / 2;
vpos = (int)(delta / screenstate.scantime);
return (screenstate.visarea.max_y + 1 + vpos) % screenstate.height;
}
public static bool video_screen_get_vblank()
{
return (Attotime.attotime_compare(EmuTimer.get_current_time(), screenstate.vblank_end_time) < 0);
}
public static Atime video_screen_get_time_until_pos(int vpos, int hpos)
{
long curdelta = Attotime.attotime_to_attoseconds(Attotime.attotime_sub(EmuTimer.get_current_time(), screenstate.vblank_start_time));
long targetdelta;
vpos += screenstate.height - (screenstate.visarea.max_y + 1);
vpos %= screenstate.height;
targetdelta = vpos * screenstate.scantime + hpos * screenstate.pixeltime;
if (targetdelta <= curdelta + screenstate.pixeltime / 2)
targetdelta += screenstate.frame_period;
while (targetdelta <= curdelta)
targetdelta += screenstate.frame_period;
return new Atime(0, targetdelta - curdelta);
}
public static Atime video_screen_get_time_until_vblank_start()
{
return video_screen_get_time_until_pos(Video.screenstate.visarea.max_y + 1, 0);
}
public static Atime video_screen_get_time_until_vblank_end()
{
Atime ret;
Atime current_time = EmuTimer.get_current_time();
if (video_screen_get_vblank())
{
ret = Attotime.attotime_sub(screenstate.vblank_end_time, current_time);
}
else
{
ret = Attotime.attotime_sub(Attotime.attotime_add_attoseconds(screenstate.vblank_end_time, screenstate.frame_period), current_time);
}
return ret;
}
private static bool effective_throttle()
{
// if (mame_is_paused(machine) || ui_is_menu_active())
// return true;
// if (global.fastforward)
// return false;
return global_throttle;
}
public static void vblank_begin_callback()
{
screenstate.vblank_start_time = EmuTimer.global_basetime;// Timer.get_current_time();
screenstate.vblank_end_time = Attotime.attotime_add_attoseconds(screenstate.vblank_start_time, screenstate.vblank_period);
Cpuexec.on_vblank();
//垂直同步
if ((video_attributes & VIDEO_UPDATE_AFTER_VBLANK) == 0)
{
video_frame_update();
}
EmuTimer.timer_adjust_periodic(vblank_begin_timer, video_screen_get_time_until_vblank_start(), Attotime.ATTOTIME_NEVER);
if (screenstate.vblank_period == 0)
{
vblank_end_callback();
}
else
{
EmuTimer.timer_adjust_periodic(vblank_end_timer, video_screen_get_time_until_vblank_end(), Attotime.ATTOTIME_NEVER);
}
}
public static void vblank_end_callback()
{
int i;
//垂直同步
if ((video_attributes & VIDEO_UPDATE_AFTER_VBLANK) != 0)
{
video_frame_update();
}
}
public static void scanline0_callback()
{
screenstate.last_partial_scan = 0;
EmuTimer.timer_adjust_periodic(scanline0_timer, video_screen_get_time_until_pos(0, 0), Attotime.ATTOTIME_NEVER);
}
public static void scanline_update_callback()
{
int scanline = scanline_param;
video_screen_update_partial(scanline);
scanline++;
if (scanline > screenstate.visarea.max_y)
{
scanline = screenstate.visarea.min_y;
}
scanline_param = scanline;
EmuTimer.timer_adjust_periodic(scanline_timer, video_screen_get_time_until_pos(scanline, 0), Attotime.ATTOTIME_NEVER);
}
public static void video_frame_update()
{
Atime current_time = EmuTimer.global_basetime;
if (!Mame.paused)
{
finish_screen_updates();
}
Keyboard.Update();
Mouse.Update();
Inptport.frame_update_callback();
Motion.ui_update_and_render();
//if (Machine.mainMotion.cheatmotion.lockState == CheatMotion.LockState.LOCK_FRAME)
//{
// Machine.mainMotion.cheatmotion.ApplyCheat();
//}
GDIDraw();
if (effective_throttle())
{
//不执行该函数避免Thread.Sleep (暂时确认无逻辑依赖)
//废弃
//update_throttle(current_time);
}
Window.osd_update(false);
//UI.ui_input_frame_update();
recompute_speed(current_time);
if (Mame.paused)
{
//Thread.Sleep(5);
}
else
{
video_eof_callback();
}
}
private static void finish_screen_updates()
{
video_screen_update_partial(screenstate.visarea.max_y);
curbitmap = 1 - curbitmap;
}
//废弃
//private static void update_throttle(Atime emutime)
//{
// long real_delta_attoseconds;
// long emu_delta_attoseconds;
// long real_is_ahead_attoseconds;
// long attoseconds_per_tick;
// long ticks_per_second;
// long target_ticks;
// long diff_ticks;
// ticks_per_second = Wintime.ticks_per_second;
// attoseconds_per_tick = Attotime.ATTOSECONDS_PER_SECOND / ticks_per_second;
// if (Mame.mame_is_paused())
// {
// throttle_emutime = Attotime.attotime_sub_attoseconds(emutime, Attotime.ATTOSECONDS_PER_SECOND / PAUSED_REFRESH_RATE);
// throttle_realtime = throttle_emutime;
// }
// emu_delta_attoseconds = Attotime.attotime_to_attoseconds(Attotime.attotime_sub(emutime, throttle_emutime));
// if (emu_delta_attoseconds < 0 || emu_delta_attoseconds > Attotime.ATTOSECONDS_PER_SECOND / 10)
// {
// goto resync;
// }
// diff_ticks = Wintime.osd_ticks() - throttle_last_ticks;
// throttle_last_ticks += diff_ticks;
// if (diff_ticks >= ticks_per_second)
// {
// goto resync;
// }
// real_delta_attoseconds = diff_ticks * attoseconds_per_tick;
// throttle_emutime = emutime;
// throttle_realtime = Attotime.attotime_add_attoseconds(throttle_realtime, real_delta_attoseconds);
// throttle_history = (throttle_history << 1) | Convert.ToUInt32(emu_delta_attoseconds > real_delta_attoseconds);
// real_is_ahead_attoseconds = Attotime.attotime_to_attoseconds(Attotime.attotime_sub(throttle_emutime, throttle_realtime));
// if ((real_is_ahead_attoseconds < -Attotime.ATTOSECONDS_PER_SECOND / 10) || (real_is_ahead_attoseconds < 0 && popcount[throttle_history & 0xff] < 6))
// {
// goto resync;
// }
// if (real_is_ahead_attoseconds < 0)
// {
// return;
// }
// target_ticks = throttle_last_ticks + real_is_ahead_attoseconds / attoseconds_per_tick;
// diff_ticks = throttle_until_ticks(target_ticks) - throttle_last_ticks;
// throttle_last_ticks += diff_ticks;
// throttle_realtime = Attotime.attotime_add_attoseconds(throttle_realtime, diff_ticks * attoseconds_per_tick);
// return;
//resync:
// throttle_realtime = throttle_emutime = emutime;
//}
//废弃
//private static long throttle_until_ticks(long target_ticks)
//{
// long minimum_sleep = Wintime.ticks_per_second / 1000;
// long current_ticks = Wintime.osd_ticks();
// long new_ticks;
// while (current_ticks < target_ticks)
// {
// long delta;
// bool slept = false;
// delta = (target_ticks - current_ticks) * 1000 / (1000 + average_oversleep);
// if (delta >= minimum_sleep)
// {
// Wintime.osd_sleep(delta);
// slept = true;
// }
// new_ticks = Wintime.osd_ticks();
// if (slept)
// {
// long actual_ticks = new_ticks - current_ticks;
// if (actual_ticks > delta)
// {
// long oversleep_milliticks = 1000 * (actual_ticks - delta) / delta;
// average_oversleep = (average_oversleep * 99 + oversleep_milliticks) / 100;
// }
// }
// current_ticks = new_ticks;
// }
// return current_ticks;
//}
private static void recompute_speed(Atime emutime)
{
long delta_emutime;
if (speed_last_realtime == 0 || Mame.mame_is_paused())
{
speed_last_realtime = Wintime.osd_ticks();
speed_last_emutime = emutime;
}
delta_emutime = Attotime.attotime_to_attoseconds(Attotime.attotime_sub(emutime, speed_last_emutime));
if (delta_emutime > Attotime.ATTOSECONDS_PER_SECOND / 4)
{
long realtime = Wintime.osd_ticks();
long delta_realtime = realtime - speed_last_realtime;
long tps = Wintime.ticks_per_second;
speed_percent = (double)delta_emutime * (double)tps / ((double)delta_realtime * (double)Attotime.ATTOSECONDS_PER_SECOND);
speed_last_realtime = realtime;
speed_last_emutime = emutime;
overall_valid_counter++;
if (overall_valid_counter >= 4)
{
overall_real_ticks += delta_realtime;
while (overall_real_ticks >= tps)
{
overall_real_ticks -= tps;
overall_real_seconds++;
}
overall_emutime = Attotime.attotime_add_attoseconds(overall_emutime, delta_emutime);
}
}
}
public static void flip_screen_set_no_update(bool on)
{
flip_screen_x = on;
}
public static bool flip_screen_get()
{
return flip_screen_x;
}
public static void SaveStateBinary(BinaryWriter writer)
{
writer.Write(scanline_param);
writer.Write(screenstate.last_partial_scan);
writer.Write(screenstate.vblank_start_time.seconds);
writer.Write(screenstate.vblank_start_time.attoseconds);
writer.Write(screenstate.vblank_end_time.seconds);
writer.Write(screenstate.vblank_end_time.attoseconds);
writer.Write(screenstate.frame_number);
}
public static void LoadStateBinary(BinaryReader reader)
{
scanline_param = reader.ReadInt32();
screenstate.last_partial_scan = reader.ReadInt32();
screenstate.vblank_start_time.seconds = reader.ReadInt32();
screenstate.vblank_start_time.attoseconds = reader.ReadInt64();
screenstate.vblank_end_time.seconds = reader.ReadInt32();
screenstate.vblank_end_time.attoseconds = reader.ReadInt64();
screenstate.frame_number = reader.ReadInt64();
}
}
}