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-10-03 17:14:51 -04:00
|
|
|
#pragma once
|
|
|
|
|
2013-03-15 11:16:23 -04:00
|
|
|
#include "common.h"
|
2019-03-10 08:34:37 -04:00
|
|
|
#include "compiler.h"
|
|
|
|
#include "log.h"
|
2019-01-18 18:30:44 -05:00
|
|
|
#include "region.h"
|
|
|
|
#include "render.h"
|
|
|
|
#include "win.h"
|
2013-03-15 11:16:23 -04:00
|
|
|
|
2019-03-10 08:34:37 -04:00
|
|
|
#include <GL/gl.h>
|
2019-08-09 19:56:04 -04:00
|
|
|
#include <GL/glx.h>
|
2013-03-15 11:16:23 -04:00
|
|
|
#include <ctype.h>
|
2013-09-14 20:56:53 -04:00
|
|
|
#include <locale.h>
|
2019-03-10 08:34:37 -04:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <xcb/render.h>
|
|
|
|
#include <xcb/xcb.h>
|
2013-03-15 11:16:23 -04:00
|
|
|
|
2019-05-05 21:23:15 -04:00
|
|
|
typedef struct {
|
|
|
|
/// Fragment shader for blur.
|
|
|
|
GLuint frag_shader;
|
|
|
|
/// GLSL program for blur.
|
|
|
|
GLuint prog;
|
|
|
|
/// Location of uniform "offset_x" in blur GLSL program.
|
|
|
|
GLint unifm_offset_x;
|
|
|
|
/// Location of uniform "offset_y" in blur GLSL program.
|
|
|
|
GLint unifm_offset_y;
|
|
|
|
/// Location of uniform "factor_center" in blur GLSL program.
|
|
|
|
GLint unifm_factor_center;
|
|
|
|
} glx_blur_pass_t;
|
|
|
|
|
2020-09-30 11:09:27 -04:00
|
|
|
typedef struct {
|
|
|
|
/// Fragment shader for rounded corners.
|
|
|
|
GLuint frag_shader;
|
|
|
|
/// GLSL program for rounded corners.
|
|
|
|
GLuint prog;
|
|
|
|
/// Location of uniform "radius" in rounded-corners GLSL program.
|
|
|
|
GLint unifm_radius;
|
|
|
|
/// Location of uniform "texcoord" in rounded-corners GLSL program.
|
|
|
|
GLint unifm_texcoord;
|
|
|
|
/// Location of uniform "texsize" in rounded-corners GLSL program.
|
|
|
|
GLint unifm_texsize;
|
|
|
|
/// Location of uniform "borderw" in rounded-corners GLSL program.
|
|
|
|
GLint unifm_borderw;
|
|
|
|
/// Location of uniform "is_focused" in rounded-corners GLSL program.
|
|
|
|
GLint unifm_is_focused;
|
|
|
|
/// Location of uniform "resolution" in rounded-corners GLSL program.
|
|
|
|
GLint unifm_resolution;
|
|
|
|
} glx_round_pass_t;
|
|
|
|
|
2019-10-23 14:27:30 -04:00
|
|
|
/// Structure containing GLX-dependent data for a session.
|
2019-05-05 21:03:07 -04:00
|
|
|
typedef struct glx_session {
|
|
|
|
// === OpenGL related ===
|
|
|
|
/// GLX context.
|
|
|
|
GLXContext context;
|
|
|
|
/// Whether we have GL_ARB_texture_non_power_of_two.
|
|
|
|
bool has_texture_non_power_of_two;
|
|
|
|
/// Current GLX Z value.
|
|
|
|
int z;
|
2019-06-06 02:37:48 -04:00
|
|
|
glx_blur_pass_t *blur_passes;
|
2020-09-30 11:09:27 -04:00
|
|
|
glx_round_pass_t *round_passes;
|
2019-05-05 21:03:07 -04:00
|
|
|
} glx_session_t;
|
|
|
|
|
2019-05-05 21:23:15 -04:00
|
|
|
/// @brief Wrapper of a binded GLX texture.
|
|
|
|
typedef struct _glx_texture {
|
|
|
|
GLuint texture;
|
|
|
|
GLXPixmap glpixmap;
|
|
|
|
xcb_pixmap_t pixmap;
|
|
|
|
GLenum target;
|
|
|
|
int width;
|
|
|
|
int height;
|
|
|
|
bool y_inverted;
|
|
|
|
} glx_texture_t;
|
|
|
|
|
2019-05-05 21:03:07 -04:00
|
|
|
#define CGLX_SESSION_INIT \
|
|
|
|
{ .context = NULL }
|
|
|
|
|
2019-03-30 05:07:21 -04:00
|
|
|
bool glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, int z,
|
2019-03-10 08:34:37 -04:00
|
|
|
GLfloat factor, const region_t *reg_tgt);
|
2018-09-29 17:47:12 -04:00
|
|
|
|
2019-03-10 08:34:37 -04:00
|
|
|
bool glx_render(session_t *ps, const glx_texture_t *ptex, int x, int y, int dx, int dy,
|
2020-09-30 11:09:27 -04:00
|
|
|
int width, int height, int z, double opacity, bool argb, bool neg, int cr,
|
2019-03-10 08:34:37 -04:00
|
|
|
const region_t *reg_tgt, const glx_prog_main_t *pprogram);
|
2018-09-29 17:47:12 -04:00
|
|
|
|
2019-03-10 08:34:37 -04:00
|
|
|
bool glx_init(session_t *ps, bool need_render);
|
2018-09-29 17:47:12 -04:00
|
|
|
|
2019-03-10 08:34:37 -04:00
|
|
|
void glx_destroy(session_t *ps);
|
2018-09-29 17:47:12 -04:00
|
|
|
|
2019-03-10 08:34:37 -04:00
|
|
|
void glx_on_root_change(session_t *ps);
|
2018-09-29 17:47:12 -04:00
|
|
|
|
2019-03-10 08:34:37 -04:00
|
|
|
bool glx_init_blur(session_t *ps);
|
2018-09-29 17:47:12 -04:00
|
|
|
|
2020-09-30 11:09:27 -04:00
|
|
|
bool glx_init_rounded_corners(session_t *ps);
|
|
|
|
|
2018-09-29 17:47:12 -04:00
|
|
|
#ifdef CONFIG_OPENGL
|
2019-07-24 21:27:02 -04:00
|
|
|
bool glx_load_prog_main(const char *vshader_str, const char *fshader_str,
|
2019-03-10 08:34:37 -04:00
|
|
|
glx_prog_main_t *pprogram);
|
2018-09-29 17:47:12 -04:00
|
|
|
#endif
|
|
|
|
|
2019-03-30 05:07:21 -04:00
|
|
|
bool glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap, int width,
|
|
|
|
int height, bool repeat, const struct glx_fbconfig_info *);
|
2018-09-29 17:47:12 -04:00
|
|
|
|
2019-03-10 08:34:37 -04:00
|
|
|
void glx_release_pixmap(session_t *ps, glx_texture_t *ptex);
|
2018-09-29 17:47:12 -04:00
|
|
|
|
2020-09-30 11:09:27 -04:00
|
|
|
bool glx_bind_texture(session_t *ps, glx_texture_t **pptex, int x, int y, int width,
|
|
|
|
int height, bool repeat);
|
|
|
|
|
|
|
|
void glx_release_texture(session_t *ps, glx_texture_t **ptex);
|
|
|
|
|
2019-03-10 08:34:37 -04:00
|
|
|
void glx_paint_pre(session_t *ps, region_t *preg) attr_nonnull(1, 2);
|
2018-09-29 17:47:12 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if a texture is binded, or is binded to the given pixmap.
|
|
|
|
*/
|
2019-03-10 08:34:37 -04:00
|
|
|
static inline bool glx_tex_binded(const glx_texture_t *ptex, xcb_pixmap_t pixmap) {
|
|
|
|
return ptex && ptex->glpixmap && ptex->texture && (!pixmap || pixmap == ptex->pixmap);
|
2018-09-29 17:47:12 -04:00
|
|
|
}
|
|
|
|
|
2019-03-10 08:34:37 -04:00
|
|
|
void glx_set_clip(session_t *ps, const region_t *reg);
|
2018-09-29 17:47:12 -04:00
|
|
|
|
2019-03-10 08:34:37 -04:00
|
|
|
bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
|
|
|
GLfloat factor_center, const region_t *reg_tgt, glx_blur_cache_t *pbc);
|
2018-09-29 17:47:12 -04:00
|
|
|
|
2020-09-30 11:09:27 -04:00
|
|
|
bool glx_round_corners_dst0(session_t *ps, struct managed_win *w, const glx_texture_t *ptex,
|
|
|
|
int shader_idx, int dx, int dy, int width, int height, float z,
|
|
|
|
float cr, const region_t *reg_tgt, glx_blur_cache_t *pbc);
|
|
|
|
|
|
|
|
bool glx_round_corners_dst1(session_t *ps, struct managed_win *w, const glx_texture_t *ptex,
|
|
|
|
int shader_idx, int dx, int dy, int width, int height, float z,
|
|
|
|
float cr, const region_t *reg_tgt, glx_blur_cache_t *pbc);
|
|
|
|
|
2019-03-10 08:34:37 -04:00
|
|
|
GLuint glx_create_shader(GLenum shader_type, const char *shader_str);
|
2018-09-29 17:47:12 -04:00
|
|
|
|
2019-03-10 08:34:37 -04:00
|
|
|
GLuint glx_create_program(const GLuint *const shaders, int nshaders);
|
2018-09-29 17:47:12 -04:00
|
|
|
|
2019-03-10 08:34:37 -04:00
|
|
|
GLuint glx_create_program_from_str(const char *vert_shader_str, const char *frag_shader_str);
|
2018-09-29 17:47:12 -04:00
|
|
|
|
2019-03-10 08:34:37 -04:00
|
|
|
unsigned char *glx_take_screenshot(session_t *ps, int *out_length);
|
2018-09-29 17:47:12 -04:00
|
|
|
|
2018-12-15 16:11:41 -05:00
|
|
|
/**
|
|
|
|
* Check if there's a GLX context.
|
|
|
|
*/
|
2019-03-10 08:34:37 -04:00
|
|
|
static inline bool glx_has_context(session_t *ps) {
|
|
|
|
return ps->psglx && ps->psglx->context;
|
2018-12-15 16:11:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Ensure we have a GLX context.
|
|
|
|
*/
|
2019-03-10 08:34:37 -04:00
|
|
|
static inline bool ensure_glx_context(session_t *ps) {
|
|
|
|
// Create GLX context
|
|
|
|
if (!glx_has_context(ps))
|
|
|
|
glx_init(ps, false);
|
2018-12-15 16:11:41 -05:00
|
|
|
|
2019-03-10 08:34:37 -04:00
|
|
|
return ps->psglx->context;
|
2018-12-15 16:11:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Free a GLX texture.
|
|
|
|
*/
|
2019-10-12 10:12:17 -04:00
|
|
|
static inline void free_texture_r(session_t *ps attr_unused, GLuint *ptexture) {
|
2019-03-10 08:34:37 -04:00
|
|
|
if (*ptexture) {
|
|
|
|
assert(glx_has_context(ps));
|
|
|
|
glDeleteTextures(1, ptexture);
|
|
|
|
*ptexture = 0;
|
|
|
|
}
|
2018-12-15 16:11:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Free a GLX Framebuffer object.
|
|
|
|
*/
|
2019-07-24 21:27:02 -04:00
|
|
|
static inline void free_glx_fbo(GLuint *pfbo) {
|
2019-03-10 08:34:37 -04:00
|
|
|
if (*pfbo) {
|
|
|
|
glDeleteFramebuffers(1, pfbo);
|
|
|
|
*pfbo = 0;
|
|
|
|
}
|
|
|
|
assert(!*pfbo);
|
2018-12-15 16:11:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Free data in glx_blur_cache_t on resize.
|
|
|
|
*/
|
2019-03-10 08:34:37 -04:00
|
|
|
static inline void free_glx_bc_resize(session_t *ps, glx_blur_cache_t *pbc) {
|
|
|
|
free_texture_r(ps, &pbc->textures[0]);
|
|
|
|
free_texture_r(ps, &pbc->textures[1]);
|
|
|
|
pbc->width = 0;
|
|
|
|
pbc->height = 0;
|
2018-12-15 16:11:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Free a glx_blur_cache_t
|
|
|
|
*/
|
2019-03-10 08:34:37 -04:00
|
|
|
static inline void free_glx_bc(session_t *ps, glx_blur_cache_t *pbc) {
|
2019-07-24 21:27:02 -04:00
|
|
|
free_glx_fbo(&pbc->fbo);
|
2019-03-10 08:34:37 -04:00
|
|
|
free_glx_bc_resize(ps, pbc);
|
2018-12-15 16:11:41 -05:00
|
|
|
}
|
|
|
|
|
2018-09-29 17:47:12 -04:00
|
|
|
/**
|
|
|
|
* Free a glx_texture_t.
|
|
|
|
*/
|
2019-03-10 08:34:37 -04:00
|
|
|
static inline void free_texture(session_t *ps, glx_texture_t **pptex) {
|
|
|
|
glx_texture_t *ptex = *pptex;
|
2018-09-29 17:47:12 -04:00
|
|
|
|
2019-03-10 08:34:37 -04:00
|
|
|
// Quit if there's nothing
|
|
|
|
if (!ptex)
|
|
|
|
return;
|
2018-09-29 17:47:12 -04:00
|
|
|
|
2019-03-10 08:34:37 -04:00
|
|
|
glx_release_pixmap(ps, ptex);
|
2018-09-29 17:47:12 -04:00
|
|
|
|
2019-03-10 08:34:37 -04:00
|
|
|
free_texture_r(ps, &ptex->texture);
|
2018-09-29 17:47:12 -04:00
|
|
|
|
2019-03-10 08:34:37 -04:00
|
|
|
// Free structure itself
|
|
|
|
free(ptex);
|
|
|
|
*pptex = NULL;
|
|
|
|
assert(!*pptex);
|
2018-09-29 17:47:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Free GLX part of paint_t.
|
|
|
|
*/
|
2019-03-10 08:34:37 -04:00
|
|
|
static inline void free_paint_glx(session_t *ps, paint_t *ppaint) {
|
|
|
|
free_texture(ps, &ppaint->ptex);
|
2020-11-02 13:23:38 -05:00
|
|
|
#ifdef CONFIG_OPENGL
|
|
|
|
free(ppaint->fbcfg);
|
|
|
|
#endif
|
2020-04-20 14:05:58 -04:00
|
|
|
ppaint->fbcfg = NULL;
|
2018-09-29 17:47:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Free GLX part of win.
|
|
|
|
*/
|
2019-04-17 18:14:45 -04:00
|
|
|
static inline void free_win_res_glx(session_t *ps, struct managed_win *w) {
|
2019-03-10 08:34:37 -04:00
|
|
|
free_paint_glx(ps, &w->paint);
|
|
|
|
free_paint_glx(ps, &w->shadow_paint);
|
2018-09-29 17:47:12 -04:00
|
|
|
#ifdef CONFIG_OPENGL
|
2019-03-10 08:34:37 -04:00
|
|
|
free_glx_bc(ps, &w->glx_blur_cache);
|
2020-09-30 11:09:27 -04:00
|
|
|
free_glx_bc(ps, &w->glx_round_cache);
|
|
|
|
free_texture(ps, &w->glx_texture_bg);
|
2018-09-29 17:47:12 -04:00
|
|
|
#endif
|
|
|
|
}
|