2 * Glide64 - Glide video plugin for Nintendo 64 emulators.
3 * Copyright (c) 2002 Dave2001
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 //****************************************************************
22 // Glide64 - Glide Plugin for Nintendo 64 emulators (tested mostly with Project64)
23 // Project started on December 29th, 2001
26 // * 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.
27 // * 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.
29 // Official Glide64 development channel: #Glide64 on EFnet
31 // Original author: Dave2001 (Dave2999@hotmail.com)
32 // Other authors: Gonetz, Gugaman
34 //****************************************************************
36 // Creation 13 August 2003 Gonetz
38 //****************************************************************
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 DWORD addr
= segoffset(rdp
.cmd1
) >> 1;
69 BYTE imageFmt
= ((BYTE
*)gfx
.RDRAM
)[(((addr
+11)<<1)+0)^3];
70 BYTE imageSiz
= ((BYTE
*)gfx
.RDRAM
)[(((addr
+11)<<1)+1)^3];
71 DWORD imagePtr
= segoffset(((DWORD
*)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 WORD frameW
= ((WORD
*)gfx
.RDRAM
)[(addr
+3)^1] >> 2;
77 WORD frameH
= ((WORD
*)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 RDP("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 //printf("toto !\n");
103 if (status
== ci_unknown
)
105 rdp
.frame_buffers
[rdp
.ci_count
-1].status
= ci_zimg
;
106 rdp
.tmpzimg
= rdp
.frame_buffers
[rdp
.ci_count
-1].addr
;
107 FRDP("rdp.frame_buffers[%d].status = ci_zimg\n", rdp
.copy_ci_index
);
112 static void fb_setscissor()
114 rdp
.scissor_o
.lr_y
= (((rdp
.cmd1
& 0x00000FFF) >> 2));
117 rdp
.scissor_o
.ul_x
= (((rdp
.cmd0
& 0x00FFF000) >> 14));
118 rdp
.scissor_o
.lr_x
= (((rdp
.cmd1
& 0x00FFF000) >> 14));
119 COLOR_IMAGE
& cur_fb
= rdp
.frame_buffers
[rdp
.ci_count
-1];
120 if (rdp
.scissor_o
.lr_x
- rdp
.scissor_o
.ul_x
> (cur_fb
.width
>> 1))
122 if (cur_fb
.height
== 0 || (cur_fb
.width
>= rdp
.scissor_o
.lr_x
-1 && cur_fb
.width
<= rdp
.scissor_o
.lr_x
+1))
123 cur_fb
.height
= rdp
.scissor_o
.lr_y
;
125 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
);
129 static void fb_rect()
131 if (rdp
.frame_buffers
[rdp
.ci_count
-1].width
== 32)
133 int ul_x
= ((rdp
.cmd1
& 0x00FFF000) >> 14);
134 int lr_x
= ((rdp
.cmd0
& 0x00FFF000) >> 14);
135 int width
= lr_x
-ul_x
;
136 DWORD lr_y
= ((rdp
.cmd0
& 0x00000FFF) >> 2);
137 int diff
= abs((int)rdp
.frame_buffers
[rdp
.ci_count
-1].width
- width
);
139 if (rdp
.frame_buffers
[rdp
.ci_count
-1].height
< lr_y
)
141 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
);
142 rdp
.frame_buffers
[rdp
.ci_count
-1].height
= lr_y
;
146 static void fb_settextureimage()
148 if (rdp
.main_ci
== 0)
150 COLOR_IMAGE
& cur_fb
= rdp
.frame_buffers
[rdp
.ci_count
-1];
151 if ( cur_fb
.status
>= ci_copy
)
153 if (((rdp
.cmd0
>> 19) & 0x03) >= 2) //check that texture is 16/32bit
155 int tex_format
= ((rdp
.cmd0
>> 21) & 0x07);
156 DWORD addr
= segoffset(rdp
.cmd1
);
157 if ( tex_format
== 0 )
159 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
);
160 if (cur_fb
.status
== ci_main
)
162 rdp
.main_ci_last_tex_addr
= addr
;
163 if (cur_fb
.height
== 0)
165 cur_fb
.height
= rdp
.scissor_o
.lr_y
;
166 rdp
.main_ci_end
= cur_fb
.addr
+ ((cur_fb
.width
* cur_fb
.height
) << cur_fb
.size
>> 1);
169 if ((addr
>= rdp
.main_ci
) && (addr
< rdp
.main_ci_end
)) //addr within main frame buffer
171 if (cur_fb
.status
== ci_main
)
173 rdp
.copy_ci_index
= rdp
.ci_count
-1;
174 cur_fb
.status
= ci_copy_self
;
175 rdp
.scale_x
= rdp
.scale_x_bak
;
176 rdp
.scale_y
= rdp
.scale_y_bak
;
177 FRDP("rdp.frame_buffers[%d].status = ci_copy_self\n", rdp
.ci_count
-1);
181 if (cur_fb
.width
== rdp
.frame_buffers
[rdp
.main_ci_index
].width
)
183 rdp
.copy_ci_index
= rdp
.ci_count
-1;
184 cur_fb
.status
= ci_copy
;
185 FRDP("rdp.frame_buffers[%d].status = ci_copy\n", rdp
.copy_ci_index
);
186 if ((rdp
.main_ci_last_tex_addr
>= cur_fb
.addr
) &&
187 (rdp
.main_ci_last_tex_addr
< (cur_fb
.addr
+ cur_fb
.width
*cur_fb
.height
*cur_fb
.size
)))
189 RDP("motion blur!\n");
190 rdp
.motionblur
= TRUE
;
198 else if (!settings
.fb_ignore_aux_copy
&& cur_fb
.width
< rdp
.frame_buffers
[rdp
.main_ci_index
].width
)
200 rdp
.copy_ci_index
= rdp
.ci_count
-1;
201 cur_fb
.status
= ci_aux_copy
;
202 FRDP("rdp.frame_buffers[%d].status = ci_aux_copy\n", rdp
.copy_ci_index
);
208 cur_fb
.status
= ci_aux
;
209 FRDP("rdp.frame_buffers[%d].status = ci_aux\n", rdp
.copy_ci_index
);
212 FRDP ("Detect FB usage. texture addr is inside framebuffer: %08lx - %08lx \n", addr
, rdp
.main_ci
);
215 else if ((cur_fb
.status
!= ci_main
) && (addr
>= rdp
.zimg
&& addr
< rdp
.zimg_end
))
217 cur_fb
.status
= ci_zcopy
;
218 FRDP("fb_settextureimage. rdp.frame_buffers[%d].status = ci_zcopy\n", rdp
.ci_count
-1);
221 else if ((addr
>= rdp
.maincimg
[0].addr
) && (addr
< (rdp
.maincimg
[0].addr
+ rdp
.maincimg
[0].width
*rdp
.maincimg
[0].height
*2)))
223 if (cur_fb
.status
!= ci_main
)
225 cur_fb
.status
= ci_old_copy
;
226 FRDP("rdp.frame_buffers[%d].status = ci_old_copy 1, addr:%08lx\n", rdp
.ci_count
-1, rdp
.last_drawn_ci_addr
);
228 rdp
.read_previous_ci
= TRUE
;
229 RDP("read_previous_ci = TRUE\n");
231 else if ((addr
>= rdp
.last_drawn_ci_addr
) && (addr
< (rdp
.last_drawn_ci_addr
+ rdp
.maincimg
[0].width
*rdp
.maincimg
[0].height
*2)))
233 if (cur_fb
.status
!= ci_main
)
235 cur_fb
.status
= ci_old_copy
;
236 FRDP("rdp.frame_buffers[%d].status = ci_old_copy 2, addr:%08lx\n", rdp
.ci_count
-1, rdp
.last_drawn_ci_addr
);
238 rdp
.read_previous_ci
= TRUE
;
239 RDP("read_previous_ci = TRUE\n");
242 else if (settings
.fb_hires
&& (cur_fb
.status
== ci_main
))
244 if ((addr
>= rdp
.main_ci
) && (addr
< rdp
.main_ci_end
)) //addr within main frame buffer
246 rdp
.copy_ci_index
= rdp
.ci_count
-1;
247 rdp
.black_ci_index
= rdp
.ci_count
-1;
248 cur_fb
.status
= ci_copy_self
;
249 FRDP("rdp.frame_buffers[%d].status = ci_copy_self\n", rdp
.ci_count
-1);
253 if (cur_fb
.status
== ci_unknown
)
255 cur_fb
.status
= ci_aux
;
256 FRDP("fb_settextureimage. rdp.frame_buffers[%d].status = ci_aux\n", rdp
.ci_count
-1);
260 static void fb_loadtxtr()
262 if (rdp
.frame_buffers
[rdp
.ci_count
-1].status
== ci_unknown
)
264 rdp
.frame_buffers
[rdp
.ci_count
-1].status
= ci_aux
;
265 FRDP("rdp.frame_buffers[%d].status = ci_aux\n", rdp
.ci_count
-1);
269 static void fb_setdepthimage()
271 rdp
.zimg
= segoffset(rdp
.cmd1
) & BMASK
;
272 rdp
.zimg_end
= rdp
.zimg
+ rdp
.ci_width
*rdp
.ci_height
*2;
273 FRDP ("fb_setdepthimage. addr %08lx - %08lx\n", rdp
.zimg
, rdp
.zimg_end
);
274 if (rdp
.zimg
== rdp
.main_ci
) //strange, but can happen
276 rdp
.frame_buffers
[rdp
.main_ci_index
].status
= ci_unknown
;
277 if (rdp
.main_ci_index
< rdp
.ci_count
)
279 rdp
.frame_buffers
[rdp
.main_ci_index
].status
= ci_zimg
;
280 FRDP("rdp.frame_buffers[%d].status = ci_zimg\n", rdp
.main_ci_index
);
282 rdp
.frame_buffers
[rdp
.main_ci_index
].status
= ci_main
;
283 FRDP("rdp.frame_buffers[%d].status = ci_main\n", rdp
.main_ci_index
);
284 rdp
.main_ci
= rdp
.frame_buffers
[rdp
.main_ci_index
].addr
;
285 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
);
292 for (int i
= 0; i
< rdp
.ci_count
; i
++)
294 COLOR_IMAGE
& fb
= rdp
.frame_buffers
[i
];
295 if ((fb
.addr
== rdp
.zimg
) && (fb
.status
== ci_aux
|| fb
.status
== ci_useless
))
298 FRDP("rdp.frame_buffers[%d].status = ci_zimg\n", i
);
303 static void fb_setcolorimage()
305 rdp
.ocimg
= rdp
.cimg
;
306 rdp
.cimg
= segoffset(rdp
.cmd1
) & BMASK
;
307 COLOR_IMAGE
& cur_fb
= rdp
.frame_buffers
[rdp
.ci_count
];
308 cur_fb
.width
= (rdp
.cmd0
& 0xFFF) + 1;
309 if (cur_fb
.width
== 32 )
311 else if (cur_fb
.width
== 16 )
313 else if (rdp
.ci_count
> 0)
314 cur_fb
.height
= rdp
.scissor_o
.lr_y
;
317 cur_fb
.format
= (rdp
.cmd0
>> 21) & 0x7;
318 cur_fb
.size
= (rdp
.cmd0
>> 19) & 0x3;
319 cur_fb
.addr
= rdp
.cimg
;
322 if (rdp.ci_count > 0)
323 if (rdp.frame_buffers[0].addr == rdp.cimg)
324 rdp.frame_buffers[0].height = rdp.scissor_o.lr_y;
326 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
);
327 if ((rdp
.cimg
== rdp
.zimg
) || (rdp
.cimg
== rdp
.tmpzimg
))
329 cur_fb
.status
= ci_zimg
;
330 if (rdp
.zimg_end
== rdp
.zimg
)
331 rdp
.zimg_end
= rdp
.zimg
+ cur_fb
.width
*rdp
.scissor_o
.lr_y
*2;
332 FRDP("rdp.frame_buffers[%d].status = ci_zimg\n", rdp
.ci_count
);
334 else if (rdp
.main_ci
!= 0)
336 if (rdp
.cimg
== rdp
.main_ci
) //switched to main fb again
338 cur_fb
.height
= max(cur_fb
.height
, rdp
.frame_buffers
[rdp
.main_ci_index
].height
);
339 rdp
.main_ci_index
= rdp
.ci_count
;
340 rdp
.main_ci_end
= rdp
.cimg
+ ((cur_fb
.width
* cur_fb
.height
) << cur_fb
.size
>> 1);
341 cur_fb
.status
= ci_main
;
342 FRDP("rdp.frame_buffers[%d].status = ci_main\n", rdp
.ci_count
);
344 else // status is not known yet
346 cur_fb
.status
= ci_unknown
;
351 if ((rdp
.zimg
!= rdp
.cimg
))//&& (rdp.ocimg != rdp.cimg))
353 rdp
.main_ci
= rdp
.cimg
;
354 rdp
.main_ci_end
= rdp
.cimg
+ ((cur_fb
.width
* cur_fb
.height
) << cur_fb
.size
>> 1);
355 rdp
.main_ci_index
= rdp
.ci_count
;
356 cur_fb
.status
= ci_main
;
357 FRDP("rdp.frame_buffers[%d].status = ci_main\n", rdp
.ci_count
);
361 cur_fb
.status
= ci_unknown
;
365 if (rdp
.frame_buffers
[rdp
.ci_count
-1].status
== ci_unknown
) //status of previous fb was not changed - it is useless
367 if (settings
.fb_hires
&& !settings
.PM
)
369 rdp
.frame_buffers
[rdp
.ci_count
-1].status
= ci_aux
;
370 rdp
.frame_buffers
[rdp
.ci_count
-1].changed
= 0;
371 FRDP("rdp.frame_buffers[%d].status = ci_aux\n", rdp
.ci_count
-1);
375 rdp
.frame_buffers
[rdp
.ci_count
-1].status
= ci_useless
;
377 DWORD addr = rdp.frame_buffers[rdp.ci_count-1].addr;
378 for (int i = 0; i < rdp.ci_count - 1; i++)
380 if (rdp.frame_buffers[i].addr == addr)
382 rdp.frame_buffers[rdp.ci_count-1].status = rdp.frame_buffers[i].status;
387 FRDP("rdp.frame_buffers[%d].status = %s\n", rdp
.ci_count
-1, CIStatus
[rdp
.frame_buffers
[rdp
.ci_count
-1].status
]);
390 if (cur_fb
.status
== ci_main
)
392 BOOL viSwapOK
= ((settings
.swapmode
== 2) && (rdp
.vi_org_reg
== *gfx
.VI_ORIGIN_REG
)) ? FALSE
: TRUE
;
393 if ((rdp
.maincimg
[0].addr
!= cur_fb
.addr
) && SwapOK
&& viSwapOK
)
396 rdp
.swap_ci_index
= rdp
.ci_count
;
400 if (rdp
.ci_count
> NUMTEXBUF
) //overflow
404 // RDP graphic instructions pointer table used in DetectFrameBufferUsage
406 static rdp_instr gfx_instruction_lite
[9][256] =
409 // uCode 0 - RSP SW 2.0X
411 // games: Super Mario 64, Tetrisphere, Demos
413 0, 0, uc0_displaylist
, 0,
445 // 80-bf: Immediate commands
461 fb_uc0_moveword
, 0, uc0_culldl
, 0,
462 // c0-ff: RDP commands
472 fb_rect
, fb_rect
, 0, 0,
474 0, fb_setscissor
, 0, 0,
478 0, fb_settextureimage
, fb_setdepthimage
, fb_setcolorimage
481 // uCode 1 - F3DEX 1.XX
483 // games: Mario Kart, Star Fox
486 0, 0, uc0_displaylist
, 0,
518 // 80-bf: Immediate commands
530 0, 0, 0, uc6_loaducode
,
531 uc1_branch_z
, 0, 0, 0,
532 uc1_rdphalf_1
, 0, 0, 0,
534 fb_uc0_moveword
, 0, uc2_culldl
, 0,
535 // c0-ff: RDP commands
545 fb_rect
, fb_rect
, 0, 0,
547 0, fb_setscissor
, 0, 0,
551 0, fb_settextureimage
, fb_setdepthimage
, fb_setcolorimage
554 // uCode 2 - F3DEX 2.XX
559 uc1_branch_z
, 0, 0, 0,
560 0, fb_bg_copy
, fb_bg_copy
, 0,
611 // c0-ff: RDP commands mixed with uc2 commands
617 0, uc2_dlist_cnt
, 0, 0,
618 0, 0, 0, fb_uc2_moveword
,
619 0/*fb_uc2_movemem*/, uc2_load_ucode
, uc0_displaylist
, uc0_enddl
,
620 0, uc1_rdphalf_1
, 0, 0,
621 fb_rect
, fb_rect
, 0, 0,
623 0, fb_setscissor
, 0, 0,
627 0, fb_settextureimage
, fb_setdepthimage
, fb_setcolorimage
630 // uCode 3 - "RSP SW 2.0D", but not really
633 // ** Added by Gonetz **
668 // 80-bf: Immediate commands
684 fb_uc0_moveword
, 0, uc0_culldl
, 0,
685 // c0-ff: RDP commands
695 fb_rect
, fb_rect
, 0, 0,
697 0, fb_setscissor
, 0, 0,
701 0, fb_settextureimage
, fb_setdepthimage
, fb_setcolorimage
705 // uCode 4 - RSP SW 2.0D EXT
707 // games: Star Wars: Shadows of the Empire
709 0, 0, uc0_displaylist
, 0,
741 // 80-bf: Immediate commands
757 fb_uc0_moveword
, 0, uc0_culldl
, 0,
758 // c0-ff: RDP commands
768 fb_rect
, fb_rect
, 0, 0,
770 0, fb_setscissor
, 0, 0,
774 0, fb_settextureimage
, fb_setdepthimage
, fb_setcolorimage
778 // uCode 5 - RSP SW 2.0 Diddy
780 // games: Diddy Kong Racing
782 0, 0, uc0_displaylist
, uc5_dl_in_mem
,
814 // 80-bf: Immediate commands
830 fb_uc0_moveword
, 0, uc0_culldl
, 0,
831 // c0-ff: RDP commands
841 fb_rect
, fb_rect
, 0, 0,
843 0, fb_setscissor
, 0, 0,
847 0, fb_settextureimage
, fb_setdepthimage
, fb_setcolorimage
850 // uCode 6 - S2DEX 1.XX
851 // games: Yoshi's Story
854 0, 0, uc0_displaylist
, 0,
886 // 80-bf: Immediate commands
898 0, 0, 0, uc6_loaducode
,
899 uc6_select_dl
, 0, 0, 0,
902 fb_uc0_moveword
, 0, uc2_culldl
, 0,
903 // c0-ff: RDP commands
904 0, fb_loadtxtr
, fb_loadtxtr
, fb_loadtxtr
,
905 fb_loadtxtr
, 0, 0, 0,
913 fb_rect
, fb_rect
, 0, 0,
915 0, fb_setscissor
, 0, 0,
919 0, fb_settextureimage
, fb_setdepthimage
, fb_setcolorimage
924 0, 0, uc0_displaylist
, 0,
956 // 80-bf: Immediate commands
972 fb_uc0_moveword
, 0, uc0_culldl
, 0,
973 // c0-ff: RDP commands
983 fb_rect
, fb_rect
, 0, 0,
985 0, fb_setscissor
, 0, 0,
989 0, fb_settextureimage
, fb_setdepthimage
, fb_setcolorimage
995 uc1_branch_z
, 0, 0, 0,
996 0, fb_bg_copy
, fb_bg_copy
, 0,
1047 // c0-ff: RDP commands mixed with uc2 commands
1053 0, uc2_dlist_cnt
, 0, 0,
1054 0, 0, 0, fb_uc2_moveword
,
1055 0, uc2_load_ucode
, uc0_displaylist
, uc0_enddl
,
1056 0, uc1_rdphalf_1
, 0, 0,
1057 fb_rect
, fb_rect
, 0, 0,
1059 0, fb_setscissor
, 0, 0,
1063 0, fb_settextureimage
, fb_setdepthimage
, fb_setcolorimage