Glide Plugin GLES2 port from mupen64plus-ae, but with special FrameSkip code
[mupen64plus-pandora.git] / source / gles2glide64 / src / Glide64 / TexBuffer.cpp
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 }