refactored X11 code in 'render.c' and 'xwin.c'

This commit is contained in:
Jarcode
2018-02-11 09:38:23 -08:00
parent ae09561d11
commit 79b99b09be
7 changed files with 152 additions and 121 deletions

View File

@@ -43,7 +43,7 @@ ifeq ($(INSTALL),osx)
SHADER_DIR = Library/glava
endif
LDFLAGS = $(ASAN) -lpulse -lpulse-simple -pthread -lglfw -ldl -lm -lX11 -lXext
LDFLAGS = $(ASAN) -lpulse -lpulse-simple -pthread -lglfw -ldl -lm -lX11 -lXext -lXcomposite
PYTHON = python

View File

@@ -274,7 +274,7 @@ int main(int argc, char** argv) {
pthread_mutex_unlock(&audio.mutex);
/* Only render if needed (ie. stop rendering when fullscreen windows are focused) */
if (xwin_should_render()) {
if (xwin_should_render(r)) {
rd_update(r, lb, rb, r->bufsize_request, modified);
} else {
/* Sleep for 50ms and then attempt to render again */

View File

@@ -16,6 +16,18 @@
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#define GLFW_EXPOSE_NATIVE_X11
/* Hack to make GLFW 3.1 headers work with GLava. We don't use the context APIs from GLFW, but
the old headers require one of them to be selected for exposure in glfw3native.h. */
#if GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR <= 1
#define GLFW_EXPOSE_NATIVE_GLX
#endif
#include <GLFW/glfw3native.h>
/* Fixes for old GLFW versions */
#ifndef GLFW_TRUE
#define GLFW_TRUE GL_TRUE
@@ -98,6 +110,7 @@ struct overlay_data {
struct gl_data {
struct gl_sfbo* stages;
struct overlay_data overlay;
Display* display;
GLuint audio_tex_r, audio_tex_l, bg_tex, sm_prog;
size_t stages_sz, bufscale, avg_frames;
GLFWwindow* w;
@@ -117,6 +130,8 @@ struct gl_data {
int geometry[4];
};
/* load shader file */
static GLuint shaderload(const char* rpath,
GLenum type,
@@ -732,6 +747,8 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
if (!glfwInit())
abort();
gl->display = glfwGetX11Display();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_FLOATING, GLFW_FALSE);
@@ -1576,6 +1593,10 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
}
void* rd_get_impl_window(struct renderer* r) { return r->gl->w; }
Display* rd_get_x11_display(struct renderer* r) { return r->gl->display; }
Window rd_get_x11_window(struct renderer* r) { return glfwGetX11Window(r->gl->w); }
void rd_get_fbsize(struct renderer* r, int* w, int* h) { glfwGetFramebufferSize(r->gl->w, w, h); }
void rd_get_wpos(struct renderer* r, int* x, int* y) { glfwGetWindowPos(r->gl->w, x, y); }
void rd_destroy(struct renderer* r) {
/* TODO: delete everything else, not really needed though (as the application exits after here) */

View File

@@ -8,8 +8,16 @@ typedef struct renderer {
struct gl_data* gl;
} renderer;
struct renderer* rd_new(const char** paths, const char* entry, const char* force_mod);
void rd_update(struct renderer*, float* lb, float* rb, size_t bsz, bool modified);
void rd_destroy(struct renderer*);
void rd_time(struct renderer*);
struct renderer* rd_new (const char** paths, const char* entry,
const char* force_mod);
void rd_update (struct renderer*, float* lb, float* rb,
size_t bsz, bool modified);
void rd_destroy (struct renderer*);
void rd_time (struct renderer*);
void* rd_get_impl_window(struct renderer*);
void rd_get_fbsize (struct renderer*, int* w, int* h);
void rd_get_wpos (struct renderer*, int* x, int* y);
#ifdef GLAVA_RDX11
Display* rd_get_x11_display(struct renderer*);
Window rd_get_x11_window (struct renderer*);
#endif

View File

@@ -17,7 +17,7 @@
/* GLFW window hints */
#request setfloating false
#request setdecorated false
#request setdecorated true
#request setfocused false
#request setmaximized false

228
xwin.c
View File

@@ -12,30 +12,21 @@
#include <sys/shm.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/XShm.h>
#define GLFW_EXPOSE_NATIVE_X11
#include <glad/glad.h>
#include <GLFW/glfw3.h>
/* Hack to make GLFW 3.1 headers work with GLava. We don't use the context APIs from GLFW, but
the old headers require one of them to be selected for exposure in glfw3native.h. */
#if GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR <= 1
#define GLFW_EXPOSE_NATIVE_GLX
#endif
#include <GLFW/glfw3native.h>
#define GLAVA_RDX11
#include "render.h"
#include "xwin.h"
static Window find_desktop(void) {
static Window find_desktop(struct renderer* r) {
static Window desktop;
static bool searched = false;
if (!searched) {
Display* d = glfwGetX11Display();
Display* d = rd_get_x11_display(r);
desktop = DefaultRootWindow(d);
Window _ignored, * children;
unsigned int nret;
@@ -47,7 +38,8 @@ static Window find_desktop(void) {
if (name) {
/* Mutter-based window managers */
if (!strcmp(name, "mutter guard window")) {
desktop = children[t];
printf("Using mutter guard window instead of root window\n");
// desktop = children[t];
t = nret; /* break after */
}
XFree(name);
@@ -60,9 +52,9 @@ static Window find_desktop(void) {
return desktop;
}
bool xwin_should_render(void) {
bool xwin_should_render(struct renderer* rd) {
bool ret = true, should_close = false;
Display* d = glfwGetX11Display();
Display* d = rd_get_x11_display(rd);
if (!d) {
d = XOpenDisplay(0);
should_close = true;
@@ -107,8 +99,8 @@ bool xwin_should_render(void) {
/* Set window types defined by the EWMH standard, possible values:
-> "desktop", "dock", "toolbar", "menu", "utility", "splash", "dialog", "normal" */
static void xwin_changeatom(struct renderer* rd, const char* type, const char* atom, const char* fmt, int mode) {
Window w = glfwGetX11Window((GLFWwindow*) rd_get_impl_window(rd));
Display* d = glfwGetX11Display();
Window w = rd_get_x11_window(rd);
Display* d = rd_get_x11_display(rd);
Atom wtype = XInternAtom(d, atom, false);
size_t len = strlen(type), t;
char formatted[len + 1];
@@ -133,8 +125,8 @@ void xwin_addstate(struct renderer* rd, const char* state) {
xwin_changeatom(rd, state, "_NET_WM_STATE", "_NET_WM_STATE_%s", PropModeAppend);
}
static Pixmap get_pixmap(Display* d, Window w) {
Pixmap p;
static Drawable get_drawable(Display* d, Window w) {
Drawable p;
Atom act_type;
int act_format;
unsigned long nitems, bytes_after;
@@ -142,14 +134,14 @@ static Pixmap get_pixmap(Display* d, Window w) {
Atom id;
id = XInternAtom(d, "_XROOTPMAP_ID", False);
if (XGetWindowProperty(d, w, id, 0, 1, False, XA_PIXMAP,
&act_type, &act_format, &nitems, &bytes_after,
&data) == Success) {
if (data) {
p = *((Pixmap *) data);
XFree(data);
}
&data) == Success && data) {
p = *((Pixmap *) data);
XFree(data);
} else {
p = w;
}
return p;
@@ -163,113 +155,123 @@ unsigned int xwin_copyglbg(struct renderer* rd, unsigned int tex) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
GLFWwindow* gwin = (GLFWwindow*) rd_get_impl_window(rd);
bool use_shm = true;
int x, y, w, h;
glfwGetFramebufferSize(gwin, &w, &h);
glfwGetWindowPos(gwin, &x, &y);
rd_get_fbsize(rd, &w, &h);
rd_get_wpos(rd, &x, &y);
XColor c;
Display* d = glfwGetX11Display();
Pixmap p = get_pixmap(d, find_desktop());
Display* d = rd_get_x11_display(rd);
Drawable src = get_drawable(d, find_desktop(rd));
/* Obtain section of root pixmap using XShm */
/* Obtain section of root pixmap */
XShmSegmentInfo shminfo;
Visual* visual = DefaultVisual(d, DefaultScreen(d));
XVisualInfo match = { .visualid = XVisualIDFromVisual(visual) };
int nret;
XVisualInfo* info = XGetVisualInfo(d, VisualIDMask, &match, &nret);
XImage* image = XShmCreateImage(d, visual, info->depth, ZPixmap, NULL,
&shminfo, (unsigned int) w, (unsigned int) h);
if ((shminfo.shmid = shmget(IPC_PRIVATE, image->bytes_per_line * image->height,
IPC_CREAT | 0777)) == -1) {
fprintf(stderr, "shmget() failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
XImage* image;
if (use_shm) {
image = XShmCreateImage(d, visual, info->depth, ZPixmap, NULL,
&shminfo, (unsigned int) w, (unsigned int) h);
if ((shminfo.shmid = shmget(IPC_PRIVATE, image->bytes_per_line * image->height,
IPC_CREAT | 0777)) == -1) {
fprintf(stderr, "shmget() failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
shminfo.shmaddr = image->data = shmat(shminfo.shmid, 0, 0);
shminfo.readOnly = false;
XShmAttach(d, &shminfo);
XShmGetImage(d, src, image, x, y, AllPlanes);
} else {
image = XGetImage(d, src, x, y, (unsigned int) w, (unsigned int) h,
ZPixmap, AllPlanes);
}
shminfo.shmaddr = image->data = shmat(shminfo.shmid, 0, 0);
shminfo.readOnly = false;
XShmAttach(d, &shminfo);
XShmGetImage(d, p, image, x, y, AllPlanes);
/* Try to convert pixel bit depth to OpenGL storage format. The following formats\
will need intermediate conversion before OpenGL can accept the data:
- 8-bit pixel formats (retro displays, low-bandwidth virtual displays)
- 36-bit pixel formats (rare deep color displays) */
bool invalid = false, aligned = false;
GLenum type;
switch (image->bits_per_pixel) {
case 16:
switch (image->depth) {
case 12: type = GL_UNSIGNED_SHORT_4_4_4_4; break; /* 12-bit (rare) */
case 15: type = GL_UNSIGNED_SHORT_5_5_5_1; break; /* 15-bit, hi-color */
case 16: /* 16-bit, hi-color */
type = GL_UNSIGNED_SHORT_5_6_5;
aligned = true;
break;
}
break;
case 32:
switch (image->depth) {
case 24: type = GL_UNSIGNED_BYTE; break; /* 24-bit, true color */
case 30: type = GL_UNSIGNED_INT_10_10_10_2; break; /* 30-bit, deep color */
}
break;
case 64:
if (image->depth == 48) /* 48-bit deep color */
type = GL_UNSIGNED_SHORT;
else goto invalid;
break;
/* >64-bit formats */
case 128:
if (image->depth == 96)
type = GL_UNSIGNED_INT;
else goto invalid;
break;
default:
invalid: invalid = true;
}
uint8_t* buf;
if (invalid) {
abort();
/* Manual reformat (slow) */
buf = malloc(4 * w * h);
int xi, yi;
Colormap map = DefaultColormap(d, DefaultScreen(d));
for (yi = 0; yi < h; ++yi) {
for (xi = 0; xi < w; ++xi) {
c.pixel = XGetPixel(image, xi, yi);
XQueryColor(d, map, &c);
size_t base = (xi + (yi * w)) * 4;
buf[base + 0] = c.red / 256;
buf[base + 1] = c.green / 256;
buf[base + 2] = c.blue / 256;
buf[base + 3] = 255;
if (image) {
bool invalid = false, aligned = false;
GLenum type;
switch (image->bits_per_pixel) {
case 16:
switch (image->depth) {
case 12: type = GL_UNSIGNED_SHORT_4_4_4_4; break; /* 12-bit (rare) */
case 15: type = GL_UNSIGNED_SHORT_5_5_5_1; break; /* 15-bit, hi-color */
case 16: /* 16-bit, hi-color */
type = GL_UNSIGNED_SHORT_5_6_5;
aligned = true;
break;
}
break;
case 32:
switch (image->depth) {
case 24: type = GL_UNSIGNED_BYTE; break; /* 24-bit, true color */
case 30: type = GL_UNSIGNED_INT_10_10_10_2; break; /* 30-bit, deep color */
}
break;
case 64:
if (image->depth == 48) /* 48-bit deep color */
type = GL_UNSIGNED_SHORT;
else goto invalid;
break;
/* >64-bit formats */
case 128:
if (image->depth == 96)
type = GL_UNSIGNED_INT;
else goto invalid;
break;
default:
invalid: invalid = true;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
free(buf);
} else {
/* Use image data directly. The alpha value is garbage/unassigned data, but
we need to read it because X11 keeps pixel data aligned */
buf = (uint8_t*) image->data;
/* Data could be 2, 4, or 8 byte aligned, the RGBA format and type (depth)
already ensures reads will be properly aligned across scanlines */
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
GLenum format = image->bitmap_bit_order == LSBFirst ?
(!aligned ? GL_BGRA : GL_BGR) :
(!aligned ? GL_RGBA : GL_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, format, type, buf);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); /* restore default */
uint8_t* buf;
if (invalid) {
abort();
/* Manual reformat (slow) */
buf = malloc(4 * w * h);
int xi, yi;
Colormap map = DefaultColormap(d, DefaultScreen(d));
for (yi = 0; yi < h; ++yi) {
for (xi = 0; xi < w; ++xi) {
c.pixel = XGetPixel(image, xi, yi);
XQueryColor(d, map, &c);
size_t base = (xi + (yi * w)) * 4;
buf[base + 0] = c.red / 256;
buf[base + 1] = c.green / 256;
buf[base + 2] = c.blue / 256;
buf[base + 3] = 255;
}
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
free(buf);
} else {
/* Use image data directly. The alpha value is garbage/unassigned data, but
we need to read it because X11 keeps pixel data aligned */
buf = (uint8_t*) image->data;
/* Data could be 2, 4, or 8 byte aligned, the RGBA format and type (depth)
already ensures reads will be properly aligned across scanlines */
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
GLenum format = image->bitmap_bit_order == LSBFirst ?
(!aligned ? GL_BGRA : GL_BGR) :
(!aligned ? GL_RGBA : GL_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, format, type, buf);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); /* restore default */
}
}
if (use_shm) {
XShmDetach(d, &shminfo);
shmdt(shminfo.shmaddr);
shmctl(shminfo.shmid, IPC_RMID, NULL);
}
XShmDetach(d, &shminfo);
shmdt(shminfo.shmaddr);
shmctl(shminfo.shmid, IPC_RMID, NULL);
XDestroyImage(image);
if (image) XDestroyImage(image);
return texture;
}

2
xwin.h
View File

@@ -1,5 +1,5 @@
bool xwin_should_render(void);
bool xwin_should_render(struct renderer* rd);
void xwin_settype(struct renderer* rd, const char* type);
void xwin_addstate(struct renderer* rd, const char* state);
unsigned int xwin_copyglbg(struct renderer* rd, unsigned int texture);