2 * Glide64 - Glide video plugin for Nintendo 64 emulators.
3 * Copyright (c) 2002 Dave2001
4 * Copyright (c) 2003-2009 Sergey 'Gonetz' Lipski
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 //****************************************************************
23 // Glide64 - Glide Plugin for Nintendo 64 emulators
24 // Project started on December 29th, 2001
27 // Dave2001, original author, founded the project in 2001, left it in 2002
28 // Gugaman, joined the project in 2002, left it in 2002
29 // Sergey 'Gonetz' Lipski, joined the project in 2002, main author since fall of 2002
30 // Hiroshi 'KoolSmoky' Morii, joined the project in 2007
32 //****************************************************************
35 // * 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.
36 // * 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.
38 //****************************************************************
40 // Creation 13 August 2003 Gonetz
42 //****************************************************************
44 static void fb_uc0_moveword()
46 if ((rdp.cmd0 & 0xFF) == 0x06) // segment
48 rdp.segment[(rdp.cmd0 >> 10) & 0x0F] = rdp.cmd1;
52 static void fb_uc2_moveword()
54 if (((rdp.cmd0 >> 16) & 0xFF) == 0x06) // segment
56 rdp.segment[((rdp.cmd0 & 0xFFFF) >> 2)&0xF] = rdp.cmd1;
60 static void fb_bg_copy ()
64 CI_STATUS status = rdp.frame_buffers[rdp.ci_count-1].status;
65 if ( (status == ci_copy) )
68 wxUint32 addr = segoffset(rdp.cmd1) >> 1;
69 wxUint8 imageFmt = ((wxUint8 *)gfx.RDRAM)[(((addr+11)<<1)+0)^3];
70 wxUint8 imageSiz = ((wxUint8 *)gfx.RDRAM)[(((addr+11)<<1)+1)^3];
71 wxUint32 imagePtr = segoffset(((wxUint32*)gfx.RDRAM)[(addr+8)>>1]);
72 FRDP ("fb_bg_copy. fmt: %d, size: %d, imagePtr %08lx, main_ci: %08lx, cur_ci: %08lx \n", imageFmt, imageSiz, imagePtr, rdp.main_ci, rdp.frame_buffers[rdp.ci_count-1].addr);
74 if (status == ci_main)
76 wxUint16 frameW = ((wxUint16 *)gfx.RDRAM)[(addr+3)^1] >> 2;
77 wxUint16 frameH = ((wxUint16 *)gfx.RDRAM)[(addr+7)^1] >> 2;
78 if ( (frameW == rdp.frame_buffers[rdp.ci_count-1].width) && (frameH == rdp.frame_buffers[rdp.ci_count-1].height) )
79 rdp.main_ci_bg = imagePtr;
81 else if (imagePtr >= rdp.main_ci && imagePtr < rdp.main_ci_end) //addr within main frame buffer
83 rdp.copy_ci_index = rdp.ci_count-1;
84 rdp.frame_buffers[rdp.copy_ci_index].status = ci_copy;
85 FRDP("rdp.frame_buffers[%d].status = ci_copy\n", rdp.copy_ci_index);
87 if (rdp.frame_buffers[rdp.copy_ci_index].addr != rdp.main_ci_bg)
94 LRDP("motion blur!\n");
95 rdp.motionblur = TRUE;
98 FRDP ("Detect FB usage. texture addr is inside framebuffer: %08lx - %08lx \n", imagePtr, rdp.main_ci);
100 else if (imagePtr == rdp.zimg)
102 if (status == ci_unknown)
104 rdp.frame_buffers[rdp.ci_count-1].status = ci_zcopy;
105 rdp.tmpzimg = rdp.frame_buffers[rdp.ci_count-1].addr;
106 if (!rdp.copy_zi_index)
107 rdp.copy_zi_index = rdp.ci_count-1;
108 FRDP("rdp.frame_buffers[%d].status = ci_zcopy\n", rdp.copy_ci_index);
113 static void fb_setscissor()
115 rdp.scissor_o.lr_y = (wxUint32)(((rdp.cmd1 & 0x00000FFF) >> 2));
118 rdp.scissor_o.ul_x = (wxUint32)(((rdp.cmd0 & 0x00FFF000) >> 14));
119 rdp.scissor_o.lr_x = (wxUint32)(((rdp.cmd1 & 0x00FFF000) >> 14));
120 COLOR_IMAGE & cur_fb = rdp.frame_buffers[rdp.ci_count-1];
121 if (rdp.scissor_o.lr_x - rdp.scissor_o.ul_x > (wxUint32)(cur_fb.width >> 1))
123 if (cur_fb.height == 0 || (cur_fb.width >= rdp.scissor_o.lr_x-1 && cur_fb.width <= rdp.scissor_o.lr_x+1))
124 cur_fb.height = rdp.scissor_o.lr_y;
126 FRDP("fb_setscissor. lr_x = %d, lr_y = %d, fb_width = %d, fb_height = %d\n", rdp.scissor_o.lr_x, rdp.scissor_o.lr_y, cur_fb.width, cur_fb.height);
130 static void fb_uc2_movemem()
132 if ((rdp.cmd0 & 0xFF) == 8)
134 wxUint32 a = segoffset(rdp.cmd1) >> 1;
135 short scale_x = ((short*)gfx.RDRAM)[(a+0)^1] >> 2;
136 short trans_x = ((short*)gfx.RDRAM)[(a+4)^1] >> 2;
137 COLOR_IMAGE & cur_fb = rdp.frame_buffers[rdp.ci_count-1];
138 if ( abs((int)(scale_x + trans_x - cur_fb.width)) < 3)
140 short scale_y = ((short*)gfx.RDRAM)[(a+1)^1] >> 2;
141 short trans_y = ((short*)gfx.RDRAM)[(a+5)^1] >> 2;
142 wxUint32 height = scale_y + trans_y;
143 if (height < rdp.scissor_o.lr_y)
144 cur_fb.height = height;
149 static void fb_rect()
151 if (rdp.frame_buffers[rdp.ci_count-1].width == 32)
153 int ul_x = ((rdp.cmd1 & 0x00FFF000) >> 14);
154 int lr_x = ((rdp.cmd0 & 0x00FFF000) >> 14);
155 int width = lr_x-ul_x;
156 int diff = abs((int)rdp.frame_buffers[rdp.ci_count-1].width - width);
159 wxUint32 lr_y = min(rdp.scissor_o.lr_y, (rdp.cmd0 & 0xFFF) >> 2);
160 if (rdp.frame_buffers[rdp.ci_count-1].height < lr_y)
162 FRDP("fb_rect. ul_x: %d, lr_x: %d, fb_height: %d -> %d\n", ul_x, lr_x, rdp.frame_buffers[rdp.ci_count-1].height, lr_y);
163 rdp.frame_buffers[rdp.ci_count-1].height = lr_y;
168 static void fb_rdphalf_1()
170 branch_dl = rdp.cmd1;
174 static void fb_settextureimage()
176 if (rdp.main_ci == 0)
178 COLOR_IMAGE & cur_fb = rdp.frame_buffers[rdp.ci_count-1];
179 if ( cur_fb.status >= ci_copy )
181 if (((rdp.cmd0 >> 19) & 0x03) >= 2) //check that texture is 16/32bit
183 int tex_format = ((rdp.cmd0 >> 21) & 0x07);
184 wxUint32 addr = segoffset(rdp.cmd1);
185 if ( tex_format == 0 )
187 FRDP ("fb_settextureimage. fmt: %d, size: %d, imagePtr %08lx, main_ci: %08lx, cur_ci: %08lx \n", ((rdp.cmd0 >> 21) & 0x07), ((rdp.cmd0 >> 19) & 0x03), addr, rdp.main_ci, rdp.frame_buffers[rdp.ci_count-1].addr);
188 if (cur_fb.status == ci_main)
190 rdp.main_ci_last_tex_addr = addr;
191 if (cur_fb.height == 0)
193 cur_fb.height = rdp.scissor_o.lr_y;
194 rdp.main_ci_end = cur_fb.addr + ((cur_fb.width * cur_fb.height) << cur_fb.size >> 1);
197 if ((addr >= rdp.main_ci) && (addr < rdp.main_ci_end)) //addr within main frame buffer
199 if (cur_fb.status == ci_main)
201 rdp.copy_ci_index = rdp.ci_count-1;
202 cur_fb.status = ci_copy_self;
203 rdp.scale_x = rdp.scale_x_bak;
204 rdp.scale_y = rdp.scale_y_bak;
205 FRDP("rdp.frame_buffers[%d].status = ci_copy_self\n", rdp.ci_count-1);
209 if (cur_fb.width == rdp.frame_buffers[rdp.main_ci_index].width)
211 rdp.copy_ci_index = rdp.ci_count-1;
212 cur_fb.status = ci_copy;
213 FRDP("rdp.frame_buffers[%d].status = ci_copy\n", rdp.copy_ci_index);
214 if ((rdp.main_ci_last_tex_addr >= cur_fb.addr) &&
215 (rdp.main_ci_last_tex_addr < (cur_fb.addr + cur_fb.width*cur_fb.height*cur_fb.size)))
217 LRDP("motion blur!\n");
218 rdp.motionblur = TRUE;
226 else if (!(settings.frame_buffer & fb_ignore_aux_copy) && cur_fb.width < rdp.frame_buffers[rdp.main_ci_index].width)
228 rdp.copy_ci_index = rdp.ci_count-1;
229 cur_fb.status = ci_aux_copy;
230 FRDP("rdp.frame_buffers[%d].status = ci_aux_copy\n", rdp.copy_ci_index);
236 cur_fb.status = ci_aux;
237 FRDP("rdp.frame_buffers[%d].status = ci_aux\n", rdp.copy_ci_index);
240 FRDP ("Detect FB usage. texture addr is inside framebuffer: %08lx - %08lx \n", addr, rdp.main_ci);
243 else if ((cur_fb.status != ci_main) && (addr >= rdp.zimg && addr < rdp.zimg_end))
245 cur_fb.status = ci_zcopy;
246 if (!rdp.copy_zi_index)
247 rdp.copy_zi_index = rdp.ci_count-1;
248 FRDP("fb_settextureimage. rdp.frame_buffers[%d].status = ci_zcopy\n", rdp.ci_count-1);
251 else if ((rdp.maincimg[0].width > 64) && (addr >= rdp.maincimg[0].addr) && (addr < (rdp.maincimg[0].addr + rdp.maincimg[0].width*rdp.maincimg[0].height*2)))
253 if (cur_fb.status != ci_main)
255 cur_fb.status = ci_old_copy;
256 FRDP("rdp.frame_buffers[%d].status = ci_old_copy 1, addr:%08lx\n", rdp.ci_count-1, rdp.last_drawn_ci_addr);
258 rdp.read_previous_ci = TRUE;
259 LRDP("read_previous_ci = TRUE\n");
261 else if ((addr >= rdp.last_drawn_ci_addr) && (addr < (rdp.last_drawn_ci_addr + rdp.maincimg[0].width*rdp.maincimg[0].height*2)))
263 if (cur_fb.status != ci_main)
265 cur_fb.status = ci_old_copy;
266 FRDP("rdp.frame_buffers[%d].status = ci_old_copy 2, addr:%08lx\n", rdp.ci_count-1, rdp.last_drawn_ci_addr);
268 rdp.read_previous_ci = TRUE;
269 LRDP("read_previous_ci = TRUE\n");
272 else if (fb_hwfbe_enabled && (cur_fb.status == ci_main))
274 if ((addr >= rdp.main_ci) && (addr < rdp.main_ci_end)) //addr within main frame buffer
276 rdp.copy_ci_index = rdp.ci_count-1;
277 rdp.black_ci_index = rdp.ci_count-1;
278 cur_fb.status = ci_copy_self;
279 FRDP("rdp.frame_buffers[%d].status = ci_copy_self\n", rdp.ci_count-1);
283 if (cur_fb.status == ci_unknown)
285 cur_fb.status = ci_aux;
286 FRDP("fb_settextureimage. rdp.frame_buffers[%d].status = ci_aux\n", rdp.ci_count-1);
290 static void fb_loadtxtr()
292 if (rdp.frame_buffers[rdp.ci_count-1].status == ci_unknown)
294 rdp.frame_buffers[rdp.ci_count-1].status = ci_aux;
295 FRDP("rdp.frame_buffers[%d].status = ci_aux\n", rdp.ci_count-1);
299 static void fb_setdepthimage()
301 rdp.zimg = segoffset(rdp.cmd1) & BMASK;
302 rdp.zimg_end = rdp.zimg + rdp.ci_width*rdp.ci_height*2;
303 FRDP ("fb_setdepthimage. addr %08lx - %08lx\n", rdp.zimg, rdp.zimg_end);
304 if (rdp.zimg == rdp.main_ci) //strange, but can happen
306 rdp.frame_buffers[rdp.main_ci_index].status = ci_unknown;
307 if (rdp.main_ci_index < rdp.ci_count)
309 rdp.frame_buffers[rdp.main_ci_index].status = ci_zimg;
310 FRDP("rdp.frame_buffers[%d].status = ci_zimg\n", rdp.main_ci_index);
312 rdp.frame_buffers[rdp.main_ci_index].status = ci_main;
313 FRDP("rdp.frame_buffers[%d].status = ci_main\n", rdp.main_ci_index);
314 rdp.main_ci = rdp.frame_buffers[rdp.main_ci_index].addr;
315 rdp.main_ci_end = rdp.main_ci + (rdp.frame_buffers[rdp.main_ci_index].width * rdp.frame_buffers[rdp.main_ci_index].height * rdp.frame_buffers[rdp.main_ci_index].size);
316 for (int i = rdp.main_ci_index+1; i < rdp.ci_count; i++)
318 COLOR_IMAGE & fb = rdp.frame_buffers[i];
319 if (fb.addr == rdp.main_ci)
322 FRDP("rdp.frame_buffers[%d].status = ci_main\n", i);
331 for (int i = 0; i < rdp.ci_count; i++)
333 COLOR_IMAGE & fb = rdp.frame_buffers[i];
334 if ((fb.addr == rdp.zimg) && (fb.status == ci_aux || fb.status == ci_useless))
337 FRDP("rdp.frame_buffers[%d].status = ci_zimg\n", i);
342 static void fb_setcolorimage()
344 rdp.ocimg = rdp.cimg;
345 rdp.cimg = segoffset(rdp.cmd1) & BMASK;
346 COLOR_IMAGE & cur_fb = rdp.frame_buffers[rdp.ci_count];
347 cur_fb.width = (rdp.cmd0 & 0xFFF) + 1;
348 if (cur_fb.width == 32 )
350 else if (cur_fb.width == 16 )
352 else if (rdp.ci_count > 0)
353 cur_fb.height = rdp.scissor_o.lr_y;
356 cur_fb.format = (rdp.cmd0 >> 21) & 0x7;
357 cur_fb.size = (rdp.cmd0 >> 19) & 0x3;
358 cur_fb.addr = rdp.cimg;
361 if (rdp.ci_count > 0)
362 if (rdp.frame_buffers[0].addr == rdp.cimg)
363 rdp.frame_buffers[0].height = rdp.scissor_o.lr_y;
365 FRDP ("fb_setcolorimage. width: %d, height: %d, fmt: %d, size: %d, addr %08lx\n", cur_fb.width, cur_fb.height, cur_fb.format, cur_fb.size, cur_fb.addr);
366 if (rdp.cimg == rdp.zimg)
368 cur_fb.status = ci_zimg;
369 rdp.zimg_end = rdp.zimg + cur_fb.width*rdp.scissor_o.lr_y*2;
370 FRDP("rdp.frame_buffers[%d].status = ci_zimg\n", rdp.ci_count);
372 else if (rdp.cimg == rdp.tmpzimg)
374 cur_fb.status = ci_zcopy;
375 if (!rdp.copy_zi_index)
376 rdp.copy_zi_index = rdp.ci_count-1;
377 FRDP("rdp.frame_buffers[%d].status = ci_zcopy\n", rdp.ci_count);
379 else if (rdp.main_ci != 0)
381 if (rdp.cimg == rdp.main_ci) //switched to main fb again
383 cur_fb.height = max(cur_fb.height, rdp.frame_buffers[rdp.main_ci_index].height);
384 rdp.main_ci_index = rdp.ci_count;
385 rdp.main_ci_end = rdp.cimg + ((cur_fb.width * cur_fb.height) << cur_fb.size >> 1);
386 cur_fb.status = ci_main;
387 FRDP("rdp.frame_buffers[%d].status = ci_main\n", rdp.ci_count);
389 else // status is not known yet
391 cur_fb.status = ci_unknown;
396 if ((rdp.zimg != rdp.cimg))//&& (rdp.ocimg != rdp.cimg))
398 rdp.main_ci = rdp.cimg;
399 rdp.main_ci_end = rdp.cimg + ((cur_fb.width * cur_fb.height) << cur_fb.size >> 1);
400 rdp.main_ci_index = rdp.ci_count;
401 cur_fb.status = ci_main;
402 FRDP("rdp.frame_buffers[%d].status = ci_main\n", rdp.ci_count);
406 cur_fb.status = ci_unknown;
410 if (rdp.ci_count > 0 && rdp.frame_buffers[rdp.ci_count-1].status == ci_unknown) //status of previous fb was not changed - it is useless
412 if (fb_hwfbe_enabled && !(settings.frame_buffer & fb_useless_is_useless))
414 rdp.frame_buffers[rdp.ci_count-1].status = ci_aux;
415 rdp.frame_buffers[rdp.ci_count-1].changed = 0;
416 FRDP("rdp.frame_buffers[%d].status = ci_aux\n", rdp.ci_count-1);
420 rdp.frame_buffers[rdp.ci_count-1].status = ci_useless;
422 wxUint32 addr = rdp.frame_buffers[rdp.ci_count-1].addr;
423 for (int i = 0; i < rdp.ci_count - 1; i++)
425 if (rdp.frame_buffers[i].addr == addr)
427 rdp.frame_buffers[rdp.ci_count-1].status = rdp.frame_buffers[i].status;
432 FRDP("rdp.frame_buffers[%d].status = %s\n", rdp.ci_count-1, CIStatus[rdp.frame_buffers[rdp.ci_count-1].status]);
435 if (cur_fb.status == ci_main)
437 int viSwapOK = ((settings.swapmode == 2) && (rdp.vi_org_reg == *gfx.VI_ORIGIN_REG)) ? FALSE : TRUE;
438 if ((rdp.maincimg[0].addr != cur_fb.addr) && SwapOK && viSwapOK)
441 rdp.swap_ci_index = rdp.ci_count;
445 if (rdp.ci_count > NUMTEXBUF) //overflow
449 // RDP graphic instructions pointer table used in DetectFrameBufferUsage
451 static rdp_instr gfx_instruction_lite[9][256] =
454 // uCode 0 - RSP SW 2.0X
456 // games: Super Mario 64, Tetrisphere, Demos
458 0, 0, uc0_displaylist, 0,
490 // 80-bf: Immediate commands
506 fb_uc0_moveword, 0, uc0_culldl, 0,
507 // c0-ff: RDP commands
517 fb_rect, fb_rect, 0, 0,
519 0, fb_setscissor, 0, 0,
523 0, fb_settextureimage, fb_setdepthimage, fb_setcolorimage
526 // uCode 1 - F3DEX 1.XX
528 // games: Mario Kart, Star Fox
531 0, 0, uc0_displaylist, 0,
563 // 80-bf: Immediate commands
575 0, 0, 0, uc6_loaducode,
576 uc1_branch_z, 0, 0, 0,
577 fb_rdphalf_1, 0, 0, 0,
579 fb_uc0_moveword, 0, uc2_culldl, 0,
580 // c0-ff: RDP commands
590 fb_rect, fb_rect, 0, 0,
592 0, fb_setscissor, 0, 0,
596 0, fb_settextureimage, fb_setdepthimage, fb_setcolorimage
599 // uCode 2 - F3DEX 2.XX
604 uc1_branch_z, 0, 0, 0,
605 0, fb_bg_copy, fb_bg_copy, 0,
656 // c0-ff: RDP commands mixed with uc2 commands
662 0, uc2_dlist_cnt, 0, 0,
663 0, 0, 0, fb_uc2_moveword,
664 fb_uc2_movemem, uc2_load_ucode, uc0_displaylist, uc0_enddl,
665 0, fb_rdphalf_1, 0, 0,
666 fb_rect, fb_rect, 0, 0,
668 0, fb_setscissor, 0, 0,
672 0, fb_settextureimage, fb_setdepthimage, fb_setcolorimage
675 // uCode 3 - "RSP SW 2.0D", but not really
678 // ** Added by Gonetz **
681 0, 0, uc0_displaylist, 0,
713 // 80-bf: Immediate commands
729 fb_uc0_moveword, 0, uc0_culldl, 0,
730 // c0-ff: RDP commands
740 fb_rect, fb_rect, 0, 0,
742 0, fb_setscissor, 0, 0,
746 0, fb_settextureimage, fb_setdepthimage, fb_setcolorimage
750 // uCode 4 - RSP SW 2.0D EXT
752 // games: Star Wars: Shadows of the Empire
754 0, 0, uc0_displaylist, 0,
786 // 80-bf: Immediate commands
802 fb_uc0_moveword, 0, uc0_culldl, 0,
803 // c0-ff: RDP commands
813 fb_rect, fb_rect, 0, 0,
815 0, fb_setscissor, 0, 0,
819 0, fb_settextureimage, fb_setdepthimage, fb_setcolorimage
823 // uCode 5 - RSP SW 2.0 Diddy
825 // games: Diddy Kong Racing
827 0, 0, uc0_displaylist, uc5_dl_in_mem,
859 // 80-bf: Immediate commands
875 fb_uc0_moveword, 0, uc0_culldl, 0,
876 // c0-ff: RDP commands
886 fb_rect, fb_rect, 0, 0,
888 0, fb_setscissor, 0, 0,
892 0, fb_settextureimage, fb_setdepthimage, fb_setcolorimage
895 // uCode 6 - S2DEX 1.XX
896 // games: Yoshi's Story
899 0, 0, uc0_displaylist, 0,
931 // 80-bf: Immediate commands
943 0, 0, 0, uc6_loaducode,
944 uc6_select_dl, 0, 0, 0,
947 fb_uc0_moveword, 0, uc2_culldl, 0,
948 // c0-ff: RDP commands
949 0, fb_loadtxtr, fb_loadtxtr, fb_loadtxtr,
950 fb_loadtxtr, 0, 0, 0,
958 fb_rect, fb_rect, 0, 0,
960 0, fb_setscissor, 0, 0,
964 0, fb_settextureimage, fb_setdepthimage, fb_setcolorimage
969 0, 0, uc0_displaylist, 0,
1001 // 80-bf: Immediate commands
1017 fb_uc0_moveword, 0, uc0_culldl, 0,
1018 // c0-ff: RDP commands
1028 fb_rect, fb_rect, 0, 0,
1030 0, fb_setscissor, 0, 0,
1034 0, fb_settextureimage, fb_setdepthimage, fb_setcolorimage
1039 0, 0, 0, uc2_culldl,
1040 uc1_branch_z, 0, 0, 0,
1041 0, fb_bg_copy, fb_bg_copy, 0,
1092 // c0-ff: RDP commands mixed with uc2 commands
1098 0, uc2_dlist_cnt, 0, 0,
1099 0, 0, 0, fb_uc2_moveword,
1100 0, uc2_load_ucode, uc0_displaylist, uc0_enddl,
1102 fb_rect, fb_rect, 0, 0,
1104 0, fb_setscissor, 0, 0,
1108 0, fb_settextureimage, fb_setdepthimage, fb_setcolorimage