2018-10-03 17:14:51 -04:00
|
|
|
// SPDX-License-Identifier: MIT
|
2013-03-15 11:16:23 -04:00
|
|
|
/*
|
|
|
|
* Compton - a compositor for X11
|
|
|
|
*
|
|
|
|
* Based on `xcompmgr` - Copyright (c) 2003, Keith Packard
|
|
|
|
*
|
|
|
|
* Copyright (c) 2011-2013, Christopher Jeffrey
|
2018-10-03 17:24:12 -04:00
|
|
|
* See LICENSE-mit for more information.
|
2013-03-15 11:16:23 -04:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2018-12-15 13:47:21 -05:00
|
|
|
#include "compiler.h"
|
2018-12-15 12:42:37 -05:00
|
|
|
#include "string_utils.h"
|
2018-12-15 12:53:17 -05:00
|
|
|
#include "log.h"
|
|
|
|
|
2013-03-15 11:16:23 -04:00
|
|
|
#include "opengl.h"
|
|
|
|
|
2018-09-29 14:24:33 -04:00
|
|
|
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) {
|
2018-12-20 11:50:11 -05:00
|
|
|
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);
|
2018-09-29 14:24:33 -04:00
|
|
|
if (!ps->psglx->fbconfigs[depth]) {
|
2018-12-15 13:47:21 -05:00
|
|
|
ps->psglx->fbconfigs[depth] = cmalloc(glx_fbconfig_t);
|
2018-09-29 14:24:33 -04:00
|
|
|
}
|
|
|
|
(*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)) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to retrieve buffer size and alpha size of FBConfig %d.", id);
|
2018-09-29 14:24:33 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (Success != glXGetFBConfigAttrib(ps->dpy, *pcur, GLX_BIND_TO_TEXTURE_TARGETS_EXT, &fbinfo.texture_tgts)) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to retrieve BIND_TO_TEXTURE_TARGETS_EXT of FBConfig %d.", id);
|
2018-09-29 14:24:33 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
int visualdepth = 0;
|
|
|
|
{
|
|
|
|
XVisualInfo *pvi = glXGetVisualFromFBConfig(ps->dpy, *pcur);
|
|
|
|
if (!pvi) {
|
|
|
|
// On nvidia-drivers-325.08 this happens slightly too often...
|
2018-12-20 11:50:11 -05:00
|
|
|
// log_error("Failed to retrieve X Visual of FBConfig %d.", id);
|
2018-09-29 14:24:33 -04:00
|
|
|
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]) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("No FBConfig found for default depth %d.", ps->depth);
|
2018-09-29 14:24:33 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ps->psglx->fbconfigs[32]) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("No FBConfig found for depth 32. Expect crazy things.");
|
2018-09-29 14:24:33 -04:00
|
|
|
}
|
|
|
|
|
2018-12-20 11:50:11 -05:00
|
|
|
log_trace("%d-bit: %p, 32-bit: %p", ps->depth, ps->psglx->fbconfigs[ps->depth]->cfg,
|
|
|
|
ps->psglx->fbconfigs[32]->cfg);
|
2018-09-29 14:24:33 -04:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-09-23 14:10:46 -04:00
|
|
|
static inline XVisualInfo *
|
|
|
|
get_visualinfo_from_visual(session_t *ps, xcb_visualid_t visual) {
|
|
|
|
XVisualInfo vreq = { .visualid = visual };
|
|
|
|
int nitems = 0;
|
|
|
|
|
|
|
|
return XGetVisualInfo(ps->dpy, VisualIDMask, &vreq, &nitems);
|
|
|
|
}
|
|
|
|
|
2018-08-22 07:58:49 -04:00
|
|
|
#ifdef DEBUG_GLX_DEBUG_CONTEXT
|
2014-03-17 11:25:34 -04:00
|
|
|
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) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_trace("source 0x%04X, type 0x%04X, id %u, severity 0x%0X, \"%s\"",
|
|
|
|
source, type, id, severity, message);
|
2014-03-17 11:25:34 -04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-03-15 11:16:23 -04:00
|
|
|
/**
|
|
|
|
* Initialize OpenGL.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
glx_init(session_t *ps, bool need_render) {
|
|
|
|
bool success = false;
|
|
|
|
XVisualInfo *pvis = NULL;
|
|
|
|
|
|
|
|
// Check for GLX extension
|
|
|
|
if (!ps->glx_exists) {
|
|
|
|
if (glXQueryExtension(ps->dpy, &ps->glx_event, &ps->glx_error))
|
|
|
|
ps->glx_exists = true;
|
|
|
|
else {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("No GLX extension.");
|
2013-03-15 11:16:23 -04:00
|
|
|
goto glx_init_end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-21 11:25:28 -05:00
|
|
|
if (ps->o.glx_swap_method > CGLX_MAX_BUFFER_AGE) {
|
|
|
|
log_error("glx-swap-method is too big");
|
|
|
|
goto glx_init_end;
|
|
|
|
}
|
|
|
|
|
2013-03-15 11:16:23 -04:00
|
|
|
// Get XVisualInfo
|
|
|
|
pvis = get_visualinfo_from_visual(ps, ps->vis);
|
|
|
|
if (!pvis) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to acquire XVisualInfo for current visual.");
|
2013-03-15 11:16:23 -04:00
|
|
|
goto glx_init_end;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure the visual is double-buffered
|
|
|
|
if (need_render) {
|
|
|
|
int value = 0;
|
|
|
|
if (Success != glXGetConfig(ps->dpy, pvis, GLX_USE_GL, &value) || !value) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Root visual is not a GL visual.");
|
2013-03-15 11:16:23 -04:00
|
|
|
goto glx_init_end;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Success != glXGetConfig(ps->dpy, pvis, GLX_DOUBLEBUFFER, &value)
|
|
|
|
|| !value) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Root visual is not a double buffered GL visual.");
|
2013-03-15 11:16:23 -04:00
|
|
|
goto glx_init_end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure GLX_EXT_texture_from_pixmap exists
|
2013-03-16 10:54:43 -04:00
|
|
|
if (need_render && !glx_hasglxext(ps, "GLX_EXT_texture_from_pixmap"))
|
2013-03-15 11:16:23 -04:00
|
|
|
goto glx_init_end;
|
|
|
|
|
2014-07-28 00:50:15 -04:00
|
|
|
// Initialize GLX data structure
|
|
|
|
if (!ps->psglx) {
|
|
|
|
static const glx_session_t CGLX_SESSION_DEF = CGLX_SESSION_INIT;
|
2018-12-15 13:47:21 -05:00
|
|
|
ps->psglx = cmalloc(glx_session_t);
|
2014-07-28 00:50:15 -04:00
|
|
|
memcpy(ps->psglx, &CGLX_SESSION_DEF, sizeof(glx_session_t));
|
|
|
|
|
|
|
|
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
|
|
|
|
glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
|
|
|
|
ppass->unifm_factor_center = -1;
|
|
|
|
ppass->unifm_offset_x = -1;
|
|
|
|
ppass->unifm_offset_y = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
glx_session_t *psglx = ps->psglx;
|
|
|
|
|
|
|
|
if (!psglx->context) {
|
2013-04-26 02:01:20 -04:00
|
|
|
// Get GLX context
|
2014-03-17 11:25:34 -04:00
|
|
|
#ifndef DEBUG_GLX_DEBUG_CONTEXT
|
2014-07-28 00:50:15 -04:00
|
|
|
psglx->context = glXCreateContext(ps->dpy, pvis, None, GL_TRUE);
|
2014-03-17 11:25:34 -04:00
|
|
|
#else
|
|
|
|
{
|
|
|
|
GLXFBConfig fbconfig = get_fbconfig_from_visualinfo(ps, pvis);
|
|
|
|
if (!fbconfig) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to get GLXFBConfig for root visual %#lx.", pvis->visualid);
|
2014-03-17 11:25:34 -04:00
|
|
|
goto glx_init_end;
|
|
|
|
}
|
|
|
|
|
|
|
|
f_glXCreateContextAttribsARB p_glXCreateContextAttribsARB =
|
|
|
|
(f_glXCreateContextAttribsARB)
|
|
|
|
glXGetProcAddress((const GLubyte *) "glXCreateContextAttribsARB");
|
|
|
|
if (!p_glXCreateContextAttribsARB) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to get glXCreateContextAttribsARB().");
|
2014-03-17 11:25:34 -04:00
|
|
|
goto glx_init_end;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const int attrib_list[] = {
|
|
|
|
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB,
|
|
|
|
None
|
|
|
|
};
|
2014-07-28 00:50:15 -04:00
|
|
|
psglx->context = p_glXCreateContextAttribsARB(ps->dpy, fbconfig, NULL,
|
2014-03-17 11:25:34 -04:00
|
|
|
GL_TRUE, attrib_list);
|
|
|
|
}
|
|
|
|
#endif
|
2013-03-15 11:16:23 -04:00
|
|
|
|
2014-07-28 00:50:15 -04:00
|
|
|
if (!psglx->context) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to get GLX context.");
|
2013-04-26 02:01:20 -04:00
|
|
|
goto glx_init_end;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attach GLX context
|
2014-07-28 00:50:15 -04:00
|
|
|
if (!glXMakeCurrent(ps->dpy, get_tgt_window(ps), psglx->context)) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to attach GLX context.");
|
2013-04-26 02:01:20 -04:00
|
|
|
goto glx_init_end;
|
|
|
|
}
|
2014-03-17 11:25:34 -04:00
|
|
|
|
|
|
|
#ifdef DEBUG_GLX_DEBUG_CONTEXT
|
|
|
|
{
|
|
|
|
f_DebugMessageCallback p_DebugMessageCallback =
|
|
|
|
(f_DebugMessageCallback)
|
|
|
|
glXGetProcAddress((const GLubyte *) "glDebugMessageCallback");
|
|
|
|
if (!p_DebugMessageCallback) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to get glDebugMessageCallback(0.");
|
2014-03-17 11:25:34 -04:00
|
|
|
goto glx_init_end;
|
|
|
|
}
|
|
|
|
p_DebugMessageCallback(glx_debug_msg_callback, ps);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-03-15 11:16:23 -04:00
|
|
|
}
|
|
|
|
|
2013-03-16 10:54:43 -04:00
|
|
|
// Ensure we have a stencil buffer. X Fixes does not guarantee rectangles
|
|
|
|
// in regions don't overlap, so we must use stencil buffer to make sure
|
|
|
|
// we don't paint a region for more than one time, I think?
|
2013-03-17 00:14:00 -04:00
|
|
|
if (need_render && !ps->o.glx_no_stencil) {
|
2013-03-16 10:54:43 -04:00
|
|
|
GLint val = 0;
|
|
|
|
glGetIntegerv(GL_STENCIL_BITS, &val);
|
|
|
|
if (!val) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Target window doesn't have stencil buffer.");
|
2013-03-16 10:54:43 -04:00
|
|
|
goto glx_init_end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check GL_ARB_texture_non_power_of_two, requires a GLX context and
|
|
|
|
// must precede FBConfig fetching
|
|
|
|
if (need_render)
|
2019-01-09 16:58:16 -05:00
|
|
|
psglx->has_texture_non_power_of_two = glx_hasglext(
|
2013-03-16 10:54:43 -04:00
|
|
|
"GL_ARB_texture_non_power_of_two");
|
|
|
|
|
2013-03-15 11:16:23 -04:00
|
|
|
// Acquire function addresses
|
|
|
|
if (need_render) {
|
2013-05-12 06:21:16 -04:00
|
|
|
#ifdef DEBUG_GLX_MARK
|
2014-07-28 00:50:15 -04:00
|
|
|
psglx->glStringMarkerGREMEDY = (f_StringMarkerGREMEDY)
|
2013-05-12 06:21:16 -04:00
|
|
|
glXGetProcAddress((const GLubyte *) "glStringMarkerGREMEDY");
|
2014-07-28 00:50:15 -04:00
|
|
|
psglx->glFrameTerminatorGREMEDY = (f_FrameTerminatorGREMEDY)
|
2013-05-12 06:21:16 -04:00
|
|
|
glXGetProcAddress((const GLubyte *) "glFrameTerminatorGREMEDY");
|
|
|
|
#endif
|
|
|
|
|
2014-07-28 00:50:15 -04:00
|
|
|
psglx->glXBindTexImageProc = (f_BindTexImageEXT)
|
2013-03-15 11:16:23 -04:00
|
|
|
glXGetProcAddress((const GLubyte *) "glXBindTexImageEXT");
|
2014-07-28 00:50:15 -04:00
|
|
|
psglx->glXReleaseTexImageProc = (f_ReleaseTexImageEXT)
|
2013-03-15 11:16:23 -04:00
|
|
|
glXGetProcAddress((const GLubyte *) "glXReleaseTexImageEXT");
|
2014-07-28 00:50:15 -04:00
|
|
|
if (!psglx->glXBindTexImageProc || !psglx->glXReleaseTexImageProc) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to acquire glXBindTexImageEXT() / glXReleaseTexImageEXT().");
|
2013-03-15 11:16:23 -04:00
|
|
|
goto glx_init_end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Acquire FBConfigs
|
|
|
|
if (need_render && !glx_update_fbconfig(ps))
|
|
|
|
goto glx_init_end;
|
|
|
|
|
2013-04-26 02:01:20 -04:00
|
|
|
// Render preparations
|
2013-03-15 11:16:23 -04:00
|
|
|
if (need_render) {
|
2013-03-16 10:54:43 -04:00
|
|
|
glx_on_root_change(ps);
|
|
|
|
|
2013-12-10 09:06:02 -05:00
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glDepthMask(GL_FALSE);
|
2013-03-15 11:16:23 -04:00
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
|
2013-03-17 00:14:00 -04:00
|
|
|
if (!ps->o.glx_no_stencil) {
|
|
|
|
// Initialize stencil buffer
|
|
|
|
glClear(GL_STENCIL_BUFFER_BIT);
|
|
|
|
glDisable(GL_STENCIL_TEST);
|
|
|
|
glStencilMask(0x1);
|
|
|
|
glStencilFunc(GL_EQUAL, 0x1, 0x1);
|
|
|
|
}
|
2013-03-16 10:54:43 -04:00
|
|
|
|
2013-03-15 11:16:23 -04:00
|
|
|
// Clear screen
|
|
|
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
2013-03-16 10:54:43 -04:00
|
|
|
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
// glXSwapBuffers(ps->dpy, get_tgt_window(ps));
|
2013-03-15 11:16:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
success = true;
|
|
|
|
|
|
|
|
glx_init_end:
|
2013-04-05 09:05:19 -04:00
|
|
|
cxfree(pvis);
|
2013-03-15 11:16:23 -04:00
|
|
|
|
|
|
|
if (!success)
|
|
|
|
glx_destroy(ps);
|
|
|
|
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
2014-05-16 03:18:17 -04:00
|
|
|
static void
|
|
|
|
glx_free_prog_main(session_t *ps, glx_prog_main_t *pprogram) {
|
|
|
|
if (!pprogram)
|
|
|
|
return;
|
|
|
|
if (pprogram->prog) {
|
|
|
|
glDeleteProgram(pprogram->prog);
|
|
|
|
pprogram->prog = 0;
|
|
|
|
}
|
|
|
|
pprogram->unifm_opacity = -1;
|
|
|
|
pprogram->unifm_invert_color = -1;
|
|
|
|
pprogram->unifm_tex = -1;
|
|
|
|
}
|
|
|
|
|
2013-03-15 11:16:23 -04:00
|
|
|
/**
|
|
|
|
* Destroy GLX related resources.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
glx_destroy(session_t *ps) {
|
2014-07-28 00:50:15 -04:00
|
|
|
if (!ps->psglx)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Free all GLX resources of windows
|
|
|
|
for (win *w = ps->list; w; w = w->next)
|
|
|
|
free_win_res_glx(ps, w);
|
|
|
|
|
2013-03-20 05:29:45 -04:00
|
|
|
// Free GLSL shaders/programs
|
2013-05-20 06:04:40 -04:00
|
|
|
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
|
2014-07-28 00:50:15 -04:00
|
|
|
glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
|
2013-05-20 06:04:40 -04:00
|
|
|
if (ppass->frag_shader)
|
|
|
|
glDeleteShader(ppass->frag_shader);
|
|
|
|
if (ppass->prog)
|
|
|
|
glDeleteProgram(ppass->prog);
|
|
|
|
}
|
2014-05-16 03:18:17 -04:00
|
|
|
|
2018-12-21 11:25:28 -05:00
|
|
|
glx_free_prog_main(ps, &ps->glx_prog_win);
|
2014-05-16 03:18:17 -04:00
|
|
|
|
|
|
|
glx_check_err(ps);
|
2013-03-20 05:29:45 -04:00
|
|
|
|
2013-03-15 11:16:23 -04:00
|
|
|
// Free FBConfigs
|
|
|
|
for (int i = 0; i <= OPENGL_MAX_DEPTH; ++i) {
|
2014-07-28 00:50:15 -04:00
|
|
|
free(ps->psglx->fbconfigs[i]);
|
|
|
|
ps->psglx->fbconfigs[i] = NULL;
|
2013-03-15 11:16:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Destroy GLX context
|
2014-07-28 00:50:15 -04:00
|
|
|
if (ps->psglx->context) {
|
|
|
|
glXDestroyContext(ps->dpy, ps->psglx->context);
|
|
|
|
ps->psglx->context = NULL;
|
2013-03-15 11:16:23 -04:00
|
|
|
}
|
2014-07-28 00:50:15 -04:00
|
|
|
|
|
|
|
free(ps->psglx);
|
|
|
|
ps->psglx = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reinitialize GLX.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
glx_reinit(session_t *ps, bool need_render) {
|
|
|
|
// Reinitialize VSync as well
|
|
|
|
vsync_deinit(ps);
|
|
|
|
|
|
|
|
glx_destroy(ps);
|
|
|
|
if (!glx_init(ps, need_render)) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to initialize GLX.");
|
2014-07-28 00:50:15 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!vsync_init(ps)) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to initialize VSync.");
|
2014-07-28 00:50:15 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2013-03-15 11:16:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Callback to run on root window size change.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
glx_on_root_change(session_t *ps) {
|
|
|
|
glViewport(0, 0, ps->root_width, ps->root_height);
|
2013-03-16 10:54:43 -04:00
|
|
|
|
|
|
|
// Initialize matrix, copied from dcompmgr
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
2013-03-19 08:58:55 -04:00
|
|
|
glOrtho(0, ps->root_width, 0, ps->root_height, -1000.0, 1000.0);
|
2013-03-16 10:54:43 -04:00
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize GLX blur filter.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
glx_init_blur(session_t *ps) {
|
2013-05-20 06:04:40 -04:00
|
|
|
assert(ps->o.blur_kerns[0]);
|
|
|
|
|
|
|
|
// Allocate PBO if more than one blur kernel is present
|
|
|
|
if (ps->o.blur_kerns[1]) {
|
|
|
|
// Try to generate a framebuffer
|
|
|
|
GLuint fbo = 0;
|
|
|
|
glGenFramebuffers(1, &fbo);
|
|
|
|
if (!fbo) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to generate Framebuffer. Cannot do multi-pass blur with GLX"
|
|
|
|
" backend.");
|
2013-05-20 06:04:40 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
glDeleteFramebuffers(1, &fbo);
|
|
|
|
}
|
|
|
|
|
2013-04-25 10:23:35 -04:00
|
|
|
{
|
2018-12-15 14:07:14 -05:00
|
|
|
char *lc_numeric_old = strdup(setlocale(LC_NUMERIC, NULL));
|
2013-09-14 20:56:53 -04:00
|
|
|
// Enforce LC_NUMERIC locale "C" here to make sure decimal point is sane
|
|
|
|
// Thanks to hiciu for reporting.
|
|
|
|
setlocale(LC_NUMERIC, "C");
|
|
|
|
|
2013-04-25 10:23:35 -04:00
|
|
|
static const char *FRAG_SHADER_BLUR_PREFIX =
|
|
|
|
"#version 110\n"
|
2013-05-08 10:44:36 -04:00
|
|
|
"%s"
|
2013-04-25 10:23:35 -04:00
|
|
|
"uniform float offset_x;\n"
|
|
|
|
"uniform float offset_y;\n"
|
|
|
|
"uniform float factor_center;\n"
|
2013-05-08 10:44:36 -04:00
|
|
|
"uniform %s tex_scr;\n"
|
2013-04-25 10:23:35 -04:00
|
|
|
"\n"
|
|
|
|
"void main() {\n"
|
|
|
|
" vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);\n";
|
|
|
|
static const char *FRAG_SHADER_BLUR_ADD =
|
2013-05-08 10:44:36 -04:00
|
|
|
" sum += float(%.7g) * %s(tex_scr, vec2(gl_TexCoord[0].x + offset_x * float(%d), gl_TexCoord[0].y + offset_y * float(%d)));\n";
|
|
|
|
static const char *FRAG_SHADER_BLUR_ADD_GPUSHADER4 =
|
|
|
|
" sum += float(%.7g) * %sOffset(tex_scr, vec2(gl_TexCoord[0].x, gl_TexCoord[0].y), ivec2(%d, %d));\n";
|
2013-04-25 10:23:35 -04:00
|
|
|
static const char *FRAG_SHADER_BLUR_SUFFIX =
|
2013-05-08 10:44:36 -04:00
|
|
|
" sum += %s(tex_scr, vec2(gl_TexCoord[0].x, gl_TexCoord[0].y)) * factor_center;\n"
|
2013-04-25 10:23:35 -04:00
|
|
|
" gl_FragColor = sum / (factor_center + float(%.7g));\n"
|
|
|
|
"}\n";
|
2013-05-08 10:44:36 -04:00
|
|
|
|
2014-07-28 00:50:15 -04:00
|
|
|
const bool use_texture_rect = !ps->psglx->has_texture_non_power_of_two;
|
2013-05-08 10:44:36 -04:00
|
|
|
const char *sampler_type = (use_texture_rect ?
|
|
|
|
"sampler2DRect": "sampler2D");
|
|
|
|
const char *texture_func = (use_texture_rect ?
|
|
|
|
"texture2DRect": "texture2D");
|
|
|
|
const char *shader_add = FRAG_SHADER_BLUR_ADD;
|
2018-12-15 14:07:14 -05:00
|
|
|
char *extension = strdup("");
|
2013-05-08 10:44:36 -04:00
|
|
|
if (use_texture_rect)
|
|
|
|
mstrextend(&extension, "#extension GL_ARB_texture_rectangle : require\n");
|
|
|
|
if (ps->o.glx_use_gpushader4) {
|
|
|
|
mstrextend(&extension, "#extension GL_EXT_gpu_shader4 : require\n");
|
|
|
|
shader_add = FRAG_SHADER_BLUR_ADD_GPUSHADER4;
|
|
|
|
}
|
|
|
|
|
2013-05-20 06:04:40 -04:00
|
|
|
for (int i = 0; i < MAX_BLUR_PASS && ps->o.blur_kerns[i]; ++i) {
|
2018-09-27 12:14:44 -04:00
|
|
|
xcb_render_fixed_t *kern = ps->o.blur_kerns[i];
|
2013-05-20 06:04:40 -04:00
|
|
|
if (!kern)
|
|
|
|
break;
|
|
|
|
|
2014-07-28 00:50:15 -04:00
|
|
|
glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
|
2013-05-20 06:04:40 -04:00
|
|
|
|
|
|
|
// Build shader
|
|
|
|
{
|
2018-09-27 12:14:44 -04:00
|
|
|
int wid = XFIXED_TO_DOUBLE(kern[0]), hei = XFIXED_TO_DOUBLE(kern[1]);
|
2013-05-20 06:04:40 -04:00
|
|
|
int nele = wid * hei - 1;
|
2018-08-22 09:25:40 -04:00
|
|
|
unsigned int len = strlen(FRAG_SHADER_BLUR_PREFIX) +
|
|
|
|
strlen(sampler_type) +
|
|
|
|
strlen(extension) +
|
|
|
|
(strlen(shader_add) + strlen(texture_func) + 42) * nele +
|
|
|
|
strlen(FRAG_SHADER_BLUR_SUFFIX) +
|
|
|
|
strlen(texture_func) + 12 + 1;
|
2018-12-15 13:47:21 -05:00
|
|
|
char *shader_str = ccalloc(len, char);
|
2018-12-20 11:50:11 -05:00
|
|
|
char *pc = shader_str;
|
|
|
|
sprintf(pc, FRAG_SHADER_BLUR_PREFIX, extension, sampler_type);
|
|
|
|
pc += strlen(pc);
|
|
|
|
assert(strlen(shader_str) < len);
|
|
|
|
|
|
|
|
double sum = 0.0;
|
|
|
|
for (int j = 0; j < hei; ++j) {
|
|
|
|
for (int k = 0; k < wid; ++k) {
|
|
|
|
if (hei / 2 == j && wid / 2 == k)
|
|
|
|
continue;
|
|
|
|
double val = XFIXED_TO_DOUBLE(kern[2 + j * wid + k]);
|
|
|
|
if (0.0 == val)
|
|
|
|
continue;
|
|
|
|
sum += val;
|
|
|
|
sprintf(pc, shader_add, val, texture_func, k - wid / 2, j - hei / 2);
|
|
|
|
pc += strlen(pc);
|
|
|
|
assert(strlen(shader_str) < len);
|
2013-05-20 06:04:40 -04:00
|
|
|
}
|
2013-04-25 10:23:35 -04:00
|
|
|
}
|
2018-12-20 11:50:11 -05:00
|
|
|
|
|
|
|
sprintf(pc, FRAG_SHADER_BLUR_SUFFIX, texture_func, sum);
|
|
|
|
assert(strlen(shader_str) < len);
|
2013-05-20 06:04:40 -04:00
|
|
|
ppass->frag_shader = glx_create_shader(GL_FRAGMENT_SHADER, shader_str);
|
|
|
|
free(shader_str);
|
2013-04-25 10:23:35 -04:00
|
|
|
}
|
|
|
|
|
2013-05-20 06:04:40 -04:00
|
|
|
if (!ppass->frag_shader) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to create fragment shader %d.", i);
|
2013-05-20 06:04:40 -04:00
|
|
|
return false;
|
|
|
|
}
|
2013-03-20 05:29:45 -04:00
|
|
|
|
2013-05-20 06:04:40 -04:00
|
|
|
// Build program
|
|
|
|
ppass->prog = glx_create_program(&ppass->frag_shader, 1);
|
|
|
|
if (!ppass->prog) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to create GLSL program.");
|
2013-05-20 06:04:40 -04:00
|
|
|
return false;
|
|
|
|
}
|
2013-03-20 05:29:45 -04:00
|
|
|
|
2013-05-20 06:04:40 -04:00
|
|
|
// Get uniform addresses
|
2013-03-20 05:29:45 -04:00
|
|
|
#define P_GET_UNIFM_LOC(name, target) { \
|
2013-05-20 06:04:40 -04:00
|
|
|
ppass->target = glGetUniformLocation(ppass->prog, name); \
|
|
|
|
if (ppass->target < 0) { \
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to get location of %d-th uniform '" name "'. Might be troublesome.", i); \
|
2013-05-20 06:04:40 -04:00
|
|
|
} \
|
|
|
|
}
|
2013-03-20 05:29:45 -04:00
|
|
|
|
2013-05-20 06:04:40 -04:00
|
|
|
P_GET_UNIFM_LOC("factor_center", unifm_factor_center);
|
|
|
|
if (!ps->o.glx_use_gpushader4) {
|
|
|
|
P_GET_UNIFM_LOC("offset_x", unifm_offset_x);
|
|
|
|
P_GET_UNIFM_LOC("offset_y", unifm_offset_y);
|
|
|
|
}
|
2014-05-16 03:18:17 -04:00
|
|
|
|
2013-05-20 06:04:40 -04:00
|
|
|
#undef P_GET_UNIFM_LOC
|
|
|
|
}
|
|
|
|
free(extension);
|
2013-09-14 20:56:53 -04:00
|
|
|
|
|
|
|
// Restore LC_NUMERIC
|
|
|
|
setlocale(LC_NUMERIC, lc_numeric_old);
|
|
|
|
free(lc_numeric_old);
|
2013-05-08 10:44:36 -04:00
|
|
|
}
|
2013-03-16 10:54:43 -04:00
|
|
|
|
2013-03-20 05:29:45 -04:00
|
|
|
|
2013-04-24 21:27:14 -04:00
|
|
|
glx_check_err(ps);
|
|
|
|
|
2013-03-20 05:29:45 -04:00
|
|
|
return true;
|
2013-03-15 11:16:23 -04:00
|
|
|
}
|
|
|
|
|
2014-05-16 03:18:17 -04:00
|
|
|
/**
|
|
|
|
* Load a GLSL main program from shader strings.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
glx_load_prog_main(session_t *ps,
|
|
|
|
const char *vshader_str, const char *fshader_str,
|
|
|
|
glx_prog_main_t *pprogram) {
|
|
|
|
assert(pprogram);
|
|
|
|
|
|
|
|
// Build program
|
|
|
|
pprogram->prog = glx_create_program_from_str(vshader_str, fshader_str);
|
|
|
|
if (!pprogram->prog) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to create GLSL program.");
|
2014-05-16 03:18:17 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get uniform addresses
|
|
|
|
#define P_GET_UNIFM_LOC(name, target) { \
|
|
|
|
pprogram->target = glGetUniformLocation(pprogram->prog, name); \
|
|
|
|
if (pprogram->target < 0) { \
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to get location of uniform '" name "'. Might be troublesome."); \
|
2014-05-16 03:18:17 -04:00
|
|
|
} \
|
|
|
|
}
|
|
|
|
P_GET_UNIFM_LOC("opacity", unifm_opacity);
|
|
|
|
P_GET_UNIFM_LOC("invert_color", unifm_invert_color);
|
|
|
|
P_GET_UNIFM_LOC("tex", unifm_tex);
|
|
|
|
#undef P_GET_UNIFM_LOC
|
|
|
|
|
|
|
|
glx_check_err(ps);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-03-15 11:16:23 -04:00
|
|
|
/**
|
|
|
|
* Bind a X pixmap to an OpenGL texture.
|
|
|
|
*/
|
|
|
|
bool
|
2018-09-30 15:53:52 -04:00
|
|
|
glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
|
2013-03-17 23:48:28 -04:00
|
|
|
unsigned width, unsigned height, unsigned depth) {
|
2018-11-04 08:49:32 -05:00
|
|
|
if (ps->o.backend != BKEND_GLX && ps->o.backend != BKEND_XR_GLX_HYBRID)
|
2018-09-29 17:47:12 -04:00
|
|
|
return true;
|
|
|
|
|
2013-03-17 23:48:28 -04:00
|
|
|
if (!pixmap) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Binding to an empty pixmap %#010x. This can't work.", pixmap);
|
2013-03-15 11:16:23 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
glx_texture_t *ptex = *pptex;
|
|
|
|
bool need_release = true;
|
|
|
|
|
|
|
|
// Allocate structure
|
|
|
|
if (!ptex) {
|
|
|
|
static const glx_texture_t GLX_TEX_DEF = {
|
|
|
|
.texture = 0,
|
|
|
|
.glpixmap = 0,
|
|
|
|
.pixmap = 0,
|
2013-03-19 08:58:55 -04:00
|
|
|
.target = 0,
|
2013-03-15 11:16:23 -04:00
|
|
|
.width = 0,
|
|
|
|
.height = 0,
|
|
|
|
.depth = 0,
|
|
|
|
.y_inverted = false,
|
|
|
|
};
|
|
|
|
|
2018-12-15 13:47:21 -05:00
|
|
|
ptex = cmalloc(glx_texture_t);
|
2013-03-15 11:16:23 -04:00
|
|
|
allocchk(ptex);
|
|
|
|
memcpy(ptex, &GLX_TEX_DEF, sizeof(glx_texture_t));
|
|
|
|
*pptex = ptex;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release pixmap if parameters are inconsistent
|
2013-03-17 23:48:28 -04:00
|
|
|
if (ptex->texture && ptex->pixmap != pixmap) {
|
2013-03-15 11:16:23 -04:00
|
|
|
glx_release_pixmap(ps, ptex);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create GLX pixmap
|
|
|
|
if (!ptex->glpixmap) {
|
|
|
|
need_release = false;
|
|
|
|
|
2013-03-17 23:48:28 -04:00
|
|
|
// Retrieve pixmap parameters, if they aren't provided
|
|
|
|
if (!(width && height && depth)) {
|
|
|
|
Window rroot = None;
|
|
|
|
int rx = 0, ry = 0;
|
|
|
|
unsigned rbdwid = 0;
|
|
|
|
if (!XGetGeometry(ps->dpy, pixmap, &rroot, &rx, &ry,
|
|
|
|
&width, &height, &rbdwid, &depth)) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to query info of pixmap %#010x.", pixmap);
|
2013-03-17 23:48:28 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (depth > OPENGL_MAX_DEPTH) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Requested depth %d higher than %d.", depth,
|
|
|
|
OPENGL_MAX_DEPTH);
|
2013-03-17 23:48:28 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-28 00:50:15 -04:00
|
|
|
const glx_fbconfig_t *pcfg = ps->psglx->fbconfigs[depth];
|
2013-03-17 23:48:28 -04:00
|
|
|
if (!pcfg) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Couldn't find FBConfig with requested depth %d.", depth);
|
2013-03-17 23:48:28 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-03-16 10:54:43 -04:00
|
|
|
// Determine texture target, copied from compiz
|
2013-03-19 08:58:55 -04:00
|
|
|
// The assumption we made here is the target never changes based on any
|
|
|
|
// pixmap-specific parameters, and this may change in the future
|
|
|
|
GLenum tex_tgt = 0;
|
2013-03-16 10:54:43 -04:00
|
|
|
if (GLX_TEXTURE_2D_BIT_EXT & pcfg->texture_tgts
|
2014-07-28 00:50:15 -04:00
|
|
|
&& ps->psglx->has_texture_non_power_of_two)
|
2013-03-16 10:54:43 -04:00
|
|
|
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;
|
|
|
|
|
2018-12-20 11:50:11 -05:00
|
|
|
log_debug("depth %d, tgt %#x, rgba %d", depth, tex_tgt,
|
|
|
|
(GLX_TEXTURE_FORMAT_RGBA_EXT == pcfg->texture_fmt));
|
2013-03-15 11:16:23 -04:00
|
|
|
|
2013-03-16 10:54:43 -04:00
|
|
|
GLint attrs[] = {
|
2013-03-15 11:16:23 -04:00
|
|
|
GLX_TEXTURE_FORMAT_EXT,
|
|
|
|
pcfg->texture_fmt,
|
2013-03-16 10:54:43 -04:00
|
|
|
GLX_TEXTURE_TARGET_EXT,
|
|
|
|
tex_tgt,
|
2013-03-15 11:16:23 -04:00
|
|
|
0,
|
|
|
|
};
|
|
|
|
|
|
|
|
ptex->glpixmap = glXCreatePixmap(ps->dpy, pcfg->cfg, pixmap, attrs);
|
2013-03-17 23:48:28 -04:00
|
|
|
ptex->pixmap = pixmap;
|
2013-03-19 08:58:55 -04:00
|
|
|
ptex->target = (GLX_TEXTURE_2D_EXT == tex_tgt ? GL_TEXTURE_2D:
|
|
|
|
GL_TEXTURE_RECTANGLE);
|
2013-03-17 23:48:28 -04:00
|
|
|
ptex->width = width;
|
|
|
|
ptex->height = height;
|
|
|
|
ptex->depth = depth;
|
|
|
|
ptex->y_inverted = pcfg->y_inverted;
|
2013-03-15 11:16:23 -04:00
|
|
|
}
|
|
|
|
if (!ptex->glpixmap) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to allocate GLX pixmap.");
|
2013-03-15 11:16:23 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-03-19 08:58:55 -04:00
|
|
|
glEnable(ptex->target);
|
|
|
|
|
|
|
|
// Create texture
|
|
|
|
if (!ptex->texture) {
|
|
|
|
need_release = false;
|
|
|
|
|
|
|
|
GLuint texture = 0;
|
|
|
|
glGenTextures(1, &texture);
|
|
|
|
glBindTexture(ptex->target, texture);
|
|
|
|
|
|
|
|
glTexParameteri(ptex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(ptex->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(ptex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(ptex->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
|
|
|
|
glBindTexture(ptex->target, 0);
|
|
|
|
|
|
|
|
ptex->texture = texture;
|
|
|
|
}
|
|
|
|
if (!ptex->texture) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to allocate texture.");
|
2013-03-19 08:58:55 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
glBindTexture(ptex->target, ptex->texture);
|
|
|
|
|
2013-03-15 11:16:23 -04:00
|
|
|
// The specification requires rebinding whenever the content changes...
|
|
|
|
// We can't follow this, too slow.
|
|
|
|
if (need_release)
|
2014-07-28 00:50:15 -04:00
|
|
|
ps->psglx->glXReleaseTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT);
|
2013-03-15 11:16:23 -04:00
|
|
|
|
2014-07-28 00:50:15 -04:00
|
|
|
ps->psglx->glXBindTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
|
2013-03-15 11:16:23 -04:00
|
|
|
|
|
|
|
// Cleanup
|
2013-03-19 08:58:55 -04:00
|
|
|
glBindTexture(ptex->target, 0);
|
|
|
|
glDisable(ptex->target);
|
2013-03-15 11:16:23 -04:00
|
|
|
|
2013-04-24 21:27:14 -04:00
|
|
|
glx_check_err(ps);
|
|
|
|
|
2013-03-15 11:16:23 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Release binding of a texture.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
glx_release_pixmap(session_t *ps, glx_texture_t *ptex) {
|
|
|
|
// Release binding
|
|
|
|
if (ptex->glpixmap && ptex->texture) {
|
2013-03-19 08:58:55 -04:00
|
|
|
glBindTexture(ptex->target, ptex->texture);
|
2014-07-28 00:50:15 -04:00
|
|
|
ps->psglx->glXReleaseTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT);
|
2013-03-19 08:58:55 -04:00
|
|
|
glBindTexture(ptex->target, 0);
|
2013-03-15 11:16:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Free GLX Pixmap
|
|
|
|
if (ptex->glpixmap) {
|
|
|
|
glXDestroyPixmap(ps->dpy, ptex->glpixmap);
|
|
|
|
ptex->glpixmap = 0;
|
|
|
|
}
|
2013-04-24 21:27:14 -04:00
|
|
|
|
|
|
|
glx_check_err(ps);
|
2013-03-15 11:16:23 -04:00
|
|
|
}
|
|
|
|
|
2013-03-19 08:58:55 -04:00
|
|
|
/**
|
|
|
|
* Preprocess function before start painting.
|
|
|
|
*/
|
|
|
|
void
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
glx_paint_pre(session_t *ps, region_t *preg) {
|
2014-07-28 00:50:15 -04:00
|
|
|
ps->psglx->z = 0.0;
|
2013-03-19 08:58:55 -04:00
|
|
|
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
2013-03-21 01:05:56 -04:00
|
|
|
|
2013-04-26 02:01:20 -04:00
|
|
|
// Get buffer age
|
|
|
|
bool trace_damage = (ps->o.glx_swap_method < 0 || ps->o.glx_swap_method > 1);
|
|
|
|
|
|
|
|
// Trace raw damage regions
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
region_t newdamage;
|
|
|
|
pixman_region32_init(&newdamage);
|
|
|
|
if (trace_damage)
|
|
|
|
copy_region(&newdamage, preg);
|
|
|
|
|
|
|
|
// We use GLX buffer_age extension to decide which pixels in
|
|
|
|
// the back buffer is reusable, and limit our redrawing
|
|
|
|
int buffer_age = 0;
|
|
|
|
|
|
|
|
// Query GLX_EXT_buffer_age for buffer age
|
|
|
|
if (ps->o.glx_swap_method == SWAPM_BUFFER_AGE) {
|
|
|
|
unsigned val = 0;
|
|
|
|
glXQueryDrawable(ps->dpy, get_tgt_window(ps),
|
|
|
|
GLX_BACK_BUFFER_AGE_EXT, &val);
|
|
|
|
buffer_age = val;
|
2013-03-19 08:58:55 -04:00
|
|
|
}
|
2013-05-08 10:44:36 -04:00
|
|
|
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
// Buffer age too high
|
|
|
|
if (buffer_age > CGLX_MAX_BUFFER_AGE + 1)
|
|
|
|
buffer_age = 0;
|
2013-03-19 08:58:55 -04:00
|
|
|
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
assert(buffer_age >= 0);
|
2013-05-08 10:44:36 -04:00
|
|
|
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
if (buffer_age) {
|
|
|
|
// Determine paint area
|
|
|
|
for (int i = 0; i < buffer_age - 1; ++i)
|
|
|
|
pixman_region32_union(preg, preg, &ps->all_damage_last[i]);
|
|
|
|
} else
|
|
|
|
// buffer_age == 0 means buffer age is not available, paint everything
|
|
|
|
copy_region(preg, &ps->screen_reg);
|
2013-03-19 08:58:55 -04:00
|
|
|
|
2013-04-26 02:01:20 -04:00
|
|
|
if (trace_damage) {
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
// XXX use a circular queue instead of memmove
|
|
|
|
pixman_region32_fini(&ps->all_damage_last[CGLX_MAX_BUFFER_AGE - 1]);
|
2013-04-26 02:01:20 -04:00
|
|
|
memmove(ps->all_damage_last + 1, ps->all_damage_last,
|
2019-01-08 16:34:56 -05:00
|
|
|
(CGLX_MAX_BUFFER_AGE - 1) * sizeof(region_t));
|
2013-04-26 02:01:20 -04:00
|
|
|
ps->all_damage_last[0] = newdamage;
|
|
|
|
}
|
2013-04-21 10:30:22 -04:00
|
|
|
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
glx_set_clip(ps, preg);
|
2013-04-24 21:27:14 -04:00
|
|
|
|
2013-05-08 21:43:40 -04:00
|
|
|
#ifdef DEBUG_GLX_PAINTREG
|
|
|
|
glx_render_color(ps, 0, 0, ps->root_width, ps->root_height, 0, *preg, NULL);
|
|
|
|
#endif
|
|
|
|
|
2013-04-24 21:27:14 -04:00
|
|
|
glx_check_err(ps);
|
2013-03-19 08:58:55 -04:00
|
|
|
}
|
|
|
|
|
2013-03-16 10:54:43 -04:00
|
|
|
/**
|
|
|
|
* Set clipping region on the target window.
|
|
|
|
*/
|
|
|
|
void
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
glx_set_clip(session_t *ps, const region_t *reg) {
|
2013-03-17 00:14:00 -04:00
|
|
|
// Quit if we aren't using stencils
|
|
|
|
if (ps->o.glx_no_stencil)
|
|
|
|
return;
|
2013-03-16 10:54:43 -04:00
|
|
|
|
2013-03-18 07:01:18 -04:00
|
|
|
glDisable(GL_STENCIL_TEST);
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
|
|
|
|
|
|
if (!reg)
|
|
|
|
return;
|
|
|
|
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
int nrects;
|
|
|
|
const rect_t *rects = pixman_region32_rectangles((region_t *)reg, &nrects);
|
2013-03-18 07:01:18 -04:00
|
|
|
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
if (nrects == 1) {
|
2013-03-18 07:01:18 -04:00
|
|
|
glEnable(GL_SCISSOR_TEST);
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
glScissor(rects[0].x1, ps->root_height-rects[0].y2,
|
|
|
|
rects[0].x2-rects[0].x1, rects[0].y2-rects[0].y1);
|
2013-03-16 10:54:43 -04:00
|
|
|
}
|
2013-03-18 07:01:18 -04:00
|
|
|
|
2013-04-24 21:27:14 -04:00
|
|
|
glx_check_err(ps);
|
2013-03-16 10:54:43 -04:00
|
|
|
}
|
|
|
|
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
#define P_PAINTREG_START(var) \
|
|
|
|
region_t reg_new; \
|
|
|
|
int nrects; \
|
|
|
|
const rect_t *rects; \
|
|
|
|
pixman_region32_init_rect(®_new, dx, dy, width, height); \
|
|
|
|
pixman_region32_intersect(®_new, ®_new, (region_t *)reg_tgt); \
|
|
|
|
rects = pixman_region32_rectangles(®_new, &nrects); \
|
2013-04-06 08:21:38 -04:00
|
|
|
glBegin(GL_QUADS); \
|
|
|
|
\
|
2013-05-20 06:04:40 -04:00
|
|
|
for (int ri = 0; ri < nrects; ++ri) { \
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
rect_t var = rects[ri];
|
2013-04-06 08:21:38 -04:00
|
|
|
|
|
|
|
#define P_PAINTREG_END() \
|
|
|
|
} \
|
|
|
|
glEnd(); \
|
|
|
|
\
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
pixman_region32_fini(®_new);
|
2013-04-06 08:21:38 -04:00
|
|
|
|
2013-05-20 06:04:40 -04:00
|
|
|
static inline GLuint
|
|
|
|
glx_gen_texture(session_t *ps, GLenum tex_tgt, int width, int height) {
|
|
|
|
GLuint tex = 0;
|
|
|
|
glGenTextures(1, &tex);
|
|
|
|
if (!tex) return 0;
|
|
|
|
glEnable(tex_tgt);
|
|
|
|
glBindTexture(tex_tgt, tex);
|
|
|
|
glTexParameteri(tex_tgt, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(tex_tgt, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(tex_tgt, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(tex_tgt, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexImage2D(tex_tgt, 0, GL_RGB, width, height, 0, GL_RGB,
|
|
|
|
GL_UNSIGNED_BYTE, NULL);
|
|
|
|
glBindTexture(tex_tgt, 0);
|
|
|
|
|
|
|
|
return tex;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
glx_copy_region_to_tex(session_t *ps, GLenum tex_tgt, int basex, int basey,
|
|
|
|
int dx, int dy, int width, int height) {
|
|
|
|
if (width > 0 && height > 0)
|
|
|
|
glCopyTexSubImage2D(tex_tgt, 0, dx - basex, dy - basey,
|
|
|
|
dx, ps->root_height - dy - height, width, height);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Blur contents in a particular region.
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
*
|
|
|
|
* XXX seems to be way to complex for what it does
|
2013-05-20 06:04:40 -04:00
|
|
|
*/
|
2013-03-19 08:58:55 -04:00
|
|
|
bool
|
2013-03-20 05:29:45 -04:00
|
|
|
glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
2013-05-20 06:04:40 -04:00
|
|
|
GLfloat factor_center,
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
const region_t *reg_tgt,
|
2013-05-20 06:04:40 -04:00
|
|
|
glx_blur_cache_t *pbc) {
|
2014-07-28 00:50:15 -04:00
|
|
|
assert(ps->psglx->blur_passes[0].prog);
|
|
|
|
const bool more_passes = ps->psglx->blur_passes[1].prog;
|
2013-05-20 06:04:40 -04:00
|
|
|
const bool have_scissors = glIsEnabled(GL_SCISSOR_TEST);
|
|
|
|
const bool have_stencil = glIsEnabled(GL_STENCIL_TEST);
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
// Calculate copy region size
|
|
|
|
glx_blur_cache_t ibc = { .width = 0, .height = 0 };
|
|
|
|
if (!pbc)
|
|
|
|
pbc = &ibc;
|
2013-03-19 08:58:55 -04:00
|
|
|
|
2013-04-27 05:34:42 -04:00
|
|
|
int mdx = dx, mdy = dy, mwidth = width, mheight = height;
|
2018-12-20 11:50:11 -05:00
|
|
|
//log_trace("%d, %d, %d, %d", mdx, mdy, mwidth, mheight);
|
2013-05-20 06:04:40 -04:00
|
|
|
|
|
|
|
/*
|
2013-04-27 05:34:42 -04:00
|
|
|
if (ps->o.resize_damage > 0) {
|
2013-05-20 06:04:40 -04:00
|
|
|
int inc_x = 0, inc_y = 0;
|
|
|
|
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
|
|
|
|
XFixed *kern = ps->o.blur_kerns[i];
|
|
|
|
if (!kern) break;
|
2018-09-27 12:14:44 -04:00
|
|
|
inc_x += XFIXED_TO_DOUBLE(kern[0]) / 2;
|
|
|
|
inc_y += XFIXED_TO_DOUBLE(kern[1]) / 2;
|
2013-05-20 06:04:40 -04:00
|
|
|
}
|
|
|
|
inc_x = min_i(ps->o.resize_damage, inc_x);
|
|
|
|
inc_y = min_i(ps->o.resize_damage, inc_y);
|
|
|
|
|
2013-04-27 05:34:42 -04:00
|
|
|
mdx = max_i(dx - inc_x, 0);
|
|
|
|
mdy = max_i(dy - inc_y, 0);
|
|
|
|
int mdx2 = min_i(dx + width + inc_x, ps->root_width),
|
|
|
|
mdy2 = min_i(dy + height + inc_y, ps->root_height);
|
|
|
|
mwidth = mdx2 - mdx;
|
|
|
|
mheight = mdy2 - mdy;
|
|
|
|
}
|
2013-05-20 06:04:40 -04:00
|
|
|
*/
|
2013-04-27 05:34:42 -04:00
|
|
|
|
2013-03-19 08:58:55 -04:00
|
|
|
GLenum tex_tgt = GL_TEXTURE_RECTANGLE;
|
2014-07-28 00:50:15 -04:00
|
|
|
if (ps->psglx->has_texture_non_power_of_two)
|
2013-03-19 08:58:55 -04:00
|
|
|
tex_tgt = GL_TEXTURE_2D;
|
|
|
|
|
2013-05-20 06:04:40 -04:00
|
|
|
// Free textures if size inconsistency discovered
|
|
|
|
if (mwidth != pbc->width || mheight != pbc->height)
|
|
|
|
free_glx_bc_resize(ps, pbc);
|
|
|
|
|
|
|
|
// Generate FBO and textures if needed
|
|
|
|
if (!pbc->textures[0])
|
|
|
|
pbc->textures[0] = glx_gen_texture(ps, tex_tgt, mwidth, mheight);
|
|
|
|
GLuint tex_scr = pbc->textures[0];
|
|
|
|
if (more_passes && !pbc->textures[1])
|
|
|
|
pbc->textures[1] = glx_gen_texture(ps, tex_tgt, mwidth, mheight);
|
|
|
|
pbc->width = mwidth;
|
|
|
|
pbc->height = mheight;
|
|
|
|
GLuint tex_scr2 = pbc->textures[1];
|
|
|
|
if (more_passes && !pbc->fbo)
|
|
|
|
glGenFramebuffers(1, &pbc->fbo);
|
|
|
|
const GLuint fbo = pbc->fbo;
|
2013-03-19 08:58:55 -04:00
|
|
|
|
2013-05-20 06:04:40 -04:00
|
|
|
if (!tex_scr || (more_passes && !tex_scr2)) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to allocate texture.");
|
2013-05-20 06:04:40 -04:00
|
|
|
goto glx_blur_dst_end;
|
|
|
|
}
|
|
|
|
if (more_passes && !fbo) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to allocate framebuffer.");
|
2013-05-20 06:04:40 -04:00
|
|
|
goto glx_blur_dst_end;
|
|
|
|
}
|
2013-03-19 08:58:55 -04:00
|
|
|
|
2013-05-20 06:04:40 -04:00
|
|
|
// Read destination pixels into a texture
|
|
|
|
glEnable(tex_tgt);
|
|
|
|
glBindTexture(tex_tgt, tex_scr);
|
|
|
|
glx_copy_region_to_tex(ps, tex_tgt, mdx, mdy, mdx, mdy, mwidth, mheight);
|
|
|
|
/*
|
|
|
|
if (tex_scr2) {
|
|
|
|
glBindTexture(tex_tgt, tex_scr2);
|
|
|
|
glx_copy_region_to_tex(ps, tex_tgt, mdx, mdy, mdx, mdy, mwidth, dx - mdx);
|
|
|
|
glx_copy_region_to_tex(ps, tex_tgt, mdx, mdy, mdx, dy + height,
|
|
|
|
mwidth, mdy + mheight - dy - height);
|
|
|
|
glx_copy_region_to_tex(ps, tex_tgt, mdx, mdy, mdx, dy, dx - mdx, height);
|
|
|
|
glx_copy_region_to_tex(ps, tex_tgt, mdx, mdy, dx + width, dy,
|
|
|
|
mdx + mwidth - dx - width, height);
|
|
|
|
} */
|
|
|
|
|
2013-05-08 10:44:36 -04:00
|
|
|
// Texture scaling factor
|
|
|
|
GLfloat texfac_x = 1.0f, texfac_y = 1.0f;
|
|
|
|
if (GL_TEXTURE_2D == tex_tgt) {
|
|
|
|
texfac_x /= mwidth;
|
|
|
|
texfac_y /= mheight;
|
|
|
|
}
|
|
|
|
|
2013-03-19 08:58:55 -04:00
|
|
|
// Paint it back
|
2013-05-20 06:04:40 -04:00
|
|
|
if (more_passes) {
|
|
|
|
glDisable(GL_STENCIL_TEST);
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
|
|
}
|
2013-03-20 05:29:45 -04:00
|
|
|
|
2013-05-20 06:04:40 -04:00
|
|
|
bool last_pass = false;
|
|
|
|
for (int i = 0; !last_pass; ++i) {
|
2014-07-28 00:50:15 -04:00
|
|
|
last_pass = !ps->psglx->blur_passes[i + 1].prog;
|
2013-05-20 06:04:40 -04:00
|
|
|
assert(i < MAX_BLUR_PASS - 1);
|
2014-07-28 00:50:15 -04:00
|
|
|
const glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
|
2013-05-20 06:04:40 -04:00
|
|
|
assert(ppass->prog);
|
|
|
|
|
|
|
|
assert(tex_scr);
|
|
|
|
glBindTexture(tex_tgt, tex_scr);
|
|
|
|
|
|
|
|
if (!last_pass) {
|
|
|
|
static const GLenum DRAWBUFS[2] = { GL_COLOR_ATTACHMENT0 };
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
2013-06-25 11:06:08 -04:00
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
|
|
|
GL_TEXTURE_2D, tex_scr2, 0);
|
2013-05-20 06:04:40 -04:00
|
|
|
glDrawBuffers(1, DRAWBUFS);
|
|
|
|
if (glCheckFramebufferStatus(GL_FRAMEBUFFER)
|
|
|
|
!= GL_FRAMEBUFFER_COMPLETE) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Framebuffer attachment failed.");
|
2013-05-20 06:04:40 -04:00
|
|
|
goto glx_blur_dst_end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
static const GLenum DRAWBUFS[2] = { GL_BACK };
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
|
|
glDrawBuffers(1, DRAWBUFS);
|
|
|
|
if (have_scissors)
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
|
|
if (have_stencil)
|
|
|
|
glEnable(GL_STENCIL_TEST);
|
|
|
|
}
|
2013-03-19 08:58:55 -04:00
|
|
|
|
2013-05-20 06:04:40 -04:00
|
|
|
// Color negation for testing...
|
|
|
|
// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
|
|
|
// glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
|
|
|
|
// glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
|
|
|
|
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
glUseProgram(ppass->prog);
|
|
|
|
if (ppass->unifm_offset_x >= 0)
|
|
|
|
glUniform1f(ppass->unifm_offset_x, texfac_x);
|
|
|
|
if (ppass->unifm_offset_y >= 0)
|
|
|
|
glUniform1f(ppass->unifm_offset_y, texfac_y);
|
|
|
|
if (ppass->unifm_factor_center >= 0)
|
|
|
|
glUniform1f(ppass->unifm_factor_center, factor_center);
|
|
|
|
|
2013-04-06 08:21:38 -04:00
|
|
|
{
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
P_PAINTREG_START(crect) {
|
|
|
|
const GLfloat rx = (crect.x1 - mdx) * texfac_x;
|
|
|
|
const GLfloat ry = (mheight - (crect.y1 - mdy)) * texfac_y;
|
|
|
|
const GLfloat rxe = rx + (crect.x2 - crect.x1) * texfac_x;
|
|
|
|
const GLfloat rye = ry - (crect.y2 - crect.y1) * texfac_y;
|
|
|
|
GLfloat rdx = crect.x1 - mdx;
|
|
|
|
GLfloat rdy = mheight - crect.y1 + mdy;
|
2013-05-20 06:04:40 -04:00
|
|
|
if (last_pass) {
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
rdx = crect.x1;
|
|
|
|
rdy = ps->root_height - crect.y1;
|
2013-05-20 06:04:40 -04:00
|
|
|
}
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
GLfloat rdxe = rdx + (crect.x2 - crect.x1);
|
|
|
|
GLfloat rdye = rdy - (crect.y2 - crect.y1);
|
2013-03-19 08:58:55 -04:00
|
|
|
|
2018-12-20 11:50:11 -05:00
|
|
|
//log_trace("%f, %f, %f, %f -> %f, %f, %f, %f", rx, ry, rxe, rye, rdx,
|
|
|
|
// rdy, rdxe, rdye);
|
2013-03-19 08:58:55 -04:00
|
|
|
|
2013-05-20 06:04:40 -04:00
|
|
|
glTexCoord2f(rx, ry);
|
|
|
|
glVertex3f(rdx, rdy, z);
|
2013-03-19 08:58:55 -04:00
|
|
|
|
2013-05-20 06:04:40 -04:00
|
|
|
glTexCoord2f(rxe, ry);
|
|
|
|
glVertex3f(rdxe, rdy, z);
|
2013-03-19 08:58:55 -04:00
|
|
|
|
2013-05-20 06:04:40 -04:00
|
|
|
glTexCoord2f(rxe, rye);
|
|
|
|
glVertex3f(rdxe, rdye, z);
|
2013-03-19 08:58:55 -04:00
|
|
|
|
2013-05-20 06:04:40 -04:00
|
|
|
glTexCoord2f(rx, rye);
|
|
|
|
glVertex3f(rdx, rdye, z);
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
} P_PAINTREG_END();
|
2013-05-20 06:04:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
glUseProgram(0);
|
|
|
|
|
|
|
|
// Swap tex_scr and tex_scr2
|
|
|
|
{
|
|
|
|
GLuint tmp = tex_scr2;
|
|
|
|
tex_scr2 = tex_scr;
|
|
|
|
tex_scr = tmp;
|
2013-04-06 08:21:38 -04:00
|
|
|
}
|
2013-03-19 08:58:55 -04:00
|
|
|
}
|
|
|
|
|
2013-05-20 06:04:40 -04:00
|
|
|
ret = true;
|
|
|
|
|
|
|
|
glx_blur_dst_end:
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
2013-03-19 08:58:55 -04:00
|
|
|
glBindTexture(tex_tgt, 0);
|
|
|
|
glDisable(tex_tgt);
|
2013-05-20 06:04:40 -04:00
|
|
|
if (have_scissors)
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
|
|
if (have_stencil)
|
|
|
|
glEnable(GL_STENCIL_TEST);
|
|
|
|
|
|
|
|
if (&ibc == pbc) {
|
|
|
|
free_glx_bc(ps, pbc);
|
|
|
|
}
|
2013-03-19 08:58:55 -04:00
|
|
|
|
2013-04-24 21:27:14 -04:00
|
|
|
glx_check_err(ps);
|
|
|
|
|
2013-05-20 06:04:40 -04:00
|
|
|
return ret;
|
2013-03-19 08:58:55 -04:00
|
|
|
}
|
|
|
|
|
2013-03-24 23:36:39 -04:00
|
|
|
bool
|
|
|
|
glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
GLfloat factor, const region_t *reg_tgt) {
|
2013-03-24 23:36:39 -04:00
|
|
|
// It's possible to dim in glx_render(), but it would be over-complicated
|
|
|
|
// considering all those mess in color negation and modulation
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glColor4f(0.0f, 0.0f, 0.0f, factor);
|
|
|
|
|
|
|
|
{
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
P_PAINTREG_START(crect) {
|
|
|
|
// XXX what does all of these variables mean?
|
|
|
|
GLint rdx = crect.x1;
|
|
|
|
GLint rdy = ps->root_height - crect.y1;
|
|
|
|
GLint rdxe = rdx + (crect.x2 - crect.x1);
|
|
|
|
GLint rdye = rdy - (crect.y2 - crect.y1);
|
2013-03-24 23:36:39 -04:00
|
|
|
|
2013-04-06 08:21:38 -04:00
|
|
|
glVertex3i(rdx, rdy, z);
|
|
|
|
glVertex3i(rdxe, rdy, z);
|
|
|
|
glVertex3i(rdxe, rdye, z);
|
|
|
|
glVertex3i(rdx, rdye, z);
|
|
|
|
}
|
|
|
|
P_PAINTREG_END();
|
2013-03-24 23:36:39 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
|
2013-04-24 21:27:14 -04:00
|
|
|
glx_check_err(ps);
|
|
|
|
|
2013-03-24 23:36:39 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-03-15 11:16:23 -04:00
|
|
|
/**
|
|
|
|
* @brief Render a region with texture data.
|
|
|
|
*/
|
|
|
|
bool
|
2018-09-29 17:47:12 -04:00
|
|
|
glx_render(session_t *ps, const glx_texture_t *ptex,
|
2013-03-15 11:16:23 -04:00
|
|
|
int x, int y, int dx, int dy, int width, int height, int z,
|
2014-05-16 03:18:17 -04:00
|
|
|
double opacity, bool argb, bool neg,
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
const region_t *reg_tgt, const glx_prog_main_t *pprogram
|
2014-05-16 03:18:17 -04:00
|
|
|
) {
|
2013-03-15 11:16:23 -04:00
|
|
|
if (!ptex || !ptex->texture) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Missing texture.");
|
2013-03-15 11:16:23 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-05-16 03:18:17 -04:00
|
|
|
argb = argb || (GLX_TEXTURE_FORMAT_RGBA_EXT ==
|
2014-09-07 06:58:09 -04:00
|
|
|
ps->psglx->fbconfigs[ptex->depth]->texture_fmt);
|
2014-05-16 03:18:17 -04:00
|
|
|
const bool has_prog = pprogram && pprogram->prog;
|
2013-03-24 23:36:39 -04:00
|
|
|
bool dual_texture = false;
|
|
|
|
|
|
|
|
// It's required by legacy versions of OpenGL to enable texture target
|
|
|
|
// before specifying environment. Thanks to madsy for telling me.
|
|
|
|
glEnable(ptex->target);
|
|
|
|
|
2013-03-15 11:16:23 -04:00
|
|
|
// Enable blending if needed
|
2013-03-24 23:36:39 -04:00
|
|
|
if (opacity < 1.0 || argb) {
|
2013-03-19 08:58:55 -04:00
|
|
|
|
2013-03-15 11:16:23 -04:00
|
|
|
glEnable(GL_BLEND);
|
2013-03-17 23:48:28 -04:00
|
|
|
|
2013-03-15 11:16:23 -04:00
|
|
|
// Needed for handling opacity of ARGB texture
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
2013-03-17 23:48:28 -04:00
|
|
|
|
2013-03-24 23:36:39 -04:00
|
|
|
// This is all weird, but X Render is using premultiplied ARGB format, and
|
2013-03-17 23:48:28 -04:00
|
|
|
// we need to use those things to correct it. Thanks to derhass for help.
|
|
|
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glColor4f(opacity, opacity, opacity, opacity);
|
2013-03-15 11:16:23 -04:00
|
|
|
}
|
|
|
|
|
2014-05-16 03:18:17 -04:00
|
|
|
if (!has_prog)
|
|
|
|
{
|
|
|
|
// The default, fixed-function path
|
|
|
|
// Color negation
|
|
|
|
if (neg) {
|
|
|
|
// Simple color negation
|
|
|
|
if (!glIsEnabled(GL_BLEND)) {
|
|
|
|
glEnable(GL_COLOR_LOGIC_OP);
|
|
|
|
glLogicOp(GL_COPY_INVERTED);
|
|
|
|
}
|
|
|
|
// ARGB texture color negation
|
|
|
|
else if (argb) {
|
|
|
|
dual_texture = true;
|
|
|
|
|
|
|
|
// Use two texture stages because the calculation is too complicated,
|
|
|
|
// thanks to madsy for providing code
|
|
|
|
// Texture stage 0
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
|
|
|
|
// Negation for premultiplied color: color = A - C
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_SUBTRACT);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
|
|
|
|
|
|
|
|
// Pass texture alpha through
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
|
|
|
|
|
|
|
|
// Texture stage 1
|
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
|
|
glEnable(ptex->target);
|
|
|
|
glBindTexture(ptex->target, ptex->texture);
|
|
|
|
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
|
|
|
|
|
|
|
// Modulation with constant factor
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
|
|
|
|
|
|
|
|
// Modulation with constant factor
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
|
|
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
}
|
|
|
|
// RGB blend color negation
|
|
|
|
else {
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
|
|
|
|
|
|
|
// Modulation with constant factor
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
|
|
|
|
|
|
|
|
// Modulation with constant factor
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
|
|
|
|
}
|
2013-03-15 11:16:23 -04:00
|
|
|
}
|
|
|
|
}
|
2014-05-16 03:18:17 -04:00
|
|
|
else {
|
|
|
|
// Programmable path
|
|
|
|
assert(pprogram->prog);
|
|
|
|
glUseProgram(pprogram->prog);
|
|
|
|
if (pprogram->unifm_opacity >= 0)
|
|
|
|
glUniform1f(pprogram->unifm_opacity, opacity);
|
|
|
|
if (pprogram->unifm_invert_color >= 0)
|
|
|
|
glUniform1i(pprogram->unifm_invert_color, neg);
|
|
|
|
if (pprogram->unifm_tex >= 0)
|
|
|
|
glUniform1i(pprogram->unifm_tex, 0);
|
|
|
|
}
|
2013-03-15 11:16:23 -04:00
|
|
|
|
2018-12-20 11:50:11 -05:00
|
|
|
//log_trace("Draw: %d, %d, %d, %d -> %d, %d (%d, %d) z %d", x, y, width, height,
|
|
|
|
// dx, dy, ptex->width, ptex->height, z);
|
2013-03-15 11:16:23 -04:00
|
|
|
|
2013-04-06 08:21:38 -04:00
|
|
|
// Bind texture
|
|
|
|
glBindTexture(ptex->target, ptex->texture);
|
|
|
|
if (dual_texture) {
|
|
|
|
glActiveTexture(GL_TEXTURE1);
|
2013-03-19 08:58:55 -04:00
|
|
|
glBindTexture(ptex->target, ptex->texture);
|
2013-04-06 08:21:38 -04:00
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
}
|
2013-03-15 11:16:23 -04:00
|
|
|
|
2013-04-06 08:21:38 -04:00
|
|
|
// Painting
|
|
|
|
{
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
P_PAINTREG_START(crect) {
|
|
|
|
// XXX explain these variables
|
|
|
|
GLfloat rx = (double) (crect.x1 - dx + x);
|
|
|
|
GLfloat ry = (double) (crect.y1 - dy + y);
|
|
|
|
GLfloat rxe = rx + (double) (crect.x2 - crect.x1);
|
|
|
|
GLfloat rye = ry + (double) (crect.y2 - crect.y1);
|
2013-05-08 10:44:36 -04:00
|
|
|
// Rectangle textures have [0-w] [0-h] while 2D texture has [0-1] [0-1]
|
|
|
|
// Thanks to amonakov for pointing out!
|
|
|
|
if (GL_TEXTURE_2D == ptex->target) {
|
|
|
|
rx = rx / ptex->width;
|
|
|
|
ry = ry / ptex->height;
|
|
|
|
rxe = rxe / ptex->width;
|
|
|
|
rye = rye / ptex->height;
|
|
|
|
}
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
GLint rdx = crect.x1;
|
|
|
|
GLint rdy = ps->root_height - crect.y1;
|
|
|
|
GLint rdxe = rdx + (crect.x2 - crect.x1);
|
|
|
|
GLint rdye = rdy - (crect.y2 - crect.y1);
|
2013-03-15 11:16:23 -04:00
|
|
|
|
|
|
|
// Invert Y if needed, this may not work as expected, though. I don't
|
|
|
|
// have such a FBConfig to test with.
|
|
|
|
if (!ptex->y_inverted) {
|
|
|
|
ry = 1.0 - ry;
|
|
|
|
rye = 1.0 - rye;
|
|
|
|
}
|
|
|
|
|
2018-12-20 11:50:11 -05:00
|
|
|
//log_trace("Rect %d: %f, %f, %f, %f -> %d, %d, %d, %d", ri, rx, ry, rxe, rye,
|
|
|
|
// rdx, rdy, rdxe, rdye);
|
2013-03-15 11:16:23 -04:00
|
|
|
|
2013-03-24 23:36:39 -04:00
|
|
|
#define P_TEXCOORD(cx, cy) { \
|
|
|
|
if (dual_texture) { \
|
|
|
|
glMultiTexCoord2f(GL_TEXTURE0, cx, cy); \
|
|
|
|
glMultiTexCoord2f(GL_TEXTURE1, cx, cy); \
|
|
|
|
} \
|
|
|
|
else glTexCoord2f(cx, cy); \
|
|
|
|
}
|
|
|
|
P_TEXCOORD(rx, ry);
|
2013-03-15 11:16:23 -04:00
|
|
|
glVertex3i(rdx, rdy, z);
|
|
|
|
|
2013-03-24 23:36:39 -04:00
|
|
|
P_TEXCOORD(rxe, ry);
|
2013-03-15 11:16:23 -04:00
|
|
|
glVertex3i(rdxe, rdy, z);
|
|
|
|
|
2013-03-24 23:36:39 -04:00
|
|
|
P_TEXCOORD(rxe, rye);
|
2013-03-15 11:16:23 -04:00
|
|
|
glVertex3i(rdxe, rdye, z);
|
|
|
|
|
2013-03-24 23:36:39 -04:00
|
|
|
P_TEXCOORD(rx, rye);
|
2013-03-15 11:16:23 -04:00
|
|
|
glVertex3i(rdx, rdye, z);
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-29 23:56:00 -04:00
|
|
|
} P_PAINTREG_END();
|
2013-03-15 11:16:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Cleanup
|
2013-03-19 08:58:55 -04:00
|
|
|
glBindTexture(ptex->target, 0);
|
2013-03-15 11:16:23 -04:00
|
|
|
glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glDisable(GL_COLOR_LOGIC_OP);
|
2013-03-19 08:58:55 -04:00
|
|
|
glDisable(ptex->target);
|
2013-03-15 11:16:23 -04:00
|
|
|
|
2013-03-24 23:36:39 -04:00
|
|
|
if (dual_texture) {
|
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
|
|
glBindTexture(ptex->target, 0);
|
|
|
|
glDisable(ptex->target);
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
}
|
|
|
|
|
2014-05-16 03:18:17 -04:00
|
|
|
if (has_prog)
|
|
|
|
glUseProgram(0);
|
|
|
|
|
2013-04-24 21:27:14 -04:00
|
|
|
glx_check_err(ps);
|
|
|
|
|
2013-03-15 11:16:23 -04:00
|
|
|
return true;
|
|
|
|
}
|
2013-03-16 10:54:43 -04:00
|
|
|
|
2014-09-07 06:58:09 -04:00
|
|
|
/**
|
|
|
|
* @brief Get tightly packed RGB888 data from GL front buffer.
|
|
|
|
*
|
|
|
|
* Don't expect any sort of decent performance.
|
|
|
|
*
|
|
|
|
* @returns tightly packed RGB888 data of the size of the screen,
|
|
|
|
* to be freed with `free()`
|
|
|
|
*/
|
|
|
|
unsigned char *
|
|
|
|
glx_take_screenshot(session_t *ps, int *out_length) {
|
|
|
|
int length = 3 * ps->root_width * ps->root_height;
|
|
|
|
GLint unpack_align_old = 0;
|
|
|
|
glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_align_old);
|
|
|
|
assert(unpack_align_old > 0);
|
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
2018-12-15 13:47:21 -05:00
|
|
|
auto buf = ccalloc(length, unsigned char);
|
2014-09-07 06:58:09 -04:00
|
|
|
glReadBuffer(GL_FRONT);
|
|
|
|
glReadPixels(0, 0, ps->root_width, ps->root_height, GL_RGB,
|
|
|
|
GL_UNSIGNED_BYTE, buf);
|
|
|
|
glReadBuffer(GL_BACK);
|
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_align_old);
|
|
|
|
if (out_length)
|
|
|
|
*out_length = sizeof(unsigned char) * length;
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2013-03-16 10:54:43 -04:00
|
|
|
GLuint
|
|
|
|
glx_create_shader(GLenum shader_type, const char *shader_str) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_trace("glx_create_shader(): ===\n%s\n===", shader_str);
|
2013-05-20 06:04:40 -04:00
|
|
|
|
2013-03-16 10:54:43 -04:00
|
|
|
bool success = false;
|
|
|
|
GLuint shader = glCreateShader(shader_type);
|
|
|
|
if (!shader) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to create shader with type %#x.", shader_type);
|
2013-03-16 10:54:43 -04:00
|
|
|
goto glx_create_shader_end;
|
|
|
|
}
|
|
|
|
glShaderSource(shader, 1, &shader_str, NULL);
|
|
|
|
glCompileShader(shader);
|
|
|
|
|
|
|
|
// Get shader status
|
|
|
|
{
|
|
|
|
GLint status = GL_FALSE;
|
|
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
|
|
|
if (GL_FALSE == status) {
|
|
|
|
GLint log_len = 0;
|
|
|
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_len);
|
|
|
|
if (log_len) {
|
|
|
|
char log[log_len + 1];
|
|
|
|
glGetShaderInfoLog(shader, log_len, NULL, log);
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to compile shader with type %d: %s", shader_type, log);
|
2013-03-16 10:54:43 -04:00
|
|
|
}
|
|
|
|
goto glx_create_shader_end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
success = true;
|
|
|
|
|
|
|
|
glx_create_shader_end:
|
|
|
|
if (shader && !success) {
|
|
|
|
glDeleteShader(shader);
|
|
|
|
shader = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return shader;
|
|
|
|
}
|
|
|
|
|
|
|
|
GLuint
|
2013-03-20 05:29:45 -04:00
|
|
|
glx_create_program(const GLuint * const shaders, int nshaders) {
|
2013-03-16 10:54:43 -04:00
|
|
|
bool success = false;
|
|
|
|
GLuint program = glCreateProgram();
|
|
|
|
if (!program) {
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to create program.");
|
2013-03-16 10:54:43 -04:00
|
|
|
goto glx_create_program_end;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < nshaders; ++i)
|
|
|
|
glAttachShader(program, shaders[i]);
|
|
|
|
glLinkProgram(program);
|
|
|
|
|
|
|
|
// Get program status
|
|
|
|
{
|
|
|
|
GLint status = GL_FALSE;
|
|
|
|
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
|
|
|
if (GL_FALSE == status) {
|
|
|
|
GLint log_len = 0;
|
|
|
|
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_len);
|
|
|
|
if (log_len) {
|
|
|
|
char log[log_len + 1];
|
|
|
|
glGetProgramInfoLog(program, log_len, NULL, log);
|
2018-12-20 11:50:11 -05:00
|
|
|
log_error("Failed to link program: %s", log);
|
2013-03-16 10:54:43 -04:00
|
|
|
}
|
|
|
|
goto glx_create_program_end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
success = true;
|
|
|
|
|
|
|
|
glx_create_program_end:
|
2013-03-20 05:29:45 -04:00
|
|
|
if (program) {
|
|
|
|
for (int i = 0; i < nshaders; ++i)
|
|
|
|
glDetachShader(program, shaders[i]);
|
|
|
|
}
|
2013-03-16 10:54:43 -04:00
|
|
|
if (program && !success) {
|
|
|
|
glDeleteProgram(program);
|
|
|
|
program = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return program;
|
|
|
|
}
|
2014-05-16 03:18:17 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Create a program from vertex and fragment shader strings.
|
|
|
|
*/
|
|
|
|
GLuint
|
|
|
|
glx_create_program_from_str(const char *vert_shader_str,
|
2014-09-07 06:58:09 -04:00
|
|
|
const char *frag_shader_str) {
|
|
|
|
GLuint vert_shader = 0;
|
|
|
|
GLuint frag_shader = 0;
|
|
|
|
GLuint prog = 0;
|
|
|
|
|
|
|
|
if (vert_shader_str)
|
|
|
|
vert_shader = glx_create_shader(GL_VERTEX_SHADER, vert_shader_str);
|
|
|
|
if (frag_shader_str)
|
|
|
|
frag_shader = glx_create_shader(GL_FRAGMENT_SHADER, frag_shader_str);
|
|
|
|
|
2018-12-20 11:50:11 -05:00
|
|
|
GLuint shaders[2];
|
|
|
|
unsigned int count = 0;
|
|
|
|
if (vert_shader)
|
|
|
|
shaders[count++] = vert_shader;
|
|
|
|
if (frag_shader)
|
|
|
|
shaders[count++] = frag_shader;
|
|
|
|
assert(count <= sizeof(shaders) / sizeof(shaders[0]));
|
|
|
|
if (count)
|
|
|
|
prog = glx_create_program(shaders, count);
|
2014-09-07 06:58:09 -04:00
|
|
|
|
|
|
|
if (vert_shader)
|
|
|
|
glDeleteShader(vert_shader);
|
|
|
|
if (frag_shader)
|
|
|
|
glDeleteShader(frag_shader);
|
|
|
|
|
|
|
|
return prog;
|
2014-05-16 03:18:17 -04:00
|
|
|
}
|