Merge pull request #104 from yshui/fix-fbconfig

Fix fbconfig lookup
This commit is contained in:
yshui 2019-02-03 18:43:58 +00:00 committed by GitHub
commit 6a5ad609ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 281 additions and 514 deletions

View File

@ -4,7 +4,6 @@
#include <GL/gl.h>
#include <GL/glext.h>
#include "common.h"
#include "region.h"
#include "log.h"
@ -62,6 +61,8 @@ typedef struct {
int height;
} gl_blur_cache_t;
typedef struct session session_t;
#define GL_PROG_MAIN_INIT \
{ .prog = 0, .unifm_opacity = -1, .unifm_invert_color = -1, .unifm_tex = -1, }

View File

@ -10,6 +10,7 @@
*/
#include <GL/glx.h>
#include <X11/Xlib-xcb.h>
#include <assert.h>
#include <pixman.h>
#include <stdbool.h>
@ -20,6 +21,7 @@
#include "backend/backend.h"
#include "backend/gl/gl_common.h"
#include "backend/gl/glx.h"
#include "common.h"
#include "compiler.h"
#include "config.h"
@ -27,14 +29,7 @@
#include "region.h"
#include "utils.h"
#include "win.h"
/// @brief Wrapper of a GLX FBConfig.
typedef struct glx_fbconfig {
GLXFBConfig cfg;
GLint texture_fmt;
GLint texture_tgts;
bool y_inverted;
} glx_fbconfig_t;
#include "x.h"
struct _glx_win_data {
gl_texture_t texture;
@ -49,13 +44,117 @@ struct _glx_data {
gl_cap_t cap;
gl_win_shader_t win_shader;
gl_blur_shader_t blur_shader[MAX_BLUR_PASS];
glx_fbconfig_t *fbconfigs[OPENGL_MAX_DEPTH + 1];
void (*glXBindTexImage)(Display *display, GLXDrawable drawable, int buffer,
const int *attrib_list);
void (*glXReleaseTexImage)(Display *display, GLXDrawable drawable, int buffer);
};
struct glx_fbconfig_info *
glx_find_fbconfig(Display *dpy, int screen, xcb_render_pictforminfo_t *pictfmt, int depth) {
// Alright, this might not be right, but it might just be enough to just match
// visual against GLX_VISUAL_ID, and use the one that matches
assert(pictfmt);
if (pictfmt->type != XCB_RENDER_PICT_TYPE_DIRECT) {
log_error("compton cannot handle non-DirectColor visuals. Report an "
"issue if you see this error message.");
return NULL;
}
int red_size = popcountl(pictfmt->direct.red_mask),
blue_size = popcountl(pictfmt->direct.blue_mask),
green_size = popcountl(pictfmt->direct.green_mask),
alpha_size = popcountl(pictfmt->direct.alpha_mask);
log_debug("Looking for FBConfig for RGBA%d%d%d%d, depth %d", red_size, blue_size,
green_size, alpha_size, depth);
int ncfg;
// clang-format off
GLXFBConfig *cfg =
glXChooseFBConfig(dpy, screen, (int[]){
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
GLX_X_RENDERABLE, true,
GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, GLX_DONT_CARE,
GLX_BUFFER_SIZE, red_size + green_size + blue_size + alpha_size,
GLX_RED_SIZE, red_size,
GLX_BLUE_SIZE, blue_size,
GLX_GREEN_SIZE, green_size,
GLX_ALPHA_SIZE, alpha_size,
GLX_STENCIL_SIZE, 0,
GLX_DEPTH_SIZE, 0,
0
}, &ncfg);
// clang-format on
#define glXGetFBConfigAttribChecked(a, b, attr, c) \
do { \
if (glXGetFBConfigAttrib(a, b, attr, c)) { \
log_info("Cannot get FBConfig attribute " #attr); \
continue; \
} \
} while (0)
int texture_tgts, y_inverted, texture_fmt;
bool found = false;
GLXFBConfig ret;
for (int i = 0; i < ncfg; i++) {
int red, green, blue;
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_RED_SIZE, &red);
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_BLUE_SIZE, &blue);
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_GREEN_SIZE, &green);
if (red != red_size || green != green_size || blue != blue_size) {
// Color size doesn't match, this cannot work
continue;
}
int rgb, rgba;
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_BIND_TO_TEXTURE_RGB_EXT, &rgb);
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_BIND_TO_TEXTURE_RGBA_EXT, &rgba);
if (!rgb && !rgba) {
log_info("FBConfig is neither RGBA nor RGB, compton cannot "
"handle this setup.");
continue;
}
int visual;
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_VISUAL_ID, &visual);
if (depth != -1 && x_get_visual_depth(XGetXCBConnection(dpy), visual) != depth) {
// Some driver might attach fbconfig to a GLX visual with a
// different depth. (That totally makes sense. - NVIDIA
// developers)
continue;
}
// All check passed, we are using this one.
found = true;
ret = cfg[i];
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_BIND_TO_TEXTURE_TARGETS_EXT, &texture_tgts);
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_Y_INVERTED_EXT, &y_inverted);
// Prefer the texture format with matching alpha, with the other one as
// fallback
if (alpha_size) {
texture_fmt = rgba ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT;
} else {
texture_fmt = rgb ? GLX_TEXTURE_FORMAT_RGB_EXT : GLX_TEXTURE_FORMAT_RGBA_EXT;
}
break;
}
#undef glXGetFBConfigAttribChecked
free(cfg);
if (!found) {
return NULL;
}
auto info = cmalloc(struct glx_fbconfig_info);
info->cfg = ret;
info->texture_tgts = texture_tgts;
info->texture_fmt = texture_fmt;
info->y_inverted = y_inverted;
return info;
}
/**
* Check if a GLX extension exists.
*/
@ -120,199 +219,10 @@ static inline void free_win_res_glx(session_t *ps, win *w) {
/*free_glx_bc(ps, &w->glx_blur_cache);*/
}
static inline int glx_cmp_fbconfig_cmpattr(session_t *ps, const glx_fbconfig_t *pfbc_a,
const glx_fbconfig_t *pfbc_b, int attr) {
int attr_a = 0, attr_b = 0;
// TODO: Error checking
glXGetFBConfigAttrib(ps->dpy, pfbc_a->cfg, attr, &attr_a);
glXGetFBConfigAttrib(ps->dpy, pfbc_b->cfg, attr, &attr_b);
return attr_a - attr_b;
}
/**
* Compare two GLX FBConfig's to find the preferred one.
*/
static int
glx_cmp_fbconfig(session_t *ps, const glx_fbconfig_t *pfbc_a, const glx_fbconfig_t *pfbc_b) {
int result = 0;
if (!pfbc_a)
return -1;
if (!pfbc_b)
return 1;
int tmpattr;
// Avoid 10-bit colors
glXGetFBConfigAttrib(ps->dpy, pfbc_a->cfg, GLX_RED_SIZE, &tmpattr);
if (tmpattr != 8)
return -1;
glXGetFBConfigAttrib(ps->dpy, pfbc_b->cfg, GLX_RED_SIZE, &tmpattr);
if (tmpattr != 8)
return 1;
#define P_CMPATTR_LT(attr) \
{ \
if ((result = glx_cmp_fbconfig_cmpattr(ps, pfbc_a, pfbc_b, (attr)))) \
return -result; \
}
#define P_CMPATTR_GT(attr) \
{ \
if ((result = glx_cmp_fbconfig_cmpattr(ps, pfbc_a, pfbc_b, (attr)))) \
return result; \
}
P_CMPATTR_LT(GLX_BIND_TO_TEXTURE_RGBA_EXT);
P_CMPATTR_LT(GLX_DOUBLEBUFFER);
P_CMPATTR_LT(GLX_STENCIL_SIZE);
P_CMPATTR_LT(GLX_DEPTH_SIZE);
P_CMPATTR_GT(GLX_BIND_TO_MIPMAP_TEXTURE_EXT);
return 0;
}
/**
* @brief Update the FBConfig of given depth.
*/
static inline void glx_update_fbconfig_bydepth(session_t *ps, struct _glx_data *gd,
int depth, glx_fbconfig_t *pfbcfg) {
// Make sure the depth is sane
if (depth < 0 || depth > OPENGL_MAX_DEPTH)
return;
// Compare new FBConfig with current one
if (glx_cmp_fbconfig(ps, gd->fbconfigs[depth], pfbcfg) < 0) {
log_debug("(depth %d): %p overrides %p, target %#x.\n", depth, pfbcfg->cfg,
gd->fbconfigs[depth] ? gd->fbconfigs[depth]->cfg : 0, pfbcfg->texture_tgts);
if (!gd->fbconfigs[depth]) {
gd->fbconfigs[depth] = cmalloc(glx_fbconfig_t);
}
(*gd->fbconfigs[depth]) = *pfbcfg;
}
}
/**
* Get GLX FBConfigs for all depths.
*/
static bool glx_update_fbconfig(struct _glx_data *gd, session_t *ps) {
// Acquire all FBConfigs and loop through them
int nele = 0;
GLXFBConfig *pfbcfgs = glXGetFBConfigs(ps->dpy, ps->scr, &nele);
for (GLXFBConfig *pcur = pfbcfgs; pcur < pfbcfgs + nele; pcur++) {
glx_fbconfig_t fbinfo = {
.cfg = *pcur,
.texture_fmt = 0,
.texture_tgts = 0,
.y_inverted = false,
};
int id = (int)(pcur - pfbcfgs);
int depth = 0, depth_alpha = 0, val = 0;
// Skip over multi-sampled visuals
// http://people.freedesktop.org/~glisse/0001-glx-do-not-use-multisample-visual-config-for-front-o.patch
#ifdef GLX_SAMPLES
if (Success == glXGetFBConfigAttrib(ps->dpy, *pcur, GLX_SAMPLES, &val) && val > 1)
continue;
#endif
if (Success != glXGetFBConfigAttrib(ps->dpy, *pcur, GLX_BUFFER_SIZE, &depth) ||
Success != glXGetFBConfigAttrib(ps->dpy, *pcur, GLX_ALPHA_SIZE, &depth_alpha)) {
log_error("Failed to retrieve buffer size and alpha size of "
"FBConfig %d.",
id);
continue;
}
if (Success != glXGetFBConfigAttrib(ps->dpy, *pcur, GLX_BIND_TO_TEXTURE_TARGETS_EXT,
&fbinfo.texture_tgts)) {
log_error("Failed to retrieve BIND_TO_TEXTURE_TARGETS_EXT of "
"FBConfig %d.",
id);
continue;
}
int visualdepth = 0;
{
XVisualInfo *pvi = glXGetVisualFromFBConfig(ps->dpy, *pcur);
if (!pvi) {
// On nvidia-drivers-325.08 this happens slightly too often...
// log_error("Failed to retrieve X Visual of FBConfig %d.", id);
continue;
}
visualdepth = pvi->depth;
cxfree(pvi);
}
bool rgb = false;
bool rgba = false;
if (depth >= 32 && depth_alpha &&
Success == glXGetFBConfigAttrib(ps->dpy, *pcur, GLX_BIND_TO_TEXTURE_RGBA_EXT, &val) && val)
rgba = true;
if (Success == glXGetFBConfigAttrib(ps->dpy, *pcur, GLX_BIND_TO_TEXTURE_RGB_EXT, &val) && val)
rgb = true;
if (Success == glXGetFBConfigAttrib(ps->dpy, *pcur, GLX_Y_INVERTED_EXT, &val))
fbinfo.y_inverted = val;
{
int tgtdpt = depth - depth_alpha;
if (tgtdpt == visualdepth && tgtdpt < 32 && rgb) {
fbinfo.texture_fmt = GLX_TEXTURE_FORMAT_RGB_EXT;
glx_update_fbconfig_bydepth(ps, gd, tgtdpt, &fbinfo);
}
}
if (depth == visualdepth && rgba) {
fbinfo.texture_fmt = GLX_TEXTURE_FORMAT_RGBA_EXT;
glx_update_fbconfig_bydepth(ps, gd, depth, &fbinfo);
}
}
cxfree(pfbcfgs);
// Sanity checks
if (!gd->fbconfigs[ps->depth]) {
log_error("No FBConfig found for default depth %d.", ps->depth);
return false;
}
if (!gd->fbconfigs[32]) {
log_error("No FBConfig found for depth 32. compton may not work "
"correctly");
}
return true;
}
#ifdef DEBUG_GLX_DEBUG_CONTEXT
static inline GLXFBConfig get_fbconfig_from_visualinfo(session_t *ps, const XVisualInfo *visualinfo) {
int nelements = 0;
GLXFBConfig *fbconfigs = glXGetFBConfigs(ps->dpy, visualinfo->screen, &nelements);
for (int i = 0; i < nelements; ++i) {
int visual_id = 0;
if (Success == glXGetFBConfigAttrib(ps->dpy, fbconfigs[i], GLX_VISUAL_ID, &visual_id) &&
visual_id == visualinfo->visualid)
return fbconfigs[i];
}
return NULL;
}
static void glx_debug_msg_callback(GLenum source, GLenum type, GLuint id, GLenum severity,
GLsizei length, const GLchar *message, GLvoid *userParam) {
log_trace("(): source 0x%04X, type 0x%04X, id %u, severity 0x%0X, \"%s\"", source,
type, id, severity, message);
}
#endif
/**
* Destroy GLX related resources.
*/
void glx_deinit(void *backend_data, session_t *ps) {
static void glx_deinit(void *backend_data, session_t *ps) {
struct _glx_data *gd = backend_data;
// Free all GLX resources of windows
@ -328,12 +238,6 @@ void glx_deinit(void *backend_data, session_t *ps) {
gl_check_err();
// Free FBConfigs
for (int i = 0; i <= OPENGL_MAX_DEPTH; ++i) {
free(gd->fbconfigs[i]);
gd->fbconfigs[i] = NULL;
}
// Destroy GLX context
if (gd->ctx) {
glXDestroyContext(ps->dpy, gd->ctx);
@ -448,10 +352,6 @@ static void *glx_init(session_t *ps) {
goto end;
}
// Acquire FBConfigs
if (!glx_update_fbconfig(gd, ps))
goto end;
// Render preparations
gl_resize(ps->root_width, ps->root_height);
@ -490,7 +390,7 @@ end:
return gd;
}
void *glx_prepare_win(void *backend_data, session_t *ps, win *w) {
static void *glx_prepare_win(void *backend_data, session_t *ps, win *w) {
struct _glx_data *gd = backend_data;
// Retrieve pixmap parameters, if they aren't provided
if (w->g.depth > OPENGL_MAX_DEPTH) {
@ -499,36 +399,7 @@ void *glx_prepare_win(void *backend_data, session_t *ps, win *w) {
return false;
}
const glx_fbconfig_t *pcfg = gd->fbconfigs[w->g.depth];
if (!pcfg) {
log_error("Couldn't find FBConfig with requested depth %d", w->g.depth);
return false;
}
// Choose a suitable texture target for our pixmap.
// Refer to GLX_EXT_texture_om_pixmap spec to see what are the mean
// of the bits in texture_tgts
GLenum tex_tgt = 0;
if (GLX_TEXTURE_2D_BIT_EXT & pcfg->texture_tgts && gd->cap.non_power_of_two_texture)
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;
log_debug("depth %d, tgt %#x, rgba %d\n", w->g.depth, tex_tgt,
(GLX_TEXTURE_FORMAT_RGBA_EXT == pcfg->texture_fmt));
GLint attrs[] = {
GLX_TEXTURE_FORMAT_EXT, pcfg->texture_fmt, GLX_TEXTURE_TARGET_EXT, tex_tgt, 0,
};
auto wd = ccalloc(1, struct _glx_win_data);
wd->texture.target = (GLX_TEXTURE_2D_EXT == tex_tgt ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE);
wd->texture.y_inverted = pcfg->y_inverted;
if (ps->has_name_pixmap) {
wd->pixmap = xcb_generate_id(ps->c);
xcb_composite_name_window_pixmap(ps->c, w->id, wd->pixmap);
@ -540,7 +411,48 @@ void *glx_prepare_win(void *backend_data, session_t *ps, win *w) {
goto err;
}
wd->glpixmap = glXCreatePixmap(ps->dpy, pcfg->cfg, wd->pixmap, attrs);
auto pictfmt = x_get_pictform_for_visual(ps->c, w->a.visual);
if (!pictfmt) {
log_error("Window %#010x has invalid visual %#x", w->id, w->a.visual);
goto err;
}
int depth = x_get_visual_depth(ps->c, w->a.visual);
auto fbcfg = glx_find_fbconfig(ps->dpy, ps->scr, pictfmt, depth);
if (!fbcfg) {
log_error("Couldn't find FBConfig with requested visual %x", w->a.visual);
goto err;
}
// Choose a suitable texture target for our pixmap.
// Refer to GLX_EXT_texture_om_pixmap spec to see what are the mean
// of the bits in texture_tgts
GLenum tex_tgt = 0;
if (GLX_TEXTURE_2D_BIT_EXT & fbcfg->texture_tgts && gd->cap.non_power_of_two_texture)
tex_tgt = GLX_TEXTURE_2D_EXT;
else if (GLX_TEXTURE_RECTANGLE_BIT_EXT & fbcfg->texture_tgts)
tex_tgt = GLX_TEXTURE_RECTANGLE_EXT;
else if (!(GLX_TEXTURE_2D_BIT_EXT & fbcfg->texture_tgts))
tex_tgt = GLX_TEXTURE_RECTANGLE_EXT;
else
tex_tgt = GLX_TEXTURE_2D_EXT;
log_debug("depth %d, tgt %#x, rgba %d\n", w->g.depth, tex_tgt,
(GLX_TEXTURE_FORMAT_RGBA_EXT == fbcfg->texture_fmt));
GLint attrs[] = {
GLX_TEXTURE_FORMAT_EXT,
fbcfg->texture_fmt,
GLX_TEXTURE_TARGET_EXT,
tex_tgt,
0,
};
wd->texture.target = (GLX_TEXTURE_2D_EXT == tex_tgt ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE);
wd->texture.y_inverted = fbcfg->y_inverted;
wd->glpixmap = glXCreatePixmap(ps->dpy, fbcfg->cfg, wd->pixmap, attrs);
free(fbcfg);
if (!wd->glpixmap) {
log_error("Failed to create glpixmap for window %#010x", w->id);
goto err;
@ -581,7 +493,8 @@ err:
/**
* Bind a X pixmap to an OpenGL texture.
*/
void glx_render_win(void *backend_data, session_t *ps, win *w, void *win_data, const region_t *reg_paint) {
static void glx_render_win(void *backend_data, session_t *ps, win *w, void *win_data,
const region_t *reg_paint) {
struct _glx_data *gd = backend_data;
struct _glx_win_data *wd = win_data;

15
src/backend/gl/glx.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#include <GL/glx.h>
#include <X11/Xlib.h>
#include <xcb/render.h>
#include <xcb/xcb.h>
struct glx_fbconfig_info {
GLXFBConfig cfg;
int texture_tgts;
int texture_fmt;
int y_inverted;
};
struct glx_fbconfig_info *
glx_find_fbconfig(Display *, int screen, xcb_render_pictforminfo_t *, int depth);

View File

@ -2,13 +2,9 @@
srcs += [ files('backend_common.c') ]
if get_option('new_backends')
srcs += [ files('xrender.c', 'backend.c') ]
# enable opengl
if get_option('opengl')
srcs += [ files('gl/gl_common.c', 'gl/glx.c') ]
endif
endif
# enable opengl
if get_option('opengl')
srcs += [ files('gl/gl_common.c') ]
srcs += [ files('gl/gl_common.c', 'gl/glx.c') ]
endif

View File

@ -221,7 +221,6 @@ struct _glx_texture {
GLenum target;
unsigned width;
unsigned height;
unsigned depth;
bool y_inverted;
};
@ -310,8 +309,6 @@ typedef struct {
f_ImportSyncEXT glImportSyncEXT;
/// Current GLX Z value.
int z;
/// FBConfig-s for GLX pixmap of different depths.
glx_fbconfig_t *fbconfigs[OPENGL_MAX_DEPTH + 1];
#ifdef CONFIG_OPENGL
glx_blur_pass_t blur_passes[MAX_BLUR_PASS];
#endif

View File

@ -68,6 +68,9 @@ module backend {
module gl_common {
header "backend/gl/gl_common.h"
}
module glx {
header "backend/gl/glx.h"
}
}
module backend {
header "backend/backend.h"

View File

@ -25,173 +25,10 @@
#include "win.h"
#include "region.h"
#include "backend/gl/gl_common.h"
#include "backend/gl/glx.h"
#include "opengl.h"
static inline int
glx_cmp_fbconfig_cmpattr(session_t *ps,
const glx_fbconfig_t *pfbc_a, const glx_fbconfig_t *pfbc_b,
int attr) {
int attr_a = 0, attr_b = 0;
// TODO: Error checking
glXGetFBConfigAttrib(ps->dpy, pfbc_a->cfg, attr, &attr_a);
glXGetFBConfigAttrib(ps->dpy, pfbc_b->cfg, attr, &attr_b);
return attr_a - attr_b;
}
/**
* Compare two GLX FBConfig's to find the preferred one.
*/
static int
glx_cmp_fbconfig(session_t *ps,
const glx_fbconfig_t *pfbc_a, const glx_fbconfig_t *pfbc_b) {
int result = 0;
if (!pfbc_a)
return -1;
if (!pfbc_b)
return 1;
int tmpattr;
// Avoid 10-bit colors
glXGetFBConfigAttrib(ps->dpy, pfbc_a->cfg, GLX_RED_SIZE, &tmpattr);
if (tmpattr != 8)
return -1;
glXGetFBConfigAttrib(ps->dpy, pfbc_b->cfg, GLX_RED_SIZE, &tmpattr);
if (tmpattr != 8)
return 1;
#define P_CMPATTR_LT(attr) { if ((result = glx_cmp_fbconfig_cmpattr(ps, pfbc_a, pfbc_b, (attr)))) return -result; }
#define P_CMPATTR_GT(attr) { if ((result = glx_cmp_fbconfig_cmpattr(ps, pfbc_a, pfbc_b, (attr)))) return result; }
P_CMPATTR_LT(GLX_BIND_TO_TEXTURE_RGBA_EXT);
P_CMPATTR_LT(GLX_DOUBLEBUFFER);
P_CMPATTR_LT(GLX_STENCIL_SIZE);
P_CMPATTR_LT(GLX_DEPTH_SIZE);
P_CMPATTR_GT(GLX_BIND_TO_MIPMAP_TEXTURE_EXT);
return 0;
}
/**
* @brief Update the FBConfig of given depth.
*/
static inline void
glx_update_fbconfig_bydepth(session_t *ps, int depth, glx_fbconfig_t *pfbcfg) {
// Make sure the depth is sane
if (depth < 0 || depth > OPENGL_MAX_DEPTH)
return;
// Compare new FBConfig with current one
if (glx_cmp_fbconfig(ps, ps->psglx->fbconfigs[depth], pfbcfg) < 0) {
log_trace("(depth %d): %p overrides %p, target %#x.", depth,
pfbcfg->cfg,
ps->psglx->fbconfigs[depth] ? ps->psglx->fbconfigs[depth]->cfg:
0,
pfbcfg->texture_tgts);
if (!ps->psglx->fbconfigs[depth]) {
ps->psglx->fbconfigs[depth] = cmalloc(glx_fbconfig_t);
}
(*ps->psglx->fbconfigs[depth]) = *pfbcfg;
}
}
/**
* Get GLX FBConfigs for all depths.
*/
static bool
glx_update_fbconfig(session_t *ps) {
// Acquire all FBConfigs and loop through them
int nele = 0;
GLXFBConfig* pfbcfgs = glXGetFBConfigs(ps->dpy, ps->scr, &nele);
for (GLXFBConfig *pcur = pfbcfgs; pcur < pfbcfgs + nele; pcur++) {
glx_fbconfig_t fbinfo = {
.cfg = *pcur,
.texture_fmt = 0,
.texture_tgts = 0,
.y_inverted = false,
};
int id = (int) (pcur - pfbcfgs);
int depth = 0, depth_alpha = 0, val = 0;
// Skip over multi-sampled visuals
// http://people.freedesktop.org/~glisse/0001-glx-do-not-use-multisample-visual-config-for-front-o.patch
#ifdef GLX_SAMPLES
if (Success == glXGetFBConfigAttrib(ps->dpy, *pcur, GLX_SAMPLES, &val)
&& val > 1)
continue;
#endif
if (Success != glXGetFBConfigAttrib(ps->dpy, *pcur, GLX_BUFFER_SIZE, &depth)
|| Success != glXGetFBConfigAttrib(ps->dpy, *pcur, GLX_ALPHA_SIZE, &depth_alpha)) {
log_error("Failed to retrieve buffer size and alpha size of FBConfig %d.", id);
continue;
}
if (Success != glXGetFBConfigAttrib(ps->dpy, *pcur, GLX_BIND_TO_TEXTURE_TARGETS_EXT, &fbinfo.texture_tgts)) {
log_error("Failed to retrieve BIND_TO_TEXTURE_TARGETS_EXT of FBConfig %d.", id);
continue;
}
int visualdepth = 0;
{
XVisualInfo *pvi = glXGetVisualFromFBConfig(ps->dpy, *pcur);
if (!pvi) {
// On nvidia-drivers-325.08 this happens slightly too often...
// log_error("Failed to retrieve X Visual of FBConfig %d.", id);
continue;
}
visualdepth = pvi->depth;
cxfree(pvi);
}
bool rgb = false;
bool rgba = false;
if (depth >= 32 && depth_alpha && Success == glXGetFBConfigAttrib(ps->dpy, *pcur, GLX_BIND_TO_TEXTURE_RGBA_EXT, &val) && val)
rgba = true;
if (Success == glXGetFBConfigAttrib(ps->dpy, *pcur, GLX_BIND_TO_TEXTURE_RGB_EXT, &val) && val)
rgb = true;
if (Success == glXGetFBConfigAttrib(ps->dpy, *pcur, GLX_Y_INVERTED_EXT, &val))
fbinfo.y_inverted = val;
{
int tgtdpt = depth - depth_alpha;
if (tgtdpt == visualdepth && tgtdpt < 32 && rgb) {
fbinfo.texture_fmt = GLX_TEXTURE_FORMAT_RGB_EXT;
glx_update_fbconfig_bydepth(ps, tgtdpt, &fbinfo);
}
}
if (depth == visualdepth && rgba) {
fbinfo.texture_fmt = GLX_TEXTURE_FORMAT_RGBA_EXT;
glx_update_fbconfig_bydepth(ps, depth, &fbinfo);
}
}
cxfree(pfbcfgs);
// Sanity checks
if (!ps->psglx->fbconfigs[ps->depth]) {
log_error("No FBConfig found for default depth %d.", ps->depth);
return false;
}
if (!ps->psglx->fbconfigs[32]) {
log_error("No FBConfig found for depth 32. compton will try to continue.");
} else {
log_trace("%d-bit: %p, 32-bit: %p", ps->depth,
ps->psglx->fbconfigs[ps->depth]->cfg, ps->psglx->fbconfigs[32]->cfg);
}
return true;
}
static inline XVisualInfo *
get_visualinfo_from_visual(session_t *ps, xcb_visualid_t visual) {
XVisualInfo vreq = { .visualid = visual };
@ -200,31 +37,6 @@ get_visualinfo_from_visual(session_t *ps, xcb_visualid_t visual) {
return XGetVisualInfo(ps->dpy, VisualIDMask, &vreq, &nitems);
}
#ifdef DEBUG_GLX_DEBUG_CONTEXT
static inline GLXFBConfig
get_fbconfig_from_visualinfo(session_t *ps, const XVisualInfo *visualinfo) {
int nelements = 0;
GLXFBConfig *fbconfigs = glXGetFBConfigs(ps->dpy, visualinfo->screen,
&nelements);
for (int i = 0; i < nelements; ++i) {
int visual_id = 0;
if (Success == glXGetFBConfigAttrib(ps->dpy, fbconfigs[i], GLX_VISUAL_ID, &visual_id)
&& visual_id == visualinfo->visualid)
return fbconfigs[i];
}
return NULL;
}
static void
glx_debug_msg_callback(GLenum source, GLenum type,
GLuint id, GLenum severity, GLsizei length, const GLchar *message,
GLvoid *userParam) {
log_trace("source 0x%04X, type 0x%04X, id %u, severity 0x%0X, \"%s\"",
source, type, id, severity, message);
}
#endif
/**
* Initialize OpenGL.
*/
@ -375,10 +187,6 @@ glx_init(session_t *ps, bool need_render) {
}
}
// Acquire FBConfigs
if (need_render && !glx_update_fbconfig(ps))
goto glx_init_end;
// Render preparations
if (need_render) {
glx_on_root_change(ps);
@ -451,12 +259,6 @@ glx_destroy(session_t *ps) {
gl_check_err();
// Free FBConfigs
for (int i = 0; i <= OPENGL_MAX_DEPTH; ++i) {
free(ps->psglx->fbconfigs[i]);
ps->psglx->fbconfigs[i] = NULL;
}
// Destroy GLX context
if (ps->psglx->context) {
glXDestroyContext(ps->dpy, ps->psglx->context);
@ -694,7 +496,7 @@ glx_load_prog_main(session_t *ps,
*/
bool
glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
unsigned width, unsigned height, unsigned depth) {
unsigned width, unsigned height, const struct glx_fbconfig_info *fbcfg) {
if (ps->o.backend != BKEND_GLX && ps->o.backend != BKEND_XR_GLX_HYBRID)
return true;
@ -703,6 +505,7 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
return false;
}
assert(fbcfg);
glx_texture_t *ptex = *pptex;
bool need_release = true;
@ -715,7 +518,6 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
.target = 0,
.width = 0,
.height = 0,
.depth = 0,
.y_inverted = false,
};
@ -731,11 +533,12 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
}
// Create GLX pixmap
unsigned depth;
if (!ptex->glpixmap) {
need_release = false;
// Retrieve pixmap parameters, if they aren't provided
if (!(width && height && depth)) {
if (!(width && height)) {
Window rroot = None;
int rx = 0, ry = 0;
unsigned rbdwid = 0;
@ -751,45 +554,38 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
}
}
const glx_fbconfig_t *pcfg = ps->psglx->fbconfigs[depth];
if (!pcfg) {
log_error("Couldn't find FBConfig with requested depth %d.", depth);
return false;
}
// Determine texture target, copied from compiz
// The assumption we made here is the target never changes based on any
// pixmap-specific parameters, and this may change in the future
GLenum tex_tgt = 0;
if (GLX_TEXTURE_2D_BIT_EXT & pcfg->texture_tgts
if (GLX_TEXTURE_2D_BIT_EXT & fbcfg->texture_tgts
&& ps->psglx->has_texture_non_power_of_two)
tex_tgt = GLX_TEXTURE_2D_EXT;
else if (GLX_TEXTURE_RECTANGLE_BIT_EXT & pcfg->texture_tgts)
else if (GLX_TEXTURE_RECTANGLE_BIT_EXT & fbcfg->texture_tgts)
tex_tgt = GLX_TEXTURE_RECTANGLE_EXT;
else if (!(GLX_TEXTURE_2D_BIT_EXT & pcfg->texture_tgts))
else if (!(GLX_TEXTURE_2D_BIT_EXT & fbcfg->texture_tgts))
tex_tgt = GLX_TEXTURE_RECTANGLE_EXT;
else
tex_tgt = GLX_TEXTURE_2D_EXT;
log_debug("depth %d, tgt %#x, rgba %d", depth, tex_tgt,
(GLX_TEXTURE_FORMAT_RGBA_EXT == pcfg->texture_fmt));
(GLX_TEXTURE_FORMAT_RGBA_EXT == fbcfg->texture_fmt));
GLint attrs[] = {
GLX_TEXTURE_FORMAT_EXT,
pcfg->texture_fmt,
fbcfg->texture_fmt,
GLX_TEXTURE_TARGET_EXT,
tex_tgt,
0,
};
ptex->glpixmap = glXCreatePixmap(ps->dpy, pcfg->cfg, pixmap, attrs);
ptex->glpixmap = glXCreatePixmap(ps->dpy, fbcfg->cfg, pixmap, attrs);
ptex->pixmap = pixmap;
ptex->target = (GLX_TEXTURE_2D_EXT == tex_tgt ? GL_TEXTURE_2D:
GL_TEXTURE_RECTANGLE);
ptex->width = width;
ptex->height = height;
ptex->depth = depth;
ptex->y_inverted = pcfg->y_inverted;
ptex->y_inverted = fbcfg->y_inverted;
}
if (!ptex->glpixmap) {
log_error("Failed to allocate GLX pixmap.");
@ -1186,8 +982,6 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
return false;
}
argb = argb || (GLX_TEXTURE_FORMAT_RGBA_EXT ==
ps->psglx->fbconfigs[ptex->depth]->texture_fmt);
const bool has_prog = pprogram && pprogram->prog;
bool dual_texture = false;

View File

@ -19,20 +19,13 @@
#include "log.h"
#include <xcb/xcb.h>
#include <xcb/render.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <locale.h>
#include <GL/glx.h>
/// @brief Wrapper of a GLX FBConfig.
typedef struct glx_fbconfig {
GLXFBConfig cfg;
GLint texture_fmt;
GLint texture_tgts;
bool y_inverted;
} glx_fbconfig_t;
/**
* Check if a word is in string.
*/
@ -108,7 +101,7 @@ glx_load_prog_main(session_t *ps,
bool
glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
unsigned width, unsigned height, unsigned depth);
unsigned width, unsigned height, const struct glx_fbconfig_info *);
void
glx_release_pixmap(session_t *ps, glx_texture_t *ptex);
@ -249,5 +242,6 @@ free_win_res_glx(session_t *ps, win *w) {
free_paint_glx(ps, &w->shadow_paint);
#ifdef CONFIG_OPENGL
free_glx_bc(ps, &w->glx_blur_cache);
free(w->paint.fbcfg);
#endif
}

View File

@ -3,10 +3,10 @@
#include <stdlib.h>
#include <string.h>
#include <xcb/xcb_image.h>
#include <xcb/composite.h>
#include <xcb/sync.h>
#include <xcb/render.h>
#include <xcb/sync.h>
#include <xcb/xcb_image.h>
#include <xcb/xcb_renderutil.h>
#include "common.h"
@ -17,40 +17,78 @@
#include "opengl.h"
#endif
#include "vsync.h"
#include "win.h"
#include "kernel.h"
#include "compiler.h"
#include "x.h"
#include "config.h"
#include "region.h"
#include "kernel.h"
#include "log.h"
#include "region.h"
#include "types.h"
#include "utils.h"
#include "vsync.h"
#include "win.h"
#include "x.h"
#include "backend/backend_common.h"
#include "backend/gl/glx.h"
#include "render.h"
#ifdef CONFIG_OPENGL
/**
* Bind texture in paint_t if we are using GLX backend.
*/
static inline bool paint_bind_tex(session_t *ps, paint_t *ppaint, unsigned wid,
unsigned hei, unsigned depth, bool force) {
static inline bool paint_bind_tex(session_t *ps, paint_t *ppaint, unsigned wid, unsigned hei,
unsigned depth, xcb_visualid_t visual, bool force) {
#ifdef CONFIG_OPENGL
// XXX This is a mess. But this will go away after the backend refactor.
static thread_local struct glx_fbconfig_info *argb_fbconfig = NULL;
if (!ppaint->pixmap)
return false;
if (force || !glx_tex_binded(ppaint->ptex, ppaint->pixmap))
return glx_bind_pixmap(ps, &ppaint->ptex, ppaint->pixmap, wid, hei, depth);
struct glx_fbconfig_info *fbcfg;
if (!visual) {
assert(depth == 32);
if (!argb_fbconfig) {
xcb_render_pictforminfo_t tmp_pictfmt = {
.direct =
{
.red_mask = 255,
.blue_mask = 255,
.green_mask = 255,
.alpha_mask = 255,
},
.type = XCB_RENDER_PICT_TYPE_DIRECT};
argb_fbconfig = glx_find_fbconfig(ps->dpy, ps->scr, &tmp_pictfmt, 32);
}
if (!argb_fbconfig) {
log_error("Failed to find appropriate FBConfig for 32 bit depth");
return false;
}
fbcfg = argb_fbconfig;
} else {
xcb_render_pictforminfo_t *pictfmt = x_get_pictform_for_visual(ps->c, visual);
if (!depth) {
assert(visual);
depth = x_get_visual_depth(ps->c, visual);
}
return true;
}
#else
static inline bool paint_bind_tex(session_t *ps, paint_t *ppaint, unsigned wid,
unsigned hei, unsigned depth, bool force) {
return true;
}
if (!pictfmt) {
return false;
}
if (!ppaint->fbcfg) {
ppaint->fbcfg = glx_find_fbconfig(ps->dpy, ps->scr, pictfmt, depth);
}
if (!ppaint->fbcfg) {
log_error("Failed to find appropriate FBConfig for X pixmap");
return false;
}
fbcfg = ppaint->fbcfg;
}
if (force || !glx_tex_binded(ppaint->ptex, ppaint->pixmap))
return glx_bind_pixmap(ps, &ppaint->ptex, ppaint->pixmap, wid, hei, fbcfg);
#endif
return true;
}
/**
* Check if current backend uses XRender for rendering.
@ -219,7 +257,8 @@ void paint_one(session_t *ps, win *w, const region_t *reg_paint) {
// Let glx_bind_pixmap() determine pixmap size, because if the user
// is resizing windows, the width and height we get may not be up-to-date,
// causing the jittering issue M4he reported in #7.
if (!paint_bind_tex(ps, &w->paint, 0, 0, 0, (!ps->o.glx_no_rebind_pixmap && w->pixmap_damaged))) {
if (!paint_bind_tex(ps, &w->paint, 0, 0, 0, w->a.visual,
(!ps->o.glx_no_rebind_pixmap && w->pixmap_damaged))) {
log_error("Failed to bind texture for window %#010x.", w->id);
}
w->pixmap_damaged = false;
@ -445,8 +484,7 @@ static bool get_root_tile(session_t *ps) {
ps->root_tile_paint.pixmap = pixmap;
#ifdef CONFIG_OPENGL
if (BKEND_GLX == ps->o.backend)
return glx_bind_pixmap(ps, &ps->root_tile_paint.ptex,
ps->root_tile_paint.pixmap, 0, 0, 0);
return paint_bind_tex(ps, &ps->root_tile_paint, 0, 0, 0, ps->vis, false);
#endif
return true;
@ -484,7 +522,8 @@ static bool win_build_shadow(session_t *ps, win *w, double opacity) {
return XCB_NONE;
}
shadow_pixmap = x_create_pixmap(ps->c, 8, ps->root, shadow_image->width, shadow_image->height);
shadow_pixmap =
x_create_pixmap(ps->c, 8, ps->root, shadow_image->width, shadow_image->height);
shadow_pixmap_argb =
x_create_pixmap(ps->c, 32, ps->root, shadow_image->width, shadow_image->height);
@ -542,7 +581,7 @@ shadow_picture_err:
*/
static inline void win_paint_shadow(session_t *ps, win *w, region_t *reg_paint) {
// Bind shadow pixmap to GLX texture if needed
paint_bind_tex(ps, &w->shadow_paint, 0, 0, 32, false);
paint_bind_tex(ps, &w->shadow_paint, 0, 0, 32, 0, false);
if (!paint_isvalid(ps, &w->shadow_paint)) {
log_error("Window %#010x is missing shadow data.", w->id);
@ -942,12 +981,14 @@ void paint_all(session_t *ps, win *const t, bool ignore_damage) {
switch (ps->o.backend) {
case BKEND_XRENDER:
if (ps->o.monitor_repaint) {
// Copy the screen content to a new picture, and highlight
// the paint region. This is not very efficient, but since
// it's for debug only, we don't really care
// Copy the screen content to a new picture, and highlight the
// paint region. This is not very efficient, but since it's for
// debug only, we don't really care
// First we create a new picture, and copy content from the buffer to it
xcb_render_pictforminfo_t *pictfmt = x_get_pictform_for_visual(ps->c, ps->vis);
// First we create a new picture, and copy content from the buffer
// to it
xcb_render_pictforminfo_t *pictfmt =
x_get_pictform_for_visual(ps->c, ps->vis);
xcb_render_picture_t new_pict = x_create_picture_with_pictfmt(
ps, ps->root_width, ps->root_height, pictfmt, 0, NULL);
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC,
@ -983,7 +1024,7 @@ void paint_all(session_t *ps, win *const t, bool ignore_damage) {
glXWaitX();
assert(ps->tgt_buffer.pixmap);
paint_bind_tex(ps, &ps->tgt_buffer, ps->root_width, ps->root_height,
ps->depth, !ps->o.glx_no_rebind_pixmap);
ps->depth, ps->vis, !ps->o.glx_no_rebind_pixmap);
if (ps->o.vsync_use_glfinish)
glFinish();
else
@ -1200,14 +1241,15 @@ void deinit_render(session_t *ps) {
// Free other X resources
free_root_tile(ps);
// Free the damage ring
for (int i = 0; i < ps->ndamage; ++i)
pixman_region32_fini(&ps->damage_ring[i]);
ps->ndamage = 0;
free(ps->damage_ring);
ps->damage_ring = ps->damage = NULL;
// Free the damage ring
for (int i = 0; i < ps->ndamage; ++i)
pixman_region32_fini(&ps->damage_ring[i]);
ps->ndamage = 0;
free(ps->damage_ring);
ps->damage_ring = ps->damage = NULL;
#ifdef CONFIG_OPENGL
free(ps->root_tile_paint.fbcfg);
glx_destroy(ps);
#endif
}

View File

@ -5,6 +5,10 @@
#include <xcb/xcb.h>
#include <xcb/render.h>
#include <stdbool.h>
#ifdef CONFIG_OPENGL
#include <GL/glx.h>
#include "backend/gl/glx.h"
#endif
#include "region.h"
typedef struct _glx_texture glx_texture_t;
@ -16,6 +20,9 @@ typedef struct paint {
xcb_pixmap_t pixmap;
xcb_render_picture_t pict;
glx_texture_t *ptex;
#ifdef CONFIG_OPENGL
struct glx_fbconfig_info *fbcfg;
#endif
} paint_t;
void

View File

@ -73,6 +73,10 @@ static inline long attr_const min_l(long a, long b) {
return (a > b ? b : a);
}
static inline int attr_const popcountl(unsigned long a) {
return __builtin_popcountl(a);
}
/**
* Normalize a double value to a specific range.
*

View File

@ -94,6 +94,7 @@ xcb_window_t wid_get_prop_window(session_t *ps, xcb_window_t wid, xcb_atom_t apr
bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char ***pstrlst, int *pnstr);
xcb_render_pictforminfo_t *x_get_pictform_for_visual(xcb_connection_t *, xcb_visualid_t);
int x_get_visual_depth(xcb_connection_t *, xcb_visualid_t);
xcb_render_picture_t
x_create_picture_with_pictfmt_and_pixmap(xcb_connection_t *, xcb_render_pictforminfo_t *pictfmt,