Skip to content
Snippets Groups Projects
Commit ea7a6600 authored by Deucе's avatar Deucе :ok_hand_tone4:
Browse files

More X11 improvements

Use the default visual and depth instead of "best"
Use Xrender for sclaing when library is available and server supports it
Set VisualIsRGB8 when possible
parent ce436546
No related branches found
No related tags found
No related merge requests found
......@@ -78,6 +78,13 @@ else
endif
endif
ifndef NO_X
ifeq ($(shell pkg-config xrender --exists && echo YES), YES)
CIOLIB-MT_CFLAGS += $(shell pkg-config xrender --cflags)
CIOLIB-MT_CFLAGS += -DWITH_XRENDER
endif
endif
# Find SDL headers!
ifdef USE_SDL
ifdef SDL_CONFIG
......
......@@ -318,6 +318,8 @@ static int try_x_init(int mode)
cio_api.map_rgb = bitmap_map_rgb;
cio_api.replace_font = bitmap_replace_font;
cio_api.mousepointer=x_mousepointer;
cio_api.setscaling_type=x_setscaling_type;
cio_api.getscaling_type=x_getscaling_type;
return(1);
}
return(0);
......
......@@ -215,7 +215,10 @@ int x_init(void)
{
dll_handle dl;
const char *libnames[]={"X11",NULL};
dll_handle dl2;
const char *libnames2[]={"Xrender",NULL};
Status (*xit)(void);
int *_Xdebug;
/* Ensure we haven't already initialized */
if(x11_initialized)
......@@ -234,6 +237,8 @@ int x_init(void)
/* Load X11 functions */
if((dl=xp_dlopen(libnames,RTLD_LAZY,7))==NULL)
return(-1);
if ((_Xdebug = xp_dlsym(dl,_Xdebug))!=NULL)
*_Xdebug=1;
if((xit=xp_dlsym(dl,XInitThreads))!=NULL)
xit();
if((x11.XChangeGC=xp_dlsym(dl,XChangeGC))==NULL) {
......@@ -472,6 +477,57 @@ int x_init(void)
xp_dlclose(dl);
return(-1);
}
#ifndef DefaultDepth
if((x11.DefaultDepth=xp_dlsym(dl,DefaultDepth))==NULL) {
xp_dlclose(dl);
return(-1);
}
#endif
#ifndef DefaultVisual
if((x11.DefaultVisual=xp_dlsym(dl,DefaultVisual))==NULL) {
xp_dlclose(dl);
return(-1);
}
#endif
#ifdef WITH_XRENDER
xrender_found = true;
if ((dl2 = xp_dlopen(libnames2,RTLD_LAZY,7)) == NULL) {
xp_dlclose(dl2);
xrender_found = false;
}
if (xrender_found && ((x11.XRenderFindStandardFormat = xp_dlsym(dl2, XRenderFindStandardFormat)) == NULL)) {
xp_dlclose(dl);
xrender_found = false;
}
if (xrender_found && ((x11.XRenderCreatePicture = xp_dlsym(dl2, XRenderCreatePicture)) == NULL)) {
xp_dlclose(dl);
xrender_found = false;
}
if (xrender_found && ((x11.XRenderFreePicture = xp_dlsym(dl2, XRenderFreePicture)) == NULL)) {
xp_dlclose(dl);
xrender_found = false;
}
if (xrender_found && ((x11.XRenderSetPictureTransform = xp_dlsym(dl2, XRenderSetPictureTransform)) == NULL)) {
xp_dlclose(dl);
xrender_found = false;
}
if (xrender_found && ((x11.XRenderComposite = xp_dlsym(dl2, XRenderComposite)) == NULL)) {
xp_dlclose(dl);
xrender_found = false;
}
if (xrender_found && ((x11.XRenderFindVisualFormat = xp_dlsym(dl2, XRenderFindVisualFormat)) == NULL)) {
xp_dlclose(dl);
xrender_found = false;
}
if (xrender_found && ((x11.XRenderQueryVersion = xp_dlsym(dl2, XRenderQueryVersion)) == NULL)) {
xp_dlclose(dl);
xrender_found = false;
}
if (xrender_found && ((x11.XRenderSetPictureFilter = xp_dlsym(dl2, XRenderSetPictureFilter)) == NULL)) {
xp_dlclose(dl);
xrender_found = false;
}
#endif
setlocale(LC_ALL, "");
x11.XSetLocaleModifiers("@im=none");
......@@ -574,3 +630,24 @@ int x_mousepointer(enum ciolib_mouse_ptr type)
}
return 0;
}
enum ciolib_scaling
x_getscaling_type(void)
{
enum ciolib_scaling ret;
ret = (x_internal_scaling ? CIOLIB_SCALING_INTERNAL : CIOLIB_SCALING_EXTERNAL);
return ret;
}
void
x_setscaling_type(enum ciolib_scaling newval)
{
struct x11_local_event ev = {0};
if ((newval == CIOLIB_SCALING_INTERNAL) != x_internal_scaling) {
ev.type = X11_LOCAL_SETSCALING_TYPE;
ev.data.st = newval;
write_event(&ev);
}
}
......@@ -82,6 +82,8 @@ void x_setscaling(double newval);
double x_getscaling(void);
void x_seticon(const void *icon, unsigned long size);
int x_mousepointer(enum ciolib_mouse_ptr type);
enum ciolib_scaling x_getscaling_type(void);
void x_setscaling_type(enum ciolib_scaling newval);
#ifdef __cplusplus
}
#endif
......
......@@ -56,6 +56,8 @@ sem_t event_thread_complete;
int terminate = 0;
Atom copybuf_format;
Atom pastebuf_format;
bool xrender_found;
bool x_internal_scaling = true;
/*
* Local variables
......@@ -68,7 +70,7 @@ static Atom WM_DELETE_WINDOW=0;
static Display *dpy=NULL;
static Window win;
static Cursor curs = None;
static Visual visual;
static Visual *visual;
static bool VisualIsRGB8 = false;
static XImage *xim;
static XIM im;
......@@ -83,6 +85,12 @@ static int r_shift;
static int g_shift;
static int b_shift;
static struct graphics_buffer *last = NULL;
#ifdef WITH_XRENDER
static XRenderPictFormat *xrender_pf = NULL;
static Pixmap xrender_pm = None;
static Picture xrender_src_pict = None;
static Picture xrender_dst_pict = None;
#endif
/* Array of Graphics Contexts */
static GC gc;
......@@ -261,13 +269,55 @@ x11_get_maxsize(int *w, int *h)
return false;
}
static void resize_xim(void)
static void
resize_pictures(void)
{
int width, height;
#ifdef WITH_XRENDER
if (xrender_pf == NULL)
xrender_pf = x11.XRenderFindStandardFormat(dpy, PictStandardRGB24);
if (xrender_pf == NULL)
xrender_pf = x11.XRenderFindVisualFormat(dpy, visual);
if (xrender_pf == NULL)
xrender_pf = x11.XRenderFindVisualFormat(dpy, DefaultVisual(dpy, DefaultScreen(dpy)));
if (xrender_pm != None)
x11.XFreePixmap(dpy, xrender_pm);
xrender_pm = x11.XCreatePixmap(dpy, win, x_cvstat.scrnwidth, x_cvstat.scrnheight, depth);
if (xrender_src_pict != None)
x11.XRenderFreePicture(dpy, xrender_src_pict);
if (xrender_dst_pict != None)
x11.XRenderFreePicture(dpy, xrender_dst_pict);
XRenderPictureAttributes pa;
xrender_src_pict = x11.XRenderCreatePicture(dpy, xrender_pm, xrender_pf, 0, &pa);
xrender_dst_pict = x11.XRenderCreatePicture(dpy, win, xrender_pf, 0, &pa);
x11.XRenderSetPictureFilter(dpy, xrender_src_pict, "best", NULL, 0);
pthread_mutex_lock(&vstatlock);
bitmap_get_scaled_win_size(x_cvstat.scaling, &width, &height, 0, 0);
XTransform transform_matrix = {{
{XDoubleToFixed((double)vstat.scrnwidth / vstat.winwidth), XDoubleToFixed(0), XDoubleToFixed(0)},
{XDoubleToFixed(0), XDoubleToFixed((double)vstat.scrnheight / vstat.winheight), XDoubleToFixed(0)},
{XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1.0)}
}};
pthread_mutex_unlock(&vstatlock);
x11.XRenderSetPictureTransform(dpy, xrender_src_pict, &transform_matrix);
#endif
}
static void resize_xim(void)
{
int width, height;
resize_pictures();
if (x_internal_scaling) {
pthread_mutex_lock(&vstatlock);
bitmap_get_scaled_win_size(x_cvstat.scaling, &width, &height, 0, 0);
pthread_mutex_unlock(&vstatlock);
}
else {
width = x_cvstat.scrnwidth;
height = x_cvstat.scrnheight;
}
if (xim) {
if (width == xim->width
......@@ -289,7 +339,7 @@ static void resize_xim(void)
release_buffer(last);
last = NULL;
}
xim = x11.XCreateImage(dpy, &visual, depth, ZPixmap, 0, NULL, width, height, 32, 0);
xim = x11.XCreateImage(dpy, visual, depth, ZPixmap, 0, NULL, width, height, 32, 0);
xim->data=(char *)calloc(1, xim->bytes_per_line*xim->height);
x11.XFillRectangle(dpy, win, gc, 0, 0, width, height);
}
......@@ -359,59 +409,48 @@ static void map_window()
static int init_window()
{
XGCValues gcv;
int i;
XWMHints *wmhints;
XClassHint *classhints;
int ret;
int best=-1;
int best_depth=0;
int best_cmap=0;
XVisualInfo template = {0};
XVisualInfo *vi;
int w, h;
int mw, mh;
int screen;
int major, minor;
dpy = x11.XOpenDisplay(NULL);
if (dpy == NULL) {
return(-1);
}
#ifdef WITH_XRENDER
if (xrender_found && x11.XRenderQueryVersion(dpy, &major, &minor) == 0)
xrender_found = false;
#endif
xfd = ConnectionNumber(dpy);
x11.utf8 = x11.XInternAtom(dpy, "UTF8_STRING", False);
x11.targets = x11.XInternAtom(dpy, "TARGETS", False);
x11.workarea = x11.XInternAtom(dpy, "_NET_WORKAREA", True);
template.screen = DefaultScreen(dpy);
template.class = TrueColor;
vi = x11.XGetVisualInfo(dpy, VisualScreenMask | VisualClassMask, &template, &ret);
for (i=0; i<ret; i++) {
if (vi[i].depth >= best_depth && vi[i].colormap_size >= best_cmap) {
best = i;
best_depth = vi[i].depth;
}
}
if (best != -1) {
visual = *vi[best].visual;
/*
* TODO: Set VisualIsRGB8 if appropriate...
* "appropriate" in this context means it's a sequence of
* unpadded uint32_t values in XXRRGGBB format where XX is
* ignored, and RR, GG, and BB are Red, Green, Blue values
* respectively.
*/
base_pixel = ULONG_MAX;
base_pixel &= ~visual.red_mask;
base_pixel &= ~visual.green_mask;
base_pixel &= ~visual.blue_mask;
r_shift = my_fls(visual.red_mask)-16;
g_shift = my_fls(visual.green_mask)-16;
b_shift = my_fls(visual.blue_mask)-16;
}
else {
fprintf(stderr, "Unable to find TrueColor visual\n");
x11.XFree(vi);
return -1;
}
x11.XFree(vi);
screen = DefaultScreen(dpy);
#ifdef DefaultVisual
visual = DefaultVisual(dpy, screen);
#else
visual = x11.DefaultVisual(dpy, screen);
#endif
#ifdef DefaultDepth
depth = DefaultDepth(dpy, screen);
#else
depth = x11.DefaultDepth(dpy, screen);
#endif
base_pixel = ULONG_MAX;
base_pixel &= ~visual->red_mask;
base_pixel &= ~visual->green_mask;
base_pixel &= ~visual->blue_mask;
r_shift = my_fls(visual->red_mask)-16;
g_shift = my_fls(visual->green_mask)-16;
b_shift = my_fls(visual->blue_mask)-16;
if (visual->red_mask == 0xff0000 && visual->green_mask == 0xff00 && visual->blue_mask == 0xff)
VisualIsRGB8 = true;
/* Allocate black and white */
black=BlackPixel(dpy, DefaultScreen(dpy));
......@@ -419,10 +458,9 @@ static int init_window()
/* Create window, but defer setting a size and GC. */
XSetWindowAttributes wa = {0};
wa.colormap = x11.XCreateColormap(dpy, DefaultRootWindow(dpy), &visual, AllocNone);
wa.colormap = x11.XCreateColormap(dpy, DefaultRootWindow(dpy), visual, AllocNone);
wa.background_pixel = black;
wa.border_pixel = black;
depth = best_depth;
x11_get_maxsize(&mw, &mh);
pthread_mutex_lock(&vstatlock);
bitmap_get_scaled_win_size(x_cvstat.scaling, &w, &h, mw, mh);
......@@ -431,7 +469,7 @@ static int init_window()
vstat.scaling = x_cvstat.scaling;
pthread_mutex_unlock(&vstatlock);
win = x11.XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0,
w, h, 2, depth, InputOutput, &visual, CWColormap | CWBorderPixel | CWBackPixel, &wa);
w, h, 2, depth, InputOutput, visual, CWColormap | CWBorderPixel | CWBackPixel, &wa);
classhints=x11.XAllocClassHint();
if (classhints)
......@@ -558,6 +596,7 @@ static int video_init()
lot easier. */
pthread_mutex_lock(&vstatlock);
x_internal_scaling = (ciolib_initial_scaling_type == CIOLIB_SCALING_INTERNAL);
if (ciolib_initial_scaling != 0.0)
x_cvstat.scaling = vstat.scaling = ciolib_initial_scaling;
if (x_cvstat.scaling < 1.0 || vstat.scaling < 1.0)
......@@ -595,6 +634,8 @@ local_draw_rect(struct rectlist *rect)
uint32_t last_pixel = 0x55555555;
struct graphics_buffer *source;
int w, h;
int dw, dh;
uint32_t *source_data;
if (x_cvstat.scrnwidth != rect->rect.width || x_cvstat.scrnheight != rect->rect.height || xim == NULL) {
bitmap_drv_free_rect(rect);
......@@ -609,25 +650,37 @@ local_draw_rect(struct rectlist *rect)
bitmap_drv_free_rect(rect);
return;
}
source = do_scale(rect, w, h);
bitmap_drv_free_rect(rect);
if (source == NULL)
return;
cleft = source->w;
ctop = source->h;
if (x_internal_scaling) {
source = do_scale(rect, w, h);
bitmap_drv_free_rect(rect);
if (source == NULL)
return;
cleft = source->w;
ctop = source->h;
source_data = source->data;
dw = source->w;
dh = source->h;
}
else {
cleft = w;
ctop = h;
source_data = rect->data;
dw = rect->rect.width;
dh = rect->rect.height;
}
pthread_mutex_lock(&vstatlock);
w = vstat.winwidth;
h = vstat.winheight;
pthread_mutex_unlock(&vstatlock);
xoff = (w - source->w) / 2;
xoff = (w - cleft) / 2;
if (xoff < 0)
xoff = 0;
yoff = (h - source->h) / 2;
yoff = (h - ctop) / 2;
if (yoff < 0)
yoff = 0;
if (last && (last->w != source->w || last->h != source->h)) {
if (last && (last->w != dw || last->h != dh)) {
release_buffer(last);
last = NULL;
}
......@@ -635,10 +688,10 @@ local_draw_rect(struct rectlist *rect)
/* TODO: Translate into local colour depth */
idx = 0;
for (y = 0; y < source->h; y++) {
for (x = 0; x < source->w; x++) {
for (y = 0; y < dh; y++) {
for (x = 0; x < dw; x++) {
if (last) {
if (last->data[idx] != source->data[idx]) {
if (last->data[idx] != source_data[idx]) {
if (x < cleft)
cleft = x;
if (x > cright)
......@@ -654,31 +707,31 @@ local_draw_rect(struct rectlist *rect)
}
}
if (VisualIsRGB8) {
pixel = source->data[idx];
pixel = source_data[idx];
((uint32_t*)xim->data)[idx] = pixel;
}
else {
if (last_pixel != source->data[idx]) {
last_pixel = source->data[idx];
r = source->data[idx] >> 16 & 0xff;
g = source->data[idx] >> 8 & 0xff;
b = source->data[idx] & 0xff;
if (last_pixel != source_data[idx]) {
last_pixel = source_data[idx];
r = source_data[idx] >> 16 & 0xff;
g = source_data[idx] >> 8 & 0xff;
b = source_data[idx] & 0xff;
r = (r<<8)|r;
g = (g<<8)|g;
b = (b<<8)|b;
pixel = base_pixel;
if (r_shift >= 0)
pixel |= (r << r_shift) & visual.red_mask;
pixel |= (r << r_shift) & visual->red_mask;
else
pixel |= (r >> (0-r_shift)) & visual.red_mask;
pixel |= (r >> (0-r_shift)) & visual->red_mask;
if (g_shift >= 0)
pixel |= (g << g_shift) & visual.green_mask;
pixel |= (g << g_shift) & visual->green_mask;
else
pixel |= (g >> (0-g_shift)) & visual.green_mask;
pixel |= (g >> (0-g_shift)) & visual->green_mask;
if (b_shift >= 0)
pixel |= (b << b_shift) & visual.blue_mask;
pixel |= (b << b_shift) & visual->blue_mask;
else
pixel |= (b >> (0-b_shift)) & visual.blue_mask;
pixel |= (b >> (0-b_shift)) & visual->blue_mask;
}
#ifdef XPutPixel
XPutPixel(xim, x, y, pixel);
......@@ -688,15 +741,17 @@ local_draw_rect(struct rectlist *rect)
}
idx++;
}
/* This line was changed */
// TODO: Previously this did one update per display line...
if (last && cright >= 0 && (cbottom != y || y == source->h - 1)) {
x11.XPutImage(dpy, win, gc, xim, cleft, ctop
, cleft + xoff, ctop + yoff
, (cright - cleft + 1), (cbottom - ctop + 1));
cleft = source->w;
cright = cbottom = -100;
ctop = source->h;
if (x_internal_scaling) {
/* This line was changed */
// TODO: Previously this did one update per display line...
if (last && cright >= 0 && (cbottom != y || y == source->h - 1)) {
x11.XPutImage(dpy, win, gc, xim, cleft, ctop
, cleft + xoff, ctop + yoff
, (cright - cleft + 1), (cbottom - ctop + 1));
cleft = source->w;
cright = cbottom = -100;
ctop = source->h;
}
}
}
......@@ -707,10 +762,25 @@ local_draw_rect(struct rectlist *rect)
x11.XFillRectangle(dpy, win, gc, xoff+xim->width, yoff, w, yoff + xim->height);
x11.XFillRectangle(dpy, win, gc, 0, yoff + xim->height, w, h);
}
if (last == NULL)
x11.XPutImage(dpy, win, gc, xim, 0, 0, xoff, yoff, source->w, source->h);
else
release_buffer(last);
if (x_internal_scaling || xrender_found == false) {
if (last == NULL)
x11.XPutImage(dpy, win, gc, xim, 0, 0, xoff, yoff, source->w, source->h);
else
release_buffer(last);
}
else {
#ifdef WITH_XRENDER
bitmap_drv_free_rect(rect);
if (last != NULL)
release_buffer(last);
x11.XPutImage(dpy, xrender_pm, gc, xim, 0, 0, 0, 0, dw, dh);
x11.XRenderComposite(dpy, PictOpSrc, xrender_src_pict, 0, xrender_dst_pict,
0, 0, 0, 0, 0, 0,
cleft, ctop);
#else
fprintf(stderr, "External scaling enabled without XRender support compiled in!\n");
#endif
}
last = source;
}
......@@ -1492,6 +1562,10 @@ void x11_event_thread(void *args)
x11.XFreeCursor(dpy, oc);
break;
}
case X11_LOCAL_SETSCALING_TYPE:
x_internal_scaling = (lev.data.st == CIOLIB_SCALING_INTERNAL);
resize_xim();
break;
}
}
}
......
......@@ -6,6 +6,9 @@
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
#ifdef WITH_XRENDER
#include <X11/extensions/Xrender.h>
#endif
enum x11_local_events {
X11_LOCAL_SETMODE
......@@ -18,17 +21,19 @@ enum x11_local_events {
,X11_LOCAL_BEEP
,X11_LOCAL_SETICON
,X11_LOCAL_MOUSEPOINTER
,X11_LOCAL_SETSCALING_TYPE
};
struct x11_local_event {
enum x11_local_events type;
union {
int mode;
char name[81];
char title[81];
struct rectlist *rect;
unsigned long *icon_data;
int mode;
char name[81];
char title[81];
struct rectlist *rect;
unsigned long *icon_data;
enum ciolib_mouse_ptr ptr;
enum ciolib_scaling st;
} data;
};
......@@ -97,6 +102,22 @@ struct x11 {
int (*XDefineCursor)(Display *display, Window w, Cursor cursor);
int (*XFreeCursor)(Display *display, Cursor cursor);
Status (*XGetGeometry)(Display *, Drawable, Window *, int *, int *, unsigned int *, unsigned int *, unsigned int *, unsigned int *);
#ifndef DefaultDepth
int (*DefaultDepth)(Display *, int);
#endif
#ifndef Defaultvisual
Visual *(*DefaultVisual)(Display *, int);
#endif
#ifdef WITH_XRENDER
XRenderPictFormat *(*XRenderFindStandardFormat)(Display *dpy, int format);
Picture (*XRenderCreatePicture)(Display *dpy, Drawable drawable, _Xconst XRenderPictFormat *format, unsigned long valuemask, _Xconst XRenderPictureAttributes *attributes);
void (*XRenderFreePicture)(Display *dpy, Picture picture);
void (*XRenderSetPictureTransform)(Display *dpy, Picture picture, XTransform *transform);
void (*XRenderComposite)(Display *dpy, int op, Picture src, Picture mask, Picture dst, int src_x, int src_y, int mask_x, int mask_y, int dst_x, int dst_y, unsigned int width, unsigned int height);
XRenderPictFormat *(*XRenderFindVisualFormat)(Display *dpy, _Xconst Visual *visual);
Status (*XRenderQueryVersion)(Display *, int *, int *);
void (*XRenderSetPictureFilter)(Display *, Picture, const char *, XFixed *, int);
#endif
Atom utf8;
Atom targets;
Atom workarea;
......@@ -122,6 +143,8 @@ extern int x11_window_xpos;
extern int x11_window_ypos;
extern int x11_initialized;
extern struct video_stats x_cvstat;
extern bool xrender_found;
extern bool x_internal_scaling;
void x11_event_thread(void *args);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment