Add Xv acceleration support to unix port.

This commit is contained in:
Greg Kennedy 2015-12-29 14:04:13 -06:00
parent 2db2c2f57c
commit 7396766588
1 changed files with 533 additions and 70 deletions

View File

@ -194,6 +194,12 @@
#include <X11/keysym.h>
#include <X11/cursorfont.h>
#ifdef USE_XVIDEO
#include <X11/extensions/Xvlib.h>
#define FOURCC_YUY2 0x32595559
#endif
#ifdef MITSHM
#include <sys/ipc.h>
#include <sys/shm.h>
@ -213,10 +219,20 @@
// Wrapper struct to make generic XvImage vs XImage
struct Image
{
XImage* ximage;
#ifdef USE_XVIDEO
union
{
XvImage* xvimage;
#endif
XImage* ximage;
#ifdef USE_XVIDEO
};
#endif
char *data;
uint32 height;
uint32 data_size;
uint32 bits_per_pixel;
uint32 bytes_per_line;
};
@ -254,6 +270,18 @@ struct GUIData
bool8 fullscreen;
int x_offset;
int y_offset;
#ifdef USE_XVIDEO
bool8 use_xvideo;
int xv_port;
int scale_w;
int scale_h;
int xv_format;
int xv_bpp;
unsigned char y_table[1 << 15];
unsigned char u_table[1 << 15];
unsigned char v_table[1 << 15];
#endif
#ifdef MITSHM
XShmSegmentInfo sm_info;
bool8 use_shared_memory;
@ -296,9 +324,13 @@ static int ErrorHandler (Display *, XErrorEvent *);
static bool8 CheckForPendingXEvents (Display *);
static void SetXRepeat (bool8);
static void SetupImage (void);
static void SetupXImage (void);
static void TakedownImage (void);
static void SetupXImage (void);
static void TakedownXImage (void);
#ifdef USE_XVIDEO
static void SetupXvImage (void);
static void TakedownXvImage (void);
#endif
static void Repaint (bool8);
static void Convert16To24 (int, int);
static void Convert16To24Packed (int, int);
@ -311,6 +343,9 @@ void S9xExtraDisplayUsage (void)
S9xMessage(S9X_INFO, S9X_USAGE, "-setrepeat Allow altering keyboard auto-repeat");
S9xMessage(S9X_INFO, S9X_USAGE, "");
S9xMessage(S9X_INFO, S9X_USAGE, "-fullscreen Switch to full-screen on start");
#ifdef USE_XVIDEO
S9xMessage(S9X_INFO, S9X_USAGE, "-xvideo Hardware accelerated scaling");
#endif
S9xMessage(S9X_INFO, S9X_USAGE, "");
S9xMessage(S9X_INFO, S9X_USAGE, "-v1 Video mode: Blocky (default)");
S9xMessage(S9X_INFO, S9X_USAGE, "-v2 Video mode: TV");
@ -331,6 +366,11 @@ void S9xParseDisplayArg (char **argv, int &i, int argc)
if (!strcasecmp(argv[i], "-fullscreen"))
GUI.fullscreen = TRUE;
else
#ifdef USE_XVIDEO
if (!strcasecmp(argv[i], "-xvideo"))
GUI.use_xvideo = TRUE;
else
#endif
if (!strncasecmp(argv[i], "-v", 2))
{
switch (argv[i][2])
@ -490,6 +530,9 @@ const char * S9xParseDisplayConfig (ConfigFile &conf, int pass)
GUI.no_repeat = !conf.GetBool("Unix/X11::SetKeyRepeat", TRUE);
GUI.fullscreen = conf.GetBool("Unix/X11::Fullscreen", FALSE);
#ifdef USE_XVIDEO
GUI.use_xvideo = conf.GetBool("Unix/X11::Xvideo", FALSE);
#endif
if (conf.Exists("Unix/X11::VideoMode"))
{
@ -517,6 +560,234 @@ static int ErrorHandler (Display *display, XErrorEvent *event)
return (0);
}
#ifdef USE_XVIDEO
static int get_inv_shift (uint32 mask, int bpp)
{
int i;
// Find mask
for (i = 0; (i < bpp) && !(mask & (1 << i)); i++) {};
// Find start of mask
for (; (i < bpp) && (mask & (1 << i)); i++) {};
return (bpp - i);
}
static unsigned char CLAMP (int v, int min, int max)
{
if (v < min) return min;
if (v > max) return max;
return v;
}
static bool8 SetupXvideo()
{
int ret;
// Init xv_port
GUI.xv_port = -1;
/////////////////////
// Check that Xvideo extension seems OK
unsigned int p_version, p_release, p_request_base, p_event_base, p_error_base;
ret = XvQueryExtension(GUI.display,
&p_version, &p_release, &p_request_base,
&p_event_base, &p_error_base);
if (ret != Success) { fprintf(stderr,"XvQueryExtension error\n"); return FALSE; }
printf("XvExtension version %i.%i\n",p_version,p_release);
/////////////////////
// Get info about the Adaptors available for this window
unsigned int p_num_adaptors;
XvAdaptorInfo* ai;
ret = XvQueryAdaptors(GUI.display, GUI.window, &p_num_adaptors, &ai);
if (ret != Success || p_num_adaptors == 0) {
fprintf(stderr,"XvQueryAdaptors error.");
return FALSE;
}
printf("XvQueryAdaptors: %d adaptor(s) found.\n",p_num_adaptors);
unsigned int minAdaptor = 0, maxAdaptor = p_num_adaptors;
// Allow user to force adaptor choice
/* if (adaptor >= 0 && adaptor < p_num_adaptors)
{
if (verbose) std::cout << "Forcing adaptor " << adaptor << ", '" << ai[adaptor].name << "'" << std::endl;
minAdaptor = adaptor;
maxAdaptor = adaptor + 1;
} */
/////////////////////
// Iterate through list of available adaptors.
// Grab a port if we can.
for (unsigned int i = minAdaptor; i < maxAdaptor && GUI.xv_port < 0; i++)
{
// We need to find one supporting XvInputMask and XvImageMask.
if (! (ai[i].type & XvImageMask)) continue;
if (! (ai[i].type & XvInputMask)) continue;
printf("\tAdaptor #%d: [%s]: %ld port(s) available.\n", i, ai[i].name, ai[i].num_ports);
// Get encodings available here
// AFAIK all ports on an adapter share the same encodings info.
unsigned int encodings;
XvEncodingInfo *ei;
ret = XvQueryEncodings(GUI.display, ai[i].base_id, &encodings, &ei);
if (ret != Success || encodings == 0) {
fprintf(stderr,"XvQueryEncodings error.");
continue;
}
// Ensure the XV_IMAGE encoding available has sufficient width/height for us.
bool8 can_fit = FALSE;
for (unsigned int j = 0; j < encodings; j++)
{
if (strcmp(ei[j].name,"XV_IMAGE")) continue;
if (ei[j].width >= SNES_WIDTH * 2 &&
ei[j].height >= SNES_HEIGHT_EXTENDED * 2)
{
can_fit = TRUE;
break;
}
}
XvFreeEncodingInfo(ei);
if (can_fit == FALSE)
{
fprintf(stderr,"\tDid not find XV_IMAGE encoding with enough max size\n");
continue;
}
// Phew. If we've made it this far, we can try to choose it for our output port.
for (unsigned int p = ai[i].base_id; p < ai[i].base_id+ai[i].num_ports; p++)
{
ret = XvGrabPort(GUI.display, p, CurrentTime);
if (ret == Success)
{
printf("\tSuccessfully bound to Xv port %d\n",p);
GUI.xv_port = p;
break;
} else {
fprintf(stderr,"\tXvGrabPort port %d fail.\n",p);
}
}
}
XvFreeAdaptorInfo(ai);
/////////////////////
// Bail out here if we haven't managed to bind to any port.
if (GUI.xv_port < 0)
{
fprintf(stderr,"No suitable xv_port found in any Adaptors.\n");
return FALSE;
}
// Xv ports can have Attributes (hue, saturation, etc)
/* Set XV_AUTOPAINT_COLORKEY _only_ if available */
int num_attrs;
XvAttribute* port_attr;
port_attr = XvQueryPortAttributes (GUI.display, GUI.xv_port, &num_attrs);
for (int i = 0; i < num_attrs; i++)
{
if (!strcmp (port_attr[i].name, "XV_AUTOPAINT_COLORKEY"))
{
Atom colorkey = None;
colorkey = XInternAtom (GUI.display, "XV_AUTOPAINT_COLORKEY", True);
if (colorkey != None)
{
XvSetPortAttribute (GUI.display, GUI.xv_port, colorkey, 1);
printf("\tSet XV_AUTOPAINT_COLORKEY.\n");
}
}
}
XFree(port_attr);
// Now we need to find to find the image format to use for output.
// There are two steps to this:
// Prefer an XvRGB version of lowest bitdepth.
// If that's not available use YUY2
int formats;
XvImageFormatValues* fo;
fo = XvListImageFormats(GUI.display, GUI.xv_port, &formats);
if (formats == 0)
{
fprintf(stderr,"No valid image formats for Xv port!");
return FALSE;
}
/* Ok time to search for a good Format */
GUI.xv_format = FOURCC_YUY2;
GUI.xv_bpp = 0x7FFFFFFF;
for (int i = 0; i < formats; i++)
{
if (fo[i].id == 0x3 || fo[i].type == XvRGB)
{
if (fo[i].bits_per_pixel < GUI.xv_bpp)
{
GUI.xv_format = fo[i].id;
GUI.xv_bpp = fo[i].bits_per_pixel;
GUI.bytes_per_pixel = (GUI.xv_bpp == 15) ? 2 : GUI.xv_bpp >> 3;
GUI.depth = fo[i].depth;
GUI.red_shift = get_inv_shift (fo[i].red_mask, GUI.xv_bpp);
GUI.green_shift = get_inv_shift (fo[i].green_mask, GUI.xv_bpp);
GUI.blue_shift = get_inv_shift (fo[i].blue_mask, GUI.xv_bpp);
/* Check for red-blue inversion on SiliconMotion drivers */
if (fo[i].red_mask == 0x001f &&
fo[i].blue_mask == 0x7c00)
{
int copy = GUI.red_shift;
GUI.red_shift = GUI.blue_shift;
GUI.blue_shift = copy;
}
/* on big-endian Xv still seems to like LSB order */
/*if (config->force_inverted_byte_order)
S9xSetEndianess (ENDIAN_MSB);
else
S9xSetEndianess (ENDIAN_LSB); */
}
}
}
free (fo);
if (GUI.xv_format != FOURCC_YUY2)
{
printf("Selected XvRGB format: %d bpp\n",GUI.xv_bpp);
} else {
// use YUY2
printf("Fallback to YUY2 format.\n");
GUI.depth = 15;
/* Build a table for yuv conversion */
for (unsigned int color = 0; color < (1 << 15); color++)
{
int r, g, b;
int y, u, v;
r = (color & 0x7c00) >> 7;
g = (color & 0x03e0) >> 2;
b = (color & 0x001F) << 3;
y = (int) ((0.257 * ((double) r)) + (0.504 * ((double) g)) + (0.098 * ((double) b)) + 16.0);
u = (int) ((-0.148 * ((double) r)) + (-0.291 * ((double) g)) + (0.439 * ((double) b)) + 128.0);
v = (int) ((0.439 * ((double) r)) + (-0.368 * ((double) g)) + (-0.071 * ((double) b)) + 128.0);
GUI.y_table[color] = CLAMP (y, 0, 255);
GUI.u_table[color] = CLAMP (u, 0, 255);
GUI.v_table[color] = CLAMP (v, 0, 255);
}
}
return TRUE;
}
#endif
void S9xInitDisplay (int argc, char **argv)
{
GUI.display = XOpenDisplay(NULL);
@ -627,6 +898,13 @@ void S9xInitDisplay (int argc, char **argv)
XMapRaised(GUI.display, GUI.window);
XClearWindow(GUI.display, GUI.window);
#ifdef USE_XVIDEO
if (GUI.use_xvideo)
{
GUI.use_xvideo = SetupXvideo();
}
#endif
switch (GUI.depth)
{
default:
@ -695,6 +973,12 @@ void S9xDeinitDisplay (void)
TakedownImage();
if (GUI.display != NULL)
{
#ifdef USE_XVIDEO
if (GUI.use_xvideo)
{
XvUngrabPort(GUI.display,GUI.xv_port,CurrentTime);
}
#endif
S9xTextMode();
XSync(GUI.display, False);
XCloseDisplay(GUI.display);
@ -704,6 +988,53 @@ void S9xDeinitDisplay (void)
S9xBlitHQ2xFilterDeinit();
}
static void SetupImage (void)
{
TakedownImage();
// Create new image struct
GUI.image = (Image *) calloc(sizeof(Image), 1);
#ifdef USE_XVIDEO
if (GUI.use_xvideo)
SetupXvImage();
if (!GUI.use_xvideo)
#endif
SetupXImage();
// Setup SNES buffers
GFX.Pitch = SNES_WIDTH * 2 * 2;
GUI.snes_buffer = (uint8 *) calloc(GFX.Pitch * ((SNES_HEIGHT_EXTENDED + 4) * 2), 1);
if (!GUI.snes_buffer)
FatalError("Failed to allocate GUI.snes_buffer.");
GFX.Screen = (uint16 *) (GUI.snes_buffer + (GFX.Pitch * 2 * 2));
GUI.filter_buffer = (uint8 *) calloc((SNES_WIDTH * 2) * 2 * (SNES_HEIGHT_EXTENDED * 2), 1);
if (!GUI.filter_buffer)
FatalError("Failed to allocate GUI.filter_buffer.");
#ifdef USE_XVIDEO
if ((GUI.depth == 15 || GUI.depth == 16) && GUI.xv_format != FOURCC_YUY2)
#else
if (GUI.depth == 15 || GUI.depth == 16)
#endif
{
GUI.blit_screen_pitch = GUI.image->bytes_per_line;
GUI.blit_screen = (uint8 *) GUI.image->data;
GUI.need_convert = FALSE;
}
else
{
GUI.blit_screen_pitch = (SNES_WIDTH * 2) * 2;
GUI.blit_screen = GUI.filter_buffer;
GUI.need_convert = TRUE;
}
if (GUI.need_convert) { printf("\tImage conversion needed before blit.\n"); }
S9xGraphicsInit();
}
static void TakedownImage (void)
{
if (GUI.snes_buffer)
@ -720,7 +1051,12 @@ static void TakedownImage (void)
if (GUI.image)
{
TakedownXImage();
#ifdef USE_XVIDEO
if (GUI.use_xvideo)
TakedownXvImage();
else
#endif
TakedownXImage();
free(GUI.image);
GUI.image = NULL;
@ -729,69 +1065,6 @@ static void TakedownImage (void)
S9xGraphicsDeinit();
}
static void TakedownXImage (void)
{
if (GUI.image->ximage)
{
#ifdef MITSHM
if (GUI.use_shared_memory)
{
XShmDetach(GUI.display, &GUI.sm_info);
GUI.image->ximage->data = NULL;
XDestroyImage(GUI.image->ximage);
if (GUI.sm_info.shmaddr)
shmdt(GUI.sm_info.shmaddr);
if (GUI.sm_info.shmid >= 0)
shmctl(GUI.sm_info.shmid, IPC_RMID, 0);
GUI.image->ximage = NULL;
}
else
#endif
{
XDestroyImage(GUI.image->ximage);
GUI.image->ximage = NULL;
}
}
}
static void SetupImage (void)
{
TakedownImage();
// Create new image struct
GUI.image = (Image *) calloc(sizeof(Image), 1);
SetupXImage();
// Setup SNES buffers
GFX.Pitch = SNES_WIDTH * 2 * 2;
GUI.snes_buffer = (uint8 *) calloc(GFX.Pitch * ((SNES_HEIGHT_EXTENDED + 4) * 2), 1);
if (!GUI.snes_buffer)
FatalError("Failed to allocate GUI.snes_buffer.");
GFX.Screen = (uint16 *) (GUI.snes_buffer + (GFX.Pitch * 2 * 2));
GUI.filter_buffer = (uint8 *) calloc((SNES_WIDTH * 2) * 2 * (SNES_HEIGHT_EXTENDED * 2), 1);
if (!GUI.filter_buffer)
FatalError("Failed to allocate GUI.filter_buffer.");
if (GUI.depth == 15 || GUI.depth == 16)
{
GUI.blit_screen_pitch = GUI.image->bytes_per_line;
GUI.blit_screen = (uint8 *) GUI.image->data;
GUI.need_convert = FALSE;
}
else
{
GUI.blit_screen_pitch = (SNES_WIDTH * 2) * 2;
GUI.blit_screen = GUI.filter_buffer;
GUI.need_convert = TRUE;
}
if (GUI.need_convert) { printf("\tImage conversion needed before blit.\n"); }
S9xGraphicsInit();
}
static void SetupXImage (void)
{
#ifdef MITSHM
@ -812,8 +1085,9 @@ static void SetupXImage (void)
// set main Image struct vars
GUI.image->height = GUI.image->ximage->height;
GUI.image->bytes_per_line = GUI.image->ximage->bytes_per_line;
GUI.image->data_size = GUI.image->bytes_per_line * GUI.image->height;
GUI.sm_info.shmid = shmget(IPC_PRIVATE, GUI.image->bytes_per_line * GUI.image->height, IPC_CREAT | 0777);
GUI.sm_info.shmid = shmget(IPC_PRIVATE, GUI.image->data_size, IPC_CREAT | 0777);
if (GUI.sm_info.shmid < 0)
{
XDestroyImage(GUI.image->ximage);
@ -842,7 +1116,8 @@ static void SetupXImage (void)
XDestroyImage(GUI.image->ximage);
shmdt(GUI.sm_info.shmaddr);
shmctl(GUI.sm_info.shmid, IPC_RMID, 0);
}
} else
printf("Created XShmImage, size %d\n",GUI.image->data_size);
}
}
}
@ -855,10 +1130,12 @@ static void SetupXImage (void)
// set main Image struct vars
GUI.image->height = GUI.image->ximage->height;
GUI.image->bytes_per_line = GUI.image->ximage->bytes_per_line;
GUI.image->data_size = GUI.image->bytes_per_line * GUI.image->height;
GUI.image->ximage->data = (char *) malloc(GUI.image->bytes_per_line * GUI.image->height);
GUI.image->ximage->data = (char *) malloc(GUI.image->data_size);
if (!GUI.image->ximage || !GUI.image->ximage->data)
FatalError("XCreateImage failed.");
printf("Created XImage, size %d\n",GUI.image->data_size);
#ifdef MITSHM
}
#endif
@ -874,6 +1151,140 @@ static void SetupXImage (void)
#endif
}
static void TakedownXImage (void)
{
if (GUI.image->ximage)
{
#ifdef MITSHM
if (GUI.use_shared_memory)
{
XShmDetach(GUI.display, &GUI.sm_info);
GUI.image->ximage->data = NULL;
XDestroyImage(GUI.image->ximage);
if (GUI.sm_info.shmaddr)
shmdt(GUI.sm_info.shmaddr);
if (GUI.sm_info.shmid >= 0)
shmctl(GUI.sm_info.shmid, IPC_RMID, 0);
GUI.image->ximage = NULL;
}
else
#endif
{
XDestroyImage(GUI.image->ximage);
GUI.image->ximage = NULL;
}
}
}
#ifdef USE_XVIDEO
static void SetupXvImage (void)
{
#ifdef MITSHM
GUI.use_shared_memory = TRUE;
int major, minor;
Bool shared;
if (!XShmQueryVersion(GUI.display, &major, &minor, &shared) || !shared)
GUI.image->xvimage = NULL;
else
GUI.image->xvimage = XvShmCreateImage(GUI.display, GUI.xv_port, GUI.xv_format, NULL, SNES_WIDTH * 2, SNES_HEIGHT_EXTENDED * 2, &GUI.sm_info);
if (!GUI.image->xvimage)
GUI.use_shared_memory = FALSE;
else
{
GUI.image->height = SNES_HEIGHT_EXTENDED * 2;
GUI.image->data_size = GUI.image->xvimage->data_size;
GUI.image->bytes_per_line = GUI.image->data_size / GUI.image->height;
GUI.sm_info.shmid = shmget(IPC_PRIVATE, GUI.image->data_size, IPC_CREAT | 0777);
if (GUI.sm_info.shmid < 0)
{
XFree(GUI.image->xvimage);
GUI.use_shared_memory = FALSE;
}
else
{
GUI.image->xvimage->data = GUI.sm_info.shmaddr = (char *) shmat(GUI.sm_info.shmid, 0, 0);
if (!GUI.image->xvimage->data)
{
XFree(GUI.image->xvimage);
shmctl(GUI.sm_info.shmid, IPC_RMID, 0);
GUI.use_shared_memory = FALSE;
}
else
{
GUI.sm_info.readOnly = False;
XSetErrorHandler(ErrorHandler);
XShmAttach(GUI.display, &GUI.sm_info);
XSync(GUI.display, False);
// X Error handler might clear GUI.use_shared_memory if XShmAttach failed.
if (!GUI.use_shared_memory)
{
XFree(GUI.image->xvimage);
shmdt(GUI.sm_info.shmaddr);
shmctl(GUI.sm_info.shmid, IPC_RMID, 0);
} else
printf("Created XvShmImage, size %d\n",GUI.image->data_size);
}
}
}
if (!GUI.use_shared_memory)
{
fprintf(stderr, "use_shared_memory failed, switching to XvPutImage.\n");
#endif
GUI.image->xvimage = XvCreateImage(GUI.display, GUI.xv_port, GUI.xv_format, NULL, SNES_WIDTH * 2, SNES_HEIGHT_EXTENDED * 2);
GUI.image->height = SNES_HEIGHT_EXTENDED * 2;
GUI.image->data_size = GUI.image->xvimage->data_size;
GUI.image->bytes_per_line = GUI.image->data_size / GUI.image->height;
GUI.image->xvimage->data = (char *) malloc(GUI.image->data_size);
if (!GUI.image->xvimage || !GUI.image->xvimage->data)
{
fprintf(stderr, "XvCreateImage failed, falling back to software blit.\n");
GUI.use_xvideo = FALSE;
return;
}
printf("Created XvImage, size %d\n",GUI.image->data_size);
#ifdef MITSHM
}
#endif
// Set final values
GUI.image->bits_per_pixel = GUI.xv_bpp;
GUI.image->data = GUI.image->xvimage->data;
}
static void TakedownXvImage (void)
{
if (GUI.image->xvimage)
{
#ifdef MITSHM
if (GUI.use_shared_memory)
{
XShmDetach(GUI.display, &GUI.sm_info);
GUI.image->xvimage->data = NULL;
XFree(GUI.image->xvimage);
if (GUI.sm_info.shmaddr)
shmdt(GUI.sm_info.shmaddr);
if (GUI.sm_info.shmid >= 0)
shmctl(GUI.sm_info.shmid, IPC_RMID, 0);
GUI.image->xvimage = NULL;
}
else
#endif
{
free(GUI.image->xvimage->data);
//GUI.image->xvimage->data = NULL;
XFree(GUI.image->xvimage);
GUI.image->xvimage = NULL;
}
}
}
#endif
void S9xPutImage (int width, int height)
{
static int prevWidth = 0, prevHeight = 0;
@ -928,7 +1339,6 @@ void S9xPutImage (int width, int height)
copyHeight = height;
blitFn = S9xBlitPixSimple1x1;
}
blitFn((uint8 *) GFX.Screen, GFX.Pitch, GUI.blit_screen, GUI.blit_screen_pitch, width, height);
if (height < prevHeight)
@ -942,6 +1352,39 @@ void S9xPutImage (int width, int height)
}
}
#ifdef USE_XVIDEO
if (GUI.use_xvideo && (GUI.xv_format == FOURCC_YUY2))
{
uint16 *s = (uint16 *)GUI.blit_screen;
uint8 *d = (uint8 *)GUI.image->data;
// convert GUI.blit_screen and copy to XV image
for (int y = 0; y < SNES_HEIGHT_EXTENDED * 2; y++)
{
for (int x = 0; x < SNES_WIDTH * 2; x += 2)
{
// Read two RGB pxls
// TODO: there is an assumption of endianness here...
// ALSO todo: The 0x7FFF works around some issue with S9xPutChar, where
// despite asking for RGB555 in InitImage, it insists on drawing with RGB565 instead.
// This may discolor messages but at least it doesn't overflow yuv-tables and crash.
unsigned short rgb1 = (*s & 0x7FFF); s++;
unsigned short rgb2 = (*s & 0x7FFF); s++;
// put two YUYV pxls
// lum1
*d = GUI.y_table[rgb1]; d++;
// U
*d = (GUI.u_table[rgb1] + GUI.u_table[rgb2]) / 2; d++;
// lum2
*d = GUI.y_table[rgb2]; d++;
// V
*d = (GUI.v_table[rgb1] + GUI.v_table[rgb2]) / 2; d++;
}
}
}
else
#endif
if (GUI.need_convert)
{
if (GUI.bytes_per_pixel == 3)
@ -1060,6 +1503,26 @@ static void Convert16To24Packed (int width, int height)
static void Repaint (bool8 isFrameBoundry)
{
#ifdef USE_XVIDEO
if (GUI.use_xvideo)
{
#ifdef MITSHM
if (GUI.use_shared_memory)
{
XvShmPutImage(GUI.display, GUI.xv_port, GUI.window, GUI.gc, GUI.image->xvimage,
0, 0, SNES_WIDTH * 2, SNES_HEIGHT_EXTENDED * 2,
GUI.x_offset, GUI.y_offset, SNES_WIDTH * 2, SNES_HEIGHT_EXTENDED * 2, False);
//GUI.x_offset, GUI.y_offset, GUI.scale_w, GUI.scale_h, False);
}
else
#endif
XvPutImage(GUI.display, GUI.xv_port, GUI.window, GUI.gc, GUI.image->xvimage,
0, 0, SNES_WIDTH * 2, SNES_HEIGHT_EXTENDED * 2,
GUI.x_offset, GUI.y_offset, SNES_WIDTH * 2, SNES_HEIGHT_EXTENDED * 2);
//GUI.x_offset, GUI.y_offset, GUI.scale_w, GUI.scale_h);
}
else
#endif
#ifdef MITSHM
if (GUI.use_shared_memory)
{