Refactor FBConfig lookup
Background: To bind a Xorg window content to a OpenGL FBConfig, which has to match the color format the Xorg window is using. Previously, compton just find a FBConfig that has the same depth. This led to chjj/compton#477, which has been fixed by a ugly hack. The commit refactor the lookup mechanism to take as much into consideration as we reasonably can. Hopefully preventing similar breakages in the future. Also, some code sharing between the old and new glx backend. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
7ac351e5b5
commit
8922312e42
|
@ -4,7 +4,6 @@
|
||||||
#include <GL/gl.h>
|
#include <GL/gl.h>
|
||||||
#include <GL/glext.h>
|
#include <GL/glext.h>
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
|
@ -62,6 +61,8 @@ typedef struct {
|
||||||
int height;
|
int height;
|
||||||
} gl_blur_cache_t;
|
} gl_blur_cache_t;
|
||||||
|
|
||||||
|
typedef struct session session_t;
|
||||||
|
|
||||||
#define GL_PROG_MAIN_INIT \
|
#define GL_PROG_MAIN_INIT \
|
||||||
{ .prog = 0, .unifm_opacity = -1, .unifm_invert_color = -1, .unifm_tex = -1, }
|
{ .prog = 0, .unifm_opacity = -1, .unifm_invert_color = -1, .unifm_tex = -1, }
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <GL/glx.h>
|
#include <GL/glx.h>
|
||||||
|
#include <X11/Xlib-xcb.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <pixman.h>
|
#include <pixman.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
@ -20,6 +21,7 @@
|
||||||
|
|
||||||
#include "backend/backend.h"
|
#include "backend/backend.h"
|
||||||
#include "backend/gl/gl_common.h"
|
#include "backend/gl/gl_common.h"
|
||||||
|
#include "backend/gl/glx.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
@ -27,14 +29,7 @@
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
|
#include "x.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;
|
|
||||||
|
|
||||||
struct _glx_win_data {
|
struct _glx_win_data {
|
||||||
gl_texture_t texture;
|
gl_texture_t texture;
|
||||||
|
@ -49,13 +44,117 @@ struct _glx_data {
|
||||||
gl_cap_t cap;
|
gl_cap_t cap;
|
||||||
gl_win_shader_t win_shader;
|
gl_win_shader_t win_shader;
|
||||||
gl_blur_shader_t blur_shader[MAX_BLUR_PASS];
|
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,
|
void (*glXBindTexImage)(Display *display, GLXDrawable drawable, int buffer,
|
||||||
const int *attrib_list);
|
const int *attrib_list);
|
||||||
void (*glXReleaseTexImage)(Display *display, GLXDrawable drawable, int buffer);
|
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.
|
* 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);*/
|
/*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.
|
* 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;
|
struct _glx_data *gd = backend_data;
|
||||||
|
|
||||||
// Free all GLX resources of windows
|
// Free all GLX resources of windows
|
||||||
|
@ -328,12 +238,6 @@ void glx_deinit(void *backend_data, session_t *ps) {
|
||||||
|
|
||||||
gl_check_err();
|
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
|
// Destroy GLX context
|
||||||
if (gd->ctx) {
|
if (gd->ctx) {
|
||||||
glXDestroyContext(ps->dpy, gd->ctx);
|
glXDestroyContext(ps->dpy, gd->ctx);
|
||||||
|
@ -448,10 +352,6 @@ static void *glx_init(session_t *ps) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Acquire FBConfigs
|
|
||||||
if (!glx_update_fbconfig(gd, ps))
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
// Render preparations
|
// Render preparations
|
||||||
gl_resize(ps->root_width, ps->root_height);
|
gl_resize(ps->root_width, ps->root_height);
|
||||||
|
|
||||||
|
@ -490,7 +390,7 @@ end:
|
||||||
return gd;
|
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;
|
struct _glx_data *gd = backend_data;
|
||||||
// Retrieve pixmap parameters, if they aren't provided
|
// Retrieve pixmap parameters, if they aren't provided
|
||||||
if (w->g.depth > OPENGL_MAX_DEPTH) {
|
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;
|
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);
|
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) {
|
if (ps->has_name_pixmap) {
|
||||||
wd->pixmap = xcb_generate_id(ps->c);
|
wd->pixmap = xcb_generate_id(ps->c);
|
||||||
xcb_composite_name_window_pixmap(ps->c, w->id, wd->pixmap);
|
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;
|
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) {
|
if (!wd->glpixmap) {
|
||||||
log_error("Failed to create glpixmap for window %#010x", w->id);
|
log_error("Failed to create glpixmap for window %#010x", w->id);
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -581,7 +493,8 @@ err:
|
||||||
/**
|
/**
|
||||||
* Bind a X pixmap to an OpenGL texture.
|
* 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_data *gd = backend_data;
|
||||||
struct _glx_win_data *wd = win_data;
|
struct _glx_win_data *wd = win_data;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
@ -2,13 +2,9 @@
|
||||||
srcs += [ files('backend_common.c') ]
|
srcs += [ files('backend_common.c') ]
|
||||||
if get_option('new_backends')
|
if get_option('new_backends')
|
||||||
srcs += [ files('xrender.c', 'backend.c') ]
|
srcs += [ files('xrender.c', 'backend.c') ]
|
||||||
|
|
||||||
# enable opengl
|
|
||||||
if get_option('opengl')
|
|
||||||
srcs += [ files('gl/gl_common.c', 'gl/glx.c') ]
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# enable opengl
|
||||||
if get_option('opengl')
|
if get_option('opengl')
|
||||||
srcs += [ files('gl/gl_common.c') ]
|
srcs += [ files('gl/gl_common.c', 'gl/glx.c') ]
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -221,7 +221,6 @@ struct _glx_texture {
|
||||||
GLenum target;
|
GLenum target;
|
||||||
unsigned width;
|
unsigned width;
|
||||||
unsigned height;
|
unsigned height;
|
||||||
unsigned depth;
|
|
||||||
bool y_inverted;
|
bool y_inverted;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -310,8 +309,6 @@ typedef struct {
|
||||||
f_ImportSyncEXT glImportSyncEXT;
|
f_ImportSyncEXT glImportSyncEXT;
|
||||||
/// Current GLX Z value.
|
/// Current GLX Z value.
|
||||||
int z;
|
int z;
|
||||||
/// FBConfig-s for GLX pixmap of different depths.
|
|
||||||
glx_fbconfig_t *fbconfigs[OPENGL_MAX_DEPTH + 1];
|
|
||||||
#ifdef CONFIG_OPENGL
|
#ifdef CONFIG_OPENGL
|
||||||
glx_blur_pass_t blur_passes[MAX_BLUR_PASS];
|
glx_blur_pass_t blur_passes[MAX_BLUR_PASS];
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -68,6 +68,9 @@ module backend {
|
||||||
module gl_common {
|
module gl_common {
|
||||||
header "backend/gl/gl_common.h"
|
header "backend/gl/gl_common.h"
|
||||||
}
|
}
|
||||||
|
module glx {
|
||||||
|
header "backend/gl/glx.h"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
module backend {
|
module backend {
|
||||||
header "backend/backend.h"
|
header "backend/backend.h"
|
||||||
|
|
230
src/opengl.c
230
src/opengl.c
|
@ -25,173 +25,10 @@
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
#include "backend/gl/gl_common.h"
|
#include "backend/gl/gl_common.h"
|
||||||
|
#include "backend/gl/glx.h"
|
||||||
|
|
||||||
#include "opengl.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 *
|
static inline XVisualInfo *
|
||||||
get_visualinfo_from_visual(session_t *ps, xcb_visualid_t visual) {
|
get_visualinfo_from_visual(session_t *ps, xcb_visualid_t visual) {
|
||||||
XVisualInfo vreq = { .visualid = 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);
|
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.
|
* 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
|
// Render preparations
|
||||||
if (need_render) {
|
if (need_render) {
|
||||||
glx_on_root_change(ps);
|
glx_on_root_change(ps);
|
||||||
|
@ -451,12 +259,6 @@ glx_destroy(session_t *ps) {
|
||||||
|
|
||||||
gl_check_err();
|
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
|
// Destroy GLX context
|
||||||
if (ps->psglx->context) {
|
if (ps->psglx->context) {
|
||||||
glXDestroyContext(ps->dpy, ps->psglx->context);
|
glXDestroyContext(ps->dpy, ps->psglx->context);
|
||||||
|
@ -694,7 +496,7 @@ glx_load_prog_main(session_t *ps,
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
|
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)
|
if (ps->o.backend != BKEND_GLX && ps->o.backend != BKEND_XR_GLX_HYBRID)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -703,6 +505,7 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(fbcfg);
|
||||||
glx_texture_t *ptex = *pptex;
|
glx_texture_t *ptex = *pptex;
|
||||||
bool need_release = true;
|
bool need_release = true;
|
||||||
|
|
||||||
|
@ -715,7 +518,6 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
|
||||||
.target = 0,
|
.target = 0,
|
||||||
.width = 0,
|
.width = 0,
|
||||||
.height = 0,
|
.height = 0,
|
||||||
.depth = 0,
|
|
||||||
.y_inverted = false,
|
.y_inverted = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -731,11 +533,12 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create GLX pixmap
|
// Create GLX pixmap
|
||||||
|
unsigned depth;
|
||||||
if (!ptex->glpixmap) {
|
if (!ptex->glpixmap) {
|
||||||
need_release = false;
|
need_release = false;
|
||||||
|
|
||||||
// Retrieve pixmap parameters, if they aren't provided
|
// Retrieve pixmap parameters, if they aren't provided
|
||||||
if (!(width && height && depth)) {
|
if (!(width && height)) {
|
||||||
Window rroot = None;
|
Window rroot = None;
|
||||||
int rx = 0, ry = 0;
|
int rx = 0, ry = 0;
|
||||||
unsigned rbdwid = 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
|
// Determine texture target, copied from compiz
|
||||||
// The assumption we made here is the target never changes based on any
|
// The assumption we made here is the target never changes based on any
|
||||||
// pixmap-specific parameters, and this may change in the future
|
// pixmap-specific parameters, and this may change in the future
|
||||||
GLenum tex_tgt = 0;
|
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)
|
&& ps->psglx->has_texture_non_power_of_two)
|
||||||
tex_tgt = GLX_TEXTURE_2D_EXT;
|
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;
|
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;
|
tex_tgt = GLX_TEXTURE_RECTANGLE_EXT;
|
||||||
else
|
else
|
||||||
tex_tgt = GLX_TEXTURE_2D_EXT;
|
tex_tgt = GLX_TEXTURE_2D_EXT;
|
||||||
|
|
||||||
log_debug("depth %d, tgt %#x, rgba %d", depth, tex_tgt,
|
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[] = {
|
GLint attrs[] = {
|
||||||
GLX_TEXTURE_FORMAT_EXT,
|
GLX_TEXTURE_FORMAT_EXT,
|
||||||
pcfg->texture_fmt,
|
fbcfg->texture_fmt,
|
||||||
GLX_TEXTURE_TARGET_EXT,
|
GLX_TEXTURE_TARGET_EXT,
|
||||||
tex_tgt,
|
tex_tgt,
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
|
||||||
ptex->glpixmap = glXCreatePixmap(ps->dpy, pcfg->cfg, pixmap, attrs);
|
ptex->glpixmap = glXCreatePixmap(ps->dpy, fbcfg->cfg, pixmap, attrs);
|
||||||
ptex->pixmap = pixmap;
|
ptex->pixmap = pixmap;
|
||||||
ptex->target = (GLX_TEXTURE_2D_EXT == tex_tgt ? GL_TEXTURE_2D:
|
ptex->target = (GLX_TEXTURE_2D_EXT == tex_tgt ? GL_TEXTURE_2D:
|
||||||
GL_TEXTURE_RECTANGLE);
|
GL_TEXTURE_RECTANGLE);
|
||||||
ptex->width = width;
|
ptex->width = width;
|
||||||
ptex->height = height;
|
ptex->height = height;
|
||||||
ptex->depth = depth;
|
ptex->y_inverted = fbcfg->y_inverted;
|
||||||
ptex->y_inverted = pcfg->y_inverted;
|
|
||||||
}
|
}
|
||||||
if (!ptex->glpixmap) {
|
if (!ptex->glpixmap) {
|
||||||
log_error("Failed to allocate GLX pixmap.");
|
log_error("Failed to allocate GLX pixmap.");
|
||||||
|
@ -1186,8 +982,6 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
argb = argb || (GLX_TEXTURE_FORMAT_RGBA_EXT ==
|
|
||||||
ps->psglx->fbconfigs[ptex->depth]->texture_fmt);
|
|
||||||
const bool has_prog = pprogram && pprogram->prog;
|
const bool has_prog = pprogram && pprogram->prog;
|
||||||
bool dual_texture = false;
|
bool dual_texture = false;
|
||||||
|
|
||||||
|
|
12
src/opengl.h
12
src/opengl.h
|
@ -19,20 +19,13 @@
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
|
#include <xcb/render.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <GL/glx.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.
|
* Check if a word is in string.
|
||||||
*/
|
*/
|
||||||
|
@ -108,7 +101,7 @@ glx_load_prog_main(session_t *ps,
|
||||||
|
|
||||||
bool
|
bool
|
||||||
glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
|
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
|
void
|
||||||
glx_release_pixmap(session_t *ps, glx_texture_t *ptex);
|
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);
|
free_paint_glx(ps, &w->shadow_paint);
|
||||||
#ifdef CONFIG_OPENGL
|
#ifdef CONFIG_OPENGL
|
||||||
free_glx_bc(ps, &w->glx_blur_cache);
|
free_glx_bc(ps, &w->glx_blur_cache);
|
||||||
|
free(w->paint.fbcfg);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
104
src/render.c
104
src/render.c
|
@ -3,10 +3,10 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <xcb/xcb_image.h>
|
|
||||||
#include <xcb/composite.h>
|
#include <xcb/composite.h>
|
||||||
#include <xcb/sync.h>
|
|
||||||
#include <xcb/render.h>
|
#include <xcb/render.h>
|
||||||
|
#include <xcb/sync.h>
|
||||||
|
#include <xcb/xcb_image.h>
|
||||||
#include <xcb/xcb_renderutil.h>
|
#include <xcb/xcb_renderutil.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
@ -17,40 +17,69 @@
|
||||||
#include "opengl.h"
|
#include "opengl.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "vsync.h"
|
|
||||||
#include "win.h"
|
|
||||||
#include "kernel.h"
|
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
#include "x.h"
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "region.h"
|
#include "kernel.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "region.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "vsync.h"
|
||||||
|
#include "win.h"
|
||||||
|
#include "x.h"
|
||||||
|
|
||||||
#include "backend/backend_common.h"
|
#include "backend/backend_common.h"
|
||||||
|
#include "backend/gl/glx.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
|
|
||||||
#ifdef CONFIG_OPENGL
|
|
||||||
/**
|
/**
|
||||||
* Bind texture in paint_t if we are using GLX backend.
|
* 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,
|
static inline bool paint_bind_tex(session_t *ps, paint_t *ppaint, unsigned wid, unsigned hei,
|
||||||
unsigned hei, unsigned depth, bool force) {
|
unsigned depth, xcb_visualid_t visual, bool force) {
|
||||||
|
#ifdef CONFIG_OPENGL
|
||||||
if (!ppaint->pixmap)
|
if (!ppaint->pixmap)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (force || !glx_tex_binded(ppaint->ptex, ppaint->pixmap))
|
xcb_render_pictforminfo_t *pictfmt = NULL;
|
||||||
return glx_bind_pixmap(ps, &ppaint->ptex, ppaint->pixmap, wid, hei, depth);
|
xcb_render_pictforminfo_t tmp_pictfmt = {.direct =
|
||||||
|
{
|
||||||
|
.red_mask = 255,
|
||||||
|
.blue_mask = 255,
|
||||||
|
.green_mask = 255,
|
||||||
|
.alpha_mask = depth == 32 ? 255 : 0,
|
||||||
|
},
|
||||||
|
.type = XCB_RENDER_PICT_TYPE_DIRECT};
|
||||||
|
|
||||||
return true;
|
if (!depth) {
|
||||||
}
|
assert(visual);
|
||||||
#else
|
depth = x_get_visual_depth(ps->c, visual);
|
||||||
static inline bool paint_bind_tex(session_t *ps, paint_t *ppaint, unsigned wid,
|
}
|
||||||
unsigned hei, unsigned depth, bool force) {
|
|
||||||
return true;
|
if (!visual) {
|
||||||
}
|
assert(depth);
|
||||||
|
pictfmt = &tmp_pictfmt;
|
||||||
|
} else {
|
||||||
|
pictfmt = x_get_pictform_for_visual(ps->c, visual);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (force || !glx_tex_binded(ppaint->ptex, ppaint->pixmap))
|
||||||
|
return glx_bind_pixmap(ps, &ppaint->ptex, ppaint->pixmap, wid, hei, ppaint->fbcfg);
|
||||||
#endif
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if current backend uses XRender for rendering.
|
* Check if current backend uses XRender for rendering.
|
||||||
|
@ -219,7 +248,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
|
// 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,
|
// is resizing windows, the width and height we get may not be up-to-date,
|
||||||
// causing the jittering issue M4he reported in #7.
|
// 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);
|
log_error("Failed to bind texture for window %#010x.", w->id);
|
||||||
}
|
}
|
||||||
w->pixmap_damaged = false;
|
w->pixmap_damaged = false;
|
||||||
|
@ -445,8 +475,7 @@ static bool get_root_tile(session_t *ps) {
|
||||||
ps->root_tile_paint.pixmap = pixmap;
|
ps->root_tile_paint.pixmap = pixmap;
|
||||||
#ifdef CONFIG_OPENGL
|
#ifdef CONFIG_OPENGL
|
||||||
if (BKEND_GLX == ps->o.backend)
|
if (BKEND_GLX == ps->o.backend)
|
||||||
return glx_bind_pixmap(ps, &ps->root_tile_paint.ptex,
|
return paint_bind_tex(ps, &ps->root_tile_paint, 0, 0, 0, ps->vis, false);
|
||||||
ps->root_tile_paint.pixmap, 0, 0, 0);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -484,7 +513,8 @@ static bool win_build_shadow(session_t *ps, win *w, double opacity) {
|
||||||
return XCB_NONE;
|
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 =
|
shadow_pixmap_argb =
|
||||||
x_create_pixmap(ps->c, 32, ps->root, shadow_image->width, shadow_image->height);
|
x_create_pixmap(ps->c, 32, ps->root, shadow_image->width, shadow_image->height);
|
||||||
|
|
||||||
|
@ -542,7 +572,7 @@ shadow_picture_err:
|
||||||
*/
|
*/
|
||||||
static inline void win_paint_shadow(session_t *ps, win *w, region_t *reg_paint) {
|
static inline void win_paint_shadow(session_t *ps, win *w, region_t *reg_paint) {
|
||||||
// Bind shadow pixmap to GLX texture if needed
|
// 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)) {
|
if (!paint_isvalid(ps, &w->shadow_paint)) {
|
||||||
log_error("Window %#010x is missing shadow data.", w->id);
|
log_error("Window %#010x is missing shadow data.", w->id);
|
||||||
|
@ -942,12 +972,14 @@ void paint_all(session_t *ps, win *const t, bool ignore_damage) {
|
||||||
switch (ps->o.backend) {
|
switch (ps->o.backend) {
|
||||||
case BKEND_XRENDER:
|
case BKEND_XRENDER:
|
||||||
if (ps->o.monitor_repaint) {
|
if (ps->o.monitor_repaint) {
|
||||||
// Copy the screen content to a new picture, and highlight
|
// Copy the screen content to a new picture, and highlight the
|
||||||
// the paint region. This is not very efficient, but since
|
// paint region. This is not very efficient, but since it's for
|
||||||
// it's for debug only, we don't really care
|
// debug only, we don't really care
|
||||||
|
|
||||||
// First we create a new picture, and copy content from the buffer to it
|
// First we create a new picture, and copy content from the buffer
|
||||||
xcb_render_pictforminfo_t *pictfmt = x_get_pictform_for_visual(ps->c, ps->vis);
|
// 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(
|
xcb_render_picture_t new_pict = x_create_picture_with_pictfmt(
|
||||||
ps, ps->root_width, ps->root_height, pictfmt, 0, NULL);
|
ps, ps->root_width, ps->root_height, pictfmt, 0, NULL);
|
||||||
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC,
|
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC,
|
||||||
|
@ -983,7 +1015,7 @@ void paint_all(session_t *ps, win *const t, bool ignore_damage) {
|
||||||
glXWaitX();
|
glXWaitX();
|
||||||
assert(ps->tgt_buffer.pixmap);
|
assert(ps->tgt_buffer.pixmap);
|
||||||
paint_bind_tex(ps, &ps->tgt_buffer, ps->root_width, ps->root_height,
|
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)
|
if (ps->o.vsync_use_glfinish)
|
||||||
glFinish();
|
glFinish();
|
||||||
else
|
else
|
||||||
|
@ -1200,12 +1232,12 @@ void deinit_render(session_t *ps) {
|
||||||
// Free other X resources
|
// Free other X resources
|
||||||
free_root_tile(ps);
|
free_root_tile(ps);
|
||||||
|
|
||||||
// Free the damage ring
|
// Free the damage ring
|
||||||
for (int i = 0; i < ps->ndamage; ++i)
|
for (int i = 0; i < ps->ndamage; ++i)
|
||||||
pixman_region32_fini(&ps->damage_ring[i]);
|
pixman_region32_fini(&ps->damage_ring[i]);
|
||||||
ps->ndamage = 0;
|
ps->ndamage = 0;
|
||||||
free(ps->damage_ring);
|
free(ps->damage_ring);
|
||||||
ps->damage_ring = ps->damage = NULL;
|
ps->damage_ring = ps->damage = NULL;
|
||||||
|
|
||||||
#ifdef CONFIG_OPENGL
|
#ifdef CONFIG_OPENGL
|
||||||
glx_destroy(ps);
|
glx_destroy(ps);
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/render.h>
|
#include <xcb/render.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#ifdef CONFIG_OPENGL
|
||||||
|
#include <GL/glx.h>
|
||||||
|
#include "backend/gl/glx.h"
|
||||||
|
#endif
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
|
|
||||||
typedef struct _glx_texture glx_texture_t;
|
typedef struct _glx_texture glx_texture_t;
|
||||||
|
@ -16,6 +20,9 @@ typedef struct paint {
|
||||||
xcb_pixmap_t pixmap;
|
xcb_pixmap_t pixmap;
|
||||||
xcb_render_picture_t pict;
|
xcb_render_picture_t pict;
|
||||||
glx_texture_t *ptex;
|
glx_texture_t *ptex;
|
||||||
|
#ifdef CONFIG_OPENGL
|
||||||
|
struct glx_fbconfig_info *fbcfg;
|
||||||
|
#endif
|
||||||
} paint_t;
|
} paint_t;
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -73,6 +73,10 @@ static inline long attr_const min_l(long a, long b) {
|
||||||
return (a > b ? b : a);
|
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.
|
* Normalize a double value to a specific range.
|
||||||
*
|
*
|
||||||
|
|
1
src/x.h
1
src/x.h
|
@ -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);
|
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);
|
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
|
xcb_render_picture_t
|
||||||
x_create_picture_with_pictfmt_and_pixmap(xcb_connection_t *, xcb_render_pictforminfo_t *pictfmt,
|
x_create_picture_with_pictfmt_and_pixmap(xcb_connection_t *, xcb_render_pictforminfo_t *pictfmt,
|
||||||
|
|
Loading…
Reference in New Issue