/* * Glide64 - Glide video plugin for Nintendo 64 emulators. * Copyright (c) 2002 Dave2001 * Copyright (c) 2008 Günther * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * Licence along with this program; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA */ //**************************************************************** // // Glide64 - Glide Plugin for Nintendo 64 emulators (tested mostly with Project64) // Project started on December 29th, 2001 // // To modify Glide64: // * Write your name and (optional)email, commented by your work, so I know who did it, and so that you can find which parts you modified when it comes time to send it to me. // * Do NOT send me the whole project or file that you modified. Take out your modified code sections, and tell me where to put them. If people sent the whole thing, I would have many different versions, but no idea how to combine them all. // // Official Glide64 development channel: #Glide64 on EFnet // // Original author: Dave2001 (Dave2999@hotmail.com) // Other authors: Gonetz, Gugaman // //**************************************************************** #define M64P_PLUGIN_PROTOTYPES 1 #include "m64p_types.h" #include "m64p_plugin.h" #include "m64p_config.h" #include "m64p_vidext.h" #include "3dmath.h" #include "Util.h" #include "Debugger.h" #include "Combine.h" #include "Util.h" #include "Ini.h" #include "Config.h" #include "Tmem.h" #include "TexCache.h" #include "TexCache.h" #include "TexBuffer.h" #include "CRC.h" #include "rdp.h" #ifndef _WIN32 #include #endif // _WIN32 char out_buf[2048]; DWORD frame_count; // frame counter BOOL ucode_error_report = TRUE; int wrong_tile = -1; int drawFlag = 1; // draw flag for rendering callback #if defined(__GNUC__) #define bswap32(x) __builtin_bswap32(x) #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) #include #define bswap32(x) _byteswap_ulong(x) #else static inline uint32_t bswap32(uint32_t val) { return (((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24)); } #endif // global strings const char *ACmp[4] = { "NONE", "THRESHOLD", "UNKNOWN", "DITHER" }; const char *Mode0[16] = { "COMBINED", "TEXEL0", "TEXEL1", "PRIMITIVE", "SHADE", "ENVIORNMENT", "1", "NOISE", "0", "0", "0", "0", "0", "0", "0", "0" }; const char *Mode1[16] = { "COMBINED", "TEXEL0", "TEXEL1", "PRIMITIVE", "SHADE", "ENVIORNMENT", "CENTER", "K4", "0", "0", "0", "0", "0", "0", "0", "0" }; const char *Mode2[32] = { "COMBINED", "TEXEL0", "TEXEL1", "PRIMITIVE", "SHADE", "ENVIORNMENT", "SCALE", "COMBINED_ALPHA", "T0_ALPHA", "T1_ALPHA", "PRIM_ALPHA", "SHADE_ALPHA", "ENV_ALPHA", "LOD_FRACTION", "PRIM_LODFRAC", "K5", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0" }; const char *Mode3[8] = { "COMBINED", "TEXEL0", "TEXEL1", "PRIMITIVE", "SHADE", "ENVIORNMENT", "1", "0" }; const char *Alpha0[8] = { "COMBINED", "TEXEL0", "TEXEL1", "PRIMITIVE", "SHADE", "ENVIORNMENT", "1", "0" }; const char *Alpha2[8] = { "LOD_FRACTION", "TEXEL0", "TEXEL1", "PRIMITIVE", "SHADE", "ENVIORNMENT", "PRIM_LODFRAC", "0" }; //FIXME:unused? //const char *FBLa[] = { "G_BL_CLR_IN", "G_BL_CLR_MEM", "G_BL_CLR_BL", "G_BL_CLR_FOG" }; //const char *FBLb[] = { "G_BL_A_IN", "G_BL_A_FOG", "G_BL_A_SHADE", "G_BL_0" }; //const char *FBLc[] = { "G_BL_CLR_IN", "G_BL_CLR_MEM", "G_BL_CLR_BL", "G_BL_CLR_FOG"}; //const char *FBLd[] = { "G_BL_1MA", "G_BL_A_MEM", "G_BL_1", "G_BL_0" }; const char *str_zs[2] = { "G_ZS_PIXEL", "G_ZS_PRIM" }; const char *str_yn[2] = { "NO", "YES" }; const char *str_offon[2] = { "OFF", "ON" }; const char *str_cull[4] = { "DISABLE", "FRONT", "BACK", "BOTH" }; // I=intensity probably const char *str_format[8] = { "RGBA", "YUV", "CI", "IA", "I", "?", "?", "?" }; const char *str_size[4] = { "4bit", "8bit", "16bit", "32bit" }; const char *str_cm[4] = { "WRAP/NO CLAMP", "MIRROR/NO CLAMP", "WRAP/CLAMP", "MIRROR/CLAMP" }; //const char *str_lod[] = { "1", "2", "4", "8", "16", "32", "64", "128", "256" }; //const char *str_aspect[] = { "1x8", "1x4", "1x2", "1x1", "2x1", "4x1", "8x1" }; const char *str_filter[3] = { "Point Sampled", "Average (box)", "Bilinear" }; const char *str_tlut[4] = { "TT_NONE", "TT_UNKNOWN", "TT_RGBA_16", "TT_IA_16" }; const char *CIStatus[10] = { "ci_main", "ci_zimg", "ci_unknown", "ci_useless", "ci_old_copy", "ci_copy", "ci_copy_self", "ci_zcopy", "ci_aux", "ci_aux_copy" }; typedef struct { int ucode; int crc; } UcodeData; static UcodeData UcodeList[] = { {0, 0x006bd77f}, {2, 0x03044b84}, {2, 0x030f4b84}, {1, 0x05165579}, {1, 0x05777c62}, {1, 0x057e7c62}, {1, 0x07200895}, {2, 0x0bf36d36}, {-1, 0x0d7bbffb}, {5, 0x0d7cbffb}, {2, 0x0ff79527}, {-1, 0x0ff795bf}, {1, 0x1118b3e0}, {2, 0x168e9cd5}, {2, 0x1a1e18a0}, {2, 0x1a1e1920}, {2, 0x1a62dbaf}, {2, 0x1a62dc2f}, {1, 0x1de712ff}, {6, 0x1ea9e30f}, {2, 0x21f91834}, {2, 0x21f91874}, {2, 0x22099872}, {1, 0x24cd885b}, {1, 0x26a7879a}, {6, 0x299d5072}, {2, 0x2b291027}, {6, 0x2b5a89c2}, {1, 0x2c7975d6}, {2, 0x2f71d1d5}, {2, 0x2f7dd1d5}, {1, 0x327b933d}, {1, 0x339872a6}, {2, 0x377359b6}, {0, 0x3a1c2b34}, {0, 0x3a1cbac3}, {0, 0x3f7247fb}, {1, 0x3ff1a4ca}, {0, 0x4165e1fd}, {1, 0x4340ac9b}, {1, 0x440cfad6}, {7, 0x47d46e86}, {2, 0x485abff2}, {1, 0x4fe6df78}, {0, 0x5182f610}, {1, 0x5257cd2a}, {1, 0x5414030c}, {1, 0x5414030d}, {1, 0x559ff7d4}, {4, 0x5b5d36e3}, {3, 0x5b5d3763}, {0, 0x5d1d6f53}, {2, 0x5d3099f1}, {1, 0x5df1408c}, {1, 0x5ef4e34a}, {1, 0x6075e9eb}, {1, 0x60c1dcc4}, {2, 0x6124a508}, {2, 0x630a61fb}, {5, 0x63be08b1}, {5, 0x63be08b3}, {1, 0x64ed27e5}, {2, 0x65201989}, {2, 0x65201a09}, {1, 0x66c0b10a}, {2, 0x679e1205}, {6, 0x6bb745c9}, {2, 0x6d8f8f8a}, {0, 0x6e4d50af}, {1, 0x6eaa1da8}, {1, 0x72a4f34e}, {1, 0x73999a23}, {6, 0x74af0a74}, {2, 0x753be4a5}, {6, 0x794c3e28}, {1, 0x7df75834}, {1, 0x7f2d0a2e}, {1, 0x82f48073}, {1, 0x841ce10f}, {-1, 0x844b55b5}, {1, 0x863e1ca7}, {-1, 0x86b1593e}, {1, 0x8805ffea}, {1, 0x8d5735b2}, {1, 0x8d5735b3}, {-1, 0x8ec3e124}, {2, 0x93d11f7b}, {2, 0x93d11ffb}, {2, 0x93d1ff7b}, {2, 0x9551177b}, {2, 0x955117fb}, {2, 0x95cd0062}, {1, 0x97d1b58a}, {2, 0xa2d0f88e}, {1, 0xa346a5cc}, {2, 0xaa86cb1d}, {2, 0xaae4a5b9}, {2, 0xad0a6292}, {2, 0xad0a6312}, {0, 0xae08d5b9}, {1, 0xb1821ed3}, {1, 0xb4577b9c}, {0, 0xb54e7f93}, {2, 0xb62f900f}, {2, 0xba65ea1e}, {8, 0xba86cb1d}, {0, 0xbc03e969}, {2, 0xbc45382e}, {1, 0xbe78677c}, {1, 0xbed8b069}, {1, 0xc3704e41}, {1, 0xc46dbc3d}, {1, 0xc99a4c6c}, {2, 0xc901ce73}, {2, 0xc901cef3}, {2, 0xcb8c9b6c}, {1, 0xcee7920f}, {2, 0xcfa35a45}, {1, 0xd1663234}, {6, 0xd20dedbf}, {1, 0xd2a9f59c}, {1, 0xd41db5f7}, {0, 0xd5604971}, {1, 0xd57049a5}, {-1, 0xd5c4dc96}, {0, 0xd5d68b1f}, {1, 0xd802ec04}, {2, 0xda13ab96}, {2, 0xde7d67d4}, {2, 0xe1290fa2}, {0, 0xe41ec47e}, {2, 0xe65cb4ad}, {1, 0xe89c2b92}, {1, 0xe9231df2}, {1, 0xec040469}, {1, 0xee47381b}, {1, 0xef54ee35}, {-1, 0xf9893f70}, {1, 0xfb816260}, {-1, 0xff372492} }; // ZIGGY // depth save/restore variables // 0 : normal mode // 1 : writing in normal depth buffer // 2 : writing in alternate depth buffer static int render_depth_mode; // ** RDP graphics functions ** static void undef(); static void spnoop(); static void rdp_noop(); static void rdp_texrect(); //static void rdp_texrectflip(); static void rdp_loadsync(); static void rdp_pipesync(); static void rdp_tilesync(); static void rdp_fullsync(); static void rdp_setkeygb(); static void rdp_setkeyr(); static void rdp_setconvert(); static void rdp_setscissor(); static void rdp_setprimdepth(); static void rdp_setothermode(); static void rdp_loadtlut(); static void rdp_settilesize(); static void rdp_loadblock(); static void rdp_loadtile(); static void rdp_settile(); static void rdp_fillrect(); static void rdp_setfillcolor(); static void rdp_setfogcolor(); static void rdp_setblendcolor(); static void rdp_setprimcolor(); static void rdp_setenvcolor(); static void rdp_setcombine(); static void rdp_settextureimage(); static void rdp_setdepthimage(); static void rdp_setcolorimage(); static void rdp_trifill(); static void rdp_trishade(); static void rdp_tritxtr(); static void rdp_trishadetxtr(); static void rdp_trifillz(); static void rdp_trishadez(); static void rdp_tritxtrz(); static void rdp_trishadetxtrz(); static void rsp_reserved0(); static void rsp_reserved1(); static void rsp_reserved2(); static void rsp_reserved3(); static void ys_memrect(); BYTE microcode[4096]; DWORD uc_crc; void microcheck (); // ** UCODE FUNCTIONS ** #include "Ucode00.h" #include "ucode01.h" #include "ucode02.h" #include "ucode03.h" #include "ucode04.h" #include "ucode05.h" #include "ucode06.h" #include "ucode07.h" #include "ucode08.h" #include "ucode.h" static BOOL reset = 0; static int old_ucode = -1; // rdp_reset - resets the RDP_E void rdp_reset () { reset = 1; rdp.model_i = 0; rdp.n_cached[0] = 0; rdp.n_cached[1] = 0; rdp.cur_cache[0] = NULL; rdp.cur_cache[1] = NULL; /* rdp.tmem_ptr[0] = offset_textures; rdp.tmem_ptr[1] = offset_textures; if (grTextureBufferExt) rdp.tmem_ptr[1] = TEXMEM_2MB_EDGE * 2; */ rdp.c_a0 = 0; rdp.c_b0 = 0; rdp.c_c0 = 0; rdp.c_d0 = 0; rdp.c_Aa0 = 0; rdp.c_Ab0 = 0; rdp.c_Ac0 = 0; rdp.c_Ad0 = 0; rdp.c_a1 = 0; rdp.c_b1 = 0; rdp.c_c1 = 0; rdp.c_d1 = 0; rdp.c_Aa1 = 0; rdp.c_Ab1 = 0; rdp.c_Ac1 = 0; rdp.c_Ad1 = 0; // Clear the palette CRC int i; for (i=0; i<16; i++) rdp.pal_8_crc[i] = 0; // Clear the palettes for (i=0; i<256; i++) rdp.pal_8[i] = 0; rdp.tlut_mode = 0; // Clear all segments ** VERY IMPORTANT FOR ZELDA ** for (i=0; i<16; i++) rdp.segment[i] = 0; for (i=0; i<512; i++) rdp.addr[i] = 0; // set all vertex numbers for (i=0; i>2; i++) { uc_crc += ((DWORD*)microcode)[i]; } FRDP_E ("crc: %08lx\n", uc_crc); #ifdef LOG_UCODE std::ofstream ucf; ucf.open ("ucode.txt", ios::out | ios::binary); char d; for (i=0; i<0x400000; i++) { d = ((char*)gfx.RDRAM)[i^3]; ucf.write (&d, 1); } ucf.close (); #endif char str[9]; sprintf (str, "%08lx", (unsigned long)uc_crc); FRDP("ucode = %s\n", str); int uc = LookupUcode(uc_crc); WriteLog(M64MSG_INFO, "ucode = %d\n", uc); if (uc == -2 && ucode_error_report) { Config_Open(); settings.ucode = Config_ReadInt ("ucode", "Force microcode", 0, FALSE, FALSE); ReleaseGfx (); WriteLog(M64MSG_ERROR, "Error: uCode crc not found in INI, using currently selected uCode\n\n%08lx", (unsigned long)uc_crc); ucode_error_report = FALSE; // don't report any more ucode errors from this game } else if (uc == -1 && ucode_error_report) { Config_Open(); settings.ucode = Config_ReadInt ("ucode", "Force microcode", 0, FALSE, FALSE); ReleaseGfx (); WriteLog(M64MSG_ERROR, "Error: Unsupported uCode!\n\ncrc: %08lx", (unsigned long)uc_crc); ucode_error_report = FALSE; // don't report any more ucode errors from this game } else { old_ucode = settings.ucode; settings.ucode = uc; FRDP("microcheck: old ucode: %d, new ucode: %d\n", old_ucode, uc); } } void drawNoFullscreenMessage() { LOG ("drawNoFullscreenMessage ()\n"); } static WORD yuv_to_rgb(BYTE y, BYTE u, BYTE v) { float r = y + (1.370705f * (v-128)); float g = y - (0.698001f * (v-128)) - (0.337633f * (u-128)); float b = y + (1.732446f * (u-128)); r *= 0.125f; g *= 0.125f; b *= 0.125f; //clipping the result if (r > 32) r = 32; if (g > 32) g = 32; if (b > 32) b = 32; if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0; WORD c = (WORD)(((WORD)(r) << 11) | ((WORD)(g) << 6) | ((WORD)(b) << 1) | 1); return c; } static void DrawYUVImageToFrameBuffer() { WORD width = (WORD)(rdp.yuv_lr_x - rdp.yuv_ul_x); WORD height = (WORD)(rdp.yuv_lr_y - rdp.yuv_ul_y); DWORD * mb = (DWORD*)(gfx.RDRAM+rdp.yuv_im_begin); //pointer to the first macro block WORD * cimg = (WORD*)(gfx.RDRAM+rdp.cimg); //yuv macro block contains 16x16 texture. we need to put it in the proper place inside cimg for (WORD y = 0; y < height; y+=16) { for (WORD x = 0; x < width; x+=16) { WORD *dst = cimg + x + y * rdp.ci_width; for (WORD h = 0; h < 16; h++) { for (WORD w = 0; w < 8; w++) { DWORD t = *(mb++); //each DWORD contains 2 pixels if ((x < rdp.ci_width) && (y < rdp.ci_height)) //clipping. texture image may be larger than color image { BYTE y0 = (BYTE)t&0xFF; BYTE v = (BYTE)(t>>8)&0xFF; BYTE y1 = (BYTE)(t>>16)&0xFF; BYTE u = (BYTE)(t>>24)&0xFF; *(dst++) = yuv_to_rgb(y0, u, v); *(dst++) = yuv_to_rgb(y1, u, v); } } dst += rdp.ci_width - 16; } mb += 64; //macro block is 768 bytes long, last 256 bytes are useless } } } static DWORD d_ul_x, d_ul_y, d_lr_x, d_lr_y; typedef struct { int ul_x, ul_y, lr_x, lr_y; } FB_PART; static void DrawPart(int scr_ul_x, int scr_ul_y, int prt_ul_x, int prt_ul_y, int width, int height, float scale_x, float scale_y) { WORD * dst = new WORD[width*height]; DWORD shift = ((d_ul_y+prt_ul_y) * rdp.ci_width + d_ul_x + prt_ul_x) << 1; WORD * src = (WORD*)(gfx.RDRAM+rdp.cimg+shift); WORD c; for (int y=0; y < height; y++) { for (int x=0; x < width; x++) { c = src[(int(x*scale_x)+int(y*scale_y)*rdp.ci_width)^1]; dst[x+y*width] = c?((c >> 1) | 0x8000):0; } } grLfbWriteRegion(GR_BUFFER_BACKBUFFER, scr_ul_x, scr_ul_y, GR_LFB_SRC_FMT_1555, width, height, FXTRUE, width<<1, dst); delete[] dst; } static void DrawFrameBufferToScreen() { FRDP("DrawFrameBufferToScreen. cimg: %08lx, ul_x: %d, uly: %d, lr_x: %d, lr_y: %d\n", rdp.cimg, d_ul_x, d_ul_y, d_lr_x, d_lr_y); if (!fullscreen) return; grColorCombine (GR_COMBINE_FUNCTION_SCALE_OTHER, GR_COMBINE_FACTOR_ONE, GR_COMBINE_LOCAL_NONE, GR_COMBINE_OTHER_TEXTURE, FXFALSE); grAlphaCombine (GR_COMBINE_FUNCTION_SCALE_OTHER, GR_COMBINE_FACTOR_ONE, GR_COMBINE_LOCAL_NONE, GR_COMBINE_OTHER_TEXTURE, FXFALSE); grConstantColorValue (0xFFFFFFFF); grAlphaBlendFunction( GR_BLEND_SRC_ALPHA, GR_BLEND_ONE_MINUS_SRC_ALPHA, GR_BLEND_ONE, GR_BLEND_ZERO); rdp.update |= UPDATE_COMBINE; float scale_x_dst = (float)settings.scr_res_x / rdp.vi_width;//(float)max(rdp.frame_buffers[rdp.main_ci_index].width, rdp.ci_width); float scale_y_dst = (float)settings.scr_res_y / rdp.vi_height;//(float)max(rdp.frame_buffers[rdp.main_ci_index].height, rdp.ci_lower_bound); float scale_x_src = (float)rdp.vi_width / (float)settings.scr_res_x;//(float)max(rdp.frame_buffers[rdp.main_ci_index].width, rdp.ci_width); float scale_y_src = (float)rdp.vi_height / (float)settings.scr_res_y;//(float)max(rdp.frame_buffers[rdp.main_ci_index].height, rdp.ci_lower_bound); int src_width = d_lr_x - d_ul_x + 1; int src_height = d_lr_y - d_ul_y + 1; int dst_width, dst_height, ul_x, ul_y; if (!settings.fb_optimize_write || ((src_width < 33) && (src_height < 33))) { dst_width = int(src_width*scale_x_dst); dst_height = int(src_height*scale_y_dst); ul_x = int(d_ul_x*scale_x_dst); ul_y = int(d_ul_y*scale_y_dst); DrawPart(ul_x, ul_y, 0, 0, dst_width, dst_height, scale_x_src, scale_y_src); memset(gfx.RDRAM+rdp.cimg, 0, rdp.ci_width*rdp.ci_height*rdp.ci_size); return; } FB_PART parts[8]; int p; for (p = 0; p < 8; p++) { parts[p].lr_x = parts[p].lr_y = 0; parts[p].ul_x = parts[p].ul_y = 0xFFFF; } int num_of_parts = 0; int cur_part = 0; int most_left = d_ul_x; int most_right = d_lr_x; DWORD shift = (d_ul_y * rdp.ci_width + d_ul_x) << 1; WORD * src = (WORD*)(gfx.RDRAM+rdp.cimg+shift); for (int h = 0; h < src_height; h++) { cur_part = 0; int w = 0; while (w < src_width) { while (w < src_width) { if (src[(w+h*rdp.ci_width)^1] == 0) w++; else break; } if (w == src_width) break; if (num_of_parts == 0) //first part { parts[0].ul_x = w; most_left = w; parts[0].ul_y = h; cur_part = 0; } else if (w < most_left - 2) //new part { parts[num_of_parts].ul_x = w; most_left = w; parts[num_of_parts].ul_y = h; cur_part = num_of_parts; num_of_parts++; } else if (w > most_right + 2) //new part { parts[num_of_parts].ul_x = w; most_right = w; parts[num_of_parts].ul_y = h; cur_part = num_of_parts; num_of_parts++; } else { for (p = 0; p < num_of_parts; p++) { if ((w > parts[p].ul_x - 2) && (w < parts[p].lr_x+2)) { if (w < parts[p].ul_x) parts[p].ul_x = w; break; } } cur_part = p; } while (w < src_width) { if (src[(w+h*rdp.ci_width)^1] != 0) w++; else break; } if (num_of_parts == 0) //first part { parts[0].lr_x = w; most_right = w; num_of_parts++; } else { if (parts[cur_part].lr_x < w) parts[cur_part].lr_x = w; if (most_right < w) most_right = w; parts[cur_part].lr_y = h; } } } /* for (p = 0; p < num_of_parts; p++) { FRDP("part#%d ul_x: %d, ul_y: %d, lr_x: %d, lr_y: %d\n", p, parts[p].ul_x, parts[p].ul_y, parts[p].lr_x, parts[p].lr_y); } */ for (p = 0; p < num_of_parts; p++) { dst_width = int((parts[p].lr_x-parts[p].ul_x + 1)*scale_x_dst); dst_height = int((parts[p].lr_y-parts[p].ul_y + 1)*scale_y_dst); ul_x = int((d_ul_x+parts[p].ul_x)*scale_x_dst); ul_y = int((d_ul_y+parts[p].ul_y)*scale_y_dst); DrawPart(ul_x, ul_y, parts[p].ul_x, parts[p].ul_y, dst_width, dst_height, scale_x_src, scale_y_src); } memset(gfx.RDRAM+rdp.cimg, 0, rdp.ci_width*rdp.ci_height*rdp.ci_size); } #define RGBA16TO32(color) \ ((color&1)?0xFF:0) | \ ((DWORD)((float)((color&0xF800) >> 11) / 31.0f * 255.0f) << 24) | \ ((DWORD)((float)((color&0x07C0) >> 6) / 31.0f * 255.0f) << 16) | \ ((DWORD)((float)((color&0x003E) >> 1) / 31.0f * 255.0f) << 8) static void CopyFrameBuffer (GrBuffer_t buffer = GR_BUFFER_BACKBUFFER) { if (!fullscreen) return; FRDP ("CopyFrameBuffer: %08lx... ", rdp.cimg); // don't bother to write the stuff in asm... the slow part is the read from video card, // not the copy. int width = rdp.ci_width;//*gfx.VI_WIDTH_REG; int height; if (settings.fb_smart && !settings.PPL) { int ind = (rdp.ci_count > 0)?rdp.ci_count-1:0; height = rdp.frame_buffers[ind].height; } else { height = rdp.ci_lower_bound; if (settings.PPL) height -= rdp.ci_upper_bound; } FRDP ("width: %d, height: %d... ", width, height); if (rdp.scale_x < 1.1f) { WORD * ptr_src = new WORD[width*height]; if (grLfbReadRegion(buffer, 0, 0,//rdp.ci_upper_bound, width, height, width<<1, ptr_src)) { WORD *ptr_dst = (WORD*)(gfx.RDRAM+rdp.cimg); DWORD *ptr_dst32 = (DWORD*)(gfx.RDRAM+rdp.cimg); WORD c; for (int y=0; y 0) c = (c&0xFFC0) | ((c&0x001F) << 1) | 1; } else { c = (c&0xFFC0) | ((c&0x001F) << 1) | 1; } if (rdp.ci_size == 2) ptr_dst[(x + y * width)^1] = c; else ptr_dst32[x + y * width] = RGBA16TO32(c); } } /* } else //8bit I or CI { BYTE *ptr_dst = (BYTE*)(gfx.RDRAM+rdp.cimg); WORD c; for (int y=0; y>5)&0x3F)/63.0f*85.0f); BYTE r = (BYTE)((float)((c>>11)&0x1F)/31.0f*85.0f); c = (c&0xFFC0) | ((c&0x001F) << 1) | 1; // FRDP("src: %08lx, dst: %d\n",c,(BYTE)(r+g+b)); ptr_dst[(x + y * width)^1] = (BYTE)(r+g+b); // ptr_dst[(x + y * width)^1] = (BYTE)((c>>8)&0xFF); } } } */ RDP ("ReadRegion. Framebuffer copy complete.\n"); } else { RDP ("Framebuffer copy failed.\n"); } delete[] ptr_src; } else { if (rdp.motionblur && settings.fb_hires) { return; } else { float scale_x = (float)settings.scr_res_x / rdp.vi_width;//(float)max(rdp.frame_buffers[rdp.main_ci_index].width, rdp.ci_width); float scale_y = (float)settings.scr_res_y / rdp.vi_height;//(float)max(rdp.frame_buffers[rdp.main_ci_index].height, rdp.ci_lower_bound); FRDP("width: %d, height: %d, ul_y: %d, lr_y: %d, scale_x: %f, scale_y: %f, ci_width: %d, ci_height: %d\n",width, height, rdp.ci_upper_bound, rdp.ci_lower_bound, scale_x, scale_y, rdp.ci_width, rdp.ci_height); GrLfbInfo_t info; info.size = sizeof(GrLfbInfo_t); // VP 888 disconnected for now if (1||rdp.ci_size <= 2) { if (grLfbLock (GR_LFB_READ_ONLY, buffer, GR_LFBWRITEMODE_565, GR_ORIGIN_UPPER_LEFT, FXFALSE, &info)) { WORD *ptr_src = (WORD*)info.lfbPtr; WORD *ptr_dst = (WORD*)(gfx.RDRAM+rdp.cimg); DWORD *ptr_dst32 = (DWORD*)(gfx.RDRAM+rdp.cimg); WORD c; DWORD stride = info.strideInBytes>>1; BOOL read_alpha = settings.fb_read_alpha; if (settings.PM && rdp.frame_buffers[rdp.ci_count-1].status != ci_aux) read_alpha = FALSE; for (int y=0; y>1; for (int y=0; y 0) SwapOK = TRUE; rdp.updatescreen = 1; rdp.tri_n = 0; // 0 triangles so far this frame rdp.debug_n = 0; rdp.model_i = 0; // 0 matrices so far in stack //stack_size can be less then 32! Important for Silicon Vally. Thanks Orkin! rdp.model_stack_size = min(32, (*(DWORD*)(gfx.DMEM+0x0FE4))>>6); if (rdp.model_stack_size == 0) rdp.model_stack_size = 32; rdp.fb_drawn = rdp.fb_drawn_front = FALSE; rdp.update = 0x7FFFFFFF; // All but clear cache rdp.geom_mode = 0; rdp.acmp = 0; rdp.maincimg[1] = rdp.maincimg[0]; rdp.skip_drawing = FALSE; rdp.s2dex_tex_loaded = FALSE; fbreads_front = fbreads_back = 0; rdp.fog_multiplier = rdp.fog_offset = 0; rdp.zsrc = 0; if (cpu_fb_write == TRUE) DrawFrameBufferToScreen(); cpu_fb_write = FALSE; cpu_fb_read_called = FALSE; cpu_fb_write_called = FALSE; cpu_fb_ignore = FALSE; d_ul_x = 0xffff; d_ul_y = 0xffff; d_lr_x = 0; d_lr_y = 0; //analize possible frame buffer usage if (settings.fb_smart) DetectFrameBufferUsage(); if (!settings.lego || rdp.num_of_ci > 1) rdp.last_bg = 0; //* End of set states *// // Get the start of the display list and the length of it DWORD dlist_start = *(DWORD*)(gfx.DMEM+0xFF0); DWORD dlist_length = *(DWORD*)(gfx.DMEM+0xFF4); FRDP("--- NEW DLIST --- crc: %08lx, ucode: %d, fbuf: %08lx, fbuf_width: %d, dlist start: %08lx, dlist_lenght: %d\n", uc_crc, settings.ucode, *gfx.VI_ORIGIN_REG, *gfx.VI_WIDTH_REG, dlist_start, dlist_length); FRDP_E("--- NEW DLIST --- crc: %08lx, ucode: %d, fbuf: %08lx\n", uc_crc, settings.ucode, *gfx.VI_ORIGIN_REG); if (settings.tonic && dlist_length < 16) { rdp_fullsync(); FRDP_E("DLIST is too short!\n"); return; } // Start executing at the start of the display list rdp.pc_i = 0; rdp.pc[rdp.pc_i] = dlist_start; rdp.dl_count = -1; rdp.halt = 0; DWORD a; // catches exceptions so that it doesn't freeze #ifdef CATCH_EXCEPTIONS try { #endif // MAIN PROCESSING LOOP do { // Get the address of the next command a = rdp.pc[rdp.pc_i] & BMASK; // Load the next command and its input rdp.cmd0 = ((DWORD*)gfx.RDRAM)[a>>2]; // \ Current command, 64 bit rdp.cmd1 = ((DWORD*)gfx.RDRAM)[(a>>2)+1]; // / // cmd2 and cmd3 are filled only when needed, by the function that needs them // Output the address before the command #ifdef LOG_COMMANDS FRDP ("%08lx (c0:%08lx, c1:%08lx): ", a, rdp.cmd0, rdp.cmd1); #else FRDP ("%08lx: ", a); #endif // Go to the next instruction rdp.pc[rdp.pc_i] = (a+8) & BMASK; #ifdef PERFORMANCE QueryPerformanceCounter ((LARGE_INTEGER*)&perf_cur); #endif // Process this instruction gfx_instruction[settings.ucode][rdp.cmd0>>24] (); // check DL counter if (rdp.dl_count != -1) { rdp.dl_count --; if (rdp.dl_count == 0) { rdp.dl_count = -1; RDP ("End of DL\n"); rdp.pc_i --; } } #ifdef PERFORMANCE QueryPerformanceCounter ((LARGE_INTEGER*)&perf_next); __int64 t = perf_next-perf_cur; sprintf (out_buf, "perf %08lx: %016I64d\n", a-8, t); rdp_log << out_buf; #endif } while (!rdp.halt); #ifdef CATCH_EXCEPTIONS } catch (...) { if (fullscreen) ReleaseGfx (); WriteLog(M64MSG_ERROR, "The GFX plugin caused an exception and has been disabled."); exception = TRUE; } #endif if (settings.fb_smart) { rdp.scale_x = rdp.scale_x_bak; rdp.scale_y = rdp.scale_y_bak; } if (settings.fb_read_always) { CopyFrameBuffer (); } if (rdp.yuv_image) { DrawYUVImageToFrameBuffer(); rdp.yuv_image = FALSE; // FRDP("yuv image draw. ul_x: %f, ul_y: %f, lr_x: %f, lr_y: %f, begin: %08lx\n", // rdp.yuv_ul_x, rdp.yuv_ul_y, rdp.yuv_lr_x, rdp.yuv_lr_y, rdp.yuv_im_begin); rdp.yuv_ul_x = rdp.yuv_ul_y = rdp.yuv_lr_x = rdp.yuv_lr_y = 0; rdp.yuv_im_begin = 0x00FFFFFF; } if (rdp.cur_image) CloseTextureBuffer(rdp.read_whole_frame && (settings.PM || rdp.swap_ci_index >= 0)); if (settings.TGR2 && rdp.vi_org_reg != *gfx.VI_ORIGIN_REG && CI_SET) { newSwapBuffers (); CI_SET = FALSE; } RDP("ProcessDList end\n"); } #ifdef __cplusplus } #endif // undef - undefined instruction, always ignore static void undef() { FRDP_E("** undefined ** (%08lx)\n", rdp.cmd0); FRDP("** undefined ** (%08lx) - IGNORED\n", rdp.cmd0); #ifdef _FINAL_RELEASE_ *gfx.MI_INTR_REG |= 0x20; gfx.CheckInterrupts(); rdp.halt = 1; #endif } // spnoop - no operation, always ignore static void spnoop() { RDP("spnoop\n"); } // noop - no operation, always ignore static void rdp_noop() { RDP("noop\n"); } static void ys_memrect () { DWORD tile = (WORD)((rdp.cmd1 & 0x07000000) >> 24); DWORD lr_x = (WORD)((rdp.cmd0 & 0x00FFF000) >> 14); DWORD lr_y = (WORD)((rdp.cmd0 & 0x00000FFF) >> 2); DWORD ul_x = (WORD)((rdp.cmd1 & 0x00FFF000) >> 14); DWORD ul_y = (WORD)((rdp.cmd1 & 0x00000FFF) >> 2); rdp.pc[rdp.pc_i] += 16; // texrect is 196-bit if (lr_y > rdp.scissor_o.lr_y) lr_y = rdp.scissor_o.lr_y; FRDP ("memrect (%d, %d, %d, %d), ci_width: %d\n", ul_x, ul_y, lr_x, lr_y, rdp.ci_width); DWORD y, width = lr_x - ul_x; DWORD texaddr = rdp.addr[rdp.tiles[tile].t_mem]; DWORD tex_width = rdp.tiles[tile].line << 3; for (y = ul_y; y < lr_y; y++) { BYTE *src = gfx.RDRAM + texaddr + (y - ul_y) * tex_width; BYTE *dst = gfx.RDRAM + rdp.cimg + ul_x + y * rdp.ci_width; memcpy (dst, src, width); } } static void pm_palette_mod () { BYTE envr = (BYTE)((float)((rdp.env_color >> 24)&0xFF)/255.0f*31.0f); BYTE envg = (BYTE)((float)((rdp.env_color >> 16)&0xFF)/255.0f*31.0f); BYTE envb = (BYTE)((float)((rdp.env_color >> 8)&0xFF)/255.0f*31.0f); WORD env16 = (WORD)((envr<<11)|(envg<<6)|(envb<<1)|1); BYTE prmr = (BYTE)((float)((rdp.prim_color >> 24)&0xFF)/255.0f*31.0f); BYTE prmg = (BYTE)((float)((rdp.prim_color >> 16)&0xFF)/255.0f*31.0f); BYTE prmb = (BYTE)((float)((rdp.prim_color >> 8)&0xFF)/255.0f*31.0f); WORD prim16 = (WORD)((prmr<<11)|(prmg<<6)|(prmb<<1)|1); WORD * dst = (WORD*)(gfx.RDRAM+rdp.cimg); for (int i = 0; i < 16; i++) { dst[i^1] = (rdp.pal_8[i]&1) ? prim16 : env16; } RDP("Texrect palette modification\n"); } static void rdp_texrect() { DWORD a = rdp.pc[rdp.pc_i]; rdp.cmd2 = ((DWORD*)gfx.RDRAM)[(a>>2)+1]; rdp.cmd3 = ((DWORD*)gfx.RDRAM)[(a>>2)+3]; if (settings.ASB) //modified Rice's hack for All-Star Baseball games { DWORD dwHalf1 = (((DWORD*)gfx.RDRAM)[(a>>2)+0]) >> 24; if ((dwHalf1 != 0xF1) && (dwHalf1 != 0xb3)) { rdp.pc[rdp.pc_i] += 16; } else { rdp.pc[rdp.pc_i] += 8; rdp.cmd3 = rdp.cmd2; rdp.cmd2 = 0; } } else if (settings.yoshi && settings.ucode == 6) { ys_memrect(); return; } else { rdp.pc[rdp.pc_i] += 16; // texrect is 196-bit } if (rdp.skip_drawing || (!settings.fb_smart && (rdp.cimg == rdp.zimg))) { if (settings.PM && rdp.ci_status == ci_useless) { pm_palette_mod (); } else { RDP("Texrect skipped\n"); } return; } if ((settings.ucode == 8) && rdp.cur_image && rdp.cur_image->format) { //FRDP("Wrong Texrect. texaddr: %08lx, cimg: %08lx, cimg_end: %08lx\n", rdp.timg.addr, rdp.maincimg[1].addr, rdp.maincimg[1].addr+rdp.ci_width*rdp.ci_height*rdp.ci_size); RDP("Shadow texrect is skipped.\n"); rdp.tri_n += 2; return; } WORD ul_x = (WORD)((rdp.cmd1 & 0x00FFF000) >> 14); WORD ul_y = (WORD)((rdp.cmd1 & 0x00000FFF) >> 2); WORD lr_x = (WORD)((rdp.cmd0 & 0x00FFF000) >> 14); WORD lr_y = (WORD)((rdp.cmd0 & 0x00000FFF) >> 2); if (ul_x >= lr_x) return; if (rdp.cycle_mode > 1 || settings.increase_texrect_edge) { lr_x++; lr_y++; } if (ul_y == lr_y) { lr_y ++; } //* if (rdp.hires_tex && settings.fb_optimize_texrect) { if (!rdp.hires_tex->drawn) { DRAWIMAGE d; d.imageX = 0; d.imageW = (WORD)rdp.hires_tex->width; d.frameX = ul_x; d.frameW = (WORD)(rdp.hires_tex->width);//(WORD)(ul_x + rdp.hires_tex->width);//lr_x; d.imageY = 0; d.imageH = (WORD)rdp.hires_tex->height; d.frameY = ul_y; d.frameH = (WORD)(rdp.hires_tex->height);//(ul_y + rdp.hires_tex->height); FRDP("texrect. ul_x: %d, ul_y: %d, lr_x: %d, lr_y: %d, width: %d, height: %d\n", ul_x, ul_y, lr_x, lr_y, rdp.hires_tex->width, rdp.hires_tex->height); d.scaleX = 1.0f; d.scaleY = 1.0f; DrawHiresImage(&d, rdp.hires_tex->width == rdp.ci_width); rdp.hires_tex->drawn = TRUE; } return; } //*/ // framebuffer workaround for Zelda: MM LOT if ((rdp.othermode_l & 0xFFFF0000) == 0x0f5a0000) return; /*Gonetz*/ //hack for Zelda MM. it removes black texrects which cover all geometry in "Link meets Zelda" cut scene if (settings.zelda && rdp.timg.addr >= rdp.cimg && rdp.timg.addr < rdp.ci_end) { FRDP("Wrong Texrect. texaddr: %08lx, cimg: %08lx, cimg_end: %08lx\n", rdp.cur_cache[0]->addr, rdp.cimg, rdp.cimg+rdp.ci_width*rdp.ci_height*2); rdp.tri_n += 2; return; } //* //hack for Banjo2. it removes black texrects under Banjo if (!settings.fb_hires && ((rdp.cycle1 << 16) | (rdp.cycle2 & 0xFFFF)) == 0xFFFFFFFF && (rdp.othermode_l & 0xFFFF0000) == 0x00500000) { rdp.tri_n += 2; return; } //*/ //* //remove motion blur in night vision if ((settings.ucode == 7) && (rdp.maincimg[1].addr != rdp.maincimg[0].addr) && (rdp.timg.addr >= rdp.maincimg[1].addr) && (rdp.timg.addr < (rdp.maincimg[1].addr+rdp.ci_width*rdp.ci_height*rdp.ci_size))) { if (settings.fb_smart) if (rdp.frame_buffers[rdp.ci_count-1].status == ci_copy_self || !settings.fb_motionblur) { // FRDP("Wrong Texrect. texaddr: %08lx, cimg: %08lx, cimg_end: %08lx\n", rdp.timg.addr, rdp.maincimg[1], rdp.maincimg[1]+rdp.ci_width*rdp.ci_height*rdp.ci_size); RDP("Wrong Texrect.\n"); rdp.tri_n += 2; return; } } //*/ int i; DWORD tile = (WORD)((rdp.cmd1 & 0x07000000) >> 24); // update MUST be at the beginning, b/c of update_scissor if (rdp.cycle_mode == 2) { rdp.tex = 1; rdp.allow_combine = 0; cmb.tmu1_func = cmb.tmu0_func = GR_COMBINE_FUNCTION_LOCAL; cmb.tmu1_fac = cmb.tmu0_fac = GR_COMBINE_FACTOR_NONE; cmb.tmu1_a_func = cmb.tmu0_a_func = GR_COMBINE_FUNCTION_LOCAL; cmb.tmu1_a_fac = cmb.tmu0_a_fac = GR_COMBINE_FACTOR_NONE; cmb.tmu1_invert = cmb.tmu0_invert = FXFALSE; cmb.tmu1_a_invert = cmb.tmu0_a_invert = FXFALSE; } rdp.texrecting = 1; DWORD prev_tile = rdp.cur_tile; rdp.cur_tile = tile; rdp.update |= UPDATE_COMBINE; update (); rdp.texrecting = 0; rdp.allow_combine = 1; if (!rdp.cur_cache[0]) { rdp.cur_tile = prev_tile; rdp.tri_n += 2; return; } // **** // ** Texrect offset by Gugaman ** float off_x = (float)((short)((rdp.cmd2 & 0xFFFF0000) >> 16)) / 32.0f; if ((int(off_x) == 512) && (rdp.timg.width < 512)) off_x = 0.0f; float off_y = (float)((short)(rdp.cmd2 & 0x0000FFFF)) / 32.0f; float dsdx = (float)((short)((rdp.cmd3 & 0xFFFF0000) >> 16)) / 1024.0f; float dtdy = (float)((short)(rdp.cmd3 & 0x0000FFFF)) / 1024.0f; if (rdp.cycle_mode == 2) dsdx /= 4.0f; float s_ul_x = ul_x * rdp.scale_x + rdp.offset_x; float s_lr_x = lr_x * rdp.scale_x + rdp.offset_x; float s_ul_y = ul_y * rdp.scale_y + rdp.offset_y; float s_lr_y = lr_y * rdp.scale_y + rdp.offset_y; FRDP("texrect (%d, %d, %d, %d), tile: %d, #%d, #%d\n", ul_x, ul_y, lr_x, lr_y, tile, rdp.tri_n, rdp.tri_n+1); FRDP ("(%f, %f) -> (%f, %f), s: (%d, %d) -> (%d, %d)\n", s_ul_x, s_ul_y, s_lr_x, s_lr_y, rdp.scissor.ul_x, rdp.scissor.ul_y, rdp.scissor.lr_x, rdp.scissor.lr_y); FRDP("\toff_x: %f, off_y: %f, dsdx: %f, dtdy: %f\n", off_x, off_y, dsdx, dtdy); float off_size_x; float off_size_y; if ( ((rdp.cmd0>>24)&0xFF) == 0xE5 ) //texrectflip { off_size_x = (float)((lr_y - ul_y - 1) * dsdx); off_size_y = (float)((lr_x - ul_x - 1) * dtdy); } else { off_size_x = (float)((lr_x - ul_x - 1) * dsdx); off_size_y = (float)((lr_y - ul_y - 1) * dtdy); } float lr_u0, lr_v0, ul_u0, ul_v0, lr_u1, lr_v1, ul_u1, ul_v1; if (rdp.cur_cache[0] && (rdp.tex & 1)) { float sx=1, sy=1; if (rdp.tiles[rdp.cur_tile].shift_s) { if (rdp.tiles[rdp.cur_tile].shift_s > 10) sx = (float)(1 << (16 - rdp.tiles[rdp.cur_tile].shift_s)); else sx = (float)1.0f/(1 << rdp.tiles[rdp.cur_tile].shift_s); } if (rdp.tiles[rdp.cur_tile].shift_t) { if (rdp.tiles[rdp.cur_tile].shift_t > 10) sy = (float)(1 << (16 - rdp.tiles[rdp.cur_tile].shift_t)); else sy = (float)1.0f/(1 << rdp.tiles[rdp.cur_tile].shift_t); } if (rdp.hires_tex && rdp.hires_tex->tile == 0) { off_x += rdp.hires_tex->u_shift;// + rdp.tiles[0].ul_s; //commented for Paper Mario motion blur off_y += rdp.hires_tex->v_shift;// + rdp.tiles[0].ul_t; FRDP("hires_tex ul_s: %d, ul_t: %d, off_x: %f, off_y: %f\n", rdp.tiles[0].ul_s, rdp.tiles[0].ul_t, off_x, off_y); ul_u0 = off_x * sx; ul_v0 = off_y * sy; lr_u0 = ul_u0 + off_size_x * sx; lr_v0 = ul_v0 + off_size_y * sy; ul_u0 *= rdp.hires_tex->u_scale; ul_v0 *= rdp.hires_tex->v_scale; lr_u0 *= rdp.hires_tex->u_scale; lr_v0 *= rdp.hires_tex->v_scale; FRDP("hires_tex ul_u0: %f, ul_v0: %f, lr_u0: %f, lr_v0: %f\n", ul_u0, ul_v0, lr_u0, lr_v0); } else { ul_u0 = off_x * sx; ul_v0 = off_y * sy; ul_u0 -= rdp.tiles[rdp.cur_tile].f_ul_s; ul_v0 -= rdp.tiles[rdp.cur_tile].f_ul_t; lr_u0 = ul_u0 + off_size_x * sx; lr_v0 = ul_v0 + off_size_y * sy; ul_u0 = rdp.cur_cache[0]->c_off + rdp.cur_cache[0]->c_scl_x * ul_u0; lr_u0 = rdp.cur_cache[0]->c_off + rdp.cur_cache[0]->c_scl_x * lr_u0; ul_v0 = rdp.cur_cache[0]->c_off + rdp.cur_cache[0]->c_scl_y * ul_v0; lr_v0 = rdp.cur_cache[0]->c_off + rdp.cur_cache[0]->c_scl_y * lr_v0; } } else { ul_u0 = ul_v0 = lr_u0 = lr_v0 = 0; } if (rdp.cur_cache[1] && (rdp.tex & 2)) { float sx=1, sy=1; if (rdp.tiles[rdp.cur_tile+1].shift_s) { if (rdp.tiles[rdp.cur_tile+1].shift_s > 10) sx = (float)(1 << (16 - rdp.tiles[rdp.cur_tile+1].shift_s)); else sx = (float)1.0f/(1 << rdp.tiles[rdp.cur_tile+1].shift_s); } if (rdp.tiles[rdp.cur_tile+1].shift_t) { if (rdp.tiles[rdp.cur_tile+1].shift_t > 10) sy = 1;//(float)(1 << (16 - rdp.tiles[rdp.cur_tile+1].shift_t)); else sy = (float)1.0f/(1 << rdp.tiles[rdp.cur_tile+1].shift_t); } if (rdp.hires_tex && rdp.hires_tex->tile == 1) { off_x += rdp.hires_tex->u_shift;// + rdp.tiles[0].ul_s; //commented for Paper Mario motion blur off_y += rdp.hires_tex->v_shift;// + rdp.tiles[0].ul_t; FRDP("hires_tex ul_s: %d, ul_t: %d, off_x: %f, off_y: %f\n", rdp.tiles[0].ul_s, rdp.tiles[0].ul_t, off_x, off_y); ul_u1 = off_x * sx; ul_v1 = off_y * sy; lr_u1 = ul_u1 + off_size_x * sx; lr_v1 = ul_v1 + off_size_y * sy; ul_u1 *= rdp.hires_tex->u_scale; ul_v1 *= rdp.hires_tex->v_scale; lr_u1 *= rdp.hires_tex->u_scale; lr_v1 *= rdp.hires_tex->v_scale; FRDP("hires_tex ul_u1: %f, ul_v1: %f, lr_u1: %f, lr_v1: %f\n", ul_u0, ul_v0, lr_u0, lr_v0); } else { ul_u1 = off_x * sx; ul_v1 = off_y * sy; ul_u1 -= rdp.tiles[rdp.cur_tile+1].f_ul_s; ul_v1 -= rdp.tiles[rdp.cur_tile+1].f_ul_t; lr_u1 = ul_u1 + off_size_x * sx; lr_v1 = ul_v1 + off_size_y * sy; ul_u1 = rdp.cur_cache[1]->c_off + rdp.cur_cache[1]->c_scl_x * ul_u1; lr_u1 = rdp.cur_cache[1]->c_off + rdp.cur_cache[1]->c_scl_x * lr_u1; ul_v1 = rdp.cur_cache[1]->c_off + rdp.cur_cache[1]->c_scl_y * ul_v1; lr_v1 = rdp.cur_cache[1]->c_off + rdp.cur_cache[1]->c_scl_y * lr_v1; } } else { ul_u1 = ul_v1 = lr_u1 = lr_v1 = 0; } rdp.cur_tile = prev_tile; // **** FRDP (" scissor: (%d, %d) -> (%d, %d)\n", rdp.scissor.ul_x, rdp.scissor.ul_y, rdp.scissor.lr_x, rdp.scissor.lr_y); CCLIP2 (s_ul_x, s_lr_x, ul_u0, lr_u0, ul_u1, lr_u1, (float)rdp.scissor.ul_x, (float)rdp.scissor.lr_x); CCLIP2 (s_ul_y, s_lr_y, ul_v0, lr_v0, ul_v1, lr_v1, (float)rdp.scissor.ul_y, (float)rdp.scissor.lr_y); // CCLIP2 (s_lr_y, s_ul_y, lr_v0, ul_v0, lr_v1, ul_v1, (float)rdp.scissor.ul_y, (float)rdp.scissor.lr_y); FRDP (" draw at: (%f, %f) -> (%f, %f)\n", s_ul_x, s_ul_y, s_lr_x, s_lr_y); // DO NOT SET CLAMP MODE HERE float Z = 1.0f; if (rdp.zsrc == 1 && (rdp.othermode_l & 0x00000030)) // othermode check makes sure it // USES the z-buffer. Otherwise it returns bad (unset) values for lot and telescope //in zelda:mm. { FRDP ("prim_depth = %d\n", rdp.prim_depth); Z = rdp.prim_depth; if (settings.increase_primdepth) Z += 8.0f; Z = ScaleZ(Z); grDepthBufferFunction (GR_CMP_LEQUAL); rdp.update |= UPDATE_ZBUF_ENABLED; } else { RDP ("no prim_depth used, using 1.0\n"); } VERTEX vstd[4] = { { s_ul_x, s_ul_y, Z, 1.0f, ul_u0, ul_v0, ul_u1, ul_v1, { 0, 0, 0, 0}, 255 }, { s_lr_x, s_ul_y, Z, 1.0f, lr_u0, ul_v0, lr_u1, ul_v1, { 0, 0, 0, 0}, 255 }, { s_ul_x, s_lr_y, Z, 1.0f, ul_u0, lr_v0, ul_u1, lr_v1, { 0, 0, 0, 0}, 255 }, { s_lr_x, s_lr_y, Z, 1.0f, lr_u0, lr_v0, lr_u1, lr_v1, { 0, 0, 0, 0}, 255 } }; if ( ((rdp.cmd0>>24)&0xFF) == 0xE5 ) //texrectflip { vstd[1].u0 = ul_u0; vstd[1].v0 = lr_v0; vstd[1].u1 = ul_u1; vstd[1].v1 = lr_v1; vstd[2].u0 = lr_u0; vstd[2].v0 = ul_v0; vstd[2].u1 = lr_u1; vstd[2].v1 = ul_v1; } VERTEX *vptr = vstd; int n_vertices = 4; VERTEX *vnew = 0; // for (int j =0; j < 4; j++) // FRDP("v[%d] u0: %f, v0: %f, u1: %f, v1: %f\n", j, vstd[j].u0, vstd[j].v0, vstd[j].u1, vstd[j].v1); if (!rdp.hires_tex && rdp.cur_cache[0]->splits != 1) { // ** LARGE TEXTURE HANDLING ** // *VERY* simple algebra for texrects float min_u, min_x, max_u, max_x; if (vstd[0].u0 < vstd[1].u0) { min_u = vstd[0].u0; min_x = vstd[0].x; max_u = vstd[1].u0; max_x = vstd[1].x; } else { min_u = vstd[1].u0; min_x = vstd[1].x; max_u = vstd[0].u0; max_x = vstd[0].x; } int start_u_256, end_u_256; if (settings.ucode == 7) { start_u_256 = 0; end_u_256 = (lr_x - ul_x - 1)>>8; } else { start_u_256 = (int)min_u >> 8; end_u_256 = (int)max_u >> 8; } //FRDP(" min_u: %f, max_u: %f start: %d, end: %d\n", min_u, max_u, start_u_256, end_u_256); int splitheight = rdp.cur_cache[0]->splitheight; int num_verts_line = 2 + ((end_u_256-start_u_256)<<1); vnew = new VERTEX [num_verts_line << 1]; n_vertices = num_verts_line << 1; vptr = vnew; vnew[0] = vstd[0]; vnew[0].u0 -= 256.0f * start_u_256; vnew[0].v0 += splitheight * start_u_256; vnew[0].u1 -= 256.0f * start_u_256; vnew[0].v1 += splitheight * start_u_256; vnew[1] = vstd[2]; vnew[1].u0 -= 256.0f * start_u_256; vnew[1].v0 += splitheight * start_u_256; vnew[1].u1 -= 256.0f * start_u_256; vnew[1].v1 += splitheight * start_u_256; vnew[n_vertices-2] = vstd[1]; vnew[n_vertices-2].u0 -= 256.0f * end_u_256; vnew[n_vertices-2].v0 += splitheight * end_u_256; vnew[n_vertices-2].u1 -= 256.0f * end_u_256; vnew[n_vertices-2].v1 += splitheight * end_u_256; vnew[n_vertices-1] = vstd[3]; vnew[n_vertices-1].u0 -= 256.0f * end_u_256; vnew[n_vertices-1].v0 += splitheight * end_u_256; vnew[n_vertices-1].u1 -= 256.0f * end_u_256; vnew[n_vertices-1].v1 += splitheight * end_u_256; // find the equation of the line of u,x float m = (max_x - min_x) / (max_u - min_u); // m = delta x / delta u float b = min_x - m * min_u; // b = y - m * x for (i=start_u_256; iu0 *= z->q; z->v0 *= z->q; z->u1 *= z->q; z->v1 *= z->q; apply_shade_mods (z); } if (fullscreen) { grFogMode (GR_FOG_DISABLE); grClipWindow (0, 0, settings.res_x, settings.res_y); grCullMode (GR_CULL_DISABLE); if (rdp.cycle_mode == 2) { grColorCombine (GR_COMBINE_FUNCTION_SCALE_OTHER, GR_COMBINE_FACTOR_ONE, GR_COMBINE_LOCAL_NONE, GR_COMBINE_OTHER_TEXTURE, FXFALSE); grAlphaCombine (GR_COMBINE_FUNCTION_SCALE_OTHER, GR_COMBINE_FACTOR_ONE, GR_COMBINE_LOCAL_NONE, GR_COMBINE_OTHER_TEXTURE, FXFALSE); grAlphaBlendFunction (GR_BLEND_ONE, GR_BLEND_ZERO, GR_BLEND_ZERO, GR_BLEND_ZERO); if (rdp.othermode_l & 1) { grAlphaTestFunction (GR_CMP_GEQUAL); grAlphaTestReferenceValue (0x80); } else grAlphaTestFunction (GR_CMP_ALWAYS); rdp.update |= UPDATE_ALPHA_COMPARE | UPDATE_COMBINE; } ConvertCoordsConvert (vptr, n_vertices); if (settings.wireframe) { SetWireframeCol (); grDrawLine (&vstd[0], &vstd[2]); grDrawLine (&vstd[2], &vstd[1]); grDrawLine (&vstd[1], &vstd[0]); grDrawLine (&vstd[2], &vstd[3]); grDrawLine (&vstd[3], &vstd[1]); } else { grDrawVertexArrayContiguous (GR_TRIANGLE_STRIP, n_vertices, vptr, sizeof(VERTEX)); } if (debug.capture) { VERTEX vl[3]; vl[0] = vstd[0]; vl[1] = vstd[2]; vl[2] = vstd[1]; add_tri (vl, 3, TRI_TEXRECT); rdp.tri_n ++; vl[0] = vstd[2]; vl[1] = vstd[3]; vl[2] = vstd[1]; add_tri (vl, 3, TRI_TEXRECT); rdp.tri_n ++; } else rdp.tri_n += 2; if (settings.fog && (rdp.flags & FOG_ENABLED)) { grFogMode (GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT); } rdp.update |= UPDATE_CULL_MODE | UPDATE_VIEWPORT; } else { rdp.tri_n += 2; } delete[] vnew; } static void rdp_loadsync() { RDP("loadsync - ignored\n"); } static void rdp_pipesync() { RDP("pipesync - ignored\n"); } static void rdp_tilesync() { RDP("tilesync - ignored\n"); } static void rdp_fullsync() { // Set an interrupt to allow the game to continue *gfx.MI_INTR_REG |= 0x20; gfx.CheckInterrupts(); RDP("fullsync\n"); } static void rdp_setkeygb() { RDP_E("setkeygb - IGNORED\n"); RDP("setkeygb - IGNORED\n"); } static void rdp_setkeyr() { RDP_E("setkeyr - IGNORED\n"); RDP("setkeyr - IGNORED\n"); } static void rdp_setconvert() { /* rdp.YUV_C0 = 1.1647f ; rdp.YUV_C1 = 0.79931f ; rdp.YUV_C2 = -0.1964f ; rdp.YUV_C3 = -0.40651f; rdp.YUV_C4 = 1.014f ; */ rdp.K5 = (BYTE)(rdp.cmd1&0x1FF); RDP_E("setconvert - IGNORED\n"); RDP("setconvert - IGNORED\n"); } // // setscissor - sets the screen clipping rectangle // static void rdp_setscissor() { // clipper resolution is 320x240, scale based on computer resolution rdp.scissor_o.ul_x = /*min(*/(DWORD)(((rdp.cmd0 & 0x00FFF000) >> 14))/*, 320)*/; rdp.scissor_o.ul_y = /*min(*/(DWORD)(((rdp.cmd0 & 0x00000FFF) >> 2))/*, 240)*/; rdp.scissor_o.lr_x = /*min(*/(DWORD)(((rdp.cmd1 & 0x00FFF000) >> 14))/*, 320)*/; rdp.scissor_o.lr_y = /*min(*/(DWORD)(((rdp.cmd1 & 0x00000FFF) >> 2))/*, 240)*/; rdp.ci_upper_bound = rdp.scissor_o.ul_y; rdp.ci_lower_bound = rdp.scissor_o.lr_y; FRDP("setscissor: (%d,%d) -> (%d,%d)\n", rdp.scissor_o.ul_x, rdp.scissor_o.ul_y, rdp.scissor_o.lr_x, rdp.scissor_o.lr_y); rdp.update |= UPDATE_SCISSOR; } static void rdp_setprimdepth() { rdp.prim_depth = (WORD)((rdp.cmd1 >> 16) & 0x7FFF); FRDP("setprimdepth: %d\n", rdp.prim_depth); } static void rdp_setothermode() { #define F3DEX2_SETOTHERMODE(cmd,sft,len,data) { \ rdp.cmd0 = (cmd<<24) | ((32-(sft)-(len))<<8) | (((len)-1)); \ rdp.cmd1 = data; \ gfx_instruction[settings.ucode][cmd] (); \ } #define SETOTHERMODE(cmd,sft,len,data) { \ rdp.cmd0 = (cmd<<24) | ((sft)<<8) | (len); \ rdp.cmd1 = data; \ gfx_instruction[settings.ucode][cmd] (); \ } RDP("rdp_setothermode\n"); if ((settings.ucode == 2) || (settings.ucode == 8)) { int cmd0 = rdp.cmd0; F3DEX2_SETOTHERMODE(0xE2, 0, 32, rdp.cmd1); // SETOTHERMODE_L F3DEX2_SETOTHERMODE(0xE3, 0, 32, cmd0 & 0x00FFFFFF); // SETOTHERMODE_H } else { int cmd0 = rdp.cmd0; SETOTHERMODE(0xB9, 0, 32, rdp.cmd1); // SETOTHERMODE_L SETOTHERMODE(0xBA, 0, 32, cmd0 & 0x00FFFFFF); // SETOTHERMODE_H } } void load_palette (DWORD addr, WORD start, WORD count) { RDP ("Loading palette... "); WORD *dpal = rdp.pal_8 + start; WORD end = start+count; // WORD *spal = (WORD*)(gfx.RDRAM + (addr & BMASK)); for (WORD i=start; i>= 4; end = start + (count >> 4); for (WORD p = start; p < end; p++) { rdp.pal_8_crc[p] = CRC_Calculate( 0xFFFFFFFF, &rdp.pal_8[(p << 4)], 32 ); } rdp.pal_256_crc = CRC_Calculate( 0xFFFFFFFF, rdp.pal_8_crc, 64 ); RDP ("Done.\n"); } static void rdp_loadtlut() { DWORD tile = (rdp.cmd1 >> 24) & 0x07; WORD start = rdp.tiles[tile].t_mem - 256; // starting location in the palettes // WORD start = ((WORD)(rdp.cmd1 >> 2) & 0x3FF) + 1; WORD count = ((WORD)(rdp.cmd1 >> 14) & 0x3FF) + 1; // number to copy if (rdp.timg.addr + (count<<1) > BMASK) count = (WORD)((BMASK - rdp.timg.addr) >> 1); if (start+count > 256) count = 256-start; FRDP("loadtlut: tile: %d, start: %d, count: %d, from: %08lx\n", tile, start, count, rdp.timg.addr); load_palette (rdp.timg.addr, start, count); rdp.timg.addr += count << 1; } BOOL tile_set = 0; static void rdp_settilesize() { DWORD tile = (rdp.cmd1 >> 24) & 0x07; rdp.last_tile_size = tile; rdp.tiles[tile].f_ul_s = (float)((rdp.cmd0 >> 12) & 0xFFF) / 4.0f; rdp.tiles[tile].f_ul_t = (float)(rdp.cmd0 & 0xFFF) / 4.0f; int ul_s = (((WORD)(rdp.cmd0 >> 14)) & 0x03ff); int ul_t = (((WORD)(rdp.cmd0 >> 2 )) & 0x03ff); int lr_s = (((WORD)(rdp.cmd1 >> 14)) & 0x03ff); int lr_t = (((WORD)(rdp.cmd1 >> 2 )) & 0x03ff); if (lr_s == 0 && ul_s == 0) //pokemon puzzle league set such tile size wrong_tile = tile; else if (wrong_tile == (int)tile) wrong_tile = -1; if (settings.use_sts1_only) { // ** USE FIRST SETTILESIZE ONLY ** // This option helps certain textures while using the 'Alternate texture size method', // but may break others. (should help more than break) if (tile_set) { // coords in 10.2 format rdp.tiles[tile].ul_s = ul_s; rdp.tiles[tile].ul_t = ul_t; rdp.tiles[tile].lr_s = lr_s; rdp.tiles[tile].lr_t = lr_t; tile_set = 0; } } else { // coords in 10.2 format rdp.tiles[tile].ul_s = ul_s; rdp.tiles[tile].ul_t = ul_t; rdp.tiles[tile].lr_s = lr_s; rdp.tiles[tile].lr_t = lr_t; } // handle wrapping if (rdp.tiles[tile].lr_s < rdp.tiles[tile].ul_s) rdp.tiles[tile].lr_s += 0x400; if (rdp.tiles[tile].lr_t < rdp.tiles[tile].ul_t) rdp.tiles[tile].lr_t += 0x400; rdp.update |= UPDATE_TEXTURE; rdp.first = 1; if (tile == 0 && rdp.hires_tex) //if ((rdp.tiles[tile].size != 2) || ((rdp.timg.width == 1) && (rdp.hires_tex->width != (DWORD)(lr_s+1)))) if (((rdp.tiles[tile].format == 0) && (rdp.tiles[tile].size != 2)) || ((rdp.timg.width == 1) && (rdp.hires_tex->width != (DWORD)(lr_s+1)))) rdp.hires_tex = 0; if (rdp.hires_tex) { if (rdp.tiles[tile].format == 0 && rdp.hires_tex->format == 0) { if (tile == 1 && (DWORD)rdp.hires_tex->tmu != tile) SwapTextureBuffer(); rdp.hires_tex->tile = tile; rdp.hires_tex->info.format = GR_TEXFMT_RGB_565; FRDP ("hires_tex: tile: %d\n", tile); } else if (tile == 0) { rdp.hires_tex->info.format = GR_TEXFMT_ALPHA_INTENSITY_88; } } FRDP ("settilesize: tile: %d, ul_s: %d, ul_t: %d, lr_s: %d, lr_t: %d\n", tile, ul_s, ul_t, lr_s, lr_t); } static void CopyswapBlock(int *pDst, unsigned int cnt, unsigned int SrcOffs) { // copy and byteswap a block of 8-byte dwords int rem = SrcOffs & 3; if (rem == 0) { int *pSrc = (int *) ((uintptr_t) gfx.RDRAM + SrcOffs); for (unsigned int x = 0; x < cnt; x++) { int s1 = bswap32(*pSrc++); int s2 = bswap32(*pSrc++); *pDst++ = s1; *pDst++ = s2; } } else { // set source pointer to 4-byte aligned RDRAM location before the start int *pSrc = (int *) ((uintptr_t) gfx.RDRAM + (SrcOffs & 0xfffffffc)); // do the first partial 32-bit word int s0 = bswap32(*pSrc++); for (int x = 0; x < rem; x++) s0 >>= 8; for (int x = 4; x > rem; x--) { *((char *) pDst) = s0 & 0xff; pDst = (int *) ((char *) pDst + 1); s0 >>= 8; } // do one full 32-bit word s0 = bswap32(*pSrc++); *pDst++ = s0; // do 'cnt-1' 64-bit dwords for (unsigned int x = 0; x < cnt-1; x++) { int s1 = bswap32(*pSrc++); int s2 = bswap32(*pSrc++); *pDst++ = s1; *pDst++ = s2; } // do last partial 32-bit word s0 = bswap32(*pSrc++); for (; rem > 0; rem--) { *((char *) pDst) = s0 & 0xff; pDst = (int *) ((char *) pDst + 1); s0 >>= 8; } } } static void WordswapBlock(int *pDst, unsigned int cnt, unsigned int TileSize) { // Since it's not loading 32-bit textures as the N64 would, 32-bit textures need to // be swapped by 64-bits, not 32. if (TileSize == 3) { // swapblock64 dst, cnt for (unsigned int x = 0; x < cnt / 2; x++, pDst += 4) { long long s1 = ((long long *) pDst)[0]; long long s2 = ((long long *) pDst)[1]; ((long long *) pDst)[0] = s2; ((long long *) pDst)[1] = s1; } } else { // swapblock32 dst, cnt for (unsigned int x = 0; x < cnt; x++, pDst += 2) { int s1 = pDst[0]; int s2 = pDst[1]; pDst[0] = s2; pDst[1] = s1; } } } static void rdp_loadblock() { if (rdp.skip_drawing) { RDP("loadblock skipped\n"); return; } DWORD tile = (DWORD)((rdp.cmd1 >> 24) & 0x07); DWORD dxt = (DWORD)(rdp.cmd1 & 0x0FFF); rdp.addr[rdp.tiles[tile].t_mem] = rdp.timg.addr; // ** DXT is used for swapping every other line /* double fdxt = (double)0x8000000F/(double)((DWORD)(2047/(dxt-1))); // F for error DWORD _dxt = (DWORD)fdxt;*/ // 0x00000800 -> 0x80000000 (so we can check the sign bit instead of the 11th bit) DWORD _dxt = dxt << 20; DWORD addr = segoffset(rdp.timg.addr) & BMASK; // lr_s specifies number of 64-bit words to copy // 10.2 format WORD ul_s = (WORD)(rdp.cmd0 >> 14) & 0x3FF; WORD ul_t = (WORD)(rdp.cmd0 >> 2) & 0x3FF; WORD lr_s = (WORD)(rdp.cmd1 >> 14) & 0x3FF; rdp.tiles[tile].ul_s = ul_s; rdp.tiles[tile].ul_t = ul_t; rdp.tiles[tile].lr_s = lr_s; rdp.timg.set_by = 0; // load block // do a quick boundary check before copying to eliminate the possibility for exception if (ul_s >= 512) { lr_s = 1; // 1 so that it doesn't die on memcpy ul_s = 511; } if (ul_s+lr_s > 512) lr_s = 512-ul_s; if (addr+(lr_s<<3) > BMASK+1) lr_s = (WORD)((BMASK-addr)>>3); DWORD offs = rdp.timg.addr; DWORD cnt = lr_s+1; if (rdp.tiles[tile].size == 3) cnt <<= 1; //FIXME: unused? DWORD start_line = 0; // if (lr_s > 0) rdp.timg.addr += cnt << 3; int * pDst = (int *) ((uintptr_t)rdp.tmem+(rdp.tiles[tile].t_mem<<3)); // Load the block from RDRAM and byteswap it as it loads CopyswapBlock(pDst, cnt, offs); // now do 32-bit or 64-bit word swapping on every other row of data int dxt_accum = 0; while (cnt > 0) { // skip over unswapped blocks do { pDst += 2; if (--cnt == 0) break; dxt_accum += _dxt; } while (!(dxt_accum & 0x80000000)); // count number of blocks to swap if (cnt == 0) break; int swapcnt = 0; do { swapcnt++; if (--cnt == 0) break; dxt_accum += _dxt; } while (dxt_accum & 0x80000000); // do 32-bit or 64-bit swap operation on this block WordswapBlock(pDst, swapcnt, rdp.tiles[tile].size); pDst += swapcnt * 2; } rdp.update |= UPDATE_TEXTURE; FRDP ("loadblock: tile: %d, ul_s: %d, ul_t: %d, lr_s: %d, dxt: %08lx -> %08lx\n", tile, ul_s, ul_t, lr_s, dxt, _dxt); } static void rdp_loadtile() { if (rdp.skip_drawing) return; rdp.timg.set_by = 1; // load tile DWORD tile = (DWORD)((rdp.cmd1 >> 24) & 0x07); if (rdp.tiles[tile].format == 1) { rdp.yuv_image = TRUE; if (rdp.timg.addr < rdp.yuv_im_begin) rdp.yuv_im_begin = rdp.timg.addr; return; } rdp.addr[rdp.tiles[tile].t_mem] = rdp.timg.addr; WORD ul_s = (WORD)((rdp.cmd0 >> 14) & 0x03FF); WORD ul_t = (WORD)((rdp.cmd0 >> 2 ) & 0x03FF); WORD lr_s = (WORD)((rdp.cmd1 >> 14) & 0x03FF); WORD lr_t = (WORD)((rdp.cmd1 >> 2 ) & 0x03FF); if (lr_s < ul_s || lr_t < ul_t) return; if (wrong_tile >= 0) //there was a tile with zero length { rdp.tiles[wrong_tile].lr_s = lr_s; if (rdp.tiles[tile].size > rdp.tiles[wrong_tile].size) rdp.tiles[wrong_tile].lr_s <<= (rdp.tiles[tile].size - rdp.tiles[wrong_tile].size); else if (rdp.tiles[tile].size < rdp.tiles[wrong_tile].size) rdp.tiles[wrong_tile].lr_s >>= (rdp.tiles[wrong_tile].size - rdp.tiles[tile].size); rdp.tiles[wrong_tile].lr_t = lr_t; // wrong_tile = -1; } if (rdp.hires_tex)// && (rdp.tiles[tile].format == 0)) { FRDP("loadtile: hires_tex ul_s: %d, ul_t:%d\n", ul_s, ul_t); rdp.hires_tex->tile_uls = ul_s; rdp.hires_tex->tile_ult = ul_t; } if (settings.tonic && tile == 7) { rdp.tiles[0].ul_s = ul_s; rdp.tiles[0].ul_t = ul_t; rdp.tiles[0].lr_s = lr_s; rdp.tiles[0].lr_t = lr_t; } DWORD height = lr_t - ul_t + 1; // get height DWORD width = lr_s - ul_s + 1; DWORD wid_64 = rdp.tiles[tile].line; // CHEAT: it's very unlikely that it loads more than 1 32-bit texture in one command, // so i don't bother to write in two different places at once. Just load once with // twice as much data. if (rdp.tiles[tile].size == 3) wid_64 <<= 1; int line_n = rdp.timg.width; if (rdp.tiles[tile].size == 0) line_n >>= 1; else line_n <<= (rdp.tiles[tile].size-1); int offs = ul_t * line_n; offs += ul_s << rdp.tiles[tile].size >> 1; offs += rdp.timg.addr; if ((unsigned int) offs >= BMASK) return; // check if points to bad location DWORD size = width * height; if (rdp.tiles[tile].size == 0) size >>= 1; else size <<= (rdp.tiles[tile].size-1); if (offs + line_n*height > BMASK) height = (BMASK - offs) / line_n; int * pDst = (int *) ((uintptr_t)rdp.tmem+(rdp.tiles[tile].t_mem<<3)); int * pEnd = (int *) ((uintptr_t)rdp.tmem+4096 - (wid_64<<3)); for (unsigned int y = 0; y < height; y++) { if (pDst > pEnd) break; CopyswapBlock(pDst, wid_64, offs); if (y & 1) { WordswapBlock(pDst, wid_64, rdp.tiles[tile].size); } pDst += wid_64 * 2; offs += line_n; } FRDP("loadtile: tile: %d, ul_s: %d, ul_t: %d, lr_s: %d, lr_t: %d\n", tile, ul_s, ul_t, lr_s, lr_t); } static void rdp_settile() { tile_set = 1; // used to check if we only load the first settilesize rdp.first = 0; //rdp.cur_tile_n = (DWORD)((rdp.cmd1 >> 24) & 0x07); //rdp.cur_tile = &rdp.tiles[rdp.cur_tile_n]; rdp.last_tile = (DWORD)((rdp.cmd1 >> 24) & 0x07); TILE *tile = &rdp.tiles[rdp.last_tile]; tile->format = (BYTE)((rdp.cmd0 >> 21) & 0x07); tile->size = (BYTE)((rdp.cmd0 >> 19) & 0x03); tile->line = (WORD)((rdp.cmd0 >> 9) & 0x01FF); tile->t_mem = (WORD)(rdp.cmd0 & 0x1FF); tile->palette = (BYTE)((rdp.cmd1 >> 20) & 0x0F); tile->clamp_t = (BYTE)((rdp.cmd1 >> 19) & 0x01); tile->mirror_t = (BYTE)((rdp.cmd1 >> 18) & 0x01); tile->mask_t = (BYTE)((rdp.cmd1 >> 14) & 0x0F); tile->shift_t = (BYTE)((rdp.cmd1 >> 10) & 0x0F); tile->clamp_s = (BYTE)((rdp.cmd1 >> 9) & 0x01); tile->mirror_s = (BYTE)((rdp.cmd1 >> 8) & 0x01); tile->mask_s = (BYTE)((rdp.cmd1 >> 4) & 0x0F); tile->shift_s = (BYTE)(rdp.cmd1 & 0x0F); rdp.update |= UPDATE_TEXTURE; FRDP ("settile: tile: %d, format: %s, size: %s, line: %d, " "t_mem: %08lx, palette: %d, clamp_t/mirror_t: %s, mask_t: %d, " "shift_t: %d, clamp_s/mirror_s: %s, mask_s: %d, shift_s: %d\n", rdp.last_tile, str_format[tile->format], str_size[tile->size], tile->line, tile->t_mem, tile->palette, str_cm[(tile->clamp_t<<1)|tile->mirror_t], tile->mask_t, tile->shift_t, str_cm[(tile->clamp_s<<1)|tile->mirror_s], tile->mask_s, tile->shift_s); } // // fillrect - fills a rectangle // static void rdp_fillrect() { DWORD ul_x = ((rdp.cmd1 & 0x00FFF000) >> 14); DWORD ul_y = (rdp.cmd1 & 0x00000FFF) >> 2; DWORD lr_x = ((rdp.cmd0 & 0x00FFF000) >> 14) + 1; DWORD lr_y = ((rdp.cmd0 & 0x00000FFF) >> 2) + 1; if ((rdp.cimg == rdp.zimg) || (settings.fb_smart && rdp.frame_buffers[rdp.ci_count-1].status == ci_zimg)) { RDP ("Fillrect - cleared the depth buffer\n"); if (fullscreen) { grDepthMask (FXTRUE); grColorMask (FXFALSE, FXFALSE); grBufferClear (0, 0, 0xFFFF); grColorMask (FXTRUE, FXTRUE); rdp.update |= UPDATE_ZBUF_ENABLED; if (settings.fb_depth_clear) { ul_x = min(max(ul_x, rdp.scissor_o.ul_x), rdp.scissor_o.lr_x); lr_x = min(max(lr_x, rdp.scissor_o.ul_x), rdp.scissor_o.lr_x); ul_y = min(max(ul_y, rdp.scissor_o.ul_y), rdp.scissor_o.lr_y); lr_y = min(max(lr_y, rdp.scissor_o.ul_y), rdp.scissor_o.lr_y); //FIXME:unused? DWORD zi_height = lr_y - ul_y - 1; // rdp.zi_nb_pixels = rdp.zi_width * zi_height; rdp.zi_lry = lr_y - 1; rdp.zi_lrx = lr_x - 1; // FRDP ("zi_width: %d, zi_height: %d\n", rdp.zi_width, zi_height); DWORD fillrect_width_in_dwords = (lr_x-ul_x) >> 1; DWORD zi_width_in_dwords = rdp.zi_width >> 1; ul_x >>= 1; DWORD * dst = (DWORD*)(gfx.RDRAM+rdp.cimg); dst += ul_y * zi_width_in_dwords; for (DWORD y = ul_y; y < lr_y; y++) { for (DWORD x = ul_x; x < fillrect_width_in_dwords; x++) { dst[x] = rdp.fill_color; } dst += zi_width_in_dwords; } } } return; } if (rdp.skip_drawing) { RDP("Fillrect skipped\n"); return; } // Update scissor update_scissor (); if ((ul_x > lr_x) || (ul_y > lr_y)) return; if (settings.bomberman64 && (lr_x == rdp.ci_width) && (rdp.cimg == rdp.ocimg)) //bomberman64 hack return; if (rdp.cur_image && (rdp.cur_image->format != 0) && (rdp.cycle_mode == 3) && (rdp.cur_image->width == lr_x)) { DWORD color = rdp.fill_color; color = ((color&1)?0xFF:0) | ((DWORD)((float)((color&0xF800) >> 11) / 31.0f * 255.0f) << 24) | ((DWORD)((float)((color&0x07C0) >> 6) / 31.0f * 255.0f) << 16) | ((DWORD)((float)((color&0x003E) >> 1) / 31.0f * 255.0f) << 8); grDepthMask (FXFALSE); grBufferClear (color, 0, 0xFFFF); grDepthMask (FXTRUE); rdp.update |= UPDATE_ZBUF_ENABLED; return; } if (settings.decrease_fillrect_edge && rdp.cycle_mode == 0) { lr_x--; lr_y--; } FRDP("fillrect (%d,%d) -> (%d,%d), cycle mode: %d, #%d, #%d\n", ul_x, ul_y, lr_x, lr_y, rdp.cycle_mode, rdp.tri_n, rdp.tri_n+1); FRDP("scissor (%d,%d) -> (%d,%d)\n", rdp.scissor.ul_x, rdp.scissor.ul_y, rdp.scissor.lr_x, rdp.scissor.lr_y); // KILL the floating point error with 0.01f DWORD s_ul_x = (DWORD)min(max(ul_x * rdp.scale_x + rdp.offset_x + 0.01f, rdp.scissor.ul_x), rdp.scissor.lr_x); DWORD s_lr_x = (DWORD)min(max(lr_x * rdp.scale_x + rdp.offset_x + 0.01f, rdp.scissor.ul_x), rdp.scissor.lr_x); DWORD s_ul_y = (DWORD)min(max(ul_y * rdp.scale_y + rdp.offset_y + 0.01f, rdp.scissor.ul_y), rdp.scissor.lr_y); DWORD s_lr_y = (DWORD)min(max(lr_y * rdp.scale_y + rdp.offset_y + 0.01f, rdp.scissor.ul_y), rdp.scissor.lr_y); if (s_lr_x < 0.0f) s_lr_x = 0; if (s_lr_y < 0.0f) s_lr_y = 0; if (s_ul_x > (float)settings.res_x) s_ul_x = settings.res_x; if (s_ul_y > (float)settings.res_y) s_ul_y = settings.res_y; FRDP (" - %d, %d, %d, %d\n", s_ul_x, s_ul_y, s_lr_x, s_lr_y); if (fullscreen) { grFogMode (GR_FOG_DISABLE); grClipWindow (0, 0, settings.res_x, settings.res_y); float Z = 1.0f; if (rdp.zsrc == 1 && (rdp.othermode_l & 0x00000030)) { Z = ScaleZ(rdp.prim_depth); grDepthBufferFunction (GR_CMP_LEQUAL); // grDepthMask (FXTRUE); FRDP ("prim_depth = %d\n", rdp.prim_depth); } else { grDepthBufferFunction (GR_CMP_ALWAYS); grDepthMask (FXFALSE); RDP ("no prim_depth used, using 1.0\n"); } // Draw the rectangle VERTEX v[4] = { { (float)s_ul_x, (float)s_ul_y, Z, 1.0f, 0,0,0,0, { 0,0,0,0 }, 0,0, 0,0,0,0 }, { (float)s_lr_x, (float)s_ul_y, Z, 1.0f, 0,0,0,0, { 0,0,0,0 }, 0,0, 0,0,0,0 }, { (float)s_ul_x, (float)s_lr_y, Z, 1.0f, 0,0,0,0, { 0,0,0,0 }, 0,0, 0,0,0,0 }, { (float)s_lr_x, (float)s_lr_y, Z, 1.0f, 0,0,0,0, { 0,0,0,0 }, 0,0, 0,0,0,0 } }; if (rdp.cycle_mode == 3) { DWORD color = (settings.fillcolor_fix) ? rdp.fill_color : (rdp.fill_color >> 16); if (settings.PM && rdp.frame_buffers[rdp.ci_count-1].status == ci_aux) { //background of auxilary frame buffers must have zero alpha. //make it black, set 0 alpha to plack pixels on frame buffer read color = 0; } else { color = ((color&1)?0xFF:0) | ((DWORD)((float)((color&0xF800) >> 11) / 31.0f * 255.0f) << 24) | ((DWORD)((float)((color&0x07C0) >> 6) / 31.0f * 255.0f) << 16) | ((DWORD)((float)((color&0x003E) >> 1) / 31.0f * 255.0f) << 8); } grConstantColorValue (color); grColorCombine (GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_NONE, GR_COMBINE_LOCAL_CONSTANT, GR_COMBINE_OTHER_NONE, FXFALSE); grAlphaCombine (GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_NONE, GR_COMBINE_LOCAL_CONSTANT, GR_COMBINE_OTHER_NONE, FXFALSE); grAlphaBlendFunction (GR_BLEND_ONE, GR_BLEND_ZERO, GR_BLEND_ONE, GR_BLEND_ZERO); rdp.update |= UPDATE_COMBINE; } else { Combine (); TexCache (); // (to update combiner) DWORD cmb_mode_c = (rdp.cycle1 << 16) | (rdp.cycle2 & 0xFFFF); DWORD cmb_mode_a = (rdp.cycle1 & 0x0FFF0000) | ((rdp.cycle2 >> 16) & 0x00000FFF); if (cmb_mode_c == 0x9fff9fff || cmb_mode_a == 0x09ff09ff) //shade { AllowShadeMods (v, 4); for (int k = 0; k < 4; k++) apply_shade_mods (&v[k]); } } grAlphaTestFunction (GR_CMP_ALWAYS); if (grStippleModeExt) grStippleModeExt(GR_STIPPLE_DISABLE); grCullMode(GR_CULL_DISABLE); if (settings.wireframe) { SetWireframeCol (); grDrawLine (&v[0], &v[2]); grDrawLine (&v[2], &v[1]); grDrawLine (&v[1], &v[0]); grDrawLine (&v[2], &v[3]); grDrawLine (&v[3], &v[1]); //grDrawLine (&v[1], &v[2]); } else { grDrawTriangle (&v[0], &v[2], &v[1]); grDrawTriangle (&v[2], &v[3], &v[1]); } if (debug.capture) { VERTEX v1[3]; v1[0] = v[0]; v1[1] = v[2]; v1[2] = v[1]; add_tri (v1, 3, TRI_FILLRECT); rdp.tri_n ++; v1[0] = v[2]; v1[1] = v[3]; add_tri (v1, 3, TRI_FILLRECT); rdp.tri_n ++; } else rdp.tri_n += 2; if (settings.fog && (rdp.flags & FOG_ENABLED)) { grFogMode (GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT); } rdp.update |= UPDATE_CULL_MODE | UPDATE_ALPHA_COMPARE | UPDATE_ZBUF_ENABLED; } else { rdp.tri_n += 2; } } // // setfillcolor - sets the filling color // static void rdp_setfillcolor() { rdp.fill_color = rdp.cmd1; rdp.update |= UPDATE_ALPHA_COMPARE | UPDATE_COMBINE; FRDP("setfillcolor: %08lx\n", rdp.cmd1); } static void rdp_setfogcolor() { rdp.fog_color = rdp.cmd1; rdp.update |= UPDATE_COMBINE | UPDATE_FOG_ENABLED; FRDP("setfogcolor - %08lx\n", rdp.cmd1); } static void rdp_setblendcolor() { rdp.blend_color = rdp.cmd1; rdp.update |= UPDATE_COMBINE; FRDP("setblendcolor: %08lx\n", rdp.cmd1); } static void rdp_setprimcolor() { rdp.prim_color = rdp.cmd1; rdp.prim_lodmin = (rdp.cmd0 >> 8) & 0xFF; rdp.prim_lodfrac = max(rdp.cmd0 & 0xFF, rdp.prim_lodmin); rdp.update |= UPDATE_COMBINE; FRDP("setprimcolor: %08lx, lodmin: %d, lodfrac: %d\n", rdp.cmd1, rdp.prim_lodmin, rdp.prim_lodfrac); } static void rdp_setenvcolor() { rdp.env_color = rdp.cmd1; rdp.update |= UPDATE_COMBINE; FRDP("setenvcolor: %08lx\n", rdp.cmd1); } static void rdp_setcombine() { rdp.c_a0 = (BYTE)((rdp.cmd0 >> 20) & 0xF); rdp.c_b0 = (BYTE)((rdp.cmd1 >> 28) & 0xF); rdp.c_c0 = (BYTE)((rdp.cmd0 >> 15) & 0x1F); rdp.c_d0 = (BYTE)((rdp.cmd1 >> 15) & 0x7); rdp.c_Aa0 = (BYTE)((rdp.cmd0 >> 12) & 0x7); rdp.c_Ab0 = (BYTE)((rdp.cmd1 >> 12) & 0x7); rdp.c_Ac0 = (BYTE)((rdp.cmd0 >> 9) & 0x7); rdp.c_Ad0 = (BYTE)((rdp.cmd1 >> 9) & 0x7); rdp.c_a1 = (BYTE)((rdp.cmd0 >> 5) & 0xF); rdp.c_b1 = (BYTE)((rdp.cmd1 >> 24) & 0xF); rdp.c_c1 = (BYTE)((rdp.cmd0 >> 0) & 0x1F); rdp.c_d1 = (BYTE)((rdp.cmd1 >> 6) & 0x7); rdp.c_Aa1 = (BYTE)((rdp.cmd1 >> 21) & 0x7); rdp.c_Ab1 = (BYTE)((rdp.cmd1 >> 3) & 0x7); rdp.c_Ac1 = (BYTE)((rdp.cmd1 >> 18) & 0x7); rdp.c_Ad1 = (BYTE)((rdp.cmd1 >> 0) & 0x7); rdp.cycle1 = (rdp.c_a0<<0) | (rdp.c_b0<<4) | (rdp.c_c0<<8) | (rdp.c_d0<<13)| (rdp.c_Aa0<<16)| (rdp.c_Ab0<<19)| (rdp.c_Ac0<<22)| (rdp.c_Ad0<<25); rdp.cycle2 = (rdp.c_a1<<0) | (rdp.c_b1<<4) | (rdp.c_c1<<8) | (rdp.c_d1<<13)| (rdp.c_Aa1<<16)| (rdp.c_Ab1<<19)| (rdp.c_Ac1<<22)| (rdp.c_Ad1<<25); rdp.update |= UPDATE_COMBINE; FRDP("setcombine\na0=%s b0=%s c0=%s d0=%s\nAa0=%s Ab0=%s Ac0=%s Ad0=%s\na1=%s b1=%s c1=%s d1=%s\nAa1=%s Ab1=%s Ac1=%s Ad1=%s\n", Mode0[rdp.c_a0], Mode1[rdp.c_b0], Mode2[rdp.c_c0], Mode3[rdp.c_d0], Alpha0[rdp.c_Aa0], Alpha1[rdp.c_Ab0], Alpha2[rdp.c_Ac0], Alpha3[rdp.c_Ad0], Mode0[rdp.c_a1], Mode1[rdp.c_b1], Mode2[rdp.c_c1], Mode3[rdp.c_d1], Alpha0[rdp.c_Aa1], Alpha1[rdp.c_Ab1], Alpha2[rdp.c_Ac1], Alpha3[rdp.c_Ad1]); } // // settextureimage - sets the source for an image copy // static void rdp_settextureimage() { static const char *format[] = { "RGBA", "YUV", "CI", "IA", "I", "?", "?", "?" }; static const char *size[] = { "4bit", "8bit", "16bit", "32bit" }; rdp.timg.format = (BYTE)((rdp.cmd0 >> 21) & 0x07); rdp.timg.size = (BYTE)((rdp.cmd0 >> 19) & 0x03); rdp.timg.width = (WORD)(1 + (rdp.cmd0 & 0x00000FFF)); rdp.timg.addr = segoffset(rdp.cmd1); rdp.s2dex_tex_loaded = TRUE; rdp.update |= UPDATE_TEXTURE; if (rdp.frame_buffers[rdp.ci_count-1].status == ci_copy_self && (rdp.timg.addr >= rdp.cimg) && (rdp.timg.addr < rdp.ci_end)) { if (!rdp.fb_drawn) { if (!rdp.cur_image) CopyFrameBuffer(); else if (rdp.frame_buffers[rdp.ci_count].status != ci_copy) CloseTextureBuffer(TRUE); rdp.fb_drawn = TRUE; } } if (settings.fb_hires) //search this texture among drawn texture buffers { if (settings.zelda) { if (rdp.timg.size == 2) FindTextureBuffer(rdp.timg.addr, rdp.timg.width); } else FindTextureBuffer(rdp.timg.addr, rdp.timg.width); } FRDP("settextureimage: format: %s, size: %s, width: %d, addr: %08lx\n", format[rdp.timg.format], size[rdp.timg.size], rdp.timg.width, rdp.timg.addr); } static void rdp_setdepthimage() { rdp.zimg = segoffset(rdp.cmd1) & BMASK; rdp.zi_width = rdp.ci_width; FRDP("setdepthimage - %08lx\n", rdp.zimg); } BOOL SwapOK = TRUE; static void RestoreScale() { FRDP("Return to original scale: x = %f, y = %f\n", rdp.scale_x_bak, rdp.scale_y_bak); rdp.scale_x = rdp.scale_x_bak; rdp.scale_y = rdp.scale_y_bak; // update_scissor(); rdp.view_scale[0] *= rdp.scale_x; rdp.view_scale[1] *= rdp.scale_y; rdp.view_trans[0] *= rdp.scale_x; rdp.view_trans[1] *= rdp.scale_y; rdp.update |= UPDATE_VIEWPORT | UPDATE_SCISSOR; //* if (fullscreen) { grDepthMask (FXFALSE); grBufferClear (0, 0, 0xFFFF); grDepthMask (FXTRUE); } //*/ } static DWORD swapped_addr = 0; static void rdp_setcolorimage() { render_depth_mode = 0; if (settings.fb_smart && (rdp.num_of_ci < NUMTEXBUF)) { COLOR_IMAGE & cur_fb = rdp.frame_buffers[rdp.ci_count]; COLOR_IMAGE & prev_fb = rdp.frame_buffers[rdp.ci_count-1]; COLOR_IMAGE & next_fb = rdp.frame_buffers[rdp.ci_count+1]; switch (cur_fb.status) { case ci_main: { if (rdp.ci_count == 0) { if (rdp.ci_status == ci_aux) //for PPL { float sx = rdp.scale_x; float sy = rdp.scale_y; rdp.scale_x = 1.0f; rdp.scale_y = 1.0f; CopyFrameBuffer (); rdp.scale_x = sx; rdp.scale_y = sy; } if (!settings.fb_hires) { if ((rdp.num_of_ci > 1) && (next_fb.status == ci_aux) && (next_fb.width >= cur_fb.width)) { rdp.scale_x = 1.0f; rdp.scale_y = 1.0f; } } else if (rdp.copy_ci_index && settings.PM) //tidal wave OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]); } else if (!rdp.motionblur && settings.fb_hires && !SwapOK && (rdp.ci_count <= rdp.copy_ci_index)) { if (next_fb.status == ci_aux_copy) OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]); else OpenTextureBuffer(rdp.frame_buffers[rdp.copy_ci_index]); } else if (settings.fb_hires && rdp.read_whole_frame && prev_fb.status == ci_aux) { OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]); } //else if (rdp.ci_status == ci_aux && !rdp.copy_ci_index) // CloseTextureBuffer(); rdp.skip_drawing = FALSE; } break; case ci_copy: { if (!rdp.motionblur || settings.fb_motionblur) { if (cur_fb.width == rdp.ci_width) { if (CopyTextureBuffer(prev_fb, cur_fb)) // if (CloseTextureBuffer(TRUE)) ; else { if (!rdp.fb_drawn || prev_fb.status == ci_copy_self) { CopyFrameBuffer (); rdp.fb_drawn = TRUE; } memcpy(gfx.RDRAM+cur_fb.addr,gfx.RDRAM+rdp.cimg, (cur_fb.width*cur_fb.height)<>1); } } else { CloseTextureBuffer(TRUE); } } else { memset(gfx.RDRAM+cur_fb.addr, 0, cur_fb.width*cur_fb.height*rdp.ci_size); } rdp.skip_drawing = TRUE; } break; case ci_aux_copy: { rdp.skip_drawing = FALSE; if (CloseTextureBuffer(prev_fb.status != ci_aux_copy)) ; else if (!rdp.fb_drawn) { CopyFrameBuffer (); rdp.fb_drawn = TRUE; } if (settings.fb_hires) OpenTextureBuffer(cur_fb); } break; case ci_old_copy: { if (!rdp.motionblur || settings.fb_motionblur) { if (cur_fb.width == rdp.ci_width) { memcpy(gfx.RDRAM+cur_fb.addr,gfx.RDRAM+rdp.maincimg[1].addr, (cur_fb.width*cur_fb.height)<>1); } //rdp.skip_drawing = TRUE; } else { memset(gfx.RDRAM+cur_fb.addr, 0, (cur_fb.width*cur_fb.height)<>1); } } break; /* else if (rdp.frame_buffers[rdp.ci_count].status == ci_main_i) { // CopyFrameBuffer (); rdp.scale_x = rdp.scale_x_bak; rdp.scale_y = rdp.scale_y_bak; rdp.skip_drawing = FALSE; } */ case ci_aux: { if (!settings.fb_hires && cur_fb.format != 0) rdp.skip_drawing = TRUE; else { rdp.skip_drawing = FALSE; if (settings.fb_hires && OpenTextureBuffer(cur_fb)) ; else { if (cur_fb.format != 0) rdp.skip_drawing = TRUE; if (rdp.ci_count == 0) { // if (rdp.num_of_ci > 1) // { rdp.scale_x = 1.0f; rdp.scale_y = 1.0f; // } } else if (!settings.fb_hires && (prev_fb.status == ci_main) && (prev_fb.width == cur_fb.width)) // for Pokemon Stadium CopyFrameBuffer (); } } cur_fb.status = ci_aux; } break; case ci_zimg: // ZIGGY // Zelda LoT effect save/restore depth buffer if (cur_fb.addr == rdp.zimg) { render_depth_mode = 1; } else { render_depth_mode = 2; } rdp.skip_drawing = TRUE; break; case ci_useless: //case ci_zcopy: rdp.skip_drawing = TRUE; break; case ci_copy_self: if (settings.fb_hires && (rdp.ci_count <= rdp.copy_ci_index) && (!SwapOK || settings.swapmode == 2)) OpenTextureBuffer(cur_fb); rdp.skip_drawing = FALSE; /* if (settings.fb_hires) { if (SwapOK) { rdp.cimg = rdp.frame_buffers[rdp.ci_count].addr; rdp.maincimg[0].addr = rdp.cimg; newSwapBuffers(); SwapOK = FALSE; OpenTextureBuffer(rdp.frame_buffers[rdp.ci_count]); } } */ break; default: rdp.skip_drawing = FALSE; } if ((rdp.ci_count > 0) && (prev_fb.status >= ci_aux)) //for Pokemon Stadium { if (!settings.fb_hires && prev_fb.format == 0) CopyFrameBuffer (); } if (!settings.fb_hires && cur_fb.status == ci_copy) { if (!rdp.motionblur && (rdp.num_of_ci > rdp.ci_count+1) && (next_fb.status != ci_aux)) { RestoreScale(); } } if (!settings.fb_hires && cur_fb.status == ci_aux) { if (cur_fb.format == 0) { if (settings.PPL && (rdp.scale_x < 1.1f)) //need to put current image back to frame buffer { int width = cur_fb.width; int height = cur_fb.height; WORD *ptr_dst = new WORD[width*height]; WORD *ptr_src = (WORD*)(gfx.RDRAM+cur_fb.addr); WORD c; for (int y=0; y> 1) | 0x8000; ptr_dst[x + y * width] = c; } } grLfbWriteRegion(GR_BUFFER_BACKBUFFER, 0, 0, GR_LFB_SRC_FMT_555, width, height, FXFALSE, width<<1, ptr_dst); delete[] ptr_dst; } /* else //just clear buffer { grColorMask(FXTRUE, FXTRUE); grBufferClear (0, 0, 0xFFFF); } */ } } if ((cur_fb.status == ci_main) && (rdp.ci_count > 0)) { BOOL to_org_res = TRUE; for (int i = rdp.ci_count + 1; i < rdp.num_of_ci; i++) { if ((rdp.frame_buffers[i].status != ci_main) && (rdp.frame_buffers[i].status != ci_zimg) && (rdp.frame_buffers[i].status != ci_zcopy)) { to_org_res = FALSE; break; } } if (to_org_res) { RDP("return to original scale\n"); rdp.scale_x = rdp.scale_x_bak; rdp.scale_y = rdp.scale_y_bak; if (settings.fb_hires && !rdp.read_whole_frame) CloseTextureBuffer(); } if (settings.fb_hires && !rdp.read_whole_frame && (prev_fb.status >= ci_aux) && (rdp.ci_count > rdp.copy_ci_index)) CloseTextureBuffer(); } rdp.ci_status = cur_fb.status; rdp.ci_count++; } rdp.ocimg = rdp.cimg; rdp.cimg = segoffset(rdp.cmd1) & BMASK; rdp.ci_width = (rdp.cmd0 & 0xFFF) + 1; if (settings.fb_smart) rdp.ci_height = rdp.frame_buffers[rdp.ci_count-1].height; else if (rdp.ci_width == 32) rdp.ci_height = 32; else rdp.ci_height = rdp.scissor_o.lr_y; if (rdp.zimg == rdp.cimg) { rdp.zi_width = rdp.ci_width; // int zi_height = min((int)rdp.zi_width*3/4, (int)rdp.vi_height); // rdp.zi_words = rdp.zi_width * zi_height; } DWORD format = (rdp.cmd0 >> 21) & 0x7; rdp.ci_size = (rdp.cmd0 >> 19) & 0x3; rdp.ci_end = rdp.cimg + ((rdp.ci_width*rdp.ci_height)<<(rdp.ci_size-1)); FRDP("setcolorimage - %08lx, width: %d, height: %d, format: %d, size: %d\n", rdp.cmd1, rdp.ci_width, rdp.ci_height, format, rdp.ci_size); FRDP("cimg: %08lx, ocimg: %08lx, SwapOK: %d\n", rdp.cimg, rdp.ocimg, SwapOK); if (format != 0 && !rdp.cur_image) //can't draw into non RGBA buffer { if (settings.fb_hires && rdp.ci_width <= 64) OpenTextureBuffer(rdp.frame_buffers[rdp.ci_count - 1]); else if (format > 2) rdp.skip_drawing = TRUE; return; } else { if (!settings.fb_smart) rdp.skip_drawing = FALSE; } CI_SET = TRUE; if (settings.swapmode > 0) { if (rdp.zimg == rdp.cimg) rdp.updatescreen = 1; BOOL viSwapOK = ((settings.swapmode == 2) && (rdp.vi_org_reg == *gfx.VI_ORIGIN_REG)) ? FALSE : TRUE; if ((rdp.zimg != rdp.cimg) && (rdp.ocimg != rdp.cimg) && SwapOK && viSwapOK && !rdp.cur_image) { if (settings.fb_smart) rdp.maincimg[0] = rdp.frame_buffers[rdp.main_ci_index]; else rdp.maincimg[0].addr = rdp.cimg; rdp.last_drawn_ci_addr = (settings.swapmode == 2) ? swapped_addr : rdp.maincimg[0].addr; swapped_addr = rdp.cimg; newSwapBuffers(); rdp.vi_org_reg = *gfx.VI_ORIGIN_REG; SwapOK = FALSE; if (settings.fb_hires) { if (rdp.copy_ci_index && (rdp.frame_buffers[rdp.ci_count-1].status != ci_zimg)) { int idx = (rdp.frame_buffers[rdp.ci_count].status == ci_aux_copy) ? rdp.main_ci_index : rdp.copy_ci_index; FRDP("attempt open tex buffer. status: %s, addr: %08lx\n", CIStatus[rdp.frame_buffers[idx].status], rdp.frame_buffers[idx].addr); OpenTextureBuffer(rdp.frame_buffers[idx]); if (rdp.frame_buffers[rdp.copy_ci_index].status == ci_main) //tidal wave rdp.copy_ci_index = 0; } else if (rdp.read_whole_frame && !rdp.cur_image) { OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]); } } } } } static void rdp_trifill() { RDP_E("trifill - IGNORED\n"); RDP("trifill - IGNORED\n"); } static void rdp_trishade() { RDP_E("trishade - IGNORED\n"); RDP("trishade - IGNORED\n"); } static void rdp_tritxtr() { RDP_E("tritxtr - IGNORED\n"); RDP("tritxtr - IGNORED\n"); } static void rdp_trishadetxtr() { RDP_E("trishadetxtr - IGNORED\n"); RDP("trishadetxtr - IGNORED\n"); } static void rdp_trifillz() { RDP_E("trifillz - IGNORED\n"); RDP("trifillz - IGNORED\n"); } static void rdp_trishadez() { RDP_E("trishadez - IGNORED\n"); RDP("trishadez - IGNORED\n"); } static void rdp_tritxtrz() { RDP_E("tritxtrz - IGNORED\n"); RDP("tritxtrz - IGNORED\n"); } static void rdp_trishadetxtrz() { RDP_E("trishadetxtrz - IGNORED\n"); RDP("trishadetxtrz - IGNORED\n"); } static void rsp_reserved0() { RDP_E("reserved0 - IGNORED\n"); RDP("reserved0 - IGNORED\n"); } static void rsp_reserved1() { RDP("reserved1 - ignored\n"); } static void rsp_reserved2() { RDP("reserved2\n"); } static void rsp_reserved3() { RDP("reserved3 - ignored\n"); } void SetWireframeCol () { if (!fullscreen) return; switch (settings.wfmode) { //case 0: // normal colors, don't do anything case 1: // vertex colors grColorCombine (GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_NONE, GR_COMBINE_LOCAL_ITERATED, GR_COMBINE_OTHER_NONE, FXFALSE); grAlphaCombine (GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_NONE, GR_COMBINE_LOCAL_ITERATED, GR_COMBINE_OTHER_NONE, FXFALSE); grAlphaBlendFunction (GR_BLEND_ONE, GR_BLEND_ZERO, GR_BLEND_ZERO, GR_BLEND_ZERO); grTexCombine (GR_TMU0, GR_COMBINE_FUNCTION_ZERO, GR_COMBINE_FACTOR_NONE, GR_COMBINE_FUNCTION_ZERO, GR_COMBINE_FACTOR_NONE, FXFALSE, FXFALSE); grTexCombine (GR_TMU1, GR_COMBINE_FUNCTION_ZERO, GR_COMBINE_FACTOR_NONE, GR_COMBINE_FUNCTION_ZERO, GR_COMBINE_FACTOR_NONE, FXFALSE, FXFALSE); break; case 2: // red only grColorCombine (GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_NONE, GR_COMBINE_LOCAL_CONSTANT, GR_COMBINE_OTHER_NONE, FXFALSE); grAlphaCombine (GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_NONE, GR_COMBINE_LOCAL_CONSTANT, GR_COMBINE_OTHER_NONE, FXFALSE); grConstantColorValue (0xFF0000FF); grAlphaBlendFunction (GR_BLEND_ONE, GR_BLEND_ZERO, GR_BLEND_ZERO, GR_BLEND_ZERO); grTexCombine (GR_TMU0, GR_COMBINE_FUNCTION_ZERO, GR_COMBINE_FACTOR_NONE, GR_COMBINE_FUNCTION_ZERO, GR_COMBINE_FACTOR_NONE, FXFALSE, FXFALSE); grTexCombine (GR_TMU1, GR_COMBINE_FUNCTION_ZERO, GR_COMBINE_FACTOR_NONE, GR_COMBINE_FUNCTION_ZERO, GR_COMBINE_FACTOR_NONE, FXFALSE, FXFALSE); break; } grAlphaTestFunction (GR_CMP_ALWAYS); grCullMode (GR_CULL_DISABLE); //grDepthBufferFunction (GR_CMP_ALWAYS); //grDepthMask (FXFALSE); rdp.update |= UPDATE_COMBINE | UPDATE_ALPHA_COMPARE; } #ifdef __cplusplus extern "C" { #endif /****************************************************************** Function: FrameBufferRead Purpose: This function is called to notify the dll that the frame buffer memory is beening read at the given address. DLL should copy content from its render buffer to the frame buffer in N64 RDRAM DLL is responsible to maintain its own frame buffer memory addr list DLL should copy 4KB block content back to RDRAM frame buffer. Emulator should not call this function again if other memory is read within the same 4KB range input: addr rdram address val val size 1 = BYTE, 2 = WORD, 4 = DWORD output: none *******************************************************************/ EXPORT void CALL FBRead(unsigned int addr) { LOG ("FBRead ()\n"); if (cpu_fb_ignore) return; if (cpu_fb_write_called) { cpu_fb_ignore = TRUE; cpu_fb_write = FALSE; return; } cpu_fb_read_called = TRUE; DWORD a = segoffset(addr); FRDP("FBRead. addr: %08lx\n", a); if (!rdp.fb_drawn && (a >= rdp.cimg) && (a < rdp.ci_end)) { fbreads_back++; //if (fbreads_back > 2) //&& (rdp.ci_width <= 320)) { CopyFrameBuffer (); rdp.fb_drawn = TRUE; } } if (!rdp.fb_drawn_front && (a >= rdp.maincimg[1].addr) && (a < rdp.maincimg[1].addr + rdp.ci_width*rdp.ci_height*2)) { fbreads_front++; //if (fbreads_front > 2)//&& (rdp.ci_width <= 320)) { DWORD cimg = rdp.cimg; rdp.cimg = rdp.maincimg[1].addr; if (settings.fb_smart) { rdp.ci_width = rdp.maincimg[1].width; rdp.ci_count = 0; DWORD h = rdp.frame_buffers[0].height; rdp.frame_buffers[0].height = rdp.maincimg[1].height; CopyFrameBuffer(GR_BUFFER_FRONTBUFFER); rdp.frame_buffers[0].height = h; } else { CopyFrameBuffer(GR_BUFFER_FRONTBUFFER); } rdp.cimg = cimg; rdp.fb_drawn_front = TRUE; } } } #if 0 //TODO: remove /****************************************************************** Function: FrameBufferWriteList Purpose: This function is called to notify the dll that the frame buffer has been modified by CPU at the given address. input: FrameBufferModifyEntry *plist size = size of the plist, max = 1024 output: none *******************************************************************/ EXPORT void CALL FBWList(FrameBufferModifyEntry *plist, DWORD size) { LOG ("FBWList ()\n"); FRDP("FBWList. size: %d\n", size); printf("FBWList. size: %d\n", size); } #endif /****************************************************************** Function: FrameBufferWrite Purpose: This function is called to notify the dll that the frame buffer has been modified by CPU at the given address. input: addr rdram address val val size 1 = BYTE, 2 = WORD, 4 = DWORD output: none *******************************************************************/ EXPORT void CALL FBWrite(unsigned int addr, unsigned int size) { LOG ("FBWrite ()\n"); if (cpu_fb_ignore) return; if (cpu_fb_read_called) { cpu_fb_ignore = TRUE; cpu_fb_write = FALSE; return; } cpu_fb_write_called = TRUE; DWORD a = segoffset(addr); FRDP("FBWrite. addr: %08lx\n", a); // ZIGGY : added a test on ci_width, otherwise we crash on zero division below if (!rdp.ci_width || a < rdp.cimg || a > rdp.ci_end) return; cpu_fb_write = TRUE; DWORD shift_l = (a-rdp.cimg) >> 1; DWORD shift_r = shift_l+2; d_ul_x = min(d_ul_x, shift_l%rdp.ci_width); d_ul_y = min(d_ul_y, shift_l/rdp.ci_width); d_lr_x = max(d_lr_x, shift_r%rdp.ci_width); d_lr_y = max(d_lr_y, shift_r/rdp.ci_width); } /************************************************************************ Function: FBGetFrameBufferInfo Purpose: This function is called by the emulator core to retrieve frame buffer information from the video plugin in order to be able to notify the video plugin about CPU frame buffer read/write operations size: = 1 byte = 2 word (16 bit) <-- this is N64 default depth buffer format = 4 dword (32 bit) when frame buffer information is not available yet, set all values in the FrameBufferInfo structure to 0 input: FrameBufferInfo pinfo[6] pinfo is pointed to a FrameBufferInfo structure which to be filled in by this function output: Values are return in the FrameBufferInfo structure Plugin can return up to 6 frame buffer info ************************************************************************/ ///* #if 0 //TODO: remove typedef struct { DWORD addr; DWORD size; DWORD width; DWORD height; } FrameBufferInfo; #endif EXPORT void CALL FBGetFrameBufferInfo(void *p) { LOG ("FBGetFrameBufferInfo ()\n"); FrameBufferInfo * pinfo = (FrameBufferInfo *)p; memset(pinfo,0,sizeof(FrameBufferInfo)*6); if (!settings.fb_get_info) return; RDP("FBGetFrameBufferInfo ()\n"); //* if (settings.fb_smart) { pinfo[0].addr = rdp.maincimg[1].addr; pinfo[0].size = rdp.maincimg[1].size; pinfo[0].width = rdp.maincimg[1].width; pinfo[0].height = rdp.maincimg[1].height; int info_index = 1; for (int i = 0; i < rdp.num_of_ci && info_index < 6; i++) { COLOR_IMAGE & cur_fb = rdp.frame_buffers[i]; if (cur_fb.status == ci_main || cur_fb.status == ci_copy_self || cur_fb.status == ci_old_copy) { pinfo[info_index].addr = cur_fb.addr; pinfo[info_index].size = cur_fb.size; pinfo[info_index].width = cur_fb.width; pinfo[info_index].height = cur_fb.height; info_index++; } } } else { pinfo[0].addr = rdp.maincimg[0].addr; pinfo[0].size = rdp.ci_size; pinfo[0].width = rdp.ci_width; pinfo[0].height = rdp.ci_width*3/4; pinfo[1].addr = rdp.maincimg[1].addr; pinfo[1].size = rdp.ci_size; pinfo[1].width = rdp.ci_width; pinfo[1].height = rdp.ci_width*3/4; } //*/ } #ifdef __cplusplus } #endif //*/ #include "UcodeFB.h" void DetectFrameBufferUsage () { RDP("DetectFrameBufferUsage\n"); DWORD dlist_start = *(DWORD*)(gfx.DMEM+0xFF0); #ifdef _WIN32 DWORD dlist_length = *(DWORD*)(gfx.DMEM+0xFF4); #endif // _WIN32 DWORD a; BOOL tidal = FALSE; if (settings.PM && (rdp.copy_ci_index || rdp.frame_buffers[rdp.copy_ci_index].status == ci_copy_self)) tidal = TRUE; DWORD ci = rdp.cimg, zi = rdp.zimg; // ci_width = rdp.ci_width; rdp.main_ci = rdp.main_ci_end = rdp.main_ci_bg = rdp.ci_count = 0; rdp.main_ci_index = rdp.copy_ci_index = 0; rdp.zimg_end = 0; rdp.tmpzimg = 0; rdp.motionblur = FALSE; rdp.main_ci_last_tex_addr = 0; BOOL previous_ci_was_read = rdp.read_previous_ci; rdp.read_previous_ci = FALSE; rdp.read_whole_frame = FALSE; rdp.swap_ci_index = rdp.black_ci_index = -1; SwapOK = TRUE; // Start executing at the start of the display list rdp.pc_i = 0; rdp.pc[rdp.pc_i] = dlist_start; rdp.dl_count = -1; rdp.halt = 0; rdp.scale_x_bak = rdp.scale_x; rdp.scale_y_bak = rdp.scale_y; // MAIN PROCESSING LOOP do { // Get the address of the next command a = rdp.pc[rdp.pc_i] & BMASK; // Load the next command and its input rdp.cmd0 = ((DWORD*)gfx.RDRAM)[a>>2]; // \ Current command, 64 bit rdp.cmd1 = ((DWORD*)gfx.RDRAM)[(a>>2)+1]; // / // Output the address before the command // Go to the next instruction rdp.pc[rdp.pc_i] = (a+8) & BMASK; if ((intptr_t)(gfx_instruction_lite[settings.ucode][rdp.cmd0>>24])) gfx_instruction_lite[settings.ucode][rdp.cmd0>>24] (); // check DL counter if (rdp.dl_count != -1) { rdp.dl_count --; if (rdp.dl_count == 0) { rdp.dl_count = -1; RDP ("End of DL\n"); rdp.pc_i --; } } } while (!rdp.halt); SwapOK = TRUE; if (rdp.ci_count > NUMTEXBUF) //overflow { rdp.cimg = ci; rdp.zimg = zi; rdp.num_of_ci = rdp.ci_count; rdp.scale_x = rdp.scale_x_bak; rdp.scale_y = rdp.scale_y_bak; return; } if (rdp.black_ci_index > 0 && rdp.black_ci_index < rdp.copy_ci_index) rdp.frame_buffers[rdp.black_ci_index].status = ci_main; if (rdp.frame_buffers[rdp.ci_count-1].status == ci_unknown) { if (rdp.ci_count > 1) rdp.frame_buffers[rdp.ci_count-1].status = ci_aux; else rdp.frame_buffers[rdp.ci_count-1].status = ci_main; } if ((rdp.frame_buffers[rdp.ci_count-1].status == ci_aux) && (rdp.frame_buffers[rdp.main_ci_index].width < 320) && (rdp.frame_buffers[rdp.ci_count-1].width > rdp.frame_buffers[rdp.main_ci_index].width)) { for (int i = 0; i < rdp.ci_count; i++) { if (rdp.frame_buffers[i].status == ci_main) rdp.frame_buffers[i].status = ci_aux; else if (rdp.frame_buffers[i].addr == rdp.frame_buffers[rdp.ci_count-1].addr) rdp.frame_buffers[i].status = ci_main; // FRDP("rdp.frame_buffers[%d].status = %d\n", i, rdp.frame_buffers[i].status); } rdp.main_ci_index = rdp.ci_count-1; } BOOL all_zimg = TRUE; int i; for (i = 0; i < rdp.ci_count; i++) { if (rdp.frame_buffers[i].status != ci_zimg) { all_zimg = FALSE; break; } } if (all_zimg) { for (i = 0; i < rdp.ci_count; i++) rdp.frame_buffers[i].status = ci_main; } RDP("detect fb final results: \n"); for (i = 0; i < rdp.ci_count; i++) { FRDP("rdp.frame_buffers[%d].status = %s, addr: %08lx, height: %d\n", i, CIStatus[rdp.frame_buffers[i].status], rdp.frame_buffers[i].addr, rdp.frame_buffers[i].height); } rdp.cimg = ci; rdp.zimg = zi; rdp.num_of_ci = rdp.ci_count; if (rdp.read_previous_ci && previous_ci_was_read) if (!settings.fb_hires || !rdp.copy_ci_index) rdp.motionblur = TRUE; if (rdp.motionblur || settings.fb_hires || (rdp.frame_buffers[rdp.copy_ci_index].status == ci_aux_copy)) { rdp.scale_x = rdp.scale_x_bak; rdp.scale_y = rdp.scale_y_bak; } if ((rdp.read_previous_ci || previous_ci_was_read) && !rdp.copy_ci_index) rdp.read_whole_frame = TRUE; if (rdp.read_whole_frame) { if (settings.fb_hires && !settings.fb_ignore_previous) { if (rdp.swap_ci_index < 0) { rdp.texbufs[0].clear_allowed = TRUE; OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]); } } else { if (rdp.motionblur) { if (settings.fb_motionblur) CopyFrameBuffer(); else memset(gfx.RDRAM+rdp.cimg, 0, rdp.ci_width*rdp.ci_height*rdp.ci_size); } else //if (ci_width == rdp.frame_buffers[rdp.main_ci_index].width) { if (rdp.maincimg[0].height > 65) //for 1080 { rdp.cimg = rdp.maincimg[0].addr; rdp.ci_width = rdp.maincimg[0].width; rdp.ci_count = 0; DWORD h = rdp.frame_buffers[0].height; rdp.frame_buffers[0].height = rdp.maincimg[0].height; CopyFrameBuffer(); rdp.frame_buffers[0].height = h; } else //conker { CopyFrameBuffer(); } } } } if (settings.fb_hires) { for (i = 0; i < num_tmu; i++) { rdp.texbufs[i].clear_allowed = TRUE; for (int j = 0; j < 256; j++) { rdp.texbufs[i].images[j].drawn = FALSE; rdp.texbufs[i].images[j].clear = TRUE; } } if (tidal) { //RDP("Tidal wave!\n"); rdp.copy_ci_index = rdp.main_ci_index; } } rdp.ci_count = 0; if (settings.fb_ignore_previous) rdp.read_whole_frame = FALSE; else rdp.maincimg[0] = rdp.frame_buffers[rdp.main_ci_index]; // rdp.scale_x = rdp.scale_x_bak; // rdp.scale_y = rdp.scale_y_bak; RDP("DetectFrameBufferUsage End\n"); } #ifdef __cplusplus extern "C" { #endif /****************************************************************** Function: ProcessRDPList Purpose: This function is called when there is a Dlist to be processed. (Low level GFX list) input: none output: none *******************************************************************/ EXPORT void CALL ProcessRDPList(void) { if (settings.KI) { *gfx.MI_INTR_REG |= 0x20; gfx.CheckInterrupts(); } LOG ("ProcessRDPList ()\n"); no_dlist = FALSE; update_screen_count = 0; ChangeSize (); #ifdef ALTTAB_FIX if (!hhkLowLevelKybd) { hhkLowLevelKybd = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hInstance, 0); } #endif LOG ("ProcessDList ()\n"); if (!fullscreen) { drawNoFullscreenMessage(); // Set an interrupt to allow the game to continue *gfx.MI_INTR_REG |= 0x20; gfx.CheckInterrupts(); } if (reset) { reset = 0; memset (microcode, 0, 4096); if (settings.autodetect_ucode) { // Thanks to ZeZu for ucode autodetection!!! DWORD startUcode = *(DWORD*)(gfx.DMEM+0xFD0); memcpy (microcode, gfx.RDRAM+startUcode, 4096); microcheck (); } } else if ( ((old_ucode == 6) && (settings.ucode == 1)) || settings.force_microcheck) { DWORD startUcode = *(DWORD*)(gfx.DMEM+0xFD0); memcpy (microcode, gfx.RDRAM+startUcode, 4096); microcheck (); } if (exception) return; // Switch to fullscreen? if (to_fullscreen) { to_fullscreen = FALSE; if (!InitGfx (FALSE)) { LOG ("FAILED!!!\n"); return; } fullscreen = TRUE; } // Clear out the RDP log #ifdef RDP_LOGGING if (settings.logging && settings.log_clear) { CLOSE_RDP_LOG (); OPEN_RDP_LOG (); } #endif #ifdef UNIMP_LOG if (settings.log_unk && settings.unk_clear) { std::ofstream unimp; unimp.open("unimp.txt"); unimp.close(); } #endif //* Set states *// if (settings.swapmode > 0) SwapOK = TRUE; rdp.updatescreen = 1; rdp.tri_n = 0; // 0 triangles so far this frame rdp.debug_n = 0; rdp.model_i = 0; // 0 matrices so far in stack //stack_size can be less then 32! Important for Silicon Vally. Thanks Orkin! rdp.model_stack_size = min(32, (*(DWORD*)(gfx.DMEM+0x0FE4))>>6); if (rdp.model_stack_size == 0) rdp.model_stack_size = 32; rdp.fb_drawn = rdp.fb_drawn_front = FALSE; rdp.update = 0x7FFFFFFF; // All but clear cache rdp.geom_mode = 0; rdp.acmp = 0; rdp.maincimg[1] = rdp.maincimg[0]; rdp.skip_drawing = FALSE; rdp.s2dex_tex_loaded = FALSE; fbreads_front = fbreads_back = 0; rdp.fog_multiplier = rdp.fog_offset = 0; rdp.zsrc = 0; if (cpu_fb_write == TRUE) DrawFrameBufferToScreen(); cpu_fb_write = FALSE; cpu_fb_read_called = FALSE; cpu_fb_write_called = FALSE; cpu_fb_ignore = FALSE; d_ul_x = 0xffff; d_ul_y = 0xffff; d_lr_x = 0; d_lr_y = 0; //analize possible frame buffer usage if (settings.fb_smart) DetectFrameBufferUsage(); if (!settings.lego || rdp.num_of_ci > 1) rdp.last_bg = 0; //* End of set states *// // Get the start of the display list and the length of it // DWORD dlist_start = *(DWORD*)(gfx.DMEM+0xFF0); // DWORD dlist_length = *(DWORD*)(gfx.DMEM+0xFF4); DWORD dlist_start = *gfx.DPC_CURRENT_REG; DWORD dlist_length = *gfx.DPC_END_REG - *gfx.DPC_CURRENT_REG; FRDP("--- NEW DLIST --- crc: %08lx, ucode: %d, fbuf: %08lx, fbuf_width: %d, dlist start: %08lx, dlist_lenght: %d\n", uc_crc, settings.ucode, *gfx.VI_ORIGIN_REG, *gfx.VI_WIDTH_REG, dlist_start, dlist_length); FRDP_E("--- NEW DLIST --- crc: %08lx, ucode: %d, fbuf: %08lx\n", uc_crc, settings.ucode, *gfx.VI_ORIGIN_REG); if (settings.tonic && dlist_length < 16) { rdp_fullsync(); FRDP_E("DLIST is too short!\n"); return; } // Start executing at the start of the display list rdp.pc_i = 0; rdp.pc[rdp.pc_i] = dlist_start; rdp.dl_count = -1; rdp.halt = 0; DWORD a; // catches exceptions so that it doesn't freeze #ifdef CATCH_EXCEPTIONS try { #endif // MAIN PROCESSING LOOP do { // Get the address of the next command a = rdp.pc[rdp.pc_i] & BMASK; // Load the next command and its input rdp.cmd0 = ((DWORD*)gfx.RDRAM)[a>>2]; // \ Current command, 64 bit rdp.cmd1 = ((DWORD*)gfx.RDRAM)[(a>>2)+1]; // / // cmd2 and cmd3 are filled only when needed, by the function that needs them // Output the address before the command #ifdef LOG_COMMANDS FRDP ("%08lx (c0:%08lx, c1:%08lx): ", a, rdp.cmd0, rdp.cmd1); #else FRDP ("%08lx: ", a); #endif // Go to the next instruction rdp.pc[rdp.pc_i] = (a+8) & BMASK; #ifdef PERFORMANCE QueryPerformanceCounter ((LARGE_INTEGER*)&perf_cur); #endif // Process this instruction gfx_instruction[settings.ucode][((rdp.cmd0>>24)&0x3f) + 0x100-0x40] (); // check DL counter if (rdp.dl_count != -1) { rdp.dl_count --; if (rdp.dl_count == 0) { rdp.dl_count = -1; RDP ("End of DL\n"); rdp.pc_i --; } } #ifdef PERFORMANCE QueryPerformanceCounter ((LARGE_INTEGER*)&perf_next); __int64 t = perf_next-perf_cur; sprintf (out_buf, "perf %08lx: %016I64d\n", a-8, t); rdp_log << out_buf; #endif } while (0); #ifdef CATCH_EXCEPTIONS } catch (...) { if (fullscreen) ReleaseGfx (); WriteLog(M64MSG_ERROR, "The GFX plugin caused an exception and has been disabled."); exception = TRUE; } #endif if (settings.fb_smart) { rdp.scale_x = rdp.scale_x_bak; rdp.scale_y = rdp.scale_y_bak; } if (settings.fb_read_always) { CopyFrameBuffer (); } if (rdp.yuv_image) { DrawYUVImageToFrameBuffer(); rdp.yuv_image = FALSE; // FRDP("yuv image draw. ul_x: %f, ul_y: %f, lr_x: %f, lr_y: %f, begin: %08lx\n", // rdp.yuv_ul_x, rdp.yuv_ul_y, rdp.yuv_lr_x, rdp.yuv_lr_y, rdp.yuv_im_begin); rdp.yuv_ul_x = rdp.yuv_ul_y = rdp.yuv_lr_x = rdp.yuv_lr_y = 0; rdp.yuv_im_begin = 0x00FFFFFF; } if (rdp.cur_image) CloseTextureBuffer(rdp.read_whole_frame && (settings.PM || rdp.swap_ci_index >= 0)); if (settings.TGR2 && rdp.vi_org_reg != *gfx.VI_ORIGIN_REG && CI_SET) { newSwapBuffers (); CI_SET = FALSE; } RDP("ProcessDList end\n"); WriteLog(M64MSG_VERBOSE, "ProcessRPDList %x %x %x\n", *gfx.DPC_START_REG, *gfx.DPC_END_REG, *gfx.DPC_CURRENT_REG); //*gfx.DPC_STATUS_REG = 0xffffffff; // &= ~0x0002; *gfx.DPC_START_REG = *gfx.DPC_END_REG; *gfx.DPC_CURRENT_REG = *gfx.DPC_END_REG; } #ifdef __cplusplus } #endif // Local Variables: *** // tab-width:4 *** // c-file-offset:4 *** // End: ***