Glide Plugin GLES2 port from mupen64plus-ae, but with special FrameSkip code
[mupen64plus-pandora.git] / source / gles2glide64 / src / Glide64 / FBtoScreen.cpp
diff --git a/source/gles2glide64/src/Glide64/FBtoScreen.cpp b/source/gles2glide64/src/Glide64/FBtoScreen.cpp
new file mode 100755 (executable)
index 0000000..46c06fa
--- /dev/null
@@ -0,0 +1,665 @@
+/*
+* Glide64 - Glide video plugin for Nintendo 64 emulators.
+* Copyright (c) 2002  Dave2001
+* Copyright (c) 2003-2009  Sergey 'Gonetz' Lipski
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+//****************************************************************
+//
+// Glide64 - Glide Plugin for Nintendo 64 emulators
+// Project started on December 29th, 2001
+//
+// Authors:
+// Dave2001, original author, founded the project in 2001, left it in 2002
+// Gugaman, joined the project in 2002, left it in 2002
+// Sergey 'Gonetz' Lipski, joined the project in 2002, main author since fall of 2002
+// Hiroshi 'KoolSmoky' Morii, joined the project in 2007
+//
+//****************************************************************
+//
+// To modify Glide64:
+// * Write your name and (optional)email, commented by your work, so I know who did it, and so that you can find which parts you modified when it comes time to send it to me.
+// * Do NOT send me the whole project or file that you modified.  Take out your modified code sections, and tell me where to put them.  If people sent the whole thing, I would have many different versions, but no idea how to combine them all.
+//
+//****************************************************************
+//
+// Draw N64 frame buffer to screen.
+// Created by Gonetz, 2007
+//
+//****************************************************************
+
+
+#include "Gfx_1.3.h"
+#include "FBtoScreen.h"
+#include "TexCache.h"
+
+static int SetupFBtoScreenCombiner(wxUint32 texture_size, wxUint32 opaque)
+{
+  int tmu;
+  if (voodoo.tmem_ptr[GR_TMU0]+texture_size < voodoo.tex_max_addr[0])
+  {
+    tmu = GR_TMU0;
+    grTexCombine( GR_TMU1,
+      GR_COMBINE_FUNCTION_NONE,
+      GR_COMBINE_FACTOR_NONE,
+      GR_COMBINE_FUNCTION_NONE,
+      GR_COMBINE_FACTOR_NONE,
+      FXFALSE,
+      FXFALSE );
+    grTexCombine( GR_TMU0,
+      GR_COMBINE_FUNCTION_LOCAL,
+      GR_COMBINE_FACTOR_NONE,
+      GR_COMBINE_FUNCTION_LOCAL,
+      GR_COMBINE_FACTOR_NONE,
+      FXFALSE,
+      FXFALSE );
+  }
+  else
+  {
+    if (voodoo.tmem_ptr[GR_TMU1]+texture_size >= voodoo.tex_max_addr[1])
+      ClearCache ();
+    tmu = GR_TMU1;
+    grTexCombine( GR_TMU1,
+      GR_COMBINE_FUNCTION_LOCAL,
+      GR_COMBINE_FACTOR_NONE,
+      GR_COMBINE_FUNCTION_LOCAL,
+      GR_COMBINE_FACTOR_NONE,
+      FXFALSE,
+      FXFALSE );
+    grTexCombine( GR_TMU0,
+      GR_COMBINE_FUNCTION_SCALE_OTHER,
+      GR_COMBINE_FACTOR_ONE,
+      GR_COMBINE_FUNCTION_SCALE_OTHER,
+      GR_COMBINE_FACTOR_ONE,
+      FXFALSE,
+      FXFALSE );
+  }
+  int filter = (rdp.filter_mode!=2)?GR_TEXTUREFILTER_POINT_SAMPLED:GR_TEXTUREFILTER_BILINEAR;
+  grTexFilterMode (tmu, filter, filter);
+  grTexClampMode (tmu,
+        GR_TEXTURECLAMP_CLAMP,
+        GR_TEXTURECLAMP_CLAMP);
+//  grConstantColorValue (0xFFFFFFFF);
+  grColorCombine (GR_COMBINE_FUNCTION_SCALE_OTHER,
+    GR_COMBINE_FACTOR_ONE,
+    GR_COMBINE_LOCAL_NONE,
+    GR_COMBINE_OTHER_TEXTURE,
+//    GR_COMBINE_OTHER_CONSTANT,
+    FXFALSE);
+  grAlphaCombine (GR_COMBINE_FUNCTION_SCALE_OTHER,
+    GR_COMBINE_FACTOR_ONE,
+    GR_COMBINE_LOCAL_NONE,
+    GR_COMBINE_OTHER_TEXTURE,
+    FXFALSE);
+  if (opaque)
+  {
+    grAlphaTestFunction (GR_CMP_ALWAYS);
+    grAlphaBlendFunction( GR_BLEND_ONE,
+      GR_BLEND_ZERO,
+      GR_BLEND_ONE,
+      GR_BLEND_ZERO);
+  }
+  else
+  {
+    grAlphaBlendFunction( GR_BLEND_SRC_ALPHA,
+      GR_BLEND_ONE_MINUS_SRC_ALPHA,
+      GR_BLEND_ONE,
+      GR_BLEND_ZERO);
+  }
+  grDepthBufferFunction (GR_CMP_ALWAYS);
+  grCullMode(GR_CULL_DISABLE);
+  grDepthMask (FXFALSE);
+  rdp.update |= UPDATE_COMBINE | UPDATE_ZBUF_ENABLED | UPDATE_CULL_MODE;
+  return tmu;
+}
+
+static void DrawRE2Video(FB_TO_SCREEN_INFO & fb_info, float scale)
+{
+  float scale_y = (float)fb_info.width/rdp.vi_height;
+  float height = settings.scr_res_x/scale_y;
+  float ul_x = 0.5f;
+  float ul_y = (settings.scr_res_y - height)/2.0f;
+  float lr_y = settings.scr_res_y - ul_y - 1.0f;
+  float lr_x = settings.scr_res_x - 1.0f;
+  float lr_u = (fb_info.width - 1)*scale;
+  float lr_v = (fb_info.height - 1)*scale;
+  VERTEX v[4] = {
+    { ul_x, ul_y, 1, 1, 0.5f, 0.5f, 0.5f, 0.5f, {0.5f, 0.5f, 0.5f, 0.5f} },
+    { lr_x, ul_y, 1, 1, lr_u, 0.5f, lr_u, 0.5f, {lr_u, 0.5f, lr_u, 0.5f} },
+    { ul_x, lr_y, 1, 1, 0.5f, lr_v, 0.5f, lr_v, {0.5f, lr_v, 0.5f, lr_v} },
+    { lr_x, lr_y, 1, 1, lr_u, lr_v, lr_u, lr_v, {lr_u, lr_v, lr_u, lr_v} }
+  };
+  grDrawTriangle (&v[0], &v[2], &v[1]);
+  grDrawTriangle (&v[2], &v[3], &v[1]);
+}
+
+static void DrawRE2Video256(FB_TO_SCREEN_INFO & fb_info)
+{
+  FRDP("DrawRE2Video256. ul_x=%d, ul_y=%d, lr_x=%d, lr_y=%d, size=%d, addr=%08lx\n", fb_info.ul_x, fb_info.ul_y, fb_info.lr_x, fb_info.lr_y, fb_info.size, fb_info.addr);
+  wxUint32 * src = (wxUint32*)(gfx.RDRAM+fb_info.addr);
+  GrTexInfo t_info;
+  t_info.smallLodLog2 = GR_LOD_LOG2_256;
+  t_info.largeLodLog2 = GR_LOD_LOG2_256;
+  t_info.aspectRatioLog2 = GR_ASPECT_LOG2_1x1;
+  wxUint16 * tex = (wxUint16*)texture_buffer;
+  wxUint16 * dst = tex;
+  wxUint32 col;
+  wxUint8 r, g, b;
+  fb_info.height = min(256, fb_info.height);
+  for (wxUint32 h = 0; h < fb_info.height; h++)
+  {
+    for (wxUint32 w = 0; w < 256; w++)
+    {
+      col = *(src++);
+      r = (wxUint8)((col >> (24+3))&0x1F);
+      g = (wxUint8)((col >> (16+2))&0x3F);
+      b = (wxUint8)((col >>  (8+3))&0x1F);
+/*      r = (wxUint8)((col >> 24)&0xFF);
+      r = (wxUint8)((float)r / 255.0f * 31.0f);
+      g = (wxUint8)((col >> 16)&0xFF);
+      g = (wxUint8)((float)g / 255.0f * 63.0f);
+      b = (wxUint8)((col >>  8)&0xFF);
+      b = (wxUint8)((float)b / 255.0f * 31.0f);*/      //*SEB*
+      *(dst++) = (r << 11) | (g << 5) | b;
+    }
+    src += (fb_info.width - 256);
+  }
+  t_info.format = GR_TEXFMT_RGB_565;
+  t_info.data = tex;
+  int tmu = SetupFBtoScreenCombiner(grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &t_info), fb_info.opaque);
+  grTexDownloadMipMap (tmu,
+    voodoo.tex_min_addr[tmu]+voodoo.tmem_ptr[tmu],
+    GR_MIPMAPLEVELMASK_BOTH,
+    &t_info);
+  grTexSource (tmu,
+      voodoo.tex_min_addr[tmu]+voodoo.tmem_ptr[tmu],
+      GR_MIPMAPLEVELMASK_BOTH,
+      &t_info);
+  DrawRE2Video(fb_info, 1.0f);
+}
+
+static void DrawFrameBufferToScreen256(FB_TO_SCREEN_INFO & fb_info)
+{
+  if (settings.hacks&hack_RE2)
+  {
+    DrawRE2Video256(fb_info);
+    return;
+  }
+  FRDP("DrawFrameBufferToScreen256. ul_x=%d, ul_y=%d, lr_x=%d, lr_y=%d, size=%d, addr=%08lx\n", fb_info.ul_x, fb_info.ul_y, fb_info.lr_x, fb_info.lr_y, fb_info.size, fb_info.addr);
+  wxUint32 width = fb_info.lr_x - fb_info.ul_x + 1;
+  wxUint32 height = fb_info.lr_y - fb_info.ul_y + 1;
+  GrTexInfo t_info;
+  wxUint8 * image = gfx.RDRAM+fb_info.addr;
+  wxUint32 width256 = ((width-1) >> 8) + 1;
+  wxUint32 height256 = ((height-1) >> 8) + 1;
+  t_info.smallLodLog2 = t_info.largeLodLog2 = GR_LOD_LOG2_256;
+  t_info.aspectRatioLog2 = GR_ASPECT_LOG2_1x1;
+  t_info.format = GR_TEXFMT_ARGB_1555;
+  wxUint16 * tex = (wxUint16*)texture_buffer;
+  t_info.data = tex;
+  wxUint32 tex_size = grTexTextureMemRequired (GR_MIPMAPLEVELMASK_BOTH, &t_info);
+  int tmu = SetupFBtoScreenCombiner(tex_size*width256*height256, fb_info.opaque);
+  wxUint16 * src = (wxUint16*)image;
+  src += fb_info.ul_x + fb_info.ul_y * fb_info.width;
+  wxUint32 * src32 = (wxUint32*)image;
+  src32 += fb_info.ul_x + fb_info.ul_y * fb_info.width;
+  wxUint32 w_tail = width%256;
+  wxUint32 h_tail = height%256;
+  wxUint16 c;
+  wxUint32 c32;
+  wxUint32 idx;
+  wxUint32 bound = BMASK+1-fb_info.addr;
+  bound = fb_info.size == 2 ? bound >> 1 : bound >> 2;
+  wxUint8 r, g, b, a;
+  wxUint32 cur_width, cur_height, cur_tail;
+  wxUint32 tex_adr = voodoo.tex_min_addr[tmu]+voodoo.tmem_ptr[tmu];
+  if ((voodoo.tmem_ptr[tmu] < TEXMEM_2MB_EDGE) && (voodoo.tmem_ptr[tmu]+tex_size*width256*height256 > TEXMEM_2MB_EDGE))
+  {
+    tex_adr = TEXMEM_2MB_EDGE;
+  }
+  for (wxUint32 h = 0; h < height256; h++)
+  {
+    for (wxUint32 w = 0; w < width256; w++)
+    {
+      cur_width = (256*(w+1) < width) ? 256 : w_tail;
+      cur_height = (256*(h+1) < height) ? 256 : h_tail;
+      cur_tail = 256 - cur_width;
+      wxUint16 * dst = tex;
+      if (fb_info.size == 2)
+      {
+        for (wxUint32 y=0; y < cur_height; y++)
+        {
+          for (wxUint32 x=0; x < cur_width; x++)
+          {
+            idx = (x+256*w+(y+256*h)*fb_info.width)^1;
+            if (idx >= bound)
+              break;
+            c = src[idx];
+            *(dst++) = (c >> 1) | ((c&1)<<15);
+          }
+          dst += cur_tail;
+        }
+      }
+      else
+      {
+        for (wxUint32 y=0; y < cur_height; y++)
+        {
+          for (wxUint32 x=0; x < cur_width; x++)
+          {
+            idx = (x+256*w+(y+256*h)*fb_info.width);
+            if (idx >= bound)
+              break;
+            c32 = src32[idx];
+            r = (wxUint8)((c32 >> (24+3))&0x1F);
+            g = (wxUint8)((c32 >> (16+2))&0x3F);
+            b = (wxUint8)((c32 >>  (8+3))&0x1F);
+/*            r = (wxUint8)((c32 >> 24)&0xFF);
+            r = (wxUint8)((float)r / 255.0f * 31.0f);
+            g = (wxUint8)((c32 >> 16)&0xFF);
+            g = (wxUint8)((float)g / 255.0f * 63.0f);
+            b = (wxUint8)((c32 >>  8)&0xFF);
+            b = (wxUint8)((float)b / 255.0f * 31.0f);*/        //*SEB*
+            a = (c32&0xFF) ? 1 : 0;
+            *(dst++) = (a<<15) | (r << 10) | (g << 5) | b;
+          }
+          dst += cur_tail;
+        }
+      }
+      grTexDownloadMipMap (tmu, tex_adr, GR_MIPMAPLEVELMASK_BOTH, &t_info);
+      grTexSource (tmu, tex_adr, GR_MIPMAPLEVELMASK_BOTH, &t_info);
+      tex_adr += tex_size;
+      float ul_x = (float)(fb_info.ul_x + 256*w);
+      float ul_y = (float)(fb_info.ul_y + 256*h);
+      float lr_x = (ul_x + (float)(cur_width)) * rdp.scale_x;
+      float lr_y = (ul_y + (float)(cur_height)) * rdp.scale_y;
+      ul_x *= rdp.scale_x;
+      ul_y *= rdp.scale_y;
+      ul_x += rdp.offset_x;
+      ul_y += rdp.offset_y;
+      lr_x += rdp.offset_x;
+      lr_y += rdp.offset_y;
+
+      float lr_u = (float)(cur_width-1);
+      float lr_v = (float)(cur_height-1);
+      // Make the vertices
+      VERTEX v[4] = {
+        { ul_x, ul_y, 1, 1, 0.5f, 0.5f, 0.5f, 0.5f, {0.5f, 0.5f, 0.5f, 0.5f} },
+        { lr_x, ul_y, 1, 1, lr_u, 0.5f, lr_u, 0.5f, {lr_u, 0.5f, lr_u, 0.5f} },
+        { ul_x, lr_y, 1, 1, 0.5f, lr_v, 0.5f, lr_v, {0.5f, lr_v, 0.5f, lr_v} },
+        { lr_x, lr_y, 1, 1, lr_u, lr_v, lr_u, lr_v, {lr_u, lr_v, lr_u, lr_v} }
+      };
+      grDrawTriangle (&v[0], &v[2], &v[1]);
+      grDrawTriangle (&v[2], &v[3], &v[1]);
+    }
+  }
+}
+
+bool DrawFrameBufferToScreen(FB_TO_SCREEN_INFO & fb_info)
+{
+  if (fb_info.width < 200 || fb_info.size < 2)
+    return false;
+  wxUint32 width = fb_info.lr_x - fb_info.ul_x + 1;
+  wxUint32 height = fb_info.lr_y - fb_info.ul_y + 1;
+  wxUint32 max_size = min(voodoo.max_tex_size, 512);
+  if (width > (wxUint32)max_size || height > (wxUint32)max_size)
+  {
+    DrawFrameBufferToScreen256(fb_info);
+    return true;
+  }
+  FRDP("DrawFrameBufferToScreen. ul_x=%d, ul_y=%d, lr_x=%d, lr_y=%d, size=%d, addr=%08lx\n", fb_info.ul_x, fb_info.ul_y, fb_info.lr_x, fb_info.lr_y, fb_info.size, fb_info.addr);
+  GrTexInfo t_info;
+  wxUint8 * image = gfx.RDRAM+fb_info.addr;
+  wxUint32 texwidth;
+  float scale;
+  if (width <= 256)
+  {
+    texwidth = 256;
+    scale = 1.0f;
+    t_info.smallLodLog2 = t_info.largeLodLog2 = GR_LOD_LOG2_256;
+  }
+  else
+  {
+    texwidth = 512;
+    scale = 0.5f;
+    t_info.smallLodLog2 = t_info.largeLodLog2 = GR_LOD_LOG2_512;
+  }
+
+  if (height <= (texwidth>>1))
+  {
+    t_info.aspectRatioLog2 = GR_ASPECT_LOG2_2x1;
+  }
+  else
+  {
+    t_info.aspectRatioLog2 = GR_ASPECT_LOG2_1x1;
+  }
+
+  if (fb_info.size == 2)
+  {
+    wxUint16 * tex = (wxUint16*)texture_buffer;
+    wxUint16 * dst = tex;
+    wxUint16 * src = (wxUint16*)image;
+    src += fb_info.ul_x + fb_info.ul_y * fb_info.width;
+    wxUint16 c;
+    wxUint32 idx;
+    const wxUint32 bound = (BMASK+1-fb_info.addr) >> 1;
+    bool empty = true;
+    for (wxUint32 y=0; y < height; y++)
+    {
+      for (wxUint32 x=0; x < width; x++)
+      {
+        idx = (x+y*fb_info.width)^1;
+        if (idx >= bound)
+          break;
+        c = src[idx];
+        if (c) empty = false;
+        *(dst++) = (c >> 1) | ((c&1)<<15);
+      }
+      dst += texwidth-width;
+    }
+    if (empty)
+      return false;
+    t_info.format = GR_TEXFMT_ARGB_1555;
+    t_info.data = tex;
+  }
+  else
+  {
+    wxUint32 * tex = (wxUint32*)texture_buffer;
+    wxUint32 * dst = tex;
+    wxUint32 * src = (wxUint32*)image;
+    src += fb_info.ul_x + fb_info.ul_y * fb_info.width;
+    wxUint32 col;
+    wxUint32 idx;
+    const wxUint32 bound = (BMASK+1-fb_info.addr) >> 2;
+    for (wxUint32 y=0; y < height; y++)
+    {
+      for (wxUint32 x=0; x < width; x++)
+      {
+        idx = x+y*fb_info.width;
+        if (idx >= bound)
+          break;
+        col = src[idx];
+        *(dst++) = (col >> 8) | 0xFF000000;
+      }
+      dst += texwidth-width;
+    }
+    t_info.format = GR_TEXFMT_ARGB_8888;
+    t_info.data = tex;
+  }
+
+  int tmu = SetupFBtoScreenCombiner(grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &t_info), fb_info.opaque);
+  grTexDownloadMipMap (tmu,
+    voodoo.tex_min_addr[tmu]+voodoo.tmem_ptr[tmu],
+    GR_MIPMAPLEVELMASK_BOTH,
+    &t_info);
+  grTexSource (tmu,
+    voodoo.tex_min_addr[tmu]+voodoo.tmem_ptr[tmu],
+    GR_MIPMAPLEVELMASK_BOTH,
+    &t_info);
+  if (settings.hacks&hack_RE2)
+  {
+    DrawRE2Video(fb_info, scale);
+  }
+  else
+  {
+    float ul_x = fb_info.ul_x * rdp.scale_x + rdp.offset_x;
+    float ul_y = fb_info.ul_y * rdp.scale_y + rdp.offset_y;
+    float lr_x = fb_info.lr_x * rdp.scale_x + rdp.offset_x;
+    float lr_y = fb_info.lr_y * rdp.scale_y + rdp.offset_y;
+    float lr_u = (width-1)*scale;
+    float lr_v = (height-1)*scale;
+    // Make the vertices
+    VERTEX v[4] = {
+      { ul_x, ul_y, 1, 1, 0.5f, 0.5f, 0.5f, 0.5f, {0.5f, 0.5f, 0.5f, 0.5f} },
+      { lr_x, ul_y, 1, 1, lr_u, 0.5f, lr_u, 0.5f, {lr_u, 0.5f, lr_u, 0.5f} },
+      { ul_x, lr_y, 1, 1, 0.5f, lr_v, 0.5f, lr_v, {0.5f, lr_v, 0.5f, lr_v} },
+      { lr_x, lr_y, 1, 1, lr_u, lr_v, lr_u, lr_v, {lr_u, lr_v, lr_u, lr_v} }
+    };
+    grDrawTriangle (&v[0], &v[2], &v[1]);
+    grDrawTriangle (&v[2], &v[3], &v[1]);
+  }
+  return true;
+}
+
+static void DrawDepthBufferToScreen256(FB_TO_SCREEN_INFO & fb_info)
+{
+  FRDP("DrawDepthBufferToScreen256. ul_x=%d, ul_y=%d, lr_x=%d, lr_y=%d, size=%d, addr=%08lx\n", fb_info.ul_x, fb_info.ul_y, fb_info.lr_x, fb_info.lr_y, fb_info.size, fb_info.addr);
+  wxUint32 width = fb_info.lr_x - fb_info.ul_x + 1;
+  wxUint32 height = fb_info.lr_y - fb_info.ul_y + 1;
+  GrTexInfo t_info;
+  wxUint8 * image = gfx.RDRAM+fb_info.addr;
+  wxUint32 width256 = ((width-1) >> 8) + 1;
+  wxUint32 height256 = ((height-1) >> 8) + 1;
+  t_info.smallLodLog2 = t_info.largeLodLog2 = GR_LOD_LOG2_256;
+  t_info.aspectRatioLog2 = GR_ASPECT_LOG2_1x1;
+  t_info.format = GR_TEXFMT_ALPHA_INTENSITY_88;
+  wxUint16 * tex = (wxUint16*)texture_buffer;
+  t_info.data = tex;
+  wxUint32 tex_size = grTexTextureMemRequired (GR_MIPMAPLEVELMASK_BOTH, &t_info);
+  int tmu = SetupFBtoScreenCombiner(tex_size*width256*height256, fb_info.opaque);
+  grConstantColorValue (rdp.fog_color);
+  grColorCombine (GR_COMBINE_FUNCTION_SCALE_OTHER,
+    GR_COMBINE_FACTOR_ONE,
+    GR_COMBINE_LOCAL_NONE,
+    GR_COMBINE_OTHER_CONSTANT,
+    FXFALSE);
+  wxUint16 * src = (wxUint16*)image;
+  src += fb_info.ul_x + fb_info.ul_y * fb_info.width;
+  wxUint32 w_tail = width%256;
+  wxUint32 h_tail = height%256;
+  wxUint32 cur_width, cur_height, cur_tail;
+  wxUint32 tex_adr = voodoo.tex_min_addr[tmu]+voodoo.tmem_ptr[tmu];
+  if ((voodoo.tmem_ptr[tmu] < TEXMEM_2MB_EDGE) && (voodoo.tmem_ptr[tmu]+tex_size*width256*height256 > TEXMEM_2MB_EDGE))
+  {
+    tex_adr = TEXMEM_2MB_EDGE;
+  }
+  for (wxUint32 h = 0; h < height256; h++)
+  {
+    for (wxUint32 w = 0; w < width256; w++)
+    {
+      cur_width = (256*(w+1) < width) ? 256 : w_tail;
+      cur_height = (256*(h+1) < height) ? 256 : h_tail;
+      cur_tail = 256 - cur_width;
+      wxUint16 * dst = tex;
+      for (wxUint32 y=0; y < cur_height; y++)
+      {
+        for (wxUint32 x=0; x < cur_width; x++)
+        {
+          *(dst++) = rdp.pal_8[src[(x+256*w+(y+256*h)*fb_info.width)^1]>>8];
+        }
+        dst += cur_tail;
+      }
+      grTexDownloadMipMap (tmu, tex_adr, GR_MIPMAPLEVELMASK_BOTH, &t_info);
+      grTexSource (tmu, tex_adr, GR_MIPMAPLEVELMASK_BOTH, &t_info);
+      tex_adr += tex_size;
+      float ul_x = (float)(fb_info.ul_x + 256*w);
+      float ul_y = (float)(fb_info.ul_y + 256*h);
+      float lr_x = (ul_x + (float)(cur_width)) * rdp.scale_x + rdp.offset_x;
+      float lr_y = (ul_y + (float)(cur_height)) * rdp.scale_y + rdp.offset_y;
+      ul_x = ul_x * rdp.scale_x + rdp.offset_x;
+      ul_y = ul_y * rdp.scale_y + rdp.offset_y;
+      float lr_u = (float)(cur_width-1);
+      float lr_v = (float)(cur_height-1);
+      // Make the vertices
+      VERTEX v[4] = {
+        { ul_x, ul_y, 1, 1, 0.5f, 0.5f, 0.5f, 0.5f, {0.5f, 0.5f, 0.5f, 0.5f} },
+        { lr_x, ul_y, 1, 1, lr_u, 0.5f, lr_u, 0.5f, {lr_u, 0.5f, lr_u, 0.5f} },
+        { ul_x, lr_y, 1, 1, 0.5f, lr_v, 0.5f, lr_v, {0.5f, lr_v, 0.5f, lr_v} },
+        { lr_x, lr_y, 1, 1, lr_u, lr_v, lr_u, lr_v, {lr_u, lr_v, lr_u, lr_v} }
+      };
+      grDrawTriangle (&v[0], &v[2], &v[1]);
+      grDrawTriangle (&v[2], &v[3], &v[1]);
+    }
+  }
+}
+
+static void DrawHiresDepthBufferToScreen(FB_TO_SCREEN_INFO & fb_info)
+{
+  FRDP("DrawHiresDepthBufferToScreen. ul_x=%d, ul_y=%d, lr_x=%d, lr_y=%d, size=%d, addr=%08lx\n", fb_info.ul_x, fb_info.ul_y, fb_info.lr_x, fb_info.lr_y, fb_info.size, fb_info.addr);
+  GrTexInfo t_info;
+  float scale = 0.25f;
+  GrLOD_t LOD = GR_LOD_LOG2_1024;
+  if (settings.scr_res_x > 1024)
+  {
+    scale = 0.125f;
+    LOD = GR_LOD_LOG2_2048;
+  }
+  t_info.format = GR_TEXFMT_ALPHA_INTENSITY_88;
+  t_info.smallLodLog2 = t_info.largeLodLog2 = LOD;
+  t_info.aspectRatioLog2 = GR_ASPECT_LOG2_1x1;
+  grConstantColorValue (rdp.fog_color);
+  grColorCombine (GR_COMBINE_FUNCTION_LOCAL,
+    GR_COMBINE_FACTOR_NONE,
+    GR_COMBINE_LOCAL_CONSTANT,
+    GR_COMBINE_OTHER_NONE,
+    FXFALSE);
+  grAlphaCombine (GR_COMBINE_FUNCTION_SCALE_OTHER,
+    GR_COMBINE_FACTOR_ONE,
+    GR_COMBINE_LOCAL_NONE,
+    GR_COMBINE_OTHER_TEXTURE,
+    FXFALSE);
+  grAlphaBlendFunction( GR_BLEND_SRC_ALPHA,
+    GR_BLEND_ONE_MINUS_SRC_ALPHA,
+    GR_BLEND_ONE,
+    GR_BLEND_ZERO);
+  grDepthBufferFunction (GR_CMP_ALWAYS);
+  grDepthMask (FXFALSE);
+  grCullMode (GR_CULL_DISABLE);
+  grTexCombine( GR_TMU1,
+    GR_COMBINE_FUNCTION_NONE,
+    GR_COMBINE_FACTOR_NONE,
+    GR_COMBINE_FUNCTION_NONE,
+    GR_COMBINE_FACTOR_NONE,
+    FXFALSE,
+    FXFALSE );
+  grTexCombine( GR_TMU0,
+    GR_COMBINE_FUNCTION_LOCAL,
+    GR_COMBINE_FACTOR_NONE,
+    GR_COMBINE_FUNCTION_LOCAL,
+    GR_COMBINE_FACTOR_NONE,
+    FXFALSE,
+    FXFALSE);
+//  grAuxBufferExt( GR_BUFFER_AUXBUFFER );
+  grTexSource( rdp.texbufs[0].tmu, rdp.texbufs[0].begin, GR_MIPMAPLEVELMASK_BOTH, &(t_info) );
+  float ul_x = (float)rdp.scissor.ul_x;
+  float ul_y = (float)rdp.scissor.ul_y;
+  float lr_x = (float)rdp.scissor.lr_x;
+  float lr_y = (float)rdp.scissor.lr_y;
+  float ul_u = (float)rdp.scissor.ul_x * scale;
+  float ul_v = (float)rdp.scissor.ul_y * scale;
+  float lr_u = (float)rdp.scissor.lr_x * scale;
+  float lr_v = (float)rdp.scissor.lr_y * scale;
+  // Make the vertices
+  VERTEX v[4] = {
+    { ul_x, ul_y, 1, 1, ul_u, ul_v, ul_u, ul_v, {ul_u, ul_v, ul_u, ul_v} },
+    { lr_x, ul_y, 1, 1, lr_u, ul_v, lr_u, ul_v, {lr_u, ul_v, lr_u, ul_v} },
+    { ul_x, lr_y, 1, 1, ul_u, lr_v, ul_u, lr_v, {ul_u, lr_v, ul_u, lr_v} },
+    { lr_x, lr_y, 1, 1, lr_u, lr_v, lr_u, lr_v, {lr_u, lr_v, lr_u, lr_v} }
+  };
+  grDrawTriangle (&v[0], &v[2], &v[1]);
+  grDrawTriangle (&v[2], &v[3], &v[1]);
+//  grAuxBufferExt( GR_BUFFER_TEXTUREAUXBUFFER_EXT );
+  rdp.update |= UPDATE_COMBINE | UPDATE_ZBUF_ENABLED | UPDATE_CULL_MODE;
+}
+
+void DrawDepthBufferToScreen(FB_TO_SCREEN_INFO & fb_info)
+{
+  wxUint32 width = fb_info.lr_x - fb_info.ul_x + 1;
+  wxUint32 height = fb_info.lr_y - fb_info.ul_y + 1;
+  if (width > (wxUint32)voodoo.max_tex_size || height > (wxUint32)voodoo.max_tex_size || width > 512)
+  {
+    DrawDepthBufferToScreen256(fb_info);
+    return;
+  }
+  if (fb_hwfbe_enabled && !evoodoo)
+  {
+    DrawHiresDepthBufferToScreen(fb_info);
+    return;
+  }
+  FRDP("DrawDepthBufferToScreen. ul_x=%d, ul_y=%d, lr_x=%d, lr_y=%d, size=%d, addr=%08lx\n", fb_info.ul_x, fb_info.ul_y, fb_info.lr_x, fb_info.lr_y, fb_info.size, fb_info.addr);
+  GrTexInfo t_info;
+  wxUint8 * image = gfx.RDRAM+fb_info.addr;
+  wxUint32 texwidth;
+  float scale;
+  if (width <= 256)
+  {
+    texwidth = 256;
+    scale = 1.0f;
+    t_info.smallLodLog2 = t_info.largeLodLog2 = GR_LOD_LOG2_256;
+  }
+  else
+  {
+    texwidth = 512;
+    scale = 0.5f;
+    t_info.smallLodLog2 = t_info.largeLodLog2 = GR_LOD_LOG2_512;
+  }
+
+  if (height <= (texwidth>>1))
+  {
+    t_info.aspectRatioLog2 = GR_ASPECT_LOG2_2x1;
+  }
+  else
+  {
+    t_info.aspectRatioLog2 = GR_ASPECT_LOG2_1x1;
+  }
+
+  wxUint16 * tex = (wxUint16*)texture_buffer;
+  wxUint16 * dst = tex;
+  wxUint16 * src = (wxUint16*)image;
+  src += fb_info.ul_x + fb_info.ul_y * fb_info.width;
+  for (wxUint32 y=0; y < height; y++)
+  {
+    for (wxUint32 x=0; x < width; x++)
+    {
+      *(dst++) = rdp.pal_8[src[(x+y*fb_info.width)^1]>>8];
+    }
+    dst += texwidth-width;
+  }
+  t_info.format = GR_TEXFMT_ALPHA_INTENSITY_88;
+  t_info.data = tex;
+
+  int tmu = SetupFBtoScreenCombiner(grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &t_info), fb_info.opaque);
+  grConstantColorValue (rdp.fog_color);
+  grColorCombine (GR_COMBINE_FUNCTION_SCALE_OTHER,
+    GR_COMBINE_FACTOR_ONE,
+    GR_COMBINE_LOCAL_NONE,
+    GR_COMBINE_OTHER_CONSTANT,
+    FXFALSE);
+  grTexDownloadMipMap (tmu,
+    voodoo.tex_min_addr[tmu]+voodoo.tmem_ptr[tmu],
+    GR_MIPMAPLEVELMASK_BOTH,
+    &t_info);
+  grTexSource (tmu,
+    voodoo.tex_min_addr[tmu]+voodoo.tmem_ptr[tmu],
+    GR_MIPMAPLEVELMASK_BOTH,
+    &t_info);
+  float ul_x = fb_info.ul_x * rdp.scale_x + rdp.offset_x;
+  float ul_y = fb_info.ul_y * rdp.scale_y + rdp.offset_y;
+  float lr_x = fb_info.lr_x * rdp.scale_x + rdp.offset_x;
+  float lr_y = fb_info.lr_y * rdp.scale_y + rdp.offset_y;
+  float lr_u = (width-1)*scale;
+  float lr_v = (height-1)*scale;
+  float zero = scale*0.5f;
+  // Make the vertices
+  VERTEX v[4] = {
+    { ul_x, ul_y, 1, 1, zero, zero, zero, zero, {zero, zero, zero, zero} },
+    { lr_x, ul_y, 1, 1, lr_u, zero, lr_u, zero, {lr_u, zero, lr_u, zero} },
+    { ul_x, lr_y, 1, 1, zero, lr_v, zero, lr_v, {zero, lr_v, zero, lr_v} },
+    { lr_x, lr_y, 1, 1, lr_u, lr_v, lr_u, lr_v, {lr_u, lr_v, lr_u, lr_v} }
+  };
+  grDrawTriangle (&v[0], &v[2], &v[1]);
+  grDrawTriangle (&v[2], &v[3], &v[1]);
+}