Bug fix: GLX backend incompatibility with mesa & others
- Fix a bug that glx_bind_pixmap() doesn't work with mesa drivers. Thanks to Janhouse and mkraemer for reporting. (#7) - Use stencil buffer to attempt to eliminate potential double-paint issue in glx_render(). X Fixes doesn't guarantee the rectangles in a region do not overlap, and this may cause some regions to be painted twice, which would be a problem if we are painting transparent things. Now the target window must have a stencil buffer. Compiz uses its own region implementation to deal with this, but as a lightweight compositor we can't really do the same. It may have a positive or negative effort over performance. Callgrind result indicates basically no change in performance, but this may or may not be true. - Correctly distinguish GL extensions and GLX extensions. Sorry. :-D - Handle screen size. Thanks to tsmithe for reporting. (#7) - Rename OpenGL backend to GLX backend, because, we might have a EGL backend someday. - Add configuration file option `backend` to specify backend. Add `backend` to D-Bus `opts_get`. - Add OpenGL shader compilation code, but currently unused. - Minor adjustments. - Known issue: Window content doesn't get updated in VirtualBox, probably because its OpenGL implementation requires constant rebinding of texture. But that's really slow... - Known issue: Blur feature is still unimplemented in GLX backend.
This commit is contained in:
parent
8ffcf1c1e8
commit
66be1f2fe1
3
Makefile
3
Makefile
|
@ -48,6 +48,9 @@ ifeq "$(NO_VSYNC_OPENGL)" ""
|
|||
# -lGL must precede some other libraries, or it segfaults on FreeBSD (#74)
|
||||
LIBS := -lGL $(LIBS)
|
||||
OBJS += opengl.o
|
||||
# ifeq "$(NO_VSYNC_OPENGL_GLSL)" ""
|
||||
# CFG += -DCONFIG_VSYNC_OPENGL_GLSL
|
||||
# endif
|
||||
endif
|
||||
|
||||
# ==== D-Bus ====
|
||||
|
|
|
@ -34,6 +34,7 @@ fade-out-step = 0.03;
|
|||
# no-fading-openclose = true;
|
||||
|
||||
# Other
|
||||
backend = "xrender"
|
||||
mark-wmwin-focused = true;
|
||||
mark-ovredir-focused = true;
|
||||
use-ewmh-active-win = false;
|
||||
|
|
28
src/common.h
28
src/common.h
|
@ -89,6 +89,10 @@
|
|||
|
||||
// libGL
|
||||
#ifdef CONFIG_VSYNC_OPENGL
|
||||
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#endif
|
||||
|
||||
#include <GL/glx.h>
|
||||
#endif
|
||||
|
||||
|
@ -263,6 +267,7 @@ typedef enum {
|
|||
enum backend {
|
||||
BKEND_XRENDER,
|
||||
BKEND_GLX,
|
||||
NUM_BKEND,
|
||||
};
|
||||
|
||||
typedef struct _glx_texture glx_texture_t;
|
||||
|
@ -594,6 +599,8 @@ typedef struct {
|
|||
// === OpenGL related ===
|
||||
/// GLX context.
|
||||
GLXContext glx_context;
|
||||
/// Whether we have GL_ARB_texture_non_power_of_two.
|
||||
bool glx_has_texture_non_power_of_two;
|
||||
/// Pointer to glXGetVideoSyncSGI function.
|
||||
f_GetVideoSync glXGetVideoSyncSGI;
|
||||
/// Pointer to glXWaitVideoSyncSGI function.
|
||||
|
@ -874,6 +881,7 @@ typedef enum {
|
|||
|
||||
extern const char * const WINTYPES[NUM_WINTYPES];
|
||||
extern const char * const VSYNC_STRS[NUM_VSYNC];
|
||||
extern const char * const BACKEND_STRS[NUM_BKEND];
|
||||
extern session_t *ps_g;
|
||||
|
||||
// == Debugging code ==
|
||||
|
@ -1252,6 +1260,20 @@ parse_vsync(session_t *ps, const char *str) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a backend option argument.
|
||||
*/
|
||||
static inline bool
|
||||
parse_backend(session_t *ps, const char *str) {
|
||||
for (enum backend i = 0; i < (sizeof(BACKEND_STRS) / sizeof(BACKEND_STRS[0])); ++i)
|
||||
if (!strcasecmp(str, BACKEND_STRS[i])) {
|
||||
ps->o.backend = i;
|
||||
return true;
|
||||
}
|
||||
printf_errf("(\"%s\"): Invalid backend argument.", str);
|
||||
return false;
|
||||
}
|
||||
|
||||
timeout_t *
|
||||
timeout_insert(session_t *ps, time_ms_t interval,
|
||||
bool (*callback)(session_t *ps, timeout_t *ptmout), void *data);
|
||||
|
@ -1542,6 +1564,9 @@ glx_destroy(session_t *ps);
|
|||
void
|
||||
glx_on_root_change(session_t *ps);
|
||||
|
||||
bool
|
||||
glx_init_blur(session_t *ps);
|
||||
|
||||
bool
|
||||
glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
|
||||
int width, int height, int depth);
|
||||
|
@ -1554,6 +1579,9 @@ glx_tex_binded(const glx_texture_t *ptex) {
|
|||
return ptex && ptex->glpixmap && ptex->texture;
|
||||
}
|
||||
|
||||
void
|
||||
glx_set_clip(session_t *ps, XserverRegion reg);
|
||||
|
||||
bool
|
||||
glx_render(session_t *ps, const glx_texture_t *ptex,
|
||||
int x, int y, int dx, int dy, int width, int height, int z,
|
||||
|
|
|
@ -40,6 +40,12 @@ const char * const VSYNC_STRS[NUM_VSYNC] = {
|
|||
"opengl-swc", // VSYNC_OPENGL_SWC
|
||||
};
|
||||
|
||||
/// Names of backends.
|
||||
const char * const BACKEND_STRS[NUM_BKEND] = {
|
||||
"xrender", // BKEND_XRENDER
|
||||
"glx", // BKEND_GLX
|
||||
};
|
||||
|
||||
/// Function pointers to init VSync modes.
|
||||
static bool (* const (VSYNC_FUNCS_INIT[NUM_VSYNC]))(session_t *ps) = {
|
||||
[VSYNC_DRM ] = vsync_drm_init,
|
||||
|
@ -1628,8 +1634,7 @@ paint_all(session_t *ps, XserverRegion region, win *t) {
|
|||
reg_paint = region;
|
||||
}
|
||||
|
||||
XFixesSetPictureClipRegion(ps->dpy, ps->tgt_buffer, 0, 0, reg_paint);
|
||||
|
||||
set_tgt_clip(ps, reg_paint);
|
||||
paint_root(ps, reg_paint);
|
||||
|
||||
// Create temporary regions for use during painting
|
||||
|
@ -1666,8 +1671,7 @@ paint_all(session_t *ps, XserverRegion region, win *t) {
|
|||
|
||||
// Detect if the region is empty before painting
|
||||
if (region == reg_paint || !is_region_empty(ps, reg_paint)) {
|
||||
XFixesSetPictureClipRegion(ps->dpy, ps->tgt_buffer, 0, 0,
|
||||
reg_paint);
|
||||
set_tgt_clip(ps, reg_paint);
|
||||
|
||||
win_paint_shadow(ps, w, reg_paint);
|
||||
}
|
||||
|
@ -1694,7 +1698,7 @@ paint_all(session_t *ps, XserverRegion region, win *t) {
|
|||
}
|
||||
|
||||
if (!is_region_empty(ps, reg_paint)) {
|
||||
XFixesSetPictureClipRegion(ps->dpy, ps->tgt_buffer, 0, 0, reg_paint);
|
||||
set_tgt_clip(ps, reg_paint);
|
||||
// Blur window background
|
||||
if ((ps->o.blur_background && WMODE_SOLID != w->mode)
|
||||
|| (ps->o.blur_background_frame && w->frame_opacity)) {
|
||||
|
@ -1713,7 +1717,7 @@ paint_all(session_t *ps, XserverRegion region, win *t) {
|
|||
|
||||
// Do this as early as possible
|
||||
if (!ps->o.dbe)
|
||||
XFixesSetPictureClipRegion(ps->dpy, ps->tgt_buffer, 0, 0, None);
|
||||
set_tgt_clip(ps, None);
|
||||
|
||||
if (ps->o.vsync) {
|
||||
// Make sure all previous requests are processed to achieve best
|
||||
|
@ -4044,7 +4048,7 @@ usage(void) {
|
|||
" opengl-oml = Try to VSync with OML_sync_control OpenGL extension.\n"
|
||||
" Only work on some drivers. Experimental." WARNING"\n"
|
||||
" opengl-swc = Try to VSync with SGI_swap_control OpenGL extension.\n"
|
||||
" Only work on some drivers. Works only with OpenGL backend.\n"
|
||||
" Only work on some drivers. Works only with GLX backend.\n"
|
||||
" Does not actually control paint timing, only buffer swap is\n"
|
||||
" affected, so it doesn't have the effect of --sw-opti unlike\n"
|
||||
" other methods. Experimental." WARNING "\n"
|
||||
|
@ -4098,8 +4102,8 @@ usage(void) {
|
|||
"--invert-color-include condition\n"
|
||||
" Specify a list of conditions of windows that should be painted with\n"
|
||||
" inverted color. Resource-hogging, and is not well tested.\n"
|
||||
"--opengl\n"
|
||||
" Enable the highly experimental OpenGL backend." WARNING "\n"
|
||||
"--backend backend\n"
|
||||
" Choose backend. Possible choices are xrender and glx" WARNING ".\n"
|
||||
#undef WARNING
|
||||
#ifndef CONFIG_DBUS
|
||||
#define WARNING WARNING_DISABLED
|
||||
|
@ -4450,6 +4454,9 @@ parse_config(session_t *ps, struct options_tmp *pcfgtmp) {
|
|||
// --vsync
|
||||
if (config_lookup_string(&cfg, "vsync", &sval) && !parse_vsync(ps, sval))
|
||||
exit(1);
|
||||
// --backend
|
||||
if (config_lookup_string(&cfg, "backend", &sval) && !parse_backend(ps, sval))
|
||||
exit(1);
|
||||
// --alpha-step
|
||||
config_lookup_float(&cfg, "alpha-step", &ps->o.alpha_step);
|
||||
// --dbe
|
||||
|
@ -4552,6 +4559,7 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
|
|||
{ "logpath", required_argument, NULL, 287 },
|
||||
{ "invert-color-include", required_argument, NULL, 288 },
|
||||
{ "opengl", no_argument, NULL, 289 },
|
||||
{ "backend", required_argument, NULL, 290 },
|
||||
// Must terminate with a NULL entry
|
||||
{ NULL, 0, NULL, 0 },
|
||||
};
|
||||
|
@ -4809,6 +4817,11 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
|
|||
// --opengl
|
||||
ps->o.backend = BKEND_GLX;
|
||||
break;
|
||||
case 290:
|
||||
// --backend
|
||||
if (!parse_backend(ps, optarg))
|
||||
exit(1);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
|
@ -5115,7 +5128,7 @@ vsync_opengl_swc_init(session_t *ps) {
|
|||
|
||||
if (BKEND_GLX != ps->o.backend) {
|
||||
printf_errf("(): I'm afraid glXSwapIntervalSGI wouldn't help if you are "
|
||||
"not using OpenGL backend. You could try, nonetheless.");
|
||||
"not using GLX backend. You could try, nonetheless.");
|
||||
}
|
||||
|
||||
// Get video sync functions
|
||||
|
@ -5283,11 +5296,13 @@ init_filters(session_t *ps) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
#ifdef CONFIG_VSYNC_OPENGL
|
||||
case BKEND_GLX:
|
||||
{
|
||||
printf_errf("(): OpenGL blur is not implemented yet.");
|
||||
return false;
|
||||
if (!glx_init_blur(ps))
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5709,6 +5724,7 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
|||
|
||||
#ifdef CONFIG_VSYNC_OPENGL
|
||||
.glx_context = None,
|
||||
.glx_has_texture_non_power_of_two = false,
|
||||
.glXGetVideoSyncSGI = NULL,
|
||||
.glXWaitVideoSyncSGI = NULL,
|
||||
.glXGetSyncValuesOML = NULL,
|
||||
|
@ -5862,6 +5878,14 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
|||
ps->o.dbe = false;
|
||||
}
|
||||
|
||||
// Start listening to events on root earlier to catch all possible
|
||||
// root geometry changes
|
||||
XSelectInput(ps->dpy, ps->root,
|
||||
SubstructureNotifyMask
|
||||
| ExposureMask
|
||||
| StructureNotifyMask
|
||||
| PropertyChangeMask);
|
||||
|
||||
ps->root_width = DisplayWidth(ps->dpy, ps->scr);
|
||||
ps->root_height = DisplayHeight(ps->dpy, ps->scr);
|
||||
|
||||
|
@ -5874,7 +5898,7 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
|||
|
||||
// Initialize DBE
|
||||
if (ps->o.dbe && BKEND_GLX == ps->o.backend) {
|
||||
printf_errf("(): DBE couldn't be used on OpenGL backend.");
|
||||
printf_errf("(): DBE couldn't be used on GLX backend.");
|
||||
ps->o.dbe = false;
|
||||
}
|
||||
|
||||
|
@ -5887,7 +5911,7 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
|||
if (!glx_init(ps, true))
|
||||
exit(1);
|
||||
#else
|
||||
printf_errfq(1, "(): OpenGL backend support not compiled in.");
|
||||
printf_errfq(1, "(): GLX backend support not compiled in.");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -5926,6 +5950,7 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
|||
}
|
||||
}
|
||||
|
||||
// Initialize filters, must be preceded by OpenGL context creation
|
||||
if (!init_filters(ps))
|
||||
exit(1);
|
||||
|
||||
|
@ -5947,12 +5972,6 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
|||
|
||||
redir_start(ps);
|
||||
|
||||
XSelectInput(ps->dpy, ps->root,
|
||||
SubstructureNotifyMask
|
||||
| ExposureMask
|
||||
| StructureNotifyMask
|
||||
| PropertyChangeMask);
|
||||
|
||||
{
|
||||
Window root_return, parent_return;
|
||||
Window *children;
|
||||
|
|
|
@ -176,7 +176,7 @@ paint_isvalid(session_t *ps, const paint_t *ppaint) {
|
|||
return true;
|
||||
}
|
||||
/**
|
||||
* Bind texture in paint_t if we are using OpenGL backend.
|
||||
* Bind texture in paint_t if we are using GLX backend.
|
||||
*/
|
||||
static inline bool
|
||||
paint_bind_tex(session_t *ps, paint_t *ppaint, int wid, int hei, int depth) {
|
||||
|
@ -542,6 +542,20 @@ win_render(session_t *ps, win *w, int x, int y, int wid, int hei, double opacity
|
|||
pict, (w ? w->paint.ptex: ps->root_tile_paint.ptex), reg_paint);
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_tgt_clip(session_t *ps, XserverRegion reg) {
|
||||
switch (ps->o.backend) {
|
||||
case BKEND_XRENDER:
|
||||
XFixesSetPictureClipRegion(ps->dpy, ps->tgt_buffer, 0, 0, reg);
|
||||
break;
|
||||
#ifdef CONFIG_VSYNC_OPENGL
|
||||
case BKEND_GLX:
|
||||
glx_set_clip(ps, reg);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
paint_all(session_t *ps, XserverRegion region, win *t);
|
||||
|
||||
|
|
|
@ -876,6 +876,11 @@ cdbus_process_opts_get(session_t *ps, DBusMessage *msg) {
|
|||
cdbus_reply_string(ps, msg, VSYNC_STRS[ps->o.vsync]);
|
||||
return true;
|
||||
}
|
||||
if (!strcmp("backend", target)) {
|
||||
assert(ps->o.backend < sizeof(BACKEND_STRS) / sizeof(BACKEND_STRS[0]));
|
||||
cdbus_reply_string(ps, msg, BACKEND_STRS[ps->o.backend]);
|
||||
return true;
|
||||
}
|
||||
cdbus_m_opts_get_do(dbe, cdbus_reply_bool);
|
||||
cdbus_m_opts_get_do(vsync_aggressive, cdbus_reply_bool);
|
||||
|
||||
|
|
232
src/opengl.c
232
src/opengl.c
|
@ -51,7 +51,7 @@ glx_init(session_t *ps, bool need_render) {
|
|||
}
|
||||
|
||||
// Ensure GLX_EXT_texture_from_pixmap exists
|
||||
if (need_render && !glx_hasext(ps, "GLX_EXT_texture_from_pixmap"))
|
||||
if (need_render && !glx_hasglxext(ps, "GLX_EXT_texture_from_pixmap"))
|
||||
goto glx_init_end;
|
||||
|
||||
// Get GLX context
|
||||
|
@ -68,6 +68,24 @@ glx_init(session_t *ps, bool need_render) {
|
|||
goto glx_init_end;
|
||||
}
|
||||
|
||||
// Ensure we have a stencil buffer. X Fixes does not guarantee rectangles
|
||||
// in regions don't overlap, so we must use stencil buffer to make sure
|
||||
// we don't paint a region for more than one time, I think?
|
||||
if (need_render) {
|
||||
GLint val = 0;
|
||||
glGetIntegerv(GL_STENCIL_BITS, &val);
|
||||
if (!val) {
|
||||
printf_errf("(): Target window doesn't have stencil buffer.");
|
||||
goto glx_init_end;
|
||||
}
|
||||
}
|
||||
|
||||
// Check GL_ARB_texture_non_power_of_two, requires a GLX context and
|
||||
// must precede FBConfig fetching
|
||||
if (need_render)
|
||||
ps->glx_has_texture_non_power_of_two = glx_hasglext(ps,
|
||||
"GL_ARB_texture_non_power_of_two");
|
||||
|
||||
// Acquire function addresses
|
||||
if (need_render) {
|
||||
ps->glXBindTexImageProc = (f_BindTexImageEXT)
|
||||
|
@ -85,24 +103,23 @@ glx_init(session_t *ps, bool need_render) {
|
|||
goto glx_init_end;
|
||||
|
||||
if (need_render) {
|
||||
// Adjust viewport
|
||||
glViewport(0, 0, ps->root_width, ps->root_height);
|
||||
glx_on_root_change(ps);
|
||||
|
||||
// Initialize settings, copied from dcompmgr
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, ps->root_width, ps->root_height, 0, -100.0, 100.0);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
// glEnable(GL_DEPTH_TEST);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
// Initialize stencil buffer
|
||||
glClear(GL_STENCIL_BUFFER_BIT);
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
glStencilMask(0x1);
|
||||
glStencilFunc(GL_EQUAL, 0x1, 0x1);
|
||||
|
||||
// Clear screen
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glXSwapBuffers(ps->dpy, get_tgt_window(ps));
|
||||
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
// glXSwapBuffers(ps->dpy, get_tgt_window(ps));
|
||||
}
|
||||
|
||||
success = true;
|
||||
|
@ -141,6 +158,34 @@ glx_destroy(session_t *ps) {
|
|||
void
|
||||
glx_on_root_change(session_t *ps) {
|
||||
glViewport(0, 0, ps->root_width, ps->root_height);
|
||||
|
||||
// Initialize matrix, copied from dcompmgr
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, ps->root_width, ps->root_height, 0, -100.0, 100.0);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize GLX blur filter.
|
||||
*/
|
||||
bool
|
||||
glx_init_blur(session_t *ps) {
|
||||
printf_errf("(): Blur on GLX backend isn't implemented yet, sorry.");
|
||||
return false;
|
||||
|
||||
// #ifdef CONFIG_VSYNC_OPENGL_GLSL
|
||||
// static const char *FRAG_SHADER_BLUR = "";
|
||||
// GLuint frag_shader = glx_create_shader(GL_FRAGMENT_SHADER, FRAG_SHADER_BLUR);
|
||||
// if (!frag_shader) {
|
||||
// printf_errf("(): Failed to create fragment shader for blurring.");
|
||||
// return false;
|
||||
// }
|
||||
// #else
|
||||
// printf_errf("(): GLSL support not compiled in. Cannot do blur with GLX backend.");
|
||||
// return false;
|
||||
// #endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -346,15 +391,28 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
|
|||
if (!ptex->glpixmap) {
|
||||
need_release = false;
|
||||
|
||||
// Determine texture target, copied from compiz
|
||||
GLint tex_tgt = 0;
|
||||
if (GLX_TEXTURE_2D_BIT_EXT & pcfg->texture_tgts
|
||||
&& ps->glx_has_texture_non_power_of_two)
|
||||
tex_tgt = GLX_TEXTURE_2D_EXT;
|
||||
else if (GLX_TEXTURE_RECTANGLE_BIT_EXT & pcfg->texture_tgts)
|
||||
tex_tgt = GLX_TEXTURE_RECTANGLE_EXT;
|
||||
else if (!(GLX_TEXTURE_2D_BIT_EXT & pcfg->texture_tgts))
|
||||
tex_tgt = GLX_TEXTURE_RECTANGLE_EXT;
|
||||
else
|
||||
tex_tgt = GLX_TEXTURE_2D_EXT;
|
||||
|
||||
#ifdef DEBUG_GLX
|
||||
printf_dbgf("(): depth %d rgba %d\n", depth, (GLX_TEXTURE_FORMAT_RGBA_EXT == pcfg->texture_fmt));
|
||||
printf_dbgf("(): depth %d, tgt %#x, rgba %d\n", depth, tex_tgt,
|
||||
(GLX_TEXTURE_FORMAT_RGBA_EXT == pcfg->texture_fmt));
|
||||
#endif
|
||||
|
||||
int attrs[] = {
|
||||
GLint attrs[] = {
|
||||
GLX_TEXTURE_FORMAT_EXT,
|
||||
pcfg->texture_fmt,
|
||||
// GLX_TEXTURE_TARGET_EXT,
|
||||
// ,
|
||||
GLX_TEXTURE_TARGET_EXT,
|
||||
tex_tgt,
|
||||
0,
|
||||
};
|
||||
|
||||
|
@ -403,6 +461,51 @@ glx_release_pixmap(session_t *ps, glx_texture_t *ptex) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set clipping region on the target window.
|
||||
*/
|
||||
void
|
||||
glx_set_clip(session_t *ps, XserverRegion reg) {
|
||||
glClear(GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
if (reg) {
|
||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
||||
glDepthMask(GL_FALSE);
|
||||
glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
|
||||
|
||||
int nrects = 0;
|
||||
XRectangle *rects = XFixesFetchRegion(ps->dpy, reg, &nrects);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
|
||||
for (int i = 0; i < nrects; ++i) {
|
||||
GLint rx = rects[i].x;
|
||||
GLint ry = rects[i].y;
|
||||
GLint rxe = rx + rects[i].width;
|
||||
GLint rye = ry + rects[i].height;
|
||||
GLint z = 0;
|
||||
|
||||
#ifdef DEBUG_GLX
|
||||
printf_dbgf("(): Rect %d: %f, %f, %f, %f\n", i, rx, ry, rxe, rye);
|
||||
#endif
|
||||
|
||||
glVertex3i(rx, ry, z);
|
||||
glVertex3i(rxe, ry, z);
|
||||
glVertex3i(rxe, rye, z);
|
||||
glVertex3i(rx, rye, z);
|
||||
}
|
||||
|
||||
glEnd();
|
||||
|
||||
if (rects)
|
||||
XFree(rects);
|
||||
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Render a region with texture data.
|
||||
*/
|
||||
|
@ -440,11 +543,6 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
|
|||
}
|
||||
}
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, ptex->texture);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
|
||||
{
|
||||
XserverRegion reg_new = None;
|
||||
|
||||
|
@ -459,9 +557,10 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
|
|||
int nrects = 1;
|
||||
|
||||
#ifdef DEBUG_GLX
|
||||
printf_dbgf("(): Draw: %d, %d, %d, %d -> %d, %d (%d, %d) z %d \n", x, y, width, height, dx, dy, ptex->width, ptex->height, z);
|
||||
printf_dbgf("(): Draw: %d, %d, %d, %d -> %d, %d (%d, %d) z %d\n", x, y, width, height, dx, dy, ptex->width, ptex->height, z);
|
||||
#endif
|
||||
|
||||
/*
|
||||
if (reg_tgt) {
|
||||
reg_new = XFixesCreateRegion(ps->dpy, &rec_all, 1);
|
||||
XFixesIntersectRegion(ps->dpy, reg_new, reg_new, reg_tgt);
|
||||
|
@ -469,6 +568,12 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
|
|||
nrects = 0;
|
||||
rects = XFixesFetchRegion(ps->dpy, reg_new, &nrects);
|
||||
}
|
||||
*/
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, ptex->texture);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
|
||||
for (int i = 0; i < nrects; ++i) {
|
||||
GLfloat rx = (double) (rects[i].x - dx + x) / ptex->width;
|
||||
|
@ -504,11 +609,12 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
|
|||
glVertex3i(rdx, rdye, z);
|
||||
}
|
||||
|
||||
glEnd();
|
||||
|
||||
if (rects && rects != &rec_all)
|
||||
XFree(rects);
|
||||
free_region(ps, ®_new);
|
||||
}
|
||||
glEnd();
|
||||
|
||||
// Cleanup
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
@ -519,3 +625,85 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
||||
GLuint
|
||||
glx_create_shader(GLenum shader_type, const char *shader_str) {
|
||||
bool success = false;
|
||||
GLuint shader = glCreateShader(shader_type);
|
||||
if (!shader) {
|
||||
printf_errf("(): Failed to create shader with type %d.", shader_type);
|
||||
goto glx_create_shader_end;
|
||||
}
|
||||
glShaderSource(shader, 1, &shader_str, NULL);
|
||||
glCompileShader(shader);
|
||||
|
||||
// Get shader status
|
||||
{
|
||||
GLint status = GL_FALSE;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
||||
if (GL_FALSE == status) {
|
||||
GLint log_len = 0;
|
||||
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_len);
|
||||
if (log_len) {
|
||||
char log[log_len + 1];
|
||||
glGetShaderInfoLog(shader, log_len, NULL, log);
|
||||
printf_errf("(): Failed to compile shader with type %d: %s",
|
||||
shader_type, log);
|
||||
}
|
||||
goto glx_create_shader_end;
|
||||
}
|
||||
}
|
||||
|
||||
success = true;
|
||||
|
||||
glx_create_shader_end:
|
||||
if (shader && !success) {
|
||||
glDeleteShader(shader);
|
||||
shader = 0;
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
GLuint
|
||||
glx_create_program(GLenum shader_type, const GLuint * const shaders,
|
||||
int nshaders) {
|
||||
bool success = false;
|
||||
GLuint program = glCreateProgram();
|
||||
if (!program) {
|
||||
printf_errf("(): Failed to create program.");
|
||||
goto glx_create_program_end;
|
||||
}
|
||||
|
||||
for (int i = 0; i < nshaders; ++i)
|
||||
glAttachShader(program, shaders[i]);
|
||||
glLinkProgram(program);
|
||||
|
||||
// Get program status
|
||||
{
|
||||
GLint status = GL_FALSE;
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
||||
if (GL_FALSE == status) {
|
||||
GLint log_len = 0;
|
||||
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_len);
|
||||
if (log_len) {
|
||||
char log[log_len + 1];
|
||||
glGetProgramInfoLog(program, log_len, NULL, log);
|
||||
printf_errf("(): Failed to link program: %s", log);
|
||||
}
|
||||
goto glx_create_program_end;
|
||||
}
|
||||
}
|
||||
success = true;
|
||||
|
||||
glx_create_program_end:
|
||||
if (program && !success) {
|
||||
glDeleteProgram(program);
|
||||
program = 0;
|
||||
}
|
||||
|
||||
return program;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
56
src/opengl.h
56
src/opengl.h
|
@ -12,22 +12,62 @@
|
|||
|
||||
#include <ctype.h>
|
||||
|
||||
/**
|
||||
* Check if a word is in string.
|
||||
*/
|
||||
static inline bool
|
||||
wd_is_in_str(const char *haystick, const char *needle) {
|
||||
if (!haystick)
|
||||
return false;
|
||||
|
||||
assert(*needle);
|
||||
|
||||
const char *pos = haystick - 1;
|
||||
while ((pos = strstr(pos + 1, needle))) {
|
||||
// Continue if it isn't a word boundary
|
||||
if (((pos - haystick) && !isspace(*(pos - 1)))
|
||||
|| (strlen(pos) > strlen(needle) && !isspace(pos[strlen(needle)])))
|
||||
continue;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a GLX extension exists.
|
||||
*/
|
||||
static inline bool
|
||||
glx_hasext(session_t *ps, const char *ext) {
|
||||
glx_hasglxext(session_t *ps, const char *ext) {
|
||||
const char *glx_exts = glXQueryExtensionsString(ps->dpy, ps->scr);
|
||||
const char *pos = strstr(glx_exts, ext);
|
||||
// Make sure the extension string is matched as a whole word
|
||||
if (!pos
|
||||
|| ((pos - glx_exts) && !isspace(*(pos - 1)))
|
||||
|| (strlen(pos) > strlen(ext) && !isspace(pos[strlen(ext)]))) {
|
||||
printf_errf("(): Missing OpenGL extension %s.", ext);
|
||||
if (!glx_exts) {
|
||||
printf_errf("(): Failed get GLX extension list.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
bool found = wd_is_in_str(glx_exts, ext);
|
||||
if (!found)
|
||||
printf_errf("(): Missing GLX extension %s.", ext);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a GLX extension exists.
|
||||
*/
|
||||
static inline bool
|
||||
glx_hasglext(session_t *ps, const char *ext) {
|
||||
const char *gl_exts = (const char *) glGetString(GL_EXTENSIONS);
|
||||
if (!gl_exts) {
|
||||
printf_errf("(): Failed get GL extension list.");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool found = wd_is_in_str(gl_exts, ext);
|
||||
if (!found)
|
||||
printf_errf("(): Missing GL extension %s.", ext);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static inline XVisualInfo *
|
||||
|
|
Loading…
Reference in New Issue