commit
6a5ad609ba
|
@ -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') ]
|
||||||
|
endif
|
||||||
|
|
||||||
# enable opengl
|
# enable opengl
|
||||||
if get_option('opengl')
|
if get_option('opengl')
|
||||||
srcs += [ files('gl/gl_common.c', 'gl/glx.c') ]
|
srcs += [ files('gl/gl_common.c', 'gl/glx.c') ]
|
||||||
endif
|
endif
|
||||||
endif
|
|
||||||
|
|
||||||
if get_option('opengl')
|
|
||||||
srcs += [ files('gl/gl_common.c') ]
|
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
98
src/render.c
98
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,78 @@
|
||||||
#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
|
||||||
|
// 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)
|
if (!ppaint->pixmap)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (force || !glx_tex_binded(ppaint->ptex, ppaint->pixmap))
|
struct glx_fbconfig_info *fbcfg;
|
||||||
return glx_bind_pixmap(ps, &ppaint->ptex, ppaint->pixmap, wid, hei, depth);
|
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;
|
if (!pictfmt) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
static inline bool paint_bind_tex(session_t *ps, paint_t *ppaint, unsigned wid,
|
if (!ppaint->fbcfg) {
|
||||||
unsigned hei, unsigned depth, bool force) {
|
ppaint->fbcfg = glx_find_fbconfig(ps->dpy, ps->scr, pictfmt, depth);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
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
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if current backend uses XRender for rendering.
|
* 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
|
// 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 +484,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 +522,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 +581,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 +981,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 +1024,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
|
||||||
|
@ -1208,6 +1249,7 @@ void deinit_render(session_t *ps) {
|
||||||
ps->damage_ring = ps->damage = NULL;
|
ps->damage_ring = ps->damage = NULL;
|
||||||
|
|
||||||
#ifdef CONFIG_OPENGL
|
#ifdef CONFIG_OPENGL
|
||||||
|
free(ps->root_tile_paint.fbcfg);
|
||||||
glx_destroy(ps);
|
glx_destroy(ps);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -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