mirror of https://github.com/snes9xgit/snes9x.git
Add Xv acceleration support to unix port.
This commit is contained in:
parent
2db2c2f57c
commit
7396766588
603
unix/x11.cpp
603
unix/x11.cpp
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue