98e75f2d |
1 | /* |
2 | * Glide64 - Glide video plugin for Nintendo 64 emulators. |
3 | * Copyright (c) 2002 Dave2001 |
4 | * Copyright (c) 2003-2009 Sergey 'Gonetz' Lipski |
5 | * |
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 |
9 | * any later version. |
10 | * |
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. |
15 | * |
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 |
19 | */ |
20 | |
21 | //**************************************************************** |
22 | // |
23 | // Glide64 - Glide Plugin for Nintendo 64 emulators |
24 | // Project started on December 29th, 2001 |
25 | // |
26 | // Authors: |
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 |
31 | // |
32 | //**************************************************************** |
33 | // |
34 | // To modify Glide64: |
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. |
37 | // |
38 | //**************************************************************** |
39 | // |
40 | // Hardware frame buffer emulation |
41 | // Dec 2003 created by Gonetz |
42 | // |
43 | //**************************************************************** |
44 | |
45 | #include "Gfx_1.3.h" |
46 | #include "TexBuffer.h" |
47 | #include "CRC.h" |
48 | |
49 | //#include "ticks.h" |
50 | |
51 | static TBUFF_COLOR_IMAGE * AllocateTextureBuffer(COLOR_IMAGE & cimage) |
52 | { |
53 | TBUFF_COLOR_IMAGE texbuf; |
54 | texbuf.addr = cimage.addr; |
55 | texbuf.end_addr = cimage.addr + ((cimage.width*cimage.height)<<cimage.size>>1); |
56 | texbuf.width = cimage.width; |
57 | texbuf.height = cimage.height; |
58 | texbuf.format = cimage.format; |
59 | texbuf.size = cimage.size; |
60 | texbuf.scr_width = min(cimage.width * rdp.scale_x, settings.scr_res_x); |
61 | float height = min(rdp.vi_height,cimage.height); |
62 | if (cimage.status == ci_copy_self || (cimage.status == ci_copy && cimage.width == rdp.frame_buffers[rdp.main_ci_index].width)) |
63 | height = rdp.vi_height; |
64 | texbuf.scr_height = height * rdp.scale_y; |
65 | // texbuf.scr_height = texbuf.height * rdp.scale_y; |
66 | |
67 | wxUint16 max_size = max((wxUint16)texbuf.scr_width, (wxUint16)texbuf.scr_height); |
68 | if (max_size > voodoo.max_tex_size) //texture size is too large |
69 | return 0; |
70 | wxUint32 tex_size; |
71 | //calculate LOD |
72 | switch ((max_size-1) >> 6) |
73 | { |
74 | case 0: |
75 | texbuf.info.smallLodLog2 = texbuf.info.largeLodLog2 = GR_LOD_LOG2_64; |
76 | tex_size = 64; |
77 | break; |
78 | case 1: |
79 | texbuf.info.smallLodLog2 = texbuf.info.largeLodLog2 = GR_LOD_LOG2_128; |
80 | tex_size = 128; |
81 | break; |
82 | case 2: |
83 | case 3: |
84 | texbuf.info.smallLodLog2 = texbuf.info.largeLodLog2 = GR_LOD_LOG2_256; |
85 | tex_size = 256; |
86 | break; |
87 | case 4: |
88 | case 5: |
89 | case 6: |
90 | case 7: |
91 | texbuf.info.smallLodLog2 = texbuf.info.largeLodLog2 = GR_LOD_LOG2_512; |
92 | tex_size = 512; |
93 | break; |
94 | case 8: |
95 | case 9: |
96 | case 10: |
97 | case 11: |
98 | case 12: |
99 | case 13: |
100 | case 14: |
101 | case 15: |
102 | texbuf.info.smallLodLog2 = texbuf.info.largeLodLog2 = GR_LOD_LOG2_1024; |
103 | tex_size = 1024; |
104 | break; |
105 | default: |
106 | texbuf.info.smallLodLog2 = texbuf.info.largeLodLog2 = GR_LOD_LOG2_2048; |
107 | tex_size = 2048; |
108 | } |
109 | //calculate aspect |
110 | if (texbuf.scr_width >= texbuf.scr_height) |
111 | { |
112 | if ((texbuf.scr_width/texbuf.scr_height) >= 2) |
113 | { |
114 | texbuf.info.aspectRatioLog2 = GR_ASPECT_LOG2_2x1; |
115 | texbuf.tex_width = tex_size; |
116 | texbuf.tex_height = tex_size >> 1; |
117 | } |
118 | else |
119 | { |
120 | texbuf.info.aspectRatioLog2 = GR_ASPECT_LOG2_1x1; |
121 | texbuf.tex_width = texbuf.tex_height = tex_size; |
122 | } |
123 | } |
124 | else |
125 | { |
126 | if ((texbuf.scr_height/texbuf.scr_width) >= 2) |
127 | { |
128 | texbuf.info.aspectRatioLog2 = GR_ASPECT_LOG2_1x2; |
129 | texbuf.tex_width = tex_size >> 1; |
130 | texbuf.tex_height = tex_size; |
131 | } |
132 | else |
133 | { |
134 | texbuf.info.aspectRatioLog2 = GR_ASPECT_LOG2_1x1; |
135 | texbuf.tex_width = texbuf.tex_height = tex_size; |
136 | } |
137 | } |
138 | if ((cimage.format != 0))// && (cimage.width <= 64)) |
139 | texbuf.info.format = GR_TEXFMT_ALPHA_INTENSITY_88; |
140 | else |
141 | texbuf.info.format = GR_TEXFMT_RGB_565; |
142 | |
143 | texbuf.lr_u = 256.0f * texbuf.scr_width / (float)tex_size;// + 1.0f; |
144 | texbuf.lr_v = 256.0f * texbuf.scr_height / (float)tex_size;// + 1.0f; |
145 | texbuf.tile = 0; |
146 | texbuf.tile_uls = 0; |
147 | texbuf.tile_ult = 0; |
148 | texbuf.u_shift = 0; |
149 | texbuf.v_shift = 0; |
150 | texbuf.drawn = FALSE; |
151 | texbuf.u_scale = texbuf.lr_u / (float)(texbuf.width); |
152 | texbuf.v_scale = texbuf.lr_v / (float)(texbuf.height); |
153 | texbuf.cache = 0; |
154 | texbuf.crc = 0; |
155 | texbuf.t_mem = 0; |
156 | |
157 | FRDP("\nAllocateTextureBuffer. width: %d, height: %d, scr_width: %f, scr_height: %f, vi_width: %f, vi_height:%f, scale_x: %f, scale_y: %f, lr_u: %f, lr_v: %f, u_scale: %f, v_scale: %f\n", texbuf.width, texbuf.height, texbuf.scr_width, texbuf.scr_height, rdp.vi_width, rdp.vi_height, rdp.scale_x, rdp.scale_y, texbuf.lr_u, texbuf.lr_v, texbuf.u_scale, texbuf.v_scale); |
158 | |
159 | wxUint32 required = grTexCalcMemRequired(texbuf.info.smallLodLog2, texbuf.info.largeLodLog2, |
160 | texbuf.info.aspectRatioLog2, texbuf.info.format); |
161 | //find free space |
162 | for (int i = 0; i < voodoo.num_tmu; i++) |
163 | { |
164 | wxUint32 available = 0; |
165 | wxUint32 top = 0; |
166 | if (rdp.texbufs[i].count) |
167 | { |
168 | TBUFF_COLOR_IMAGE & t = rdp.texbufs[i].images[rdp.texbufs[i].count - 1]; |
169 | if (rdp.read_whole_frame || rdp.motionblur) |
170 | { |
171 | if ((cimage.status == ci_aux) && (rdp.cur_tex_buf == i)) |
172 | { |
173 | top = t.tex_addr + t.tex_width * (int)(t.scr_height+1) * 2; |
174 | if (rdp.texbufs[i].end - top < required) |
175 | return 0; |
176 | } |
177 | else |
178 | top = rdp.texbufs[i].end; |
179 | } |
180 | else |
181 | top = t.tex_addr + t.tex_width * t.tex_height * 2; |
182 | available = rdp.texbufs[i].end - top; |
183 | } |
184 | else |
185 | { |
186 | available = rdp.texbufs[i].end - rdp.texbufs[i].begin; |
187 | top = rdp.texbufs[i].begin; |
188 | } |
189 | if (available >= required) |
190 | { |
191 | rdp.texbufs[i].count++; |
192 | rdp.texbufs[i].clear_allowed = FALSE; |
193 | texbuf.tex_addr = top; |
194 | rdp.cur_tex_buf = i; |
195 | texbuf.tmu = rdp.texbufs[i].tmu; |
196 | rdp.texbufs[i].images[rdp.texbufs[i].count - 1] = texbuf; |
197 | return &(rdp.texbufs[i].images[rdp.texbufs[i].count - 1]); |
198 | } |
199 | } |
200 | //not found. keep recently accessed bank, clear second one |
201 | if (!rdp.texbufs[rdp.cur_tex_buf^1].clear_allowed) //can't clear => can't allocate |
202 | return 0; |
203 | rdp.cur_tex_buf ^= 1; |
204 | rdp.texbufs[rdp.cur_tex_buf].count = 1; |
205 | rdp.texbufs[rdp.cur_tex_buf].clear_allowed = FALSE; |
206 | texbuf.tmu = rdp.texbufs[rdp.cur_tex_buf].tmu; |
207 | texbuf.tex_addr = rdp.texbufs[rdp.cur_tex_buf].begin; |
208 | rdp.texbufs[rdp.cur_tex_buf].images[0] = texbuf; |
209 | return &(rdp.texbufs[rdp.cur_tex_buf].images[0]); |
210 | } |
211 | |
212 | int OpenTextureBuffer(COLOR_IMAGE & cimage) |
213 | { |
214 | //printf("OpenTextureBuffer. cur_tex_buf: %d, addr: %08lx, width: %d, height: %d\n", rdp.cur_tex_buf, cimage.addr, cimage.width, cimage.height); |
215 | //unsigned int ticks = ticksGetTicks(); |
216 | FRDP("OpenTextureBuffer. cur_tex_buf: %d, addr: %08lx, width: %d, height: %d", rdp.cur_tex_buf, cimage.addr, cimage.width, cimage.height); |
217 | if (!fullscreen) return FALSE; |
218 | |
219 | int found = FALSE, search = TRUE; |
220 | TBUFF_COLOR_IMAGE *texbuf = 0; |
221 | wxUint32 addr = cimage.addr; |
222 | if ((settings.hacks&hack_Banjo2) && cimage.status == ci_copy_self) |
223 | addr = rdp.frame_buffers[rdp.copy_ci_index].addr; |
224 | wxUint32 end_addr = addr + ((cimage.width*cimage.height)<<cimage.size>>1); |
225 | if (rdp.motionblur) |
226 | { |
227 | // if (cimage.format != 0) |
228 | // return FALSE; |
229 | search = FALSE; |
230 | } |
231 | if (rdp.read_whole_frame) |
232 | { |
233 | if (settings.hacks&hack_PMario) //motion blur effects in Paper Mario |
234 | { |
235 | rdp.cur_tex_buf = rdp.acc_tex_buf; |
236 | FRDP("\nread_whole_frame. last allocated bank: %d\n", rdp.acc_tex_buf); |
237 | } |
238 | // else |
239 | { |
240 | if (!rdp.texbufs[0].clear_allowed || !rdp.texbufs[1].clear_allowed) |
241 | { |
242 | if (cimage.status == ci_main) |
243 | { |
244 | texbuf = &(rdp.texbufs[rdp.cur_tex_buf].images[0]); |
245 | found = TRUE; |
246 | } |
247 | else |
248 | { |
249 | for (int t = 0; (t < rdp.texbufs[rdp.cur_tex_buf].count) && !found; t++) |
250 | { |
251 | texbuf = &(rdp.texbufs[rdp.cur_tex_buf].images[t]); |
252 | if (addr == texbuf->addr && cimage.width == texbuf->width) |
253 | { |
254 | texbuf->drawn = FALSE; |
255 | found = TRUE; |
256 | } |
257 | } |
258 | } |
259 | } |
260 | search = FALSE; |
261 | } |
262 | } |
263 | if (search) |
264 | { |
265 | //printf("search ! (%i) : ", voodoo.num_tmu); |
266 | for (int i = 0; (i < voodoo.num_tmu) && !found; i++) |
267 | { |
268 | //printf("[%i] ", rdp.texbufs[i].count); |
269 | for (int j = 0; (j < rdp.texbufs[i].count) && !found; j++) |
270 | { |
271 | texbuf = &(rdp.texbufs[i].images[j]); |
272 | if (addr == texbuf->addr && cimage.width == texbuf->width) |
273 | { |
274 | //texbuf->height = cimage.height; |
275 | //texbuf->end_addr = end_addr; |
276 | texbuf->drawn = FALSE; |
277 | texbuf->format = (wxUint16)cimage.format; |
278 | if ((cimage.format != 0)) |
279 | texbuf->info.format = GR_TEXFMT_ALPHA_INTENSITY_88; |
280 | else |
281 | texbuf->info.format = GR_TEXFMT_RGB_565; |
282 | texbuf->crc = 0; |
283 | texbuf->t_mem = 0; |
284 | texbuf->tile = 0; |
285 | found = TRUE; |
286 | rdp.cur_tex_buf = i; |
287 | rdp.texbufs[i].clear_allowed = FALSE; |
288 | } |
289 | else //check intersection |
290 | { |
291 | if (!((end_addr <= texbuf->addr) || (addr >= texbuf->end_addr))) //intersected, remove |
292 | { |
293 | grRenderBuffer( GR_BUFFER_TEXTUREBUFFER_EXT ); |
294 | grTextureBufferExt( texbuf->tmu, texbuf->tex_addr, texbuf->info.smallLodLog2, texbuf->info.largeLodLog2, |
295 | texbuf->info.aspectRatioLog2, texbuf->info.format, GR_MIPMAPLEVELMASK_BOTH ); |
296 | grDepthMask (FXFALSE); |
297 | grBufferClear (0, 0, 0xFFFF); |
298 | grDepthMask (FXTRUE); |
299 | grRenderBuffer( GR_BUFFER_BACKBUFFER ); |
300 | rdp.texbufs[i].count--; |
301 | if (j < rdp.texbufs[i].count) |
302 | memcpy(&(rdp.texbufs[i].images[j]), &(rdp.texbufs[i].images[j+1]), sizeof(TBUFF_COLOR_IMAGE)*(rdp.texbufs[i].count-j)); |
303 | } |
304 | } |
305 | } |
306 | } |
307 | } |
308 | else |
309 | { |
310 | LRDP(" not searched"); |
311 | } |
312 | |
313 | if (!found) |
314 | { |
315 | LRDP(" not found"); |
316 | texbuf = AllocateTextureBuffer(cimage); |
317 | //printf(" not found\n"); |
318 | } |
319 | else |
320 | { |
321 | LRDP(" found"); |
322 | //printf(" found\n"); |
323 | } |
324 | |
325 | if (!texbuf) |
326 | { |
327 | LRDP(" KO\n"); |
328 | return FALSE; |
329 | } |
330 | |
331 | //unsigned int tticks=ticksGetTicks(); |
332 | rdp.acc_tex_buf = rdp.cur_tex_buf; |
333 | rdp.cur_image = texbuf; |
334 | grRenderBuffer( GR_BUFFER_TEXTUREBUFFER_EXT ); |
335 | grTextureBufferExt( rdp.cur_image->tmu, rdp.cur_image->tex_addr, rdp.cur_image->info.smallLodLog2, rdp.cur_image->info.largeLodLog2, |
336 | rdp.cur_image->info.aspectRatioLog2, rdp.cur_image->info.format, GR_MIPMAPLEVELMASK_BOTH ); |
337 | ///* |
338 | //printf("mesured %u ms\n", ticksGetTicks()-tticks); |
339 | if (rdp.cur_image->clear && (settings.frame_buffer&fb_hwfbe_buf_clear) && cimage.changed) |
340 | { |
341 | rdp.cur_image->clear = FALSE; |
342 | grDepthMask (FXFALSE); |
343 | grBufferClear (0, 0, 0xFFFF); |
344 | grDepthMask (FXTRUE); |
345 | } |
346 | |
347 | //*/ |
348 | // memset(gfx.RDRAM+cimage.addr, 0, cimage.width*cimage.height*cimage.size); |
349 | FRDP(" texaddr: %08lx, tex_width: %d, tex_height: %d, cur_tex_buf: %d, texformat: %d, motionblur: %d\n", rdp.cur_image->tex_addr, rdp.cur_image->tex_width, rdp.cur_image->tex_height, rdp.cur_tex_buf, rdp.cur_image->info.format, rdp.motionblur); |
350 | //printf(" time = %u ms, texaddr: %08x, tex_width: %d, tex_height: %d, cur_tex_buf: %d, texformat: %d, motionblur: %d\n", ticksGetTicks()-ticks, rdp.cur_image->tex_addr, rdp.cur_image->tex_width, rdp.cur_image->tex_height, rdp.cur_tex_buf, rdp.cur_image->info.format, rdp.motionblur); |
351 | if (!rdp.offset_x_bak) |
352 | { |
353 | rdp.offset_x_bak = rdp.offset_x; |
354 | rdp.offset_x = 0; |
355 | } |
356 | if (!rdp.offset_y_bak) |
357 | { |
358 | rdp.offset_y_bak = rdp.offset_y; |
359 | rdp.offset_y = 0; |
360 | } |
361 | rdp.update |= UPDATE_VIEWPORT | UPDATE_SCISSOR; |
362 | |
363 | return TRUE; |
364 | } |
365 | |
366 | static GrTextureFormat_t TexBufSetupCombiner(int force_rgb = FALSE) |
367 | { |
368 | grColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER, |
369 | GR_COMBINE_FACTOR_ONE, |
370 | GR_COMBINE_LOCAL_NONE, |
371 | GR_COMBINE_OTHER_TEXTURE, |
372 | // GR_COMBINE_OTHER_CONSTANT, |
373 | FXFALSE); |
374 | grAlphaCombine (GR_COMBINE_FUNCTION_SCALE_OTHER, |
375 | GR_COMBINE_FACTOR_ONE, |
376 | GR_COMBINE_LOCAL_NONE, |
377 | GR_COMBINE_OTHER_TEXTURE, |
378 | FXFALSE); |
379 | // grConstantColorValue (0xFFFFFFFF); |
380 | grAlphaBlendFunction (GR_BLEND_ONE, // use alpha compare, but not T0 alpha |
381 | GR_BLEND_ZERO, |
382 | GR_BLEND_ONE, |
383 | GR_BLEND_ZERO); |
384 | grClipWindow (0, 0, settings.scr_res_x, settings.scr_res_y); |
385 | grDepthBufferFunction (GR_CMP_ALWAYS); |
386 | grDepthMask (FXFALSE); |
387 | grCullMode (GR_CULL_DISABLE); |
388 | grFogMode (GR_FOG_DISABLE); |
389 | GrTextureFormat_t buf_format = (rdp.tbuff_tex) ? rdp.tbuff_tex->info.format : GR_TEXFMT_RGB_565; |
390 | GrCombineFunction_t color_source = GR_COMBINE_FUNCTION_LOCAL; |
391 | if (!force_rgb && rdp.black_ci_index > 0 && rdp.black_ci_index <= rdp.copy_ci_index) |
392 | { |
393 | color_source = GR_COMBINE_FUNCTION_LOCAL_ALPHA; |
394 | buf_format = GR_TEXFMT_ALPHA_INTENSITY_88; |
395 | } |
396 | if (rdp.tbuff_tex->tmu == GR_TMU0) |
397 | { |
398 | grTexCombine( GR_TMU1, |
399 | GR_COMBINE_FUNCTION_NONE, |
400 | GR_COMBINE_FACTOR_NONE, |
401 | GR_COMBINE_FUNCTION_NONE, |
402 | GR_COMBINE_FACTOR_NONE, |
403 | FXFALSE, |
404 | FXFALSE ); |
405 | grTexCombine( GR_TMU0, |
406 | color_source, |
407 | GR_COMBINE_FACTOR_NONE, |
408 | GR_COMBINE_FUNCTION_ZERO, |
409 | GR_COMBINE_FACTOR_NONE, |
410 | FXFALSE, |
411 | FXTRUE ); |
412 | } |
413 | else |
414 | { |
415 | grTexCombine( GR_TMU1, |
416 | color_source, |
417 | GR_COMBINE_FACTOR_NONE, |
418 | GR_COMBINE_FUNCTION_ZERO, |
419 | GR_COMBINE_FACTOR_NONE, |
420 | FXFALSE, |
421 | FXTRUE ); |
422 | grTexCombine( GR_TMU0, |
423 | GR_COMBINE_FUNCTION_SCALE_OTHER, |
424 | GR_COMBINE_FACTOR_ONE, |
425 | GR_COMBINE_FUNCTION_SCALE_OTHER, |
426 | GR_COMBINE_FACTOR_ONE, |
427 | FXFALSE, |
428 | FXFALSE ); |
429 | } |
430 | return buf_format; |
431 | } |
432 | |
433 | int CloseTextureBuffer(int draw) |
434 | { |
435 | if (!fullscreen || !rdp.cur_image) |
436 | { |
437 | LRDP("CloseTextureBuffer KO\n"); |
438 | return FALSE; |
439 | } |
440 | grRenderBuffer( GR_BUFFER_BACKBUFFER ); |
441 | rdp.offset_x = rdp.offset_x_bak; |
442 | rdp.offset_y = rdp.offset_y_bak; |
443 | rdp.offset_x_bak = rdp.offset_y_bak = 0; |
444 | rdp.update |= UPDATE_VIEWPORT | UPDATE_SCISSOR; |
445 | if (!draw) |
446 | { |
447 | LRDP("CloseTextureBuffer no draw, OK\n"); |
448 | rdp.cur_image = 0; |
449 | return TRUE; |
450 | } |
451 | rdp.tbuff_tex = rdp.cur_image; |
452 | rdp.cur_image = 0; |
453 | rdp.tbuff_tex->info.format = TexBufSetupCombiner(); |
454 | float zero = 0.0f; |
455 | float ul_x = rdp.offset_x; |
456 | float ul_y = rdp.offset_y; |
457 | float lr_x = rdp.tbuff_tex->scr_width + rdp.offset_x; |
458 | float lr_y = rdp.tbuff_tex->scr_height + rdp.offset_y; |
459 | float lr_u = rdp.tbuff_tex->lr_u; |
460 | float lr_v = rdp.tbuff_tex->lr_v; |
461 | FRDP("lr_x: %f, lr_y: %f, lr_u: %f, lr_v: %f\n", lr_x, lr_y, lr_u, lr_v); |
462 | |
463 | |
464 | // Make the vertices |
465 | VERTEX v[4] = { |
466 | { ul_x, ul_y, 1, 1, zero, zero, zero, zero, {zero, zero, zero, zero} }, |
467 | { lr_x, ul_y, 1, 1, lr_u, zero, lr_u, zero, {lr_u, zero, lr_u, zero} }, |
468 | { ul_x, lr_y, 1, 1, zero, lr_v, zero, lr_v, {zero, lr_v, zero, lr_v} }, |
469 | { lr_x, lr_y, 1, 1, lr_u, lr_v, lr_u, lr_v, {lr_u, lr_v, lr_u, lr_v} } |
470 | }; |
471 | |
472 | grTexSource( rdp.tbuff_tex->tmu, rdp.tbuff_tex->tex_addr, GR_MIPMAPLEVELMASK_BOTH, &(rdp.tbuff_tex->info) ); |
473 | grClipWindow (0, 0, settings.res_x, settings.res_y); |
474 | grDrawTriangle (&v[0], &v[2], &v[1]); |
475 | grDrawTriangle (&v[2], &v[3], &v[1]); |
476 | rdp.update |= UPDATE_ZBUF_ENABLED | UPDATE_COMBINE | UPDATE_TEXTURE | UPDATE_ALPHA_COMPARE; |
477 | if (settings.fog && (rdp.flags & FOG_ENABLED)) |
478 | { |
479 | grFogMode (GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT); |
480 | } |
481 | LRDP("CloseTextureBuffer draw, OK\n"); |
482 | rdp.tbuff_tex = 0; |
483 | return TRUE; |
484 | } |
485 | |
486 | int CopyTextureBuffer(COLOR_IMAGE & fb_from, COLOR_IMAGE & fb_to) |
487 | { |
488 | if (!fullscreen) |
489 | return FALSE; |
490 | FRDP("CopyTextureBuffer from %08x to %08x\n", fb_from.addr, fb_to.addr); |
491 | if (rdp.cur_image) |
492 | { |
493 | rdp.cur_image->crc = 0; |
494 | if (rdp.cur_image->addr == fb_to.addr) |
495 | return CloseTextureBuffer(TRUE); |
496 | rdp.tbuff_tex = rdp.cur_image; |
497 | } |
498 | else if (!FindTextureBuffer(fb_from.addr, (wxUint16)fb_from.width)) |
499 | { |
500 | LRDP("Can't find 'from' buffer.\n"); |
501 | return FALSE; |
502 | } |
503 | if (!OpenTextureBuffer(fb_to)) |
504 | { |
505 | LRDP("Can't open new buffer.\n"); |
506 | return CloseTextureBuffer(TRUE); |
507 | } |
508 | rdp.tbuff_tex->crc = 0; |
509 | GrTextureFormat_t buf_format = rdp.tbuff_tex->info.format; |
510 | rdp.tbuff_tex->info.format = GR_TEXFMT_RGB_565; |
511 | TexBufSetupCombiner(TRUE); |
512 | float ul_x = 0.0f; |
513 | float ul_y = 0.0f; |
514 | float lr_x = rdp.tbuff_tex->scr_width; |
515 | float lr_y = rdp.tbuff_tex->scr_height; |
516 | float zero = 0.0f; |
517 | float lr_u = rdp.tbuff_tex->lr_u; |
518 | float lr_v = rdp.tbuff_tex->lr_v; |
519 | FRDP("lr_x: %f, lr_y: %f\n", lr_x, lr_y); |
520 | |
521 | |
522 | // Make the vertices |
523 | VERTEX v[4] = { |
524 | { ul_x, ul_y, 1, 1, zero, zero, zero, zero, {zero, zero, zero, zero} }, |
525 | { lr_x, ul_y, 1, 1, lr_u, zero, lr_u, zero, {lr_u, zero, lr_u, zero} }, |
526 | { ul_x, lr_y, 1, 1, zero, lr_v, zero, lr_v, {zero, lr_v, zero, lr_v} }, |
527 | { lr_x, lr_y, 1, 1, lr_u, lr_v, lr_u, lr_v, {lr_u, lr_v, lr_u, lr_v} } |
528 | }; |
529 | |
530 | grTexSource( rdp.tbuff_tex->tmu, rdp.tbuff_tex->tex_addr, GR_MIPMAPLEVELMASK_BOTH, &(rdp.tbuff_tex->info) ); |
531 | grDrawTriangle (&v[0], &v[2], &v[1]); |
532 | grDrawTriangle (&v[2], &v[3], &v[1]); |
533 | grRenderBuffer( GR_BUFFER_BACKBUFFER ); |
534 | rdp.offset_x = rdp.offset_x_bak; |
535 | rdp.offset_y = rdp.offset_y_bak; |
536 | rdp.offset_x_bak = rdp.offset_y_bak = 0; |
537 | AddOffset(v, 4); |
538 | grClipWindow (0, 0, settings.res_x, settings.res_y); |
539 | grDrawTriangle (&v[0], &v[2], &v[1]); |
540 | grDrawTriangle (&v[2], &v[3], &v[1]); |
541 | rdp.tbuff_tex->info.format = buf_format; |
542 | |
543 | rdp.update |= UPDATE_ZBUF_ENABLED | UPDATE_COMBINE | UPDATE_TEXTURE | UPDATE_ALPHA_COMPARE; |
544 | rdp.update |= UPDATE_VIEWPORT | UPDATE_SCISSOR; |
545 | if (settings.fog && (rdp.flags & FOG_ENABLED)) |
546 | grFogMode (GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT); |
547 | LRDP("CopyTextureBuffer draw, OK\n"); |
548 | rdp.tbuff_tex = 0; |
549 | rdp.cur_image = 0; |
550 | return TRUE; |
551 | } |
552 | |
553 | int CopyDepthBuffer() |
554 | { |
555 | if (!fullscreen) |
556 | return FALSE; |
557 | LRDP("CopyDepthBuffer. "); |
558 | float bound = 1024.0f; |
559 | GrLOD_t LOD = GR_LOD_LOG2_1024; |
560 | if (settings.scr_res_x > 1024) |
561 | { |
562 | bound = 2048.0f; |
563 | LOD = GR_LOD_LOG2_2048; |
564 | } |
565 | rdp.tbuff_tex = &(rdp.texbufs[0].images[0]); |
566 | rdp.tbuff_tex->tmu = rdp.texbufs[0].tmu; |
567 | rdp.tbuff_tex->info.format = GR_TEXFMT_RGB_565; |
568 | rdp.tbuff_tex->info.smallLodLog2 = rdp.tbuff_tex->info.largeLodLog2 = LOD; |
569 | rdp.tbuff_tex->info.aspectRatioLog2 = GR_ASPECT_LOG2_1x1; |
570 | TexBufSetupCombiner(TRUE); |
571 | float ul_x = 0.0f; |
572 | float ul_y = 0.0f; |
573 | float lr_x = bound; |
574 | float lr_y = bound; |
575 | float zero = 0.0f; |
576 | float lr_u = 255.5f; |
577 | float lr_v = 255.5f; |
578 | FRDP("lr_x: %f, lr_y: %f\n", lr_x, lr_y); |
579 | |
580 | |
581 | // Make the vertices |
582 | VERTEX v[4] = { |
583 | { ul_x, ul_y, 1, 1, zero, zero, zero, zero, {zero, zero, zero, zero} }, |
584 | { lr_x, ul_y, 1, 1, lr_u, zero, lr_u, zero, {lr_u, zero, lr_u, zero} }, |
585 | { ul_x, lr_y, 1, 1, zero, lr_v, zero, lr_v, {zero, lr_v, zero, lr_v} }, |
586 | { lr_x, lr_y, 1, 1, lr_u, lr_v, lr_u, lr_v, {lr_u, lr_v, lr_u, lr_v} } |
587 | }; |
588 | |
589 | grAuxBufferExt( GR_BUFFER_AUXBUFFER ); |
590 | grTexSource( rdp.texbufs[0].tmu, rdp.texbufs[0].begin, GR_MIPMAPLEVELMASK_BOTH, &(rdp.tbuff_tex->info) ); |
591 | grRenderBuffer( GR_BUFFER_TEXTUREBUFFER_EXT ); |
592 | grTextureBufferExt( rdp.texbufs[1].tmu, rdp.texbufs[1].begin, LOD, LOD, |
593 | GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565, GR_MIPMAPLEVELMASK_BOTH ); |
594 | grDrawTriangle (&v[0], &v[2], &v[1]); |
595 | grDrawTriangle (&v[2], &v[3], &v[1]); |
596 | grRenderBuffer( GR_BUFFER_BACKBUFFER ); |
597 | grTextureAuxBufferExt( rdp.texbufs[1].tmu, rdp.texbufs[1].begin, LOD, LOD, |
598 | GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565, GR_MIPMAPLEVELMASK_BOTH ); |
599 | grAuxBufferExt( GR_BUFFER_TEXTUREAUXBUFFER_EXT ); |
600 | |
601 | rdp.update |= UPDATE_ZBUF_ENABLED | UPDATE_COMBINE | UPDATE_TEXTURE | UPDATE_ALPHA_COMPARE; |
602 | if (settings.fog && (rdp.flags & FOG_ENABLED)) |
603 | grFogMode (GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT); |
604 | LRDP("CopyDepthBuffer draw, OK\n"); |
605 | rdp.tbuff_tex = 0; |
606 | return TRUE; |
607 | } |
608 | |
609 | int SwapTextureBuffer() |
610 | { |
611 | if (!fullscreen || !rdp.tbuff_tex) |
612 | return FALSE; |
613 | LRDP("SwapTextureBuffer."); |
614 | COLOR_IMAGE ci; |
615 | ci.addr = rdp.tbuff_tex->addr; |
616 | ci.format = rdp.tbuff_tex->format; |
617 | ci.width = rdp.tbuff_tex->width; |
618 | ci.height = rdp.tbuff_tex->height; |
619 | ci.size = 2; |
620 | ci.status = ci_main; |
621 | ci.changed = FALSE; |
622 | TBUFF_COLOR_IMAGE * texbuf = AllocateTextureBuffer(ci); |
623 | if (!texbuf) |
624 | { |
625 | LRDP("Failed!\n"); |
626 | return FALSE; |
627 | } |
628 | TexBufSetupCombiner(); |
629 | |
630 | float ul_x = 0.0f; |
631 | float ul_y = 0.0f; |
632 | float lr_x = rdp.tbuff_tex->scr_width; |
633 | float lr_y = rdp.tbuff_tex->scr_height; |
634 | float zero = 0.0f; |
635 | float lr_u = rdp.tbuff_tex->lr_u; |
636 | float lr_v = rdp.tbuff_tex->lr_v; |
637 | |
638 | // Make the vertices |
639 | VERTEX v[4] = { |
640 | { ul_x, ul_y, 1, 1, zero, zero, zero, zero, {zero, zero, zero, zero} }, |
641 | { lr_x, ul_y, 1, 1, lr_u, zero, lr_u, zero, {lr_u, zero, lr_u, zero} }, |
642 | { ul_x, lr_y, 1, 1, zero, lr_v, zero, lr_v, {zero, lr_v, zero, lr_v} }, |
643 | { lr_x, lr_y, 1, 1, lr_u, lr_v, lr_u, lr_v, {lr_u, lr_v, lr_u, lr_v} } |
644 | }; |
645 | |
646 | grTexSource( rdp.tbuff_tex->tmu, rdp.tbuff_tex->tex_addr, GR_MIPMAPLEVELMASK_BOTH, &(rdp.tbuff_tex->info) ); |
647 | texbuf->tile_uls = rdp.tbuff_tex->tile_uls; |
648 | texbuf->tile_ult = rdp.tbuff_tex->tile_ult; |
649 | texbuf->v_shift = rdp.tbuff_tex->v_shift; |
650 | grRenderBuffer( GR_BUFFER_TEXTUREBUFFER_EXT ); |
651 | grTextureBufferExt( texbuf->tmu, texbuf->tex_addr, texbuf->info.smallLodLog2, texbuf->info.largeLodLog2, |
652 | texbuf->info.aspectRatioLog2, texbuf->info.format, GR_MIPMAPLEVELMASK_BOTH ); |
653 | grDrawTriangle (&v[0], &v[2], &v[1]); |
654 | grDrawTriangle (&v[2], &v[3], &v[1]); |
655 | rdp.texbufs[rdp.tbuff_tex->tmu].clear_allowed = TRUE; |
656 | rdp.texbufs[rdp.tbuff_tex->tmu].count = 0; |
657 | texbuf->tile_uls = rdp.tbuff_tex->tile_uls; |
658 | texbuf->tile_ult = rdp.tbuff_tex->tile_ult; |
659 | texbuf->u_shift = rdp.tbuff_tex->u_shift; |
660 | texbuf->v_shift = rdp.tbuff_tex->v_shift; |
661 | rdp.tbuff_tex = texbuf; |
662 | if (rdp.cur_image) |
663 | { |
664 | grTextureBufferExt( rdp.cur_image->tmu, rdp.cur_image->tex_addr, rdp.cur_image->info.smallLodLog2, rdp.cur_image->info.largeLodLog2, |
665 | rdp.cur_image->info.aspectRatioLog2, rdp.cur_image->info.format, GR_MIPMAPLEVELMASK_BOTH ); |
666 | } |
667 | else |
668 | { |
669 | grRenderBuffer( GR_BUFFER_BACKBUFFER ); |
670 | rdp.offset_x = rdp.offset_x_bak; |
671 | rdp.offset_y = rdp.offset_y_bak; |
672 | rdp.offset_x_bak = rdp.offset_y_bak = 0; |
673 | rdp.update |= UPDATE_VIEWPORT | UPDATE_SCISSOR; |
674 | } |
675 | rdp.update |= UPDATE_ZBUF_ENABLED | UPDATE_COMBINE | UPDATE_TEXTURE | UPDATE_ALPHA_COMPARE; |
676 | if (settings.fog && (rdp.flags & FOG_ENABLED)) |
677 | { |
678 | grFogMode (GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT); |
679 | } |
680 | LRDP("SwapTextureBuffer draw, OK\n"); |
681 | return TRUE; |
682 | } |
683 | |
684 | static wxUint32 CalcCRC(TBUFF_COLOR_IMAGE * pTCI) |
685 | { |
686 | wxUint32 result = 0; |
687 | if ((settings.frame_buffer&fb_ref) > 0) |
688 | pTCI->crc = 0; //Since fb content changes each frame, crc check is meaningless. |
689 | else if (settings.fb_crc_mode == SETTINGS::fbcrcFast) |
690 | result = *((wxUint32*)(gfx.RDRAM + pTCI->addr + (pTCI->end_addr-pTCI->addr)/2)); |
691 | else if (settings.fb_crc_mode == SETTINGS::fbcrcSafe) |
692 | { |
693 | wxUint8 * pSrc = gfx.RDRAM + pTCI->addr; |
694 | const wxUint32 nSize = pTCI->end_addr-pTCI->addr; |
695 | result = CRC32(0xFFFFFFFF, pSrc, 32); |
696 | result = CRC32(result, pSrc + (nSize>>1), 32); |
697 | result = CRC32(result, pSrc + nSize - 32, 32); |
698 | } |
699 | return result; |
700 | } |
701 | |
702 | int FindTextureBuffer(wxUint32 addr, wxUint16 width) |
703 | { |
704 | if (rdp.skip_drawing) |
705 | return FALSE; |
706 | FRDP("FindTextureBuffer. addr: %08lx, width: %d, scale_x: %f\n", addr, width, rdp.scale_x); |
707 | int found = FALSE; |
708 | wxUint32 shift = 0; |
709 | for (int i = 0; i < voodoo.num_tmu && !found; i++) |
710 | { |
711 | wxUint8 index = rdp.cur_tex_buf^i; |
712 | for (int j = 0; j < rdp.texbufs[index].count && !found; j++) |
713 | { |
714 | rdp.tbuff_tex = &(rdp.texbufs[index].images[j]); |
715 | if(addr >= rdp.tbuff_tex->addr && addr < rdp.tbuff_tex->end_addr)// && rdp.timg.format == 0) |
716 | { |
717 | bool bCorrect; |
718 | if (rdp.tbuff_tex->crc == 0) |
719 | { |
720 | rdp.tbuff_tex->crc = CalcCRC(rdp.tbuff_tex); |
721 | bCorrect = width == 1 || rdp.tbuff_tex->width == width || (rdp.tbuff_tex->width > 320 && rdp.tbuff_tex->width == width*2); |
722 | } |
723 | else |
724 | bCorrect = rdp.tbuff_tex->crc == CalcCRC(rdp.tbuff_tex); |
725 | if (bCorrect) |
726 | { |
727 | shift = addr - rdp.tbuff_tex->addr; |
728 | // if (!rdp.motionblur) |
729 | if (!rdp.cur_image) |
730 | rdp.cur_tex_buf = index; |
731 | found = TRUE; |
732 | // FRDP("FindTextureBuffer, found in TMU%d buffer: %d\n", rdp.tbuff_tex->tmu, j); |
733 | } |
734 | else //new texture is loaded into this place, texture buffer is not valid anymore |
735 | { |
736 | rdp.texbufs[index].count--; |
737 | if (j < rdp.texbufs[index].count) |
738 | memcpy(&(rdp.texbufs[index].images[j]), &(rdp.texbufs[index].images[j+1]), sizeof(TBUFF_COLOR_IMAGE)*(rdp.texbufs[index].count-j)); |
739 | } |
740 | } |
741 | } |
742 | } |
743 | if (found) |
744 | { |
745 | rdp.tbuff_tex->tile_uls = 0; |
746 | rdp.tbuff_tex->tile_ult = 0; |
747 | if (shift > 0) |
748 | { |
749 | shift >>= 1; |
750 | rdp.tbuff_tex->v_shift = shift / rdp.tbuff_tex->width; |
751 | rdp.tbuff_tex->u_shift = shift % rdp.tbuff_tex->width; |
752 | } |
753 | else |
754 | { |
755 | rdp.tbuff_tex->v_shift = 0; |
756 | rdp.tbuff_tex->u_shift = 0; |
757 | } |
758 | FRDP("FindTextureBuffer, found, u_shift: %d, v_shift: %d, format: %s\n", rdp.tbuff_tex->u_shift, rdp.tbuff_tex->v_shift, str_format[rdp.tbuff_tex->format]); |
759 | //FRDP("Buffer, addr=%08lx, end_addr=%08lx, width: %d, height: %d\n", rdp.tbuff_tex->addr, rdp.tbuff_tex->end_addr, rdp.tbuff_tex->width, rdp.tbuff_tex->height); |
760 | return TRUE; |
761 | } |
762 | rdp.tbuff_tex = 0; |
763 | LRDP("FindTextureBuffer, not found\n"); |
764 | return FALSE; |
765 | } |