2018-11-15 23:42:29 +00:00
|
|
|
/*****************************************************************************\
|
|
|
|
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
|
|
|
|
This file is licensed under the Snes9x License.
|
|
|
|
For further information, consult the LICENSE file in the root directory.
|
|
|
|
\*****************************************************************************/
|
|
|
|
|
2018-11-07 00:04:10 +00:00
|
|
|
#include "gtk_2_3_compat.h"
|
2010-09-25 15:46:12 +00:00
|
|
|
#include <X11/extensions/XShm.h>
|
|
|
|
#include <X11/extensions/Xv.h>
|
|
|
|
#include <X11/extensions/Xvlib.h>
|
|
|
|
#include <sys/ipc.h>
|
|
|
|
#include <sys/shm.h>
|
|
|
|
|
|
|
|
#include "gtk_display.h"
|
|
|
|
#include "gtk_display_driver_xv.h"
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
static int get_inv_shift(uint32 mask, int bpp)
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Find mask */
|
2020-06-30 22:28:10 +00:00
|
|
|
for (i = 0; (i < bpp) && !(mask & (1 << i)); i++)
|
|
|
|
{
|
|
|
|
};
|
2010-09-25 15:46:12 +00:00
|
|
|
|
|
|
|
/* Find start of mask */
|
2020-06-30 22:28:10 +00:00
|
|
|
for (; (i < bpp) && (mask & (1 << i)); i++)
|
|
|
|
{
|
|
|
|
};
|
2010-09-25 15:46:12 +00:00
|
|
|
|
|
|
|
return (bpp - i);
|
|
|
|
}
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
S9xXVDisplayDriver::S9xXVDisplayDriver(Snes9xWindow *window,
|
|
|
|
Snes9xConfig *config)
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
|
|
|
this->window = window;
|
|
|
|
this->config = config;
|
2020-06-30 22:28:10 +00:00
|
|
|
this->drawing_area = GTK_WIDGET(window->drawing_area);
|
2010-09-25 15:46:12 +00:00
|
|
|
display =
|
2020-06-30 22:28:10 +00:00
|
|
|
gdk_x11_display_get_xdisplay(gtk_widget_get_display(drawing_area));
|
2010-09-25 15:46:12 +00:00
|
|
|
last_known_width = last_known_height = -1;
|
|
|
|
}
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
void S9xXVDisplayDriver::resize_window(int width, int height)
|
2010-09-26 09:19:15 +00:00
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
gdk_window_destroy(gdk_window);
|
|
|
|
create_window(width, height);
|
2010-09-26 09:19:15 +00:00
|
|
|
}
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
void S9xXVDisplayDriver::create_window(int width, int height)
|
2010-09-26 09:19:15 +00:00
|
|
|
{
|
2018-05-05 18:49:42 +00:00
|
|
|
GdkWindowAttr window_attr;
|
2020-06-30 22:28:10 +00:00
|
|
|
memset(&window_attr, 0, sizeof(GdkWindowAttr));
|
2018-05-05 18:49:42 +00:00
|
|
|
window_attr.event_mask = GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK;
|
|
|
|
window_attr.width = width;
|
|
|
|
window_attr.height = height;
|
|
|
|
window_attr.x = 0;
|
|
|
|
window_attr.y = 0;
|
|
|
|
window_attr.wclass = GDK_INPUT_OUTPUT;
|
|
|
|
window_attr.window_type = GDK_WINDOW_CHILD;
|
2020-06-30 22:28:10 +00:00
|
|
|
window_attr.visual = gdk_x11_screen_lookup_visual(gtk_widget_get_screen(drawing_area), vi->visualid);
|
2018-05-05 18:49:42 +00:00
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
gdk_window = gdk_window_new(gtk_widget_get_window(drawing_area),
|
|
|
|
&window_attr,
|
|
|
|
GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL);
|
|
|
|
gdk_window_set_user_data(gdk_window, (gpointer)drawing_area);
|
2018-05-05 18:49:42 +00:00
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
gdk_window_show(gdk_window);
|
|
|
|
xwindow = gdk_x11_window_get_xid(gdk_window);
|
2010-09-26 09:19:15 +00:00
|
|
|
|
|
|
|
output_window_width = width;
|
|
|
|
output_window_height = height;
|
|
|
|
}
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
void S9xXVDisplayDriver::update(uint16_t *buffer, int width, int height, int stride_in_pixels)
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
int current_width, current_height;
|
2010-09-26 09:19:15 +00:00
|
|
|
GtkAllocation allocation;
|
2010-09-25 15:46:12 +00:00
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
gtk_widget_get_allocation(drawing_area, &allocation);
|
2018-05-05 19:14:06 +00:00
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
if (output_window_width != allocation.width ||
|
2018-05-05 19:14:06 +00:00
|
|
|
output_window_height != allocation.height)
|
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
resize_window(allocation.width, allocation.height);
|
2018-05-05 19:14:06 +00:00
|
|
|
}
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
#if GTK_CHECK_VERSION(3, 10, 0)
|
|
|
|
int gdk_scale_factor = gdk_window_get_scale_factor(gdk_window);
|
2016-10-03 00:41:42 +00:00
|
|
|
|
|
|
|
allocation.width *= gdk_scale_factor;
|
|
|
|
allocation.height *= gdk_scale_factor;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2010-09-26 09:19:15 +00:00
|
|
|
current_width = allocation.width;
|
|
|
|
current_height = allocation.height;
|
2010-09-25 15:46:12 +00:00
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
update_image_size(width, height);
|
2010-09-25 15:46:12 +00:00
|
|
|
|
|
|
|
if (format == FOURCC_YUY2)
|
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
S9xConvertYUV(buffer,
|
|
|
|
(uint8 *)xv_image->data,
|
|
|
|
stride_in_pixels * 2,
|
|
|
|
2 * xv_image->width,
|
|
|
|
width + (width < xv_image->width ? (width % 2) + 4 : 0),
|
|
|
|
height + (height < xv_image->height ? 4 : 0));
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
S9xConvertMask(buffer,
|
|
|
|
(uint8 *)xv_image->data,
|
|
|
|
stride_in_pixels * 2,
|
|
|
|
bytes_per_pixel * xv_image->width,
|
|
|
|
width + (width < xv_image->width ? (width % 2) + 4 : 0),
|
|
|
|
height + (height < xv_image->height ? 4 : 0),
|
|
|
|
rshift,
|
|
|
|
gshift,
|
|
|
|
bshift,
|
|
|
|
bpp);
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
|
|
|
|
2019-05-14 19:59:51 +00:00
|
|
|
S9xRect dst = S9xApplyAspect(width, height, current_width, current_height);
|
2010-09-25 15:46:12 +00:00
|
|
|
|
2019-05-14 19:59:51 +00:00
|
|
|
if (last_known_width != dst.w || last_known_height != dst.h)
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
2019-05-14 19:59:51 +00:00
|
|
|
last_known_width = dst.w;
|
|
|
|
last_known_height = dst.h;
|
2020-06-30 22:28:10 +00:00
|
|
|
clear();
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
XvShmPutImage(display,
|
|
|
|
xv_portid,
|
|
|
|
xwindow,
|
|
|
|
XDefaultGC(display, XDefaultScreen(display)),
|
|
|
|
xv_image,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
dst.x,
|
|
|
|
dst.y,
|
|
|
|
dst.w,
|
|
|
|
dst.h,
|
|
|
|
False);
|
|
|
|
|
|
|
|
top_level->set_mouseable_area(dst.x, dst.y, dst.w, dst.h);
|
|
|
|
|
|
|
|
XSync(display, False);
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
void S9xXVDisplayDriver::update_image_size(int width, int height)
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
if (xv_image_width != width || xv_image_height != height)
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
XShmDetach(display, &shm);
|
|
|
|
XSync(display, 0);
|
2010-09-25 15:46:12 +00:00
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
shmctl(shm.shmid, IPC_RMID, 0);
|
|
|
|
shmdt(shm.shmaddr);
|
2010-09-25 15:46:12 +00:00
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
xv_image = XvShmCreateImage(display,
|
|
|
|
xv_portid,
|
|
|
|
format,
|
|
|
|
0,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
&shm);
|
2010-09-25 15:46:12 +00:00
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
shm.shmid = shmget(IPC_PRIVATE, xv_image->data_size, IPC_CREAT | 0777);
|
2010-09-25 15:46:12 +00:00
|
|
|
for (int tries = 0; tries <= 10; tries++)
|
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
shm.shmaddr = (char *)shmat(shm.shmid, 0, 0);
|
2010-09-25 15:46:12 +00:00
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
if (shm.shmaddr == (void *)-1 && tries >= 10)
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
|
|
|
/* Can't recover, send exit. */
|
2020-06-30 22:28:10 +00:00
|
|
|
fprintf(stderr, "Couldn't reallocate shared memory.\n");
|
|
|
|
S9xExit();
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
2020-06-30 22:28:10 +00:00
|
|
|
else if (shm.shmaddr != (void *)-1)
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-28 22:32:32 +00:00
|
|
|
shm.readOnly = false;
|
2010-09-25 15:46:12 +00:00
|
|
|
|
|
|
|
xv_image->data = shm.shmaddr;
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
XShmAttach(display, &shm);
|
2010-09-25 15:46:12 +00:00
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
xv_image_width = width;
|
|
|
|
xv_image_height = height;
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
int S9xXVDisplayDriver::init()
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
int depth = 0, num_formats, num_attrs, highest_formats = 0;
|
2010-09-25 15:46:12 +00:00
|
|
|
XvImageFormatValues *formats = NULL;
|
2020-06-30 22:28:10 +00:00
|
|
|
XvAdaptorInfo *adaptors;
|
|
|
|
XvAttribute *port_attr;
|
|
|
|
VisualID visualid = None;
|
|
|
|
unsigned int num_adaptors = 0;
|
|
|
|
GdkScreen *screen;
|
|
|
|
GdkWindow *root;
|
2010-09-25 15:46:12 +00:00
|
|
|
|
|
|
|
/* Setup XV */
|
2020-06-30 22:28:10 +00:00
|
|
|
gtk_widget_realize(drawing_area);
|
2010-09-25 15:46:12 +00:00
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
display = gdk_x11_display_get_xdisplay(gtk_widget_get_display(drawing_area));
|
|
|
|
screen = gtk_widget_get_screen(drawing_area);
|
|
|
|
root = gdk_screen_get_root_window(screen);
|
2010-09-25 15:46:12 +00:00
|
|
|
|
|
|
|
xv_portid = -1;
|
2020-06-30 22:28:10 +00:00
|
|
|
if ((XvQueryAdaptors(display,
|
|
|
|
gdk_x11_window_get_xid(root),
|
|
|
|
&num_adaptors,
|
|
|
|
&adaptors)) != Success)
|
2019-09-08 17:45:18 +00:00
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
fprintf(stderr, "No Xv compatible adaptors.\n");
|
2019-09-08 17:45:18 +00:00
|
|
|
}
|
2010-09-25 15:46:12 +00:00
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
for (int i = 0; i < (int)num_adaptors; i++)
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
|
|
|
if (adaptors[i].type & XvInputMask &&
|
|
|
|
adaptors[i].type & XvImageMask)
|
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
formats = XvListImageFormats(display,
|
|
|
|
adaptors[i].base_id,
|
|
|
|
&num_formats);
|
2010-09-25 15:46:12 +00:00
|
|
|
|
|
|
|
if (num_formats > highest_formats)
|
|
|
|
{
|
|
|
|
xv_portid = adaptors[i].base_id;
|
|
|
|
highest_formats = num_formats;
|
|
|
|
visualid = adaptors[i].formats->visual_id;
|
|
|
|
}
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
free(formats);
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
XvFreeAdaptorInfo(adaptors);
|
2010-09-25 15:46:12 +00:00
|
|
|
|
|
|
|
if (xv_portid < 0)
|
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
fprintf(stderr, "Could not open Xv output port.\n");
|
2010-09-25 15:46:12 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set XV_AUTOPAINT_COLORKEY _only_ if available */
|
2020-06-30 22:28:10 +00:00
|
|
|
port_attr = XvQueryPortAttributes(display, xv_portid, &num_attrs);
|
2010-09-25 15:46:12 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < num_attrs; i++)
|
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
if (!strcmp(port_attr[i].name, "XV_AUTOPAINT_COLORKEY"))
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
2016-09-27 20:25:37 +00:00
|
|
|
Atom colorkey;
|
2010-09-25 15:46:12 +00:00
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
colorkey = XInternAtom(display, "XV_AUTOPAINT_COLORKEY", True);
|
2010-09-25 15:46:12 +00:00
|
|
|
if (colorkey != None)
|
2020-06-30 22:28:10 +00:00
|
|
|
XvSetPortAttribute(display, xv_portid, colorkey, 1);
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try to find an RGB format */
|
2018-10-15 19:54:36 +00:00
|
|
|
format = -1;
|
2010-09-25 15:46:12 +00:00
|
|
|
bpp = 100;
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
formats = XvListImageFormats(display,
|
|
|
|
xv_portid,
|
|
|
|
&num_formats);
|
2010-09-25 15:46:12 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < num_formats; i++)
|
|
|
|
{
|
|
|
|
if (formats[i].id == 0x3 || formats[i].type == XvRGB)
|
|
|
|
{
|
|
|
|
if (formats[i].bits_per_pixel < bpp)
|
|
|
|
{
|
|
|
|
format = formats[i].id;
|
|
|
|
bpp = formats[i].bits_per_pixel;
|
|
|
|
bytes_per_pixel = (bpp == 15) ? 2 : bpp >> 3;
|
|
|
|
depth = formats[i].depth;
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
this->rshift = get_inv_shift(formats[i].red_mask, bpp);
|
|
|
|
this->gshift = get_inv_shift(formats[i].green_mask, bpp);
|
|
|
|
this->bshift = get_inv_shift(formats[i].blue_mask, bpp);
|
2010-09-25 15:46:12 +00:00
|
|
|
|
|
|
|
/* Check for red-blue inversion on SiliconMotion drivers */
|
2020-06-30 22:28:10 +00:00
|
|
|
if (formats[i].red_mask == 0x001f &&
|
2010-09-25 15:46:12 +00:00
|
|
|
formats[i].blue_mask == 0x7c00)
|
|
|
|
{
|
|
|
|
int copy = this->rshift;
|
|
|
|
this->rshift = this->bshift;
|
|
|
|
this->bshift = copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* on big-endian Xv still seems to like LSB order */
|
|
|
|
if (config->force_inverted_byte_order)
|
2020-06-30 22:28:10 +00:00
|
|
|
S9xSetEndianess(ENDIAN_SWAPPED);
|
2010-09-25 15:46:12 +00:00
|
|
|
else
|
2020-06-30 22:28:10 +00:00
|
|
|
S9xSetEndianess(ENDIAN_NORMAL);
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-15 19:54:36 +00:00
|
|
|
if (format == -1)
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
|
|
|
for (int i = 0; i < num_formats; i++)
|
|
|
|
{
|
|
|
|
if (formats[i].id == FOURCC_YUY2)
|
|
|
|
{
|
2018-10-15 19:54:36 +00:00
|
|
|
format = formats[i].id;
|
2010-09-25 15:46:12 +00:00
|
|
|
depth = formats[i].depth;
|
|
|
|
|
|
|
|
if (formats[i].byte_order == LSBFirst)
|
|
|
|
{
|
|
|
|
if (config->force_inverted_byte_order)
|
2020-06-30 22:28:10 +00:00
|
|
|
S9xSetEndianess(ENDIAN_SWAPPED);
|
2010-09-25 15:46:12 +00:00
|
|
|
else
|
2020-06-30 22:28:10 +00:00
|
|
|
S9xSetEndianess(ENDIAN_NORMAL);
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (config->force_inverted_byte_order)
|
2020-06-30 22:28:10 +00:00
|
|
|
S9xSetEndianess(ENDIAN_NORMAL);
|
2010-09-25 15:46:12 +00:00
|
|
|
else
|
2020-06-30 22:28:10 +00:00
|
|
|
S9xSetEndianess(ENDIAN_SWAPPED);
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
free(formats);
|
2010-09-25 15:46:12 +00:00
|
|
|
|
2018-10-15 19:54:36 +00:00
|
|
|
if (format == -1)
|
2019-09-08 17:45:18 +00:00
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
fprintf(stderr, "No compatible formats found for Xv.\n");
|
2018-10-15 19:54:36 +00:00
|
|
|
return -1;
|
2019-09-08 17:45:18 +00:00
|
|
|
}
|
2018-10-15 19:54:36 +00:00
|
|
|
|
2010-09-25 15:46:12 +00:00
|
|
|
/* Build a table for yuv conversion */
|
|
|
|
if (format == FOURCC_YUY2)
|
|
|
|
{
|
|
|
|
for (unsigned int color = 0; color < 65536; color++)
|
|
|
|
{
|
|
|
|
int r, g, b;
|
|
|
|
int y, u, v;
|
|
|
|
|
2018-05-05 18:49:42 +00:00
|
|
|
r = ((color & 0xf800) >> 8) | ((color >> 13) & 0x7);
|
2020-06-30 22:28:10 +00:00
|
|
|
g = ((color & 0x07e0) >> 3) | ((color >> 9) & 0x3);
|
|
|
|
b = ((color & 0x001F) << 3) | ((color >> 3) & 0x7);
|
2010-09-25 15:46:12 +00:00
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
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);
|
2010-09-25 15:46:12 +00:00
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
y_table[color] = CLAMP(y, 0, 255);
|
|
|
|
u_table[color] = CLAMP(u, 0, 255);
|
|
|
|
v_table[color] = CLAMP(v, 0, 255);
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
S9xRegisterYUVTables(y_table, u_table, v_table);
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Create a sub-window */
|
2010-09-26 09:19:15 +00:00
|
|
|
XVisualInfo vi_template;
|
2010-09-25 15:46:12 +00:00
|
|
|
int vi_num_items;
|
|
|
|
|
|
|
|
vi_template.visualid = visualid;
|
|
|
|
vi_template.depth = depth;
|
|
|
|
vi_template.visual = NULL;
|
2020-06-30 22:28:10 +00:00
|
|
|
vi = XGetVisualInfo(display, VisualIDMask | VisualDepthMask, &vi_template, &vi_num_items);
|
2010-09-25 15:46:12 +00:00
|
|
|
|
|
|
|
if (!vi)
|
|
|
|
{
|
|
|
|
vi_template.depth = 0;
|
2020-06-30 22:28:10 +00:00
|
|
|
vi = XGetVisualInfo(display, VisualIDMask, &vi_template, &vi_num_items);
|
2010-09-25 15:46:12 +00:00
|
|
|
|
|
|
|
if (!vi)
|
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
fprintf(stderr, "Couldn't map visual.\n");
|
2010-09-25 15:46:12 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
xcolormap = XCreateColormap(display,
|
|
|
|
gdk_x11_window_get_xid(gtk_widget_get_window(drawing_area)),
|
2010-09-25 15:46:12 +00:00
|
|
|
vi->visual,
|
|
|
|
AllocNone);
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
create_window(1, 1);
|
|
|
|
gdk_window_hide(gdk_window);
|
2010-09-25 15:46:12 +00:00
|
|
|
|
|
|
|
/* Allocate a shared memory image. */
|
2020-06-30 22:28:10 +00:00
|
|
|
xv_image = XvShmCreateImage(display,
|
|
|
|
xv_portid,
|
|
|
|
format,
|
|
|
|
0,
|
|
|
|
512,
|
|
|
|
512,
|
|
|
|
&shm);
|
|
|
|
|
|
|
|
shm.shmid = shmget(IPC_PRIVATE, xv_image->data_size, IPC_CREAT | 0777);
|
|
|
|
shm.shmaddr = (char *)shmat(shm.shmid, 0, 0);
|
|
|
|
if (shm.shmaddr == (void *)-1)
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
fprintf(stderr, "Could not attach shared memory segment.\n");
|
2010-09-25 15:46:12 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-12-28 22:32:32 +00:00
|
|
|
shm.readOnly = false;
|
2010-09-25 15:46:12 +00:00
|
|
|
|
|
|
|
xv_image->data = shm.shmaddr;
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
XShmAttach(display, &shm);
|
2018-10-15 19:54:36 +00:00
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
xv_image_width = 512;
|
|
|
|
xv_image_height = 512;
|
2010-09-25 15:46:12 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
void S9xXVDisplayDriver::deinit()
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
gdk_window_destroy(gdk_window);
|
2010-09-26 09:19:15 +00:00
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
XShmDetach(display, &shm);
|
|
|
|
XSync(display, 0);
|
2010-09-25 15:46:12 +00:00
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
XFreeColormap(display, xcolormap);
|
|
|
|
XFree(vi);
|
2010-09-25 15:46:12 +00:00
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
shmctl(shm.shmid, IPC_RMID, 0);
|
|
|
|
shmdt(shm.shmaddr);
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
void S9xXVDisplayDriver::clear()
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
int width, height;
|
2010-09-26 09:19:15 +00:00
|
|
|
GtkAllocation allocation;
|
2020-06-30 22:28:10 +00:00
|
|
|
GC xgc = XDefaultGC(display, XDefaultScreen(display));
|
2010-09-26 09:19:15 +00:00
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
gtk_widget_get_allocation(drawing_area, &allocation);
|
|
|
|
#if GTK_CHECK_VERSION(3, 10, 0)
|
|
|
|
int gdk_scale_factor = gdk_window_get_scale_factor(gdk_window);
|
2016-10-03 00:41:42 +00:00
|
|
|
|
|
|
|
allocation.width *= gdk_scale_factor;
|
|
|
|
allocation.height *= gdk_scale_factor;
|
|
|
|
|
|
|
|
#endif
|
2010-09-26 09:19:15 +00:00
|
|
|
width = allocation.width;
|
|
|
|
height = allocation.height;
|
2010-09-25 15:46:12 +00:00
|
|
|
|
|
|
|
if (window->last_width <= 0 || window->last_height <= 0)
|
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
XDrawRectangle(display, xwindow, xgc, 0, 0, width, height);
|
2010-09-25 15:46:12 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get width of modified display */
|
2019-05-14 19:59:51 +00:00
|
|
|
S9xRect dst;
|
|
|
|
dst.w = window->last_width;
|
|
|
|
dst.h = window->last_height;
|
2020-06-30 22:28:10 +00:00
|
|
|
get_filter_scale(dst.w, dst.h);
|
|
|
|
dst = S9xApplyAspect(dst.w, dst.h, width, height);
|
2019-05-14 19:59:51 +00:00
|
|
|
|
|
|
|
if (dst.x > 0)
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
XFillRectangle(display, xwindow, xgc, 0, dst.y, dst.x, dst.h);
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
2019-05-14 19:59:51 +00:00
|
|
|
if (dst.x + dst.w < width)
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
XFillRectangle(display, xwindow, xgc, dst.x + dst.w, dst.y, width - (dst.x + dst.w), dst.h);
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
2019-05-14 19:59:51 +00:00
|
|
|
if (dst.y > 0)
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
XFillRectangle(display, xwindow, xgc, 0, 0, width, dst.y);
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
2019-05-14 19:59:51 +00:00
|
|
|
if (dst.y + dst.h < height)
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
XFillRectangle(display, xwindow, xgc, 0, dst.y + dst.h, width, height - (dst.y + dst.h));
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
XSync(display, False);
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
void S9xXVDisplayDriver::refresh(int width, int height)
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
2020-06-30 22:28:10 +00:00
|
|
|
clear();
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
int S9xXVDisplayDriver::query_availability()
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
|
|
|
unsigned int p_version,
|
2020-06-30 22:28:10 +00:00
|
|
|
p_release,
|
|
|
|
p_request_base,
|
|
|
|
p_event_base,
|
|
|
|
p_error_base;
|
|
|
|
Display *display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
|
2010-09-25 15:46:12 +00:00
|
|
|
|
2018-07-12 15:15:07 +00:00
|
|
|
if (!display)
|
|
|
|
return 0;
|
|
|
|
|
2010-09-25 15:46:12 +00:00
|
|
|
/* Test if XV and SHM are feasible */
|
2020-06-30 22:28:10 +00:00
|
|
|
if (!XShmQueryExtension(display))
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-06-30 22:28:10 +00:00
|
|
|
if (XvQueryExtension(display,
|
|
|
|
&p_version,
|
|
|
|
&p_release,
|
|
|
|
&p_request_base,
|
|
|
|
&p_event_base,
|
|
|
|
&p_error_base) != Success)
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|