Zsnes en linux con tarjetas ati = lento (Solución)
Si usas tarjeta de video ATI y te gusta jugar juegos de snes con zsnes pero el emulador te anda mas lento que la cresta con filtros en modo OpenGL?. Bueno tengo una solución, en realidad el problema es de los drivers de linux y todavía en la última version que salió (8.42) no ha habido solución por parte de ellos. Los autores de zsnes lo saben pero no quieren arreglar el emulador para "forzar" a los de ATI a arreglar sus drivers.
Bueno, investigando un poco encontré la solución, ademas de postearla en el foro de zsnes la posteo aca para los interesados. Tienen que bajarse el código fuente del zsnes 1.51, después usar el archivo que voy a copiar aquí:
Spoiler
Code:
/*
Copyright (C) 1997-2006 ZSNES Team ( zsKnight, _Demo_, pagefault, Nach )
http://www.zsnes.com
http://sourceforge.net/projects/zsnes
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "gblhdr.h"
#define BYTE unsigned char
#define WORD unsigned short
#define DWORD unsigned long
typedef enum
{ FALSE = 0, TRUE = !FALSE }
BOOL;
// FUNCTIONS
extern void hq2x_16b(void);
extern char hqFilter;
// VIDEO VARIABLES
extern unsigned char cvidmode;
extern SDL_Surface *surface;
extern int SurfaceX, SurfaceY;
extern int SurfaceLocking;
extern DWORD BitDepth;
// OPENGL VARIABLES
static unsigned short *glvidbuffer = 0;
static GLuint gltextures[3];
static int gltexture256, gltexture512;
static int glfilters = GL_NEAREST;
static int glscanready = 0;
extern Uint8 En2xSaI, scanlines;
extern Uint8 BilinearFilter;
extern Uint8 FilteredGUI;
extern Uint8 GUIOn2;
extern unsigned int vidbuffer;
extern unsigned char curblank;
extern BYTE GUIRESIZE[];
unsigned long * RGBAbuffer;
void gl_clearwin();
void UpdateVFrame(void);
void gl_scanlines(void);
void rgb_SHORT_5_6_5_To_bgra_BYTE
(unsigned long *Dest, const unsigned short * Src, unsigned int size);
int gl_start(int width, int height, int req_depth, int FullScreen)
{
Uint32 flags =
SDL_DOUBLEBUF | SDL_HWSURFACE | SDL_HWPALETTE | SDL_OPENGL;
int i;
flags |= (GUIRESIZE[cvidmode] ? SDL_RESIZABLE : 0);
flags |= (FullScreen ? SDL_FULLSCREEN : 0);
SurfaceX = width; SurfaceY = height;
surface = SDL_SetVideoMode(SurfaceX, SurfaceY, req_depth, flags);
if (surface == NULL)
{
fprintf(stderr, "Could not set %dx%d-GL video mode.\n",
SurfaceX, SurfaceY);
return FALSE;
}
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
glvidbuffer = (unsigned short *) malloc(512 * 512 * sizeof(short));
gl_clearwin();
SDL_WarpMouse(SurfaceX / 4, SurfaceY / 4);
// Grab mouse in fullscreen mode
FullScreen ? SDL_WM_GrabInput(SDL_GRAB_ON) :
SDL_WM_GrabInput(SDL_GRAB_OFF);
SDL_WM_SetCaption("ZSNES", "ZSNES");
SDL_ShowCursor(0);
/* Setup some GL stuff */
glEnable(GL_TEXTURE_1D);
glEnable(GL_TEXTURE_2D);
glViewport(0, 0, SurfaceX, SurfaceY);
/*
* gltextures[0]: 2D texture, 256*256
* gltextures[1]: 2D texture, 512x512
* gltextures[2]: 1D texture, 256 lines of alternating alpha
*/
glGenTextures(3, gltextures);
for (i = 0; i < 2; i++) {
glBindTexture(GL_TEXTURE_2D, gltextures[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, glfilters);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, glfilters);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
}
glBindTexture(GL_TEXTURE_2D, gltextures[0]);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D, 0, 3, 256, 256, 0,
GL_BGRA, GL_UNSIGNED_BYTE,
NULL);
glBindTexture(GL_TEXTURE_2D, gltextures[1]);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D, 0, 3, 512, 512, 0,
GL_BGRA, GL_UNSIGNED_BYTE,
NULL);
RGBAbuffer = (unsigned long *) malloc (512 * 512 * sizeof(long));
if (scanlines) gl_scanlines();
return TRUE;
}
void gl_end()
{
glDeleteTextures(3, gltextures);
free(glvidbuffer);
free(RGBAbuffer);
}
extern DWORD AddEndBytes;
extern DWORD NumBytesPerLine;
extern unsigned char *WinVidMemStart;
extern unsigned char MMXSupport;
extern unsigned char NGNoTransp;
extern unsigned char newengen;
extern void copy640x480x16bwin(void);
extern unsigned char SpecialLine[224]; /* 0 if lo-res, > 0 if hi-res */
void gl_clearwin()
{
glClear(GL_COLOR_BUFFER_BIT);
if (En2xSaI)
memset(glvidbuffer, 0, 512 * 448 * 2);
}
/* gl_drawspan:
* Puts a quad on the screen for hires/lores portions, starting at line start,
* and ending at line end..
* Builds the 256x256/512x256 textures if gltexture256 or gltexture512 == 0
*/
static void gl_drawspan(int hires, int start, int end)
{
int i, j;
switch (hires)
{
case 0:
break;
case 3:
case 7:
hires = 2;
break;
default:
hires = 1;
break;
}
if (hires)
{
if (hires != gltexture512)
{
unsigned short *vbuf1 = &((unsigned short *) vidbuffer)[16];
unsigned short *vbuf2 = &((unsigned short *) vidbuffer)[75036 * 2 + 16];
unsigned short *vbuf = &glvidbuffer[0];
if (hires>1) // mode 7
{
for (j = 224; j--;)
{
for (i = 256; i--;)
*vbuf++ = *vbuf1++;
for (i = 256; i--;)
*vbuf++ = *vbuf2++;
vbuf1 += 32;
vbuf2 += 32;
}
glBindTexture(GL_TEXTURE_2D, gltextures[1]);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 256);
rgb_SHORT_5_6_5_To_bgra_BYTE(RGBAbuffer,
glvidbuffer, 256*448);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256,
448,GL_RGBA,
GL_UNSIGNED_BYTE,
RGBAbuffer);
gltexture512 = 2;
}
else
{
for (j = 224; j--;)
{
for (i = 256; i--;)
{
*vbuf++ = *vbuf1++;
*vbuf++ = *vbuf2++;
}
vbuf1 += 32;
vbuf2 += 32; // skip the two 16-pixel-wide columns
}
glBindTexture(GL_TEXTURE_2D, gltextures[1]);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 512);
rgb_SHORT_5_6_5_To_bgra_BYTE(RGBAbuffer,
glvidbuffer, 512*224);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 512,
224,GL_RGBA,
GL_UNSIGNED_BYTE,
RGBAbuffer);
gltexture512 = 1;
}
}
if (hires>1) // mode 7
{
glBindTexture(GL_TEXTURE_2D, gltextures[1]);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, (224.0 / 256.0)
* (start / 224.0));
glVertex2f(-1.0f, (112 - start) / 112.0);
glTexCoord2f(0.5f, (224.0 / 256.0)
* (start / 224.0));
glVertex2f(1.0f, (112 - start) / 112.0);
glTexCoord2f(0.5f, (224.0 / 256.0)
* (end / 224.0));
glVertex2f(1.0f, (112 - end) / 112.0);
glTexCoord2f(0.0f, (224.0 / 256.0)
* (end / 224.0));
glVertex2f(-1.0f, (112 - end) / 112.0);
glEnd();
}
else
{
glBindTexture(GL_TEXTURE_2D, gltextures[1]);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, (224.0 / 512.0)
* (start / 224.0));
glVertex2f(-1.0f, (112 - start) / 112.0);
glTexCoord2f(1.0f, (224.0 / 512.0)
* (start / 224.0));
glVertex2f(1.0f, (112 - start) / 112.0);
glTexCoord2f(1.0f, (224.0 / 512.0)
* (end / 224.0));
glVertex2f(1.0f, (112 - end) / 112.0);
glTexCoord2f(0.0f, (224.0 / 512.0)
* (end / 224.0));
glVertex2f(-1.0f, (112 - end) / 112.0);
glEnd();
}
}
else
{
glBindTexture(GL_TEXTURE_2D, gltextures[0]);
if (!gltexture256)
{
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 16);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 288);
rgb_SHORT_5_6_5_To_bgra_BYTE(RGBAbuffer,
((unsigned short *) vidbuffer) + 288, 288*224);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256,
224,GL_RGBA,
GL_UNSIGNED_BYTE,RGBAbuffer);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 256);
gltexture256 = 1;
}
glBegin(GL_QUADS);
glTexCoord2f(0.0f, (224.0 / 256.0) * (start / 224.0));
glVertex2f(-1.0f, (112 - start) / 112.0);
glTexCoord2f(1.0f, (224.0 / 256.0) * (start / 224.0));
glVertex2f(1.0f, (112 - start) / 112.0);
glTexCoord2f(1.0f, (224.0 / 256.0) * (end / 224.0));
glVertex2f(1.0f, (112 - end) / 112.0);
glTexCoord2f(0.0f, (224.0 / 256.0) * (end / 224.0));
glVertex2f(-1.0f, (112 - end) / 112.0);
glEnd();
}
}
void gl_drawwin()
{
int i;
NGNoTransp = 0; // Set this value to 1 within the appropriate
// video mode if you want to add a custom
// transparency routine or hardware
// transparency. This only works if
// the value of newengen is equal to 1.
// (see ProcessTransparencies in newgfx16.asm
// for ZSNES' current transparency code)
UpdateVFrame();
if (curblank || cvidmode<6)
return;
if (BilinearFilter)
{
glfilters = GL_LINEAR;
if (GUIOn2 && !FilteredGUI)
glfilters = GL_NEAREST;
}
else
{
glfilters = GL_NEAREST;
}
if (SurfaceX >= 512 && (hqFilter || En2xSaI))
{
AddEndBytes = 0;
NumBytesPerLine = 1024;
WinVidMemStart = (void *) glvidbuffer;
if (hqFilter) {
hq2x_16b();
} else {
copy640x480x16bwin();
}
/* Display 1 512x448 quad for the 512x448 buffer */
glBindTexture(GL_TEXTURE_2D, gltextures[1]);
glTexEnvi(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_DECAL);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 512);
rgb_SHORT_5_6_5_To_bgra_BYTE(RGBAbuffer,
glvidbuffer, 512*448);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 512,
448,GL_RGBA,
GL_UNSIGNED_BYTE,
RGBAbuffer );
glDisable (GL_DEPTH_TEST);
glDisable (GL_LIGHTING);
glDisable (GL_BLEND);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, 1.0f, -1.0f);
glTexCoord2f(1.0f, 448.0f / 512.0f);
glVertex3f(1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 448.0f / 512.0f);
glVertex3f(-1.0f, -1.0f, -1.0f);
glEnd();
}
else
{
/*
* This code splits the hires/lores portions up, and draws
* them with gl_drawspan
*/
int lasthires, lasthires_line = 0;
gltexture256 = gltexture512 = 0;
lasthires = SpecialLine[1];
for (i = 0; i < 224; i++)
{
if (SpecialLine[i + 1])
{
if (lasthires)
continue;
gl_drawspan(lasthires, lasthires_line, i);
lasthires = SpecialLine[i + 1];
lasthires_line = i;
}
else
{
if (!lasthires)
continue;
gl_drawspan(lasthires, lasthires_line, i);
lasthires = SpecialLine[i + 1];
lasthires_line = i;
}
}
if (i - lasthires_line > 1)
gl_drawspan(lasthires, lasthires_line, i);
/*
* This is here rather than right outside this if because the
* GUI doesn't allow scanlines to be selected while filters are
* on.. There is no technical reason they can't be on while
* filters are on, however. Feel free to change the GUI, and
* move this outside the if (En2xSaI) {}, if you do.
*/
if (scanlines)
{
glDisable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
if (scanlines != glscanready) gl_scanlines();
glBlendFunc(GL_DST_COLOR, GL_ZERO);
glBindTexture(GL_TEXTURE_1D, gltextures[2]);
glBegin(GL_QUADS);
for (i = 0; i < SurfaceY; i += 256)
{
glTexCoord1f(0.0f);
glVertex3f(-1.0f, (SurfaceY - i * 2.0) / SurfaceY, -1.0f);
glTexCoord1f(0.0f);
glVertex3f(1.0f, (SurfaceY - i * 2.0) / SurfaceY, -1.0f);
glTexCoord1f(1.0f);
glVertex3f(1.0f, (SurfaceY - (i + 256) * 2.0) / SurfaceY, -1.0f);
glTexCoord1f(1.0f);
glVertex3f(-1.0f, (SurfaceY - (i + 256) * 2.0) / SurfaceY, -1.0f);
}
glEnd();
glDisable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
}
}
SDL_GL_SwapBuffers();
}
void gl_scanlines(void)
{
GLubyte scanbuffer[256][4];
int i, j = scanlines==1 ? 0 : (scanlines==2 ? 192 : 128);
for (i = 0; i < 256; i += 2)
{
scanbuffer[i][0] = scanbuffer[i][1] = scanbuffer[i][2] = j;
scanbuffer[i][3] = 0xFF;
scanbuffer[i+1][0] = scanbuffer[i+1][1] = scanbuffer[i+1][2] = 0xFF;
scanbuffer[i+1][3] = 0xFF;
}
glBindTexture(GL_TEXTURE_1D, gltextures[2]);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 256, 0, GL_RGBA,
GL_UNSIGNED_BYTE, scanbuffer);
glscanready = scanlines;
}
/** This convert a RGB 16bits buffer (Src) into a BGRA 32 bits buffer (Dest) */
/* size is the number of pixels (short) of Src*/
void rgb_SHORT_5_6_5_To_bgra_BYTE(unsigned long *dest, const unsigned short * src, unsigned int size)
{
while (size--)
{
*dest = ((*(char *)src & 0x1F) << 19) | //B
((*src & 0x7E0)<<5) | //G
((((char *)src)[1] & 0xF8)) | //R
0xFF000000; //A
src++;
dest++;
}
}
Este archivo es gl_draw.c y va adentro de la carpeta linux en la carpeta creada al descomprimir el codigo fuente. Reemplazan ese con este y luego compilan el zsnes. Debería funcionar bien ahora. Diganme si les soluciona el problema o no. Si tienes tarjeta Nvidia ni te molestes en usar este archivo porque debería ser un poco más lento con este. Si no sabes compilar el emulador hay instrucciones en el foro de zsnes para varias distribuciones.
Saludos,
Alberto
Editado por Lugaidster en 10-nov-2007 a las 18:36.
Razón: Cambio de titulo