From aa6943ea8852d461ea3f6b5aba30d0d421a041ad Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Sat, 10 Feb 2024 16:19:54 +0000 Subject: [PATCH] Remove the legacy backends --- src/common.h | 11 - src/config.c | 1 - src/config.h | 2 - src/meson.build | 10 +- src/opengl.c | 1544 ---------------------------------------------- src/opengl.h | 244 -------- src/options.c | 66 +- src/picom.c | 236 +++----- src/picom.h | 9 - src/render.c | 1547 ----------------------------------------------- src/render.h | 48 -- src/vsync.c | 208 ------- src/vsync.h | 7 - src/win.c | 20 - src/win.h | 28 - 15 files changed, 87 insertions(+), 3894 deletions(-) delete mode 100644 src/opengl.c delete mode 100644 src/opengl.h delete mode 100644 src/render.c delete mode 100644 src/render.h delete mode 100644 src/vsync.c delete mode 100644 src/vsync.h diff --git a/src/common.h b/src/common.h index a8ddfb32..91c4a87d 100644 --- a/src/common.h +++ b/src/common.h @@ -57,7 +57,6 @@ #include "config.h" #include "list.h" #include "region.h" -#include "render.h" #include "statistics.h" #include "types.h" #include "utils.h" @@ -183,8 +182,6 @@ typedef struct session { xcb_window_t debug_window; /// Whether the root tile is filled by us. bool root_tile_fill; - /// Picture of the root window background. - paint_t root_tile_paint; /// The backend data the root pixmap bound to image_handle root_image; /// A region of the size of the screen. @@ -194,8 +191,6 @@ typedef struct session { xcb_render_picture_t root_picture; /// A Picture acting as the painting target. xcb_render_picture_t tgt_picture; - /// Temporary buffer to paint to before sending to display. - paint_t tgt_buffer; /// Window ID of the window we register as a symbol. xcb_window_t reg_win; #ifdef CONFIG_OPENGL @@ -316,12 +311,6 @@ typedef struct session { /// Nanosecond offset of the first painting. long paint_tm_offset; -#ifdef CONFIG_VSYNC_DRM - // === DRM VSync related === - /// File descriptor of DRI device file. Used for DRM VSync. - int drm_fd; -#endif - // === X extension related === /// Event base number for X Fixes extension. int xfixes_event; diff --git a/src/config.c b/src/config.c index 63b8fb0c..1fe49278 100644 --- a/src/config.c +++ b/src/config.c @@ -808,7 +808,6 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable, // clang-format off *opt = (struct options){ .backend = BKEND_XRENDER, - .legacy_backends = false, .glx_no_stencil = false, .mark_wmwin_focused = false, .mark_ovredir_focused = false, diff --git a/src/config.h b/src/config.h index 3b398877..6d8ab514 100644 --- a/src/config.h +++ b/src/config.h @@ -102,8 +102,6 @@ typedef struct options { /// Render to a separate window instead of taking over the screen bool debug_mode; // === General === - /// Use the legacy backends? - bool legacy_backends; /// Path to write PID to. char *write_pid_path; /// The backend in use. diff --git a/src/meson.build b/src/meson.build index 9b06ffae..698ccfee 100644 --- a/src/meson.build +++ b/src/meson.build @@ -7,8 +7,8 @@ base_deps = [ libev ] -srcs = [ files('picom.c', 'win.c', 'c2.c', 'x.c', 'config.c', 'vsync.c', 'utils.c', - 'diagnostic.c', 'string_utils.c', 'render.c', 'kernel.c', 'log.c', +srcs = [ files('picom.c', 'win.c', 'c2.c', 'x.c', 'config.c', 'utils.c', + 'diagnostic.c', 'string_utils.c', 'kernel.c', 'log.c', 'options.c', 'event.c', 'cache.c', 'atom.c', 'file_watch.c', 'statistics.c', 'vblank.c') ] picom_inc = include_directories('.') @@ -52,15 +52,9 @@ if get_option('regex') deps += [pcre] endif -if get_option('vsync_drm') - cflags += ['-DCONFIG_VSYNC_DRM'] - deps += [dependency('libdrm', required: true)] -endif - if get_option('opengl') cflags += ['-DCONFIG_OPENGL'] deps += [dependency('epoxy', required: true)] - srcs += [ 'opengl.c' ] endif if get_option('dbus') diff --git a/src/opengl.c b/src/opengl.c deleted file mode 100644 index 26679b37..00000000 --- a/src/opengl.c +++ /dev/null @@ -1,1544 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Compton - a compositor for X11 - * - * Based on `xcompmgr` - Copyright (c) 2003, Keith Packard - * - * Copyright (c) 2011-2013, Christopher Jeffrey - * See LICENSE-mit for more information. - * - */ - -#include -#include -#include -#include -#include -#include - -#include "backend/gl/gl_common.h" -#include "backend/gl/glx.h" -#include "common.h" -#include "compiler.h" -#include "config.h" -#include "kernel.h" -#include "log.h" -#include "region.h" -#include "string_utils.h" -#include "uthash_extra.h" -#include "utils.h" -#include "win.h" - -#include "opengl.h" - -#ifndef GL_TEXTURE_RECTANGLE -#define GL_TEXTURE_RECTANGLE 0x84F5 -#endif - -static inline XVisualInfo *get_visualinfo_from_visual(session_t *ps, xcb_visualid_t visual) { - XVisualInfo vreq = {.visualid = visual}; - int nitems = 0; - - return XGetVisualInfo(ps->c.dpy, VisualIDMask, &vreq, &nitems); -} - -/** - * 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) { - log_error("No GLX extension."); - goto glx_init_end; - } - - // Get XVisualInfo - pvis = get_visualinfo_from_visual(ps, ps->c.screen_info->root_visual); - if (!pvis) { - log_error("Failed to acquire XVisualInfo for current visual."); - goto glx_init_end; - } - - // Ensure the visual is double-buffered - if (need_render) { - int value = 0; - if (Success != glXGetConfig(ps->c.dpy, pvis, GLX_USE_GL, &value) || !value) { - log_error("Root visual is not a GL visual."); - goto glx_init_end; - } - - if (Success != glXGetConfig(ps->c.dpy, pvis, GLX_DOUBLEBUFFER, &value) || - !value) { - log_error("Root visual is not a double buffered GL visual."); - goto glx_init_end; - } - } - - // Ensure GLX_EXT_texture_from_pixmap exists - if (need_render && !glxext.has_GLX_EXT_texture_from_pixmap) { - goto glx_init_end; - } - - // Initialize GLX data structure - if (!ps->psglx) { - static const glx_session_t CGLX_SESSION_DEF = CGLX_SESSION_INIT; - ps->psglx = cmalloc(glx_session_t); - memcpy(ps->psglx, &CGLX_SESSION_DEF, sizeof(glx_session_t)); - - // +1 for the zero terminator - ps->psglx->blur_passes = ccalloc(ps->o.blur_kernel_count, glx_blur_pass_t); - - for (int i = 0; i < ps->o.blur_kernel_count; ++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; - } - - ps->psglx->round_passes = ccalloc(1, glx_round_pass_t); - glx_round_pass_t *ppass = ps->psglx->round_passes; - ppass->unifm_radius = -1; - ppass->unifm_texcoord = -1; - ppass->unifm_texsize = -1; - ppass->unifm_borderw = -1; - ppass->unifm_borderc = -1; - ppass->unifm_resolution = -1; - ppass->unifm_tex_scr = -1; - } - - glx_session_t *psglx = ps->psglx; - - if (!psglx->context) { - // Get GLX context -#ifndef DEBUG_GLX_DEBUG_CONTEXT - psglx->context = glXCreateContext(ps->c.dpy, pvis, None, GL_TRUE); -#else - { - GLXFBConfig fbconfig = get_fbconfig_from_visualinfo(ps, pvis); - if (!fbconfig) { - log_error("Failed to get GLXFBConfig for root visual " - "%#lx.", - pvis->visualid); - goto glx_init_end; - } - - f_glXCreateContextAttribsARB p_glXCreateContextAttribsARB = - (f_glXCreateContextAttribsARB)glXGetProcAddress( - (const GLubyte *)"glXCreateContextAttribsARB"); - if (!p_glXCreateContextAttribsARB) { - log_error("Failed to get glXCreateContextAttribsARB()."); - goto glx_init_end; - } - - static const int attrib_list[] = { - GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, None}; - psglx->context = p_glXCreateContextAttribsARB( - ps->c.dpy, fbconfig, NULL, GL_TRUE, attrib_list); - } -#endif - - if (!psglx->context) { - log_error("Failed to get GLX context."); - goto glx_init_end; - } - - // Attach GLX context - if (!glXMakeCurrent(ps->c.dpy, get_tgt_window(ps), psglx->context)) { - log_error("Failed to attach GLX context."); - goto glx_init_end; - } - -#ifdef DEBUG_GLX_DEBUG_CONTEXT - { - f_DebugMessageCallback p_DebugMessageCallback = - (f_DebugMessageCallback)glXGetProcAddress( - (const GLubyte *)"glDebugMessageCallback"); - if (!p_DebugMessageCallback) { - log_error("Failed to get glDebugMessageCallback(0."); - goto glx_init_end; - } - p_DebugMessageCallback(glx_debug_msg_callback, ps); - } -#endif - } - - // 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? - if (need_render && !ps->o.glx_no_stencil) { - GLint val = 0; - glGetIntegerv(GL_STENCIL_BITS, &val); - if (!val) { - log_error("Target window doesn't have stencil buffer."); - goto glx_init_end; - } - } - - // Check GL_ARB_texture_non_power_of_two, requires a GLX context and - // must precede FBConfig fetching - if (need_render) { - psglx->has_texture_non_power_of_two = - epoxy_has_gl_extension("GL_ARB_texture_non_power_of_two"); - } - - // Render preparations - if (need_render) { - glx_on_root_change(ps); - - glDisable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - glDisable(GL_BLEND); - - 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); - } - - // Clear screen - glClearColor(0.0F, 0.0F, 0.0F, 1.0F); - // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // glXSwapBuffers(ps->c.dpy, get_tgt_window(ps)); - } - - success = true; - -glx_init_end: - XFree(pvis); - - if (!success) { - glx_destroy(ps); - } - - return success; -} - -static void glx_free_prog_main(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; -} - -/** - * Destroy GLX related resources. - */ -void glx_destroy(session_t *ps) { - if (!ps->psglx) { - return; - } - - // Free all GLX resources of windows - win_stack_foreach_managed(w, &ps->window_stack) { - free_win_res_glx(ps, w); - } - - // Free GLSL shaders/programs - for (int i = 0; i < ps->o.blur_kernel_count; ++i) { - glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i]; - if (ppass->frag_shader) { - glDeleteShader(ppass->frag_shader); - } - if (ppass->prog) { - glDeleteProgram(ppass->prog); - } - } - free(ps->psglx->blur_passes); - - glx_round_pass_t *ppass = ps->psglx->round_passes; - if (ppass->frag_shader) { - glDeleteShader(ppass->frag_shader); - } - if (ppass->prog) { - glDeleteProgram(ppass->prog); - } - free(ps->psglx->round_passes); - - glx_free_prog_main(&ps->glx_prog_win); - - gl_check_err(); - - // Destroy GLX context - if (ps->psglx->context) { - glXMakeCurrent(ps->c.dpy, None, NULL); - glXDestroyContext(ps->c.dpy, ps->psglx->context); - ps->psglx->context = NULL; - } - - free(ps->psglx); - ps->psglx = NULL; - ps->argb_fbconfig = (struct glx_fbconfig_info){0}; -} - -/** - * 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); - - // Initialize matrix, copied from dcompmgr - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, ps->root_width, 0, ps->root_height, -1000.0, 1000.0); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); -} - -/** - * Initialize GLX blur filter. - */ -bool glx_init_blur(session_t *ps) { - assert(ps->o.blur_kernel_count > 0); - assert(ps->o.blur_kerns); - assert(ps->o.blur_kerns[0]); - - // Allocate PBO if more than one blur kernel is present - if (ps->o.blur_kernel_count > 1) { - // Try to generate a framebuffer - GLuint fbo = 0; - glGenFramebuffers(1, &fbo); - if (!fbo) { - log_error("Failed to generate Framebuffer. Cannot do multi-pass " - "blur with GLX" - " backend."); - return false; - } - glDeleteFramebuffers(1, &fbo); - } - - { - char *lc_numeric_old = strdup(setlocale(LC_NUMERIC, NULL)); - // Enforce LC_NUMERIC locale "C" here to make sure decimal point is sane - // Thanks to hiciu for reporting. - setlocale(LC_NUMERIC, "C"); - - static const char *FRAG_SHADER_BLUR_PREFIX = - "#version 110\n" - "%s" - "uniform float offset_x;\n" - "uniform float offset_y;\n" - "uniform float factor_center;\n" - "uniform %s tex_scr;\n" - "\n" - "void main() {\n" - " vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);\n"; - static const char *FRAG_SHADER_BLUR_ADD = - " 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_SUFFIX = - " sum += %s(tex_scr, vec2(gl_TexCoord[0].x, gl_TexCoord[0].y)) * " - "factor_center;\n" - " gl_FragColor = sum / (factor_center + float(%.7g));\n" - "}\n"; - - const bool use_texture_rect = !ps->psglx->has_texture_non_power_of_two; - 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; - char *extension = NULL; - if (use_texture_rect) { - mstrextend(&extension, "#extension GL_ARB_texture_rectangle : " - "require\n"); - } - if (!extension) { - extension = strdup(""); - } - - for (int i = 0; i < ps->o.blur_kernel_count; ++i) { - auto kern = ps->o.blur_kerns[i]; - glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i]; - - // Build shader - int width = kern->w, height = kern->h; - int nele = width * height - 1; - assert(nele >= 0); - auto len = - strlen(FRAG_SHADER_BLUR_PREFIX) + strlen(sampler_type) + - strlen(extension) + - (strlen(shader_add) + strlen(texture_func) + 42) * (uint)nele + - strlen(FRAG_SHADER_BLUR_SUFFIX) + strlen(texture_func) + 12 + 1; - char *shader_str = ccalloc(len, char); - 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 < height; ++j) { - for (int k = 0; k < width; ++k) { - if (height / 2 == j && width / 2 == k) { - continue; - } - double val = kern->data[j * width + k]; - if (val == 0) { - continue; - } - sum += val; - sprintf(pc, shader_add, val, texture_func, - k - width / 2, j - height / 2); - pc += strlen(pc); - assert(strlen(shader_str) < len); - } - } - - sprintf(pc, FRAG_SHADER_BLUR_SUFFIX, texture_func, sum); - assert(strlen(shader_str) < len); - ppass->frag_shader = gl_create_shader(GL_FRAGMENT_SHADER, shader_str); - free(shader_str); - - if (!ppass->frag_shader) { - log_error("Failed to create fragment shader %d.", i); - free(extension); - free(lc_numeric_old); - return false; - } - - // Build program - ppass->prog = gl_create_program(&ppass->frag_shader, 1); - if (!ppass->prog) { - log_error("Failed to create GLSL program."); - free(extension); - free(lc_numeric_old); - return false; - } - - // Get uniform addresses -#define P_GET_UNIFM_LOC(name, target) \ - { \ - ppass->target = glGetUniformLocation(ppass->prog, name); \ - if (ppass->target < 0) { \ - log_error("Failed to get location of %d-th uniform '" name \ - "'. Might be troublesome.", \ - i); \ - } \ - } - - P_GET_UNIFM_LOC("factor_center", unifm_factor_center); - P_GET_UNIFM_LOC("offset_x", unifm_offset_x); - P_GET_UNIFM_LOC("offset_y", unifm_offset_y); - -#undef P_GET_UNIFM_LOC - } - free(extension); - - // Restore LC_NUMERIC - setlocale(LC_NUMERIC, lc_numeric_old); - free(lc_numeric_old); - } - - gl_check_err(); - - return true; -} - -/** - * Initialize GLX rounded corners filter. - */ -bool glx_init_rounded_corners(session_t *ps) { - char *lc_numeric_old = strdup(setlocale(LC_NUMERIC, NULL)); - // Enforce LC_NUMERIC locale "C" here to make sure decimal point is sane - // Thanks to hiciu for reporting. - setlocale(LC_NUMERIC, "C"); - - static const char *FRAG_SHADER = - "#version 110\n" - "%s" // extensions - "uniform float u_radius;\n" - "uniform float u_borderw;\n" - "uniform vec4 u_borderc;\n" - "uniform vec2 u_texcoord;\n" - "uniform vec2 u_texsize;\n" - "uniform vec2 u_resolution;\n" - "uniform %s tex_scr;\n" // sampler2D | sampler2DRect - "\n" - "// https://www.shadertoy.com/view/ltS3zW\n" - "float RectSDF(vec2 p, vec2 b, float r) {\n" - " vec2 d = abs(p) - b + vec2(r);\n" - " return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - r;\n" - "}\n\n" - "void main()\n" - "{\n" - " vec2 coord = vec2(u_texcoord.x, " - "u_resolution.y-u_texsize.y-u_texcoord.y);\n" - " vec4 u_v4WndBgColor = %s(tex_scr, vec2(gl_TexCoord[0].st));\n" - " float u_fRadiusPx = u_radius;\n" - " float u_fHalfBorderThickness = u_borderw / 2.0;\n" - " vec4 u_v4BorderColor = u_borderc;\n" - " vec4 u_v4FillColor = vec4(0.0, 0.0, 0.0, 0.0);\n" - " vec4 v4FromColor = u_v4BorderColor; //Always the border " - "color. If no border, this still should be set\n" - " vec4 v4ToColor = u_v4WndBgColor; //Outside color is the " - "background texture\n" - "\n" - " vec2 u_v2HalfShapeSizePx = u_texsize/2.0 - " - "vec2(u_fHalfBorderThickness);\n" - " vec2 v_v2CenteredPos = (gl_FragCoord.xy - u_texsize.xy / 2.0 - " - "coord);\n" - "\n" - " float fDist = RectSDF(v_v2CenteredPos, u_v2HalfShapeSizePx, " - "u_fRadiusPx - u_fHalfBorderThickness);\n" - " if (u_fHalfBorderThickness > 0.0) {\n" - " if (fDist < 0.0) {\n" - " v4ToColor = u_v4FillColor;\n" - " }\n" - " fDist = abs(fDist) - u_fHalfBorderThickness;\n" - " } else {\n" - " v4FromColor = u_v4FillColor;\n" - " }\n" - " float fBlendAmount = smoothstep(-1.0, 1.0, fDist);\n" - " vec4 c = mix(v4FromColor, v4ToColor, fBlendAmount);\n" - "\n" - " // final color\n" - " gl_FragColor = c;\n" - "\n" - "}\n"; - - const bool use_texture_rect = !ps->psglx->has_texture_non_power_of_two; - const char *sampler_type = (use_texture_rect ? "sampler2DRect" : "sampler2D"); - const char *texture_func = (use_texture_rect ? "texture2DRect" : "texture2D"); - char *extension = NULL; - if (use_texture_rect) { - mstrextend(&extension, "#extension GL_ARB_texture_rectangle : " - "require\n"); - } - if (!extension) { - extension = strdup(""); - } - - bool success = false; - // Build rounded corners shader - auto ppass = ps->psglx->round_passes; - auto len = strlen(FRAG_SHADER) + strlen(extension) + strlen(sampler_type) + - strlen(texture_func) + 1; - char *shader_str = ccalloc(len, char); - - sprintf(shader_str, FRAG_SHADER, extension, sampler_type, texture_func); - assert(strlen(shader_str) < len); - - log_debug("Generated rounded corners shader:\n%s\n", shader_str); - - ppass->frag_shader = gl_create_shader(GL_FRAGMENT_SHADER, shader_str); - free(shader_str); - - if (!ppass->frag_shader) { - log_error("Failed to create rounded corners fragment shader."); - goto out; - } - - // Build program - ppass->prog = gl_create_program(&ppass->frag_shader, 1); - if (!ppass->prog) { - log_error("Failed to create GLSL program."); - goto out; - } - - // Get uniform addresses -#define P_GET_UNIFM_LOC(name, target) \ - { \ - ppass->target = glGetUniformLocation(ppass->prog, name); \ - if (ppass->target < 0) { \ - log_debug("Failed to get location of rounded corners uniform " \ - "'" name "'. Might be troublesome."); \ - } \ - } - P_GET_UNIFM_LOC("u_radius", unifm_radius); - P_GET_UNIFM_LOC("u_texcoord", unifm_texcoord); - P_GET_UNIFM_LOC("u_texsize", unifm_texsize); - P_GET_UNIFM_LOC("u_borderw", unifm_borderw); - P_GET_UNIFM_LOC("u_borderc", unifm_borderc); - P_GET_UNIFM_LOC("u_resolution", unifm_resolution); - P_GET_UNIFM_LOC("tex_scr", unifm_tex_scr); -#undef P_GET_UNIFM_LOC - - success = true; - -out: - free(extension); - - // Restore LC_NUMERIC - setlocale(LC_NUMERIC, lc_numeric_old); - free(lc_numeric_old); - - gl_check_err(); - - return success; -} - -/** - * Load a GLSL main program from shader strings. - */ -bool glx_load_prog_main(const char *vshader_str, const char *fshader_str, - glx_prog_main_t *pprogram) { - assert(pprogram); - - // Build program - pprogram->prog = gl_create_program_from_str(vshader_str, fshader_str); - if (!pprogram->prog) { - log_error("Failed to create GLSL program."); - return false; - } - - // Get uniform addresses -#define P_GET_UNIFM_LOC(name, target) \ - { \ - pprogram->target = glGetUniformLocation(pprogram->prog, name); \ - if (pprogram->target < 0) { \ - log_error("Failed to get location of uniform '" name \ - "'. Might be troublesome."); \ - } \ - } - P_GET_UNIFM_LOC("opacity", unifm_opacity); - P_GET_UNIFM_LOC("invert_color", unifm_invert_color); - P_GET_UNIFM_LOC("tex", unifm_tex); - P_GET_UNIFM_LOC("time", unifm_time); -#undef P_GET_UNIFM_LOC - - gl_check_err(); - - return true; -} - -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); - } -} - -static inline GLuint glx_gen_texture(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; -} - -/** - * Bind an OpenGL texture and fill it with pixel data from back buffer - */ -bool glx_bind_texture(session_t *ps attr_unused, glx_texture_t **pptex, int x, int y, - int width, int height) { - if (ps->o.backend != BKEND_GLX && ps->o.backend != BKEND_XR_GLX_HYBRID) { - return true; - } - - glx_texture_t *ptex = *pptex; - - // log_trace("Copying xy(%d %d) wh(%d %d) ptex(%p)", x, y, width, height, ptex); - - // Release texture if parameters are inconsistent - if (ptex && ptex->texture && (ptex->width != width || ptex->height != height)) { - free_texture(ps, &ptex); - } - - // Allocate structure - if (!ptex) { - ptex = ccalloc(1, glx_texture_t); - *pptex = ptex; - - ptex->width = width; - ptex->height = height; - ptex->target = GL_TEXTURE_RECTANGLE; - if (ps->psglx->has_texture_non_power_of_two) { - ptex->target = GL_TEXTURE_2D; - } - } - - // Create texture - if (!ptex->texture) { - ptex->texture = glx_gen_texture(ptex->target, width, height); - } - if (!ptex->texture) { - log_error("Failed to allocate texture."); - return false; - } - - // Read destination pixels into a texture - glEnable(ptex->target); - glBindTexture(ptex->target, ptex->texture); - if (width > 0 && height > 0) { - glx_copy_region_to_tex(ps, ptex->target, x, y, x, y, width, height); - } - - // Cleanup - glBindTexture(ptex->target, 0); - glDisable(ptex->target); - - gl_check_err(); - - return true; -} - -/** - * Bind a X pixmap to an OpenGL texture. - */ -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 *fbcfg) { - if (ps->o.backend != BKEND_GLX && ps->o.backend != BKEND_XR_GLX_HYBRID) { - return true; - } - - if (!pixmap) { - log_error("Binding to an empty pixmap %#010x. This can't work.", pixmap); - return false; - } - - assert(fbcfg); - glx_texture_t *ptex = *pptex; - bool need_release = true; - - // Release pixmap if parameters are inconsistent - if (ptex && ptex->texture && ptex->pixmap != pixmap) { - glx_release_pixmap(ps, ptex); - } - - // Allocate structure - if (!ptex) { - static const glx_texture_t GLX_TEX_DEF = { - .texture = 0, - .glpixmap = 0, - .pixmap = 0, - .target = 0, - .width = 0, - .height = 0, - .y_inverted = false, - }; - - ptex = cmalloc(glx_texture_t); - memcpy(ptex, &GLX_TEX_DEF, sizeof(glx_texture_t)); - *pptex = ptex; - } - - // Create GLX pixmap - int depth = 0; - if (!ptex->glpixmap) { - need_release = false; - - // Retrieve pixmap parameters, if they aren't provided - if (!width || !height) { - auto r = xcb_get_geometry_reply( - ps->c.c, xcb_get_geometry(ps->c.c, pixmap), NULL); - if (!r) { - log_error("Failed to query info of pixmap %#010x.", pixmap); - return false; - } - if (r->depth > OPENGL_MAX_DEPTH) { - log_error("Requested depth %d higher than %d.", depth, - OPENGL_MAX_DEPTH); - return false; - } - depth = r->depth; - width = r->width; - height = r->height; - free(r); - } - - // Determine texture target, copied from compiz - // The assumption we made here is the target never changes based on any - // pixmap-specific parameters, and this may change in the future - GLenum tex_tgt = 0; - if (GLX_TEXTURE_2D_BIT_EXT & fbcfg->texture_tgts && - ps->psglx->has_texture_non_power_of_two) { - tex_tgt = GLX_TEXTURE_2D_EXT; - } else if (GLX_TEXTURE_RECTANGLE_BIT_EXT & fbcfg->texture_tgts) { - tex_tgt = GLX_TEXTURE_RECTANGLE_EXT; - } else if (!(GLX_TEXTURE_2D_BIT_EXT & fbcfg->texture_tgts)) { - tex_tgt = GLX_TEXTURE_RECTANGLE_EXT; - } else { - tex_tgt = GLX_TEXTURE_2D_EXT; - } - - log_debug("depth %d, tgt %#x, rgba %d", depth, tex_tgt, - (GLX_TEXTURE_FORMAT_RGBA_EXT == fbcfg->texture_fmt)); - - GLint attrs[] = { - GLX_TEXTURE_FORMAT_EXT, - fbcfg->texture_fmt, - GLX_TEXTURE_TARGET_EXT, - (GLint)tex_tgt, - 0, - }; - - ptex->glpixmap = glXCreatePixmap(ps->c.dpy, fbcfg->cfg, pixmap, attrs); - ptex->pixmap = pixmap; - ptex->target = - (GLX_TEXTURE_2D_EXT == tex_tgt ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE); - ptex->width = width; - ptex->height = height; - ptex->y_inverted = fbcfg->y_inverted; - } - if (!ptex->glpixmap) { - log_error("Failed to allocate GLX pixmap."); - return false; - } - - 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); - if (repeat) { - glTexParameteri(ptex->target, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(ptex->target, GL_TEXTURE_WRAP_T, GL_REPEAT); - } else { - 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) { - log_error("Failed to allocate texture."); - return false; - } - - glBindTexture(ptex->target, ptex->texture); - - // The specification requires rebinding whenever the content changes... - // We can't follow this, too slow. - if (need_release) { - glXReleaseTexImageEXT(ps->c.dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT); - } - - glXBindTexImageEXT(ps->c.dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT, NULL); - - // Cleanup - glBindTexture(ptex->target, 0); - glDisable(ptex->target); - - gl_check_err(); - - 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) { - glBindTexture(ptex->target, ptex->texture); - glXReleaseTexImageEXT(ps->c.dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT); - glBindTexture(ptex->target, 0); - } - - // Free GLX Pixmap - if (ptex->glpixmap) { - glXDestroyPixmap(ps->c.dpy, ptex->glpixmap); - ptex->glpixmap = 0; - } - - gl_check_err(); -} - -/** - * Set clipping region on the target window. - */ -void glx_set_clip(session_t *ps, const region_t *reg) { - // Quit if we aren't using stencils - if (ps->o.glx_no_stencil) { - return; - } - - glDisable(GL_STENCIL_TEST); - glDisable(GL_SCISSOR_TEST); - - if (!reg) { - return; - } - - int nrects; - const rect_t *rects = pixman_region32_rectangles((region_t *)reg, &nrects); - - if (nrects == 1) { - glEnable(GL_SCISSOR_TEST); - glScissor(rects[0].x1, ps->root_height - rects[0].y2, - rects[0].x2 - rects[0].x1, rects[0].y2 - rects[0].y1); - } - - gl_check_err(); -} - -#define P_PAINTREG_START(var) \ - region_t reg_new; \ - int nrects; \ - const rect_t *rects; \ - assert(width >= 0 && height >= 0); \ - pixman_region32_init_rect(®_new, dx, dy, (uint)width, (uint)height); \ - pixman_region32_intersect(®_new, ®_new, (region_t *)reg_tgt); \ - rects = pixman_region32_rectangles(®_new, &nrects); \ - glBegin(GL_QUADS); \ - \ - for (int ri = 0; ri < nrects; ++ri) { \ - rect_t var = rects[ri]; - -#define P_PAINTREG_END() \ - } \ - glEnd(); \ - \ - pixman_region32_fini(®_new); - -/** - * Blur contents in a particular region. - * - * XXX seems to be way to complex for what it does - */ -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) { - assert(ps->psglx->blur_passes[0].prog); - const bool more_passes = ps->o.blur_kernel_count > 1; - 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; - } - - int mdx = dx, mdy = dy, mwidth = width, mheight = height; - // log_trace("%d, %d, %d, %d", mdx, mdy, mwidth, mheight); - - /* - if (ps->o.resize_damage > 0) { - 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; - inc_x += XFIXED_TO_DOUBLE(kern[0]) / 2; - inc_y += XFIXED_TO_DOUBLE(kern[1]) / 2; - } - inc_x = min2(ps->o.resize_damage, inc_x); - inc_y = min2(ps->o.resize_damage, inc_y); - - mdx = max2(dx - inc_x, 0); - mdy = max2(dy - inc_y, 0); - int mdx2 = min2(dx + width + inc_x, ps->root_width), - mdy2 = min2(dy + height + inc_y, ps->root_height); - mwidth = mdx2 - mdx; - mheight = mdy2 - mdy; - } - */ - - GLenum tex_tgt = GL_TEXTURE_RECTANGLE; - if (ps->psglx->has_texture_non_power_of_two) { - tex_tgt = GL_TEXTURE_2D; - } - - // 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(tex_tgt, mwidth, mheight); - } - GLuint tex_scr = pbc->textures[0]; - if (more_passes && !pbc->textures[1]) { - pbc->textures[1] = glx_gen_texture(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; - - if (!tex_scr || (more_passes && !tex_scr2)) { - log_error("Failed to allocate texture."); - goto glx_blur_dst_end; - } - if (more_passes && !fbo) { - log_error("Failed to allocate framebuffer."); - goto glx_blur_dst_end; - } - - // 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); - } */ - - // Texture scaling factor - GLfloat texfac_x = 1.0F, texfac_y = 1.0F; - if (tex_tgt == GL_TEXTURE_2D) { - texfac_x /= (GLfloat)mwidth; - texfac_y /= (GLfloat)mheight; - } - - // Paint it back - if (more_passes) { - glDisable(GL_STENCIL_TEST); - glDisable(GL_SCISSOR_TEST); - } - - bool last_pass = false; - for (int i = 0; i < ps->o.blur_kernel_count; ++i) { - last_pass = (i == ps->o.blur_kernel_count - 1); - const glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i]; - assert(ppass->prog); - - assert(tex_scr); - glBindTexture(tex_tgt, tex_scr); - - if (!last_pass) { - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, tex_scr2, 0); - glDrawBuffer(GL_COLOR_ATTACHMENT0); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - log_error("Framebuffer attachment failed."); - goto glx_blur_dst_end; - } - } else { - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glDrawBuffer(GL_BACK); - if (have_scissors) { - glEnable(GL_SCISSOR_TEST); - } - if (have_stencil) { - glEnable(GL_STENCIL_TEST); - } - } - - // 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); - } - - P_PAINTREG_START(crect) { - auto rx = (GLfloat)(crect.x1 - mdx) * texfac_x; - auto ry = (GLfloat)(mheight - (crect.y1 - mdy)) * texfac_y; - auto rxe = rx + (GLfloat)(crect.x2 - crect.x1) * texfac_x; - auto rye = ry - (GLfloat)(crect.y2 - crect.y1) * texfac_y; - auto rdx = (GLfloat)(crect.x1 - mdx); - auto rdy = (GLfloat)(mheight - crect.y1 + mdy); - if (last_pass) { - rdx = (GLfloat)crect.x1; - rdy = (GLfloat)(ps->root_height - crect.y1); - } - auto rdxe = rdx + (GLfloat)(crect.x2 - crect.x1); - auto rdye = rdy - (GLfloat)(crect.y2 - crect.y1); - - // log_trace("%f, %f, %f, %f -> %f, %f, %f, %f", rx, ry, - // rxe, rye, rdx, - // rdy, rdxe, rdye); - - glTexCoord2f(rx, ry); - glVertex3f(rdx, rdy, z); - - glTexCoord2f(rxe, ry); - glVertex3f(rdxe, rdy, z); - - glTexCoord2f(rxe, rye); - glVertex3f(rdxe, rdye, z); - - glTexCoord2f(rx, rye); - glVertex3f(rdx, rdye, z); - } - P_PAINTREG_END(); - - glUseProgram(0); - - // Swap tex_scr and tex_scr2 - { - GLuint tmp = tex_scr2; - tex_scr2 = tex_scr; - tex_scr = tmp; - } - } - - ret = true; - -glx_blur_dst_end: - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glBindTexture(tex_tgt, 0); - glDisable(tex_tgt); - if (have_scissors) { - glEnable(GL_SCISSOR_TEST); - } - if (have_stencil) { - glEnable(GL_STENCIL_TEST); - } - - if (&ibc == pbc) { - free_glx_bc(ps, pbc); - } - - gl_check_err(); - - return ret; -} - -// TODO(bhagwan) this is a mess and needs a more consistent way of getting the border -// pixel I tried looking for a notify event for XCB_CW_BORDER_PIXEL (in -// xcb_create_window()) or a way to get the pixels from xcb_render_picture_t but the -// documentation for the xcb_xrender extension is literally non existent... -// -// NOTE(yshui) There is no consistent way to get the "border" color of a X window. From -// the WM's perspective there are multiple ways to implement window borders. Using -// glReadPixel is probably the most reliable way. -void glx_read_border_pixel(int root_height, int root_width, int x, int y, int width, - int height, float *ppixel) { - assert(ppixel); - - // Reset the color so the shader doesn't use it - ppixel[0] = ppixel[1] = ppixel[2] = ppixel[3] = -1.0F; - - // First try bottom left corner past the - // circle radius (after the rounded corner ends) - auto screen_x = x; - auto screen_y = root_height - height - y; - - // X is out of bounds - // move to the right side - if (screen_x < 0) { - screen_x += width; - } - - // Y is out of bounds - // move to to top part - if (screen_y < 0) { - screen_y += height; - } - - // All corners are out of bounds, give up - if (screen_x < 0 || screen_y < 0 || screen_x >= root_width || screen_y >= root_height) { - return; - } - - // Invert Y-axis so we can query border color from texture (0,0) - glReadPixels(screen_x, screen_y, 1, 1, GL_RGBA, GL_FLOAT, (void *)ppixel); - - log_trace("xy(%d, %d), glxy(%d %d) wh(%d %d), border_col(%.2f, %.2f, %.2f, %.2f)", - x, y, screen_x, screen_y, width, height, (float)ppixel[0], - (float)ppixel[1], (float)ppixel[2], (float)ppixel[3]); - - gl_check_err(); -} - -bool glx_round_corners_dst(session_t *ps, struct managed_win *w, - const glx_texture_t *ptex, int dx, int dy, int width, - int height, float z, float cr, const region_t *reg_tgt) { - assert(ps->psglx->round_passes->prog); - bool ret = false; - - // log_warn("dxy(%d, %d) wh(%d %d) rwh(%d %d) b(%d), f(%d)", - // dx, dy, width, height, ps->root_width, ps->root_height, w->g.border_width, - // w->focused); - - int mdx = dx, mdy = dy, mwidth = width, mheight = height; - log_trace("%d, %d, %d, %d", mdx, mdy, mwidth, mheight); - - if (w->g.border_width > 0) { - glx_read_border_pixel(ps->root_height, ps->root_width, dx, dy, width, - height, &w->border_col[0]); - } - - { - const glx_round_pass_t *ppass = ps->psglx->round_passes; - assert(ppass->prog); - - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - glUseProgram(ppass->prog); - - // If caller specified a texture use it as source - log_trace("ptex: %p wh(%d %d) %d %d", ptex, ptex->width, ptex->height, - ptex->target, ptex->texture); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(ptex->target, ptex->texture); - - if (ppass->unifm_tex_scr >= 0) { - glUniform1i(ppass->unifm_tex_scr, (GLint)0); - } - if (ppass->unifm_radius >= 0) { - glUniform1f(ppass->unifm_radius, cr); - } - if (ppass->unifm_texcoord >= 0) { - glUniform2f(ppass->unifm_texcoord, (float)dx, (float)dy); - } - if (ppass->unifm_texsize >= 0) { - glUniform2f(ppass->unifm_texsize, (float)mwidth, (float)mheight); - } - if (ppass->unifm_borderw >= 0) { - // Don't render rounded border if we don't know the border color - glUniform1f(ppass->unifm_borderw, - w->border_col[0] != -1. ? (GLfloat)w->g.border_width : 0); - } - if (ppass->unifm_borderc >= 0) { - glUniform4f(ppass->unifm_borderc, w->border_col[0], - w->border_col[1], w->border_col[2], w->border_col[3]); - } - if (ppass->unifm_resolution >= 0) { - glUniform2f(ppass->unifm_resolution, (float)ps->root_width, - (float)ps->root_height); - } - - // Painting - { - P_PAINTREG_START(crect) { - // texture-local coordinates - auto rx = (GLfloat)(crect.x1 - dx); - auto ry = (GLfloat)(crect.y1 - dy); - auto rxe = rx + (GLfloat)(crect.x2 - crect.x1); - auto rye = ry + (GLfloat)(crect.y2 - crect.y1); - if (GL_TEXTURE_2D == ptex->target) { - rx = rx / (GLfloat)width; - ry = ry / (GLfloat)height; - rxe = rxe / (GLfloat)width; - rye = rye / (GLfloat)height; - } - - // coordinates for the texture in the target - auto rdx = (GLfloat)crect.x1; - auto rdy = (GLfloat)(ps->root_height - crect.y1); - auto rdxe = (GLfloat)rdx + (GLfloat)(crect.x2 - crect.x1); - auto rdye = (GLfloat)rdy - (GLfloat)(crect.y2 - crect.y1); - - // Invert Y if needed, this may not work as expected, - // though. I don't have such a FBConfig to test with. - ry = 1.0F - ry; - rye = 1.0F - rye; - - // log_trace("Rect %d (i:%d): %f, %f, %f, %f -> %f, %f, - // %f, %f", ri ,ptex ? ptex->y_inverted : -1, rx, ry, - // rxe, - // rye, rdx, rdy, rdxe, rdye); - - glTexCoord2f(rx, ry); - glVertex3f(rdx, rdy, z); - - glTexCoord2f(rxe, ry); - glVertex3f(rdxe, rdy, z); - - glTexCoord2f(rxe, rye); - glVertex3f(rdxe, rdye, z); - - glTexCoord2f(rx, rye); - glVertex3f(rdx, rdye, z); - } - P_PAINTREG_END(); - } - - glUseProgram(0); - glDisable(GL_BLEND); - } - - ret = true; - - glBindTexture(ptex->target, 0); - glDisable(ptex->target); - glDisable(GL_BLEND); - - gl_check_err(); - - return ret; -} - -bool glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, int z, - GLfloat factor, const region_t *reg_tgt) { - // 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); - - 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); - - glVertex3i(rdx, rdy, z); - glVertex3i(rdxe, rdy, z); - glVertex3i(rdxe, rdye, z); - glVertex3i(rdx, rdye, z); - } - P_PAINTREG_END(); - - glColor4f(0.0F, 0.0F, 0.0F, 0.0F); - glDisable(GL_BLEND); - - gl_check_err(); - - return true; -} - -/** - * @brief Render a region with texture data. - */ -bool glx_render(session_t *ps, const glx_texture_t *ptex, int x, int y, int dx, int dy, - int width, int height, int z, double opacity, bool argb, bool neg, - const region_t *reg_tgt, const glx_prog_main_t *pprogram) { - if (!ptex || !ptex->texture) { - log_error("Missing texture."); - return false; - } - - const bool has_prog = pprogram && pprogram->prog; - 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); - - // Enable blending if needed - if (opacity < 1.0 || argb) { - - glEnable(GL_BLEND); - - // Needed for handling opacity of ARGB texture - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - // This is all weird, but X Render is using premultiplied ARGB format, and - // we need to use those things to correct it. Thanks to derhass for help. - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - glColor4d(opacity, opacity, opacity, opacity); - } - - 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); - } - } - } else { - // Programmable path - assert(pprogram->prog); - glUseProgram(pprogram->prog); - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - if (pprogram->unifm_opacity >= 0) { - glUniform1f(pprogram->unifm_opacity, (float)opacity); - } - if (pprogram->unifm_invert_color >= 0) { - glUniform1i(pprogram->unifm_invert_color, neg); - } - if (pprogram->unifm_tex >= 0) { - glUniform1i(pprogram->unifm_tex, 0); - } - if (pprogram->unifm_time >= 0) { - glUniform1f(pprogram->unifm_time, (float)ts.tv_sec * 1000.0F + - (float)ts.tv_nsec / 1.0e6F); - } - } - - // log_trace("Draw: %d, %d, %d, %d -> %d, %d (%d, %d) z %d", x, y, width, height, - // dx, dy, ptex->width, ptex->height, z); - - // Bind texture - glBindTexture(ptex->target, ptex->texture); - if (dual_texture) { - glActiveTexture(GL_TEXTURE1); - glBindTexture(ptex->target, ptex->texture); - glActiveTexture(GL_TEXTURE0); - } - - // Painting - { - P_PAINTREG_START(crect) { - // texture-local coordinates - auto rx = (GLfloat)(crect.x1 - dx + x); - auto ry = (GLfloat)(crect.y1 - dy + y); - auto rxe = rx + (GLfloat)(crect.x2 - crect.x1); - auto rye = ry + (GLfloat)(crect.y2 - crect.y1); - // 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 / (GLfloat)ptex->width; - ry = ry / (GLfloat)ptex->height; - rxe = rxe / (GLfloat)ptex->width; - rye = rye / (GLfloat)ptex->height; - } - - // coordinates for the texture in the target - 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); - - // 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.0F - ry; - rye = 1.0F - rye; - } - - // log_trace("Rect %d: %f, %f, %f, %f -> %d, %d, %d, %d", ri, rx, - // ry, rxe, rye, - // rdx, rdy, rdxe, rdye); - -#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); - glVertex3i(rdx, rdy, z); - - P_TEXCOORD(rxe, ry); - glVertex3i(rdxe, rdy, z); - - P_TEXCOORD(rxe, rye); - glVertex3i(rdxe, rdye, z); - - P_TEXCOORD(rx, rye); - glVertex3i(rdx, rdye, z); - } - P_PAINTREG_END(); - } - - // Cleanup - glBindTexture(ptex->target, 0); - 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); - glDisable(ptex->target); - - if (dual_texture) { - glActiveTexture(GL_TEXTURE1); - glBindTexture(ptex->target, 0); - glDisable(ptex->target); - glActiveTexture(GL_TEXTURE0); - } - - if (has_prog) { - glUseProgram(0); - } - - gl_check_err(); - - return true; -} diff --git a/src/opengl.h b/src/opengl.h deleted file mode 100644 index 5bf92ed4..00000000 --- a/src/opengl.h +++ /dev/null @@ -1,244 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Compton - a compositor for X11 - * - * Based on `xcompmgr` - Copyright (c) 2003, Keith Packard - * - * Copyright (c) 2011-2013, Christopher Jeffrey - * See LICENSE-mit for more information. - * - */ - -#pragma once - -#include "common.h" -#include "compiler.h" -#include "log.h" -#include "region.h" -#include "render.h" -#include "win.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -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; - -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 "borderc" in rounded-corners GLSL program. - GLint unifm_borderc; - /// Location of uniform "resolution" in rounded-corners GLSL program. - GLint unifm_resolution; - /// Location of uniform "texture_scr" in rounded-corners GLSL program. - GLint unifm_tex_scr; - -} glx_round_pass_t; - -/// Structure containing GLX-dependent data for a session. -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; - glx_blur_pass_t *blur_passes; - glx_round_pass_t *round_passes; -} glx_session_t; - -/// @brief Wrapper of a bound 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; - -#define CGLX_SESSION_INIT \ - { .context = NULL } - -bool glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, int z, - GLfloat factor, const region_t *reg_tgt); - -bool glx_render(session_t *ps, const glx_texture_t *ptex, int x, int y, int dx, int dy, - int width, int height, int z, double opacity, bool argb, bool neg, - const region_t *reg_tgt, const glx_prog_main_t *pprogram); - -bool glx_init(session_t *ps, bool need_render); - -void glx_destroy(session_t *ps); - -void glx_on_root_change(session_t *ps); - -bool glx_init_blur(session_t *ps); - -bool glx_init_rounded_corners(session_t *ps); - -#ifdef CONFIG_OPENGL -bool glx_load_prog_main(const char *vshader_str, const char *fshader_str, - glx_prog_main_t *pprogram); -#endif - -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 *); - -void glx_release_pixmap(session_t *ps, glx_texture_t *ptex); - -bool glx_bind_texture(session_t *ps, glx_texture_t **pptex, int x, int y, int width, int height); - -void glx_paint_pre(session_t *ps, region_t *preg) attr_nonnull(1, 2); - -/** - * Check if a texture is bound, or is bound to the given pixmap. - */ -static inline bool glx_tex_bound(const glx_texture_t *ptex, xcb_pixmap_t pixmap) { - return ptex && ptex->glpixmap && ptex->texture && (!pixmap || pixmap == ptex->pixmap); -} - -void glx_set_clip(session_t *ps, const region_t *reg); - -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); - -bool glx_round_corners_dst(session_t *ps, struct managed_win *w, - const glx_texture_t *ptex, int dx, int dy, int width, - int height, float z, float cr, const region_t *reg_tgt); - -GLuint glx_create_shader(GLenum shader_type, const char *shader_str); - -GLuint glx_create_program(const GLuint *const shaders, int nshaders); - -GLuint glx_create_program_from_str(const char *vert_shader_str, const char *frag_shader_str); - -unsigned char *glx_take_screenshot(session_t *ps, int *out_length); - -/** - * Check if there's a GLX context. - */ -static inline bool glx_has_context(session_t *ps) { - return ps->psglx && ps->psglx->context; -} - -/** - * Ensure we have a GLX context. - */ -static inline bool ensure_glx_context(session_t *ps) { - // Create GLX context - if (!glx_has_context(ps)) { - glx_init(ps, false); - } - - return glx_has_context(ps); -} - -/** - * Free a GLX texture. - */ -static inline void free_texture_r(session_t *ps attr_unused, GLuint *ptexture) { - if (*ptexture) { - assert(glx_has_context(ps)); - glDeleteTextures(1, ptexture); - *ptexture = 0; - } -} - -/** - * Free a GLX Framebuffer object. - */ -static inline void free_glx_fbo(GLuint *pfbo) { - if (*pfbo) { - glDeleteFramebuffers(1, pfbo); - *pfbo = 0; - } - assert(!*pfbo); -} - -/** - * Free data in glx_blur_cache_t on resize. - */ -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; -} - -/** - * Free a glx_blur_cache_t - */ -static inline void free_glx_bc(session_t *ps, glx_blur_cache_t *pbc) { - free_glx_fbo(&pbc->fbo); - free_glx_bc_resize(ps, pbc); -} - -/** - * Free a glx_texture_t. - */ -static inline void free_texture(session_t *ps, glx_texture_t **pptex) { - glx_texture_t *ptex = *pptex; - - // Quit if there's nothing - if (!ptex) { - return; - } - - glx_release_pixmap(ps, ptex); - - free_texture_r(ps, &ptex->texture); - - // Free structure itself - free(ptex); - *pptex = NULL; -} - -/** - * Free GLX part of paint_t. - */ -static inline void free_paint_glx(session_t *ps, paint_t *ppaint) { - free_texture(ps, &ppaint->ptex); - ppaint->fbcfg = (struct glx_fbconfig_info){0}; -} - -/** - * Free GLX part of win. - */ -static inline void free_win_res_glx(session_t *ps, struct managed_win *w) { - free_paint_glx(ps, &w->paint); - free_paint_glx(ps, &w->shadow_paint); -#ifdef CONFIG_OPENGL - free_glx_bc(ps, &w->glx_blur_cache); - free_texture(ps, &w->glx_texture_bg); -#endif -} diff --git a/src/options.c b/src/options.c index 148760cc..df497add 100644 --- a/src/options.c +++ b/src/options.c @@ -153,7 +153,7 @@ static const struct picom_option picom_options[] = { "need to be able to see through transparent parts of the window."}, {"blur-method" , required_argument, 328, NULL , "The algorithm used for background bluring. Available choices are: 'none' to " "disable, 'gaussian', 'box' or 'kernel' for custom convolution blur with " - "--blur-kern. Note: 'gaussian' and 'box' is not supported by --legacy-backends."}, + "--blur-kern."}, {"blur-size" , required_argument, 329, NULL , "The radius of the blur kernel for 'box' and 'gaussian' blur method."}, {"blur-deviation" , required_argument, 330, NULL , "The standard deviation for the 'gaussian' blur method."}, {"blur-strength" , required_argument, 331, NULL , "The strength level of the 'dual_kawase' blur method."}, @@ -164,20 +164,18 @@ static const struct picom_option picom_options[] = { {"corner-radius-rules" , required_argument, 340, "RADIUS:COND" , "Window rules for specific rounded corner radii."}, {"clip-shadow-above" , required_argument, 335, NULL , "Specify a list of conditions of windows to not paint a shadow over, such " "as a dock window."}, - {"window-shader-fg" , required_argument, 336, "PATH" , "Specify GLSL fragment shader path for rendering window contents. Does not" - " work when `--legacy-backends` is enabled. See man page for more details."}, + {"window-shader-fg" , required_argument, 336, "PATH" , "Specify GLSL fragment shader path for rendering window contents. " + "See man page for more details."}, {"window-shader-fg-rule" , required_argument, 337, "PATH:COND" , "Specify GLSL fragment shader path for rendering window contents using " "patterns. Pattern should be in the format of SHADER_PATH:PATTERN, " "similar to --opacity-rule. SHADER_PATH can be \"default\", in which case " - "the default shader will be used. Does not work when --legacy-backends is " - "enabled. See man page for more details"}, + "the default shader will be used. See man page for more details"}, // 338 is transparent-clipping-exclude {"dithered-present" , no_argument , 339, NULL , "Use higher precision during rendering, and apply dither when presenting the " "rendered screen. Reduces banding artifacts, but might cause performance " "degradation. Only works with OpenGL."}, // 340 is corner-radius-rules {"no-frame-pacing" , no_argument , 341, NULL , "Disable frame pacing. This might increase the latency."}, - {"legacy-backends" , no_argument , 733, NULL , "Use deprecated version of the backends."}, {"monitor-repaint" , no_argument , 800, NULL , "Highlight the updated area of the screen. For debugging."}, {"diagnostics" , no_argument , 801, NULL , "Print diagnostic information"}, {"debug-mode" , no_argument , 802, NULL , "Render into a separate window, and don't take over the screen. Useful when " @@ -381,9 +379,7 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, while (-1 != (o = getopt_long(argc, argv, shortopts, longopts, &longopt_idx))) { switch (o) { #define P_CASEBOOL(idx, option) \ - case idx: \ - opt->option = true; \ - break + case idx: opt->option = true; break #define P_CASELONG(idx, option) \ case idx: \ if (!parse_long(optarg, &opt->option)) { \ @@ -744,7 +740,6 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, opt->dithered_present = true; break; P_CASEBOOL(341, no_frame_pacing); - P_CASEBOOL(733, legacy_backends); P_CASEBOOL(800, monitor_repaint); case 801: opt->print_diagnostics = true; @@ -770,53 +765,22 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, return false; } - if (opt->monitor_repaint && opt->backend != BKEND_XRENDER && opt->legacy_backends) { - log_warn("--monitor-repaint has no effect when backend is not xrender"); - } - if (opt->backend == BKEND_EGL) { - if (opt->legacy_backends) { - log_error("The egl backend is not supported with " - "--legacy-backends"); - return false; - } log_warn("The egl backend is still experimental, use with care."); } - if (!opt->legacy_backends && !backend_list[opt->backend]) { + if (!backend_list[opt->backend]) { log_error("Backend \"%s\" is only available as part of the legacy " - "backends.", + "backends, which has been removed.", BACKEND_STRS[opt->backend]); return false; } - if (opt->debug_mode && opt->legacy_backends) { - log_error("Debug mode does not work with the legacy backends."); - return false; - } - - if (opt->transparent_clipping && opt->legacy_backends) { - log_error("Transparent clipping does not work with the legacy " - "backends"); - return false; - } - - if (opt->glx_fshader_win_str && !opt->legacy_backends) { - log_warn("--glx-fshader-win has been replaced by " - "\"--window-shader-fg\" for the new backends."); - } - - if (opt->window_shader_fg || opt->window_shader_fg_rules) { - if (opt->backend == BKEND_XRENDER || opt->legacy_backends) { - log_warn(opt->backend == BKEND_XRENDER - ? "Shader interface is not supported by the xrender " - "backend." - : "The new shader interface is not supported by the " - "legacy glx backend. You may want to use " - "--glx-fshader-win instead."); - opt->window_shader_fg = NULL; - c2_list_free(&opt->window_shader_fg_rules, free); - } + if ((opt->window_shader_fg || opt->window_shader_fg_rules) && + opt->backend == BKEND_XRENDER) { + log_warn("Shader interface is not supported by the xrender backend."); + opt->window_shader_fg = NULL; + c2_list_free(&opt->window_shader_fg_rules, free); } // Range checking and option assignments @@ -830,7 +794,7 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, opt->shadow_opacity = normalize_d(opt->shadow_opacity); opt->max_brightness = normalize_d(opt->max_brightness); if (opt->max_brightness < 1.0) { - if (opt->backend == BKEND_XRENDER || opt->legacy_backends) { + if (opt->backend == BKEND_XRENDER) { log_warn("--max-brightness is not supported by the %s backend. " "Falling back to 1.0.", opt->backend == BKEND_XRENDER ? "xrender" : "legacy glx"); @@ -879,10 +843,6 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, "capping to 20."); opt->blur_strength = 20; } - if (opt->legacy_backends) { - log_warn("Dual-kawase blur is not implemented by the legacy " - "backends."); - } } if (opt->resize_damage < 0) { diff --git a/src/picom.c b/src/picom.c index 7f5e8df4..69caebfb 100644 --- a/src/picom.c +++ b/src/picom.c @@ -40,21 +40,17 @@ #include #include +#include "backend/backend.h" +#include "c2.h" #include "common.h" #include "compiler.h" #include "config.h" +#include "diagnostic.h" #include "err.h" #include "kernel.h" -#include "picom.h" -#ifdef CONFIG_OPENGL -#include "opengl.h" -#endif -#include "backend/backend.h" -#include "c2.h" -#include "diagnostic.h" #include "log.h" +#include "picom.h" #include "region.h" -#include "render.h" #include "types.h" #include "utils.h" #include "win.h" @@ -640,7 +636,6 @@ static void destroy_backend(session_t *ps) { win_clear_flags(w, WIN_FLAGS_PIXMAP_STALE); win_release_images(ps->backend_data, w); } - free_paint(ps, &w->paint); } HASH_ITER2(ps->shaders, shader) { @@ -710,71 +705,68 @@ static bool initialize_blur(session_t *ps) { /// Init the backend and bind all the window pixmap to backend images static bool initialize_backend(session_t *ps) { - if (!ps->o.legacy_backends) { - assert(!ps->backend_data); - // Reinitialize win_data - assert(backend_list[ps->o.backend]); - ps->backend_data = - backend_list[ps->o.backend]->init(ps, session_get_target_window(ps)); - if (!ps->backend_data) { - log_fatal("Failed to initialize backend, aborting..."); - quit(ps); - return false; - } - ps->backend_data->ops = backend_list[ps->o.backend]; - ps->shadow_context = ps->backend_data->ops->create_shadow_context( - ps->backend_data, ps->o.shadow_radius); - if (!ps->shadow_context) { - log_fatal("Failed to initialize shadow context, aborting..."); - goto err; - } + assert(!ps->backend_data); + // Reinitialize win_data + assert(backend_list[ps->o.backend]); + ps->backend_data = + backend_list[ps->o.backend]->init(ps, session_get_target_window(ps)); + if (!ps->backend_data) { + log_fatal("Failed to initialize backend, aborting..."); + quit(ps); + return false; + } + ps->backend_data->ops = backend_list[ps->o.backend]; + ps->shadow_context = ps->backend_data->ops->create_shadow_context( + ps->backend_data, ps->o.shadow_radius); + if (!ps->shadow_context) { + log_fatal("Failed to initialize shadow context, aborting..."); + goto err; + } - if (!initialize_blur(ps)) { - log_fatal("Failed to prepare for background blur, aborting..."); - goto err; - } + if (!initialize_blur(ps)) { + log_fatal("Failed to prepare for background blur, aborting..."); + goto err; + } - // Create shaders - HASH_ITER2(ps->shaders, shader) { - assert(shader->backend_shader == NULL); - shader->backend_shader = ps->backend_data->ops->create_shader( - ps->backend_data, shader->source); - if (shader->backend_shader == NULL) { - log_warn("Failed to create shader for shader file %s, " - "this shader will not be used", - shader->key); + // Create shaders + HASH_ITER2(ps->shaders, shader) { + assert(shader->backend_shader == NULL); + shader->backend_shader = + ps->backend_data->ops->create_shader(ps->backend_data, shader->source); + if (shader->backend_shader == NULL) { + log_warn("Failed to create shader for shader file %s, " + "this shader will not be used", + shader->key); + } else { + if (ps->backend_data->ops->get_shader_attributes) { + shader->attributes = + ps->backend_data->ops->get_shader_attributes( + ps->backend_data, shader->backend_shader); } else { - if (ps->backend_data->ops->get_shader_attributes) { - shader->attributes = - ps->backend_data->ops->get_shader_attributes( - ps->backend_data, shader->backend_shader); - } else { - shader->attributes = 0; - } - log_debug("Shader %s has attributes %" PRIu64, - shader->key, shader->attributes); + shader->attributes = 0; } - } - - // window_stack shouldn't include window that's - // not in the hash table at this point. Since - // there cannot be any fading windows. - HASH_ITER2(ps->windows, _w) { - if (!_w->managed) { - continue; - } - auto w = (struct managed_win *)_w; - assert(w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED); - // We need to reacquire image - log_debug("Marking window %#010x (%s) for update after " - "redirection", - w->base.id, w->name); - win_set_flags(w, WIN_FLAGS_PIXMAP_STALE); - ps->pending_updates = true; + log_debug("Shader %s has attributes %" PRIu64, shader->key, + shader->attributes); } } - // The old backends binds pixmap lazily, nothing to do here + // window_stack shouldn't include window that's + // not in the hash table at this point. Since + // there cannot be any fading windows. + HASH_ITER2(ps->windows, _w) { + if (!_w->managed) { + continue; + } + auto w = (struct managed_win *)_w; + assert(w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED); + // We need to reacquire image + log_debug("Marking window %#010x (%s) for update after " + "redirection", + w->base.id, w->name); + win_set_flags(w, WIN_FLAGS_PIXMAP_STALE); + ps->pending_updates = true; + } + return true; err: if (ps->shadow_context) { @@ -802,20 +794,14 @@ static void configure_root(session_t *ps) { bool has_root_change = false; if (ps->redirected) { // On root window changes - if (!ps->o.legacy_backends) { - assert(ps->backend_data); - has_root_change = ps->backend_data->ops->root_change != NULL; - } else { - // Old backend can handle root change - has_root_change = true; - } + assert(ps->backend_data); + has_root_change = ps->backend_data->ops->root_change != NULL; if (!has_root_change) { // deinit/reinit backend and free up resources if the backend // cannot handle root change destroy_backend(ps); } - free_paint(ps, &ps->tgt_buffer); } ps->root_width = r->width; @@ -843,12 +829,6 @@ static void configure_root(session_t *ps) { pixman_region32_clear(&ps->damage_ring[i]); } ps->damage = ps->damage_ring + ps->ndamage - 1; -#ifdef CONFIG_OPENGL - // GLX root change callback - if (BKEND_GLX == ps->o.backend && ps->o.legacy_backends) { - glx_on_root_change(ps); - } -#endif if (has_root_change) { if (ps->backend_data != NULL) { ps->backend_data->ops->root_change(ps->backend_data, ps); @@ -1155,10 +1135,6 @@ static bool paint_preprocess(session_t *ps, bool *fade_running, bool *animation, } void root_damaged(session_t *ps) { - if (ps->root_tile_paint.pixmap) { - free_root_tile(ps); - } - if (!ps->redirected) { return; } @@ -1475,10 +1451,9 @@ uint8_t session_redirection_mode(session_t *ps) { if (ps->o.debug_mode) { // If the backend is not rendering to the screen, we don't need to // take over the screen. - assert(!ps->o.legacy_backends); return XCB_COMPOSITE_REDIRECT_AUTOMATIC; } - if (!ps->o.legacy_backends && !backend_list[ps->o.backend]->present) { + if (!backend_list[ps->o.backend]->present) { // if the backend doesn't render anything, we don't need to take over the // screen. return XCB_COMPOSITE_REDIRECT_AUTOMATIC; @@ -1515,12 +1490,8 @@ static bool redirect_start(session_t *ps) { return false; } - if (!ps->o.legacy_backends) { - assert(ps->backend_data); - ps->ndamage = ps->backend_data->ops->max_buffer_age; - } else { - ps->ndamage = maximum_buffer_age(ps); - } + assert(ps->backend_data); + ps->ndamage = ps->backend_data->ops->max_buffer_age; ps->damage_ring = ccalloc(ps->ndamage, region_t); ps->damage = ps->damage_ring + ps->ndamage - 1; @@ -1529,8 +1500,7 @@ static bool redirect_start(session_t *ps) { } ps->frame_pacing = !ps->o.no_frame_pacing && ps->o.vsync; - if ((ps->o.legacy_backends || ps->o.benchmark || !ps->backend_data->ops->last_render_time) && - ps->frame_pacing) { + if ((ps->o.benchmark || !ps->backend_data->ops->last_render_time) && ps->frame_pacing) { // Disable frame pacing if we are using a legacy backend or if we are in // benchmark mode, or if the backend doesn't report render time log_info("Disabling frame pacing."); @@ -1854,11 +1824,7 @@ static void draw_callback_impl(EV_P_ session_t *ps, int revents attr_unused) { static int paint = 0; log_verbose("Render start, frame %d", paint); - if (!ps->o.legacy_backends) { - did_render = paint_all_new(ps, bottom); - } else { - paint_all(ps, bottom); - } + did_render = paint_all_new(ps, bottom); log_verbose("Render end"); ps->first_frame = false; @@ -2018,9 +1984,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy, // .root_damage = XCB_NONE, .overlay = XCB_NONE, .root_tile_fill = false, - .root_tile_paint = PAINT_INIT, .tgt_picture = XCB_NONE, - .tgt_buffer = PAINT_INIT, .reg_win = XCB_NONE, #ifdef CONFIG_OPENGL .glx_prog_win = GLX_PROG_MAIN_INIT, @@ -2045,10 +2009,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy, .last_msc = 0, -#ifdef CONFIG_VSYNC_DRM - .drm_fd = -1, -#endif - .xfixes_event = 0, .xfixes_error = 0, .damage_event = 0, @@ -2299,12 +2259,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy, } } - if (ps->o.legacy_backends) { - ps->shadow_context = - (void *)gaussian_kernel_autodetect_deviation(ps->o.shadow_radius); - sum_kernel_preprocess((conv *)ps->shadow_context); - } - rebuild_shadow_exclude_reg(ps); // Query X Shape @@ -2422,7 +2376,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy, // The old backends doesn't have a automatic redirection mode log_info("The compositor is started in automatic redirection mode."); - assert(!ps->o.legacy_backends); if (backend_list[ps->o.backend]->present) { // If the backend has `present`, we couldn't be in automatic @@ -2437,12 +2390,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy, ps->drivers = detect_driver(ps->c.c, ps->backend_data, ps->c.screen_info->root); apply_driver_workarounds(ps, ps->drivers); - // Initialize filters, must be preceded by OpenGL context creation - if (ps->o.legacy_backends && !init_render(ps)) { - log_fatal("Failed to initialize the backend"); - exit(1); - } - if (ps->o.print_diagnostics) { print_diagnostics(ps, config_file, compositor_running); free(config_file_to_free); @@ -2456,20 +2403,10 @@ static session_t *session_init(int argc, char **argv, Display *dpy, free(config_file_to_free); - if (bkend_use_glx(ps) && ps->o.legacy_backends) { - auto gl_logger = gl_string_marker_logger_new(); - if (gl_logger) { - log_info("Enabling gl string marker"); - log_add_target_tls(gl_logger); - } - } - - if (!ps->o.legacy_backends) { - if (ps->o.monitor_repaint && !backend_list[ps->o.backend]->fill) { - log_warn("--monitor-repaint is not supported by the backend, " - "disabling"); - ps->o.monitor_repaint = false; - } + if (ps->o.monitor_repaint && !backend_list[ps->o.backend]->fill) { + log_warn("--monitor-repaint is not supported by the backend, " + "disabling"); + ps->o.monitor_repaint = false; } // Monitor screen changes if vsync_sw is enabled and we are using @@ -2662,19 +2599,12 @@ static void session_destroy(session_t *ps) { c2_list_free(&ps->o.window_shader_fg_rules, free); c2_state_free(ps->c2_state); - // Free tgt_{buffer,picture} and root_picture - if (ps->tgt_buffer.pict == ps->tgt_picture) { - ps->tgt_buffer.pict = XCB_NONE; - } - if (ps->tgt_picture != ps->root_picture) { x_free_picture(&ps->c, ps->tgt_picture); } x_free_picture(&ps->c, ps->root_picture); ps->tgt_picture = ps->root_picture = XCB_NONE; - free_paint(ps, &ps->tgt_buffer); - pixman_region32_fini(&ps->screen_reg); free(ps->expose_rects); @@ -2700,14 +2630,6 @@ static void session_destroy(session_t *ps) { free(shader); } -#ifdef CONFIG_VSYNC_DRM - // Close file opened for DRM VSync - if (ps->drm_fd >= 0) { - close(ps->drm_fd); - ps->drm_fd = -1; - } -#endif - // Release overlay window if (ps->overlay) { xcb_composite_release_overlay_window(ps->c.c, ps->overlay); @@ -2735,26 +2657,12 @@ static void session_destroy(session_t *ps) { ps->damaged_region = XCB_NONE; } - if (!ps->o.legacy_backends) { - // backend is deinitialized in unredirect() - assert(ps->backend_data == NULL); - } else { - deinit_render(ps); - } - -#if CONFIG_OPENGL - if (glx_has_context(ps)) { - // GLX context created, but not for rendering - glx_destroy(ps); - } -#endif + // backend is deinitialized in unredirect() + assert(ps->backend_data == NULL); // Flush all events xcb_aux_sync(ps->c.c); ev_io_stop(ps->loop, &ps->xiow); - if (ps->o.legacy_backends) { - free_conv((conv *)ps->shadow_context); - } destroy_atoms(ps->atoms); #ifdef DEBUG_XRC diff --git a/src/picom.h b/src/picom.h index d42ae042..57a1cd38 100644 --- a/src/picom.h +++ b/src/picom.h @@ -19,7 +19,6 @@ #include "config.h" #include "log.h" // XXX clean up #include "region.h" -#include "render.h" #include "types.h" #include "utils.h" #include "win.h" @@ -84,14 +83,6 @@ static inline bool array_wid_exists(const xcb_window_t *arr, int count, xcb_wind return false; } -#ifndef CONFIG_OPENGL -static inline void free_paint_glx(session_t *ps attr_unused, paint_t *p attr_unused) { -} -static inline void -free_win_res_glx(session_t *ps attr_unused, struct managed_win *w attr_unused) { -} -#endif - /** * Dump an drawable's info. */ diff --git a/src/render.c b/src/render.c deleted file mode 100644 index 6f788b79..00000000 --- a/src/render.c +++ /dev/null @@ -1,1547 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// Copyright (c) Yuxuan Shui - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "common.h" -#include "options.h" - -#ifdef CONFIG_OPENGL -#include "backend/gl/glx.h" -#include "opengl.h" - -#ifndef GLX_BACK_BUFFER_AGE_EXT -#define GLX_BACK_BUFFER_AGE_EXT 0x20F4 -#endif - -#endif - -#include "compiler.h" -#include "config.h" -#include "kernel.h" -#include "log.h" -#include "region.h" -#include "types.h" -#include "utils.h" -#include "vsync.h" -#include "win.h" -#include "x.h" - -#include "backend/backend.h" -#include "backend/backend_common.h" -#include "render.h" - -#define XRFILTER_CONVOLUTION "convolution" -#define XRFILTER_GAUSSIAN "gaussian" -#define XRFILTER_BINOMIAL "binomial" - -/** - * Bind texture in paint_t if we are using GLX backend. - */ -static inline bool paint_bind_tex(session_t *ps, paint_t *ppaint, int wid, int hei, - bool repeat, int depth, xcb_visualid_t visual, bool force) { -#ifdef CONFIG_OPENGL - // XXX This is a mess. But this will go away after the backend refactor. - if (!ppaint->pixmap) { - return false; - } - - struct glx_fbconfig_info *fbcfg; - if (!visual) { - assert(depth == 32); - if (!ps->argb_fbconfig.cfg) { - glx_find_fbconfig(&ps->c, - (struct xvisual_info){.red_size = 8, - .green_size = 8, - .blue_size = 8, - .alpha_size = 8, - .visual_depth = 32}, - &ps->argb_fbconfig); - } - if (!ps->argb_fbconfig.cfg) { - log_error("Failed to find appropriate FBConfig for 32 bit depth"); - return false; - } - fbcfg = &ps->argb_fbconfig; - } else { - auto m = x_get_visual_info(&ps->c, visual); - if (m.visual_depth < 0) { - return false; - } - - if (depth && depth != m.visual_depth) { - log_error("Mismatching visual depth: %d != %d", depth, m.visual_depth); - return false; - } - - if (!ppaint->fbcfg.cfg) { - glx_find_fbconfig(&ps->c, m, &ppaint->fbcfg); - } - if (!ppaint->fbcfg.cfg) { - log_error("Failed to find appropriate FBConfig for X pixmap"); - return false; - } - fbcfg = &ppaint->fbcfg; - } - - if (force || !glx_tex_bound(ppaint->ptex, ppaint->pixmap)) { - return glx_bind_pixmap(ps, &ppaint->ptex, ppaint->pixmap, wid, hei, - repeat, fbcfg); - } -#else - (void)ps; - (void)ppaint; - (void)wid; - (void)hei; - (void)repeat; - (void)depth; - (void)visual; - (void)force; -#endif - return true; -} - -/** - * Check if current backend uses XRender for rendering. - */ -static inline bool bkend_use_xrender(session_t *ps) { - return BKEND_XRENDER == ps->o.backend || BKEND_XR_GLX_HYBRID == ps->o.backend; -} - -int maximum_buffer_age(session_t *ps) { - if (bkend_use_glx(ps) && ps->o.use_damage) { - return CGLX_MAX_BUFFER_AGE; - } - return 1; -} - -static int get_buffer_age(session_t *ps) { -#ifdef CONFIG_OPENGL - if (bkend_use_glx(ps)) { - if (!glxext.has_GLX_EXT_buffer_age && ps->o.use_damage) { - log_warn("GLX_EXT_buffer_age not supported by your driver," - "`use-damage` has to be disabled"); - ps->o.use_damage = false; - } - if (ps->o.use_damage) { - unsigned int val; - glXQueryDrawable(ps->c.dpy, get_tgt_window(ps), - GLX_BACK_BUFFER_AGE_EXT, &val); - return (int)val ?: -1; - } - return -1; - } -#endif - return ps->o.use_damage ? 1 : -1; -} - -/** - * Reset filter on a Picture. - */ -static inline void xrfilter_reset(session_t *ps, xcb_render_picture_t p) { -#define FILTER "Nearest" - xcb_render_set_picture_filter(ps->c.c, p, strlen(FILTER), FILTER, 0, NULL); -#undef FILTER -} - -/// Set the input/output clip region of the target buffer (not the actual target!) -static inline void attr_nonnull(1, 2) set_tgt_clip(session_t *ps, region_t *reg) { - switch (ps->o.backend) { - case BKEND_XRENDER: - case BKEND_XR_GLX_HYBRID: - x_set_picture_clip_region(&ps->c, ps->tgt_buffer.pict, 0, 0, reg); - break; -#ifdef CONFIG_OPENGL - case BKEND_GLX: glx_set_clip(ps, reg); break; -#endif - default: assert(false); - } -} - -/** - * Free paint_t. - */ -void free_paint(session_t *ps, paint_t *ppaint) { -#ifdef CONFIG_OPENGL - free_paint_glx(ps, ppaint); -#endif - if (ppaint->pict != XCB_NONE) { - x_free_picture(&ps->c, ppaint->pict); - ppaint->pict = XCB_NONE; - } - if (ppaint->pixmap) { - xcb_free_pixmap(ps->c.c, ppaint->pixmap); - ppaint->pixmap = XCB_NONE; - } -} - -uint32_t -make_circle(int cx, int cy, int radius, uint32_t max_ntraps, xcb_render_trapezoid_t traps[]) { - uint32_t n = 0, k = 0; - int y1, y2; - double w; - while (k < max_ntraps) { - y1 = (int)(-radius * cos(M_PI * k / max_ntraps)); - traps[n].top = (cy + y1) * 65536; - traps[n].left.p1.y = (cy + y1) * 65536; - traps[n].right.p1.y = (cy + y1) * 65536; - w = sqrt(radius * radius - y1 * y1) * 65536; - traps[n].left.p1.x = (int)((cx * 65536) - w); - traps[n].right.p1.x = (int)((cx * 65536) + w); - - do { - k++; - y2 = (int)(-radius * cos(M_PI * k / max_ntraps)); - } while (y1 == y2); - - traps[n].bottom = (cy + y2) * 65536; - traps[n].left.p2.y = (cy + y2) * 65536; - traps[n].right.p2.y = (cy + y2) * 65536; - w = sqrt(radius * radius - y2 * y2) * 65536; - traps[n].left.p2.x = (int)((cx * 65536) - w); - traps[n].right.p2.x = (int)((cx * 65536) + w); - n++; - } - return n; -} - -uint32_t make_rectangle(int x, int y, int wid, int hei, xcb_render_trapezoid_t traps[]) { - traps[0].top = y * 65536; - traps[0].left.p1.y = y * 65536; - traps[0].left.p1.x = x * 65536; - traps[0].left.p2.y = (y + hei) * 65536; - traps[0].left.p2.x = x * 65536; - traps[0].bottom = (y + hei) * 65536; - traps[0].right.p1.x = (x + wid) * 65536; - traps[0].right.p1.y = y * 65536; - traps[0].right.p2.x = (x + wid) * 65536; - traps[0].right.p2.y = (y + hei) * 65536; - return 1; -} - -uint32_t make_rounded_window_shape(xcb_render_trapezoid_t traps[], uint32_t max_ntraps, - int cr, int wid, int hei) { - uint32_t n = make_circle(cr, cr, cr, max_ntraps, traps); - n += make_circle(wid - cr, cr, cr, max_ntraps, traps + n); - n += make_circle(wid - cr, hei - cr, cr, max_ntraps, traps + n); - n += make_circle(cr, hei - cr, cr, max_ntraps, traps + n); - n += make_rectangle(0, cr, wid, hei - 2 * cr, traps + n); - n += make_rectangle(cr, 0, wid - 2 * cr, cr, traps + n); - n += make_rectangle(cr, hei - cr, wid - 2 * cr, cr, traps + n); - return n; -} - -void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int fullwid, - int fullhei, double opacity, bool argb, bool neg, int cr, - xcb_render_picture_t pict, glx_texture_t *ptex, const region_t *reg_paint, - const glx_prog_main_t *pprogram, clip_t *clip) { - switch (ps->o.backend) { - case BKEND_XRENDER: - case BKEND_XR_GLX_HYBRID: { - auto alpha_step = (int)(opacity * MAX_ALPHA); - xcb_render_picture_t alpha_pict = ps->alpha_picts[alpha_step]; - if (alpha_step != 0) { - if (cr) { - xcb_render_picture_t p_tmp = x_create_picture_with_standard( - &ps->c, fullwid, fullhei, XCB_PICT_STANDARD_ARGB_32, 0, 0); - xcb_render_color_t trans = { - .red = 0, .blue = 0, .green = 0, .alpha = 0}; - const xcb_rectangle_t rect = { - .x = 0, - .y = 0, - .width = to_u16_checked(fullwid), - .height = to_u16_checked(fullhei)}; - xcb_render_fill_rectangles(ps->c.c, XCB_RENDER_PICT_OP_SRC, - p_tmp, trans, 1, &rect); - - uint32_t max_ntraps = to_u32_checked(cr); - xcb_render_trapezoid_t traps[4 * max_ntraps + 3]; - - uint32_t n = make_rounded_window_shape( - traps, max_ntraps, cr, fullwid, fullhei); - - xcb_render_trapezoids( - ps->c.c, XCB_RENDER_PICT_OP_OVER, alpha_pict, p_tmp, - x_get_pictfmt_for_standard(&ps->c, XCB_PICT_STANDARD_A_8), - 0, 0, n, traps); - - xcb_render_composite( - ps->c.c, XCB_RENDER_PICT_OP_OVER, pict, p_tmp, - ps->tgt_buffer.pict, to_i16_checked(x), - to_i16_checked(y), to_i16_checked(x), to_i16_checked(y), - to_i16_checked(dx), to_i16_checked(dy), - to_u16_checked(wid), to_u16_checked(hei)); - - x_free_picture(&ps->c, p_tmp); - - } else { - xcb_render_picture_t p_tmp = alpha_pict; - if (clip) { - p_tmp = x_create_picture_with_standard( - &ps->c, wid, hei, XCB_PICT_STANDARD_ARGB_32, 0, 0); - - xcb_render_color_t black = { - .red = 255, .blue = 255, .green = 255, .alpha = 255}; - const xcb_rectangle_t rect = { - .x = 0, - .y = 0, - .width = to_u16_checked(wid), - .height = to_u16_checked(hei)}; - xcb_render_fill_rectangles(ps->c.c, - XCB_RENDER_PICT_OP_SRC, - p_tmp, black, 1, &rect); - if (alpha_pict) { - xcb_render_composite( - ps->c.c, XCB_RENDER_PICT_OP_SRC, - alpha_pict, XCB_NONE, p_tmp, 0, 0, 0, - 0, 0, 0, to_u16_checked(wid), - to_u16_checked(hei)); - } - xcb_render_composite( - ps->c.c, XCB_RENDER_PICT_OP_OUT_REVERSE, - clip->pict, XCB_NONE, p_tmp, 0, 0, 0, 0, - to_i16_checked(clip->x), to_i16_checked(clip->y), - to_u16_checked(wid), to_u16_checked(hei)); - } - uint8_t op = ((!argb && !alpha_pict && !clip) - ? XCB_RENDER_PICT_OP_SRC - : XCB_RENDER_PICT_OP_OVER); - - xcb_render_composite( - ps->c.c, op, pict, p_tmp, ps->tgt_buffer.pict, - to_i16_checked(x), to_i16_checked(y), 0, 0, - to_i16_checked(dx), to_i16_checked(dy), - to_u16_checked(wid), to_u16_checked(hei)); - if (clip) { - x_free_picture(&ps->c, p_tmp); - } - } - } - break; - } -#ifdef CONFIG_OPENGL - case BKEND_GLX: - glx_render(ps, ptex, x, y, dx, dy, wid, hei, ps->psglx->z, opacity, argb, - neg, reg_paint, pprogram); - ps->psglx->z += 1; - break; -#endif - default: assert(0); - } -#ifndef CONFIG_OPENGL - (void)neg; - (void)ptex; - (void)reg_paint; - (void)pprogram; -#endif -} - -static inline void -paint_region(session_t *ps, const struct managed_win *w, int x, int y, int wid, int hei, - double opacity, const region_t *reg_paint, xcb_render_picture_t pict) { - const int dx = (w ? w->g.x : 0) + x; - const int dy = (w ? w->g.y : 0) + y; - const int fullwid = w ? w->widthb : 0; - const int fullhei = w ? w->heightb : 0; - const bool argb = (w && (win_has_alpha(w) || ps->o.force_win_blend)); - const bool neg = (w && w->invert_color); - - render(ps, x, y, dx, dy, wid, hei, fullwid, fullhei, opacity, argb, neg, - w ? w->corner_radius : 0, pict, - (w ? w->paint.ptex : ps->root_tile_paint.ptex), reg_paint, -#ifdef CONFIG_OPENGL - w ? &ps->glx_prog_win : NULL -#else - NULL -#endif - , - XCB_NONE); -} - -/** - * Check whether a paint_t contains enough data. - */ -static inline bool paint_isvalid(session_t *ps, const paint_t *ppaint) { - // Don't check for presence of Pixmap here, because older X Composite doesn't - // provide it - if (!ppaint) { - return false; - } - - if (bkend_use_xrender(ps) && !ppaint->pict) { - return false; - } - -#ifdef CONFIG_OPENGL - if (BKEND_GLX == ps->o.backend && !glx_tex_bound(ppaint->ptex, XCB_NONE)) { - return false; - } -#endif - - return true; -} - -/** - * Paint a window itself and dim it if asked. - */ -void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint) { - // Fetch Pixmap - if (!w->paint.pixmap) { - w->paint.pixmap = x_new_id(&ps->c); - set_ignore_cookie(&ps->c, xcb_composite_name_window_pixmap( - ps->c.c, w->base.id, w->paint.pixmap)); - } - - xcb_drawable_t draw = w->paint.pixmap; - if (!draw) { - log_error("Failed to get pixmap from window %#010x (%s), window won't be " - "visible", - w->base.id, w->name); - return; - } - - // XRender: Build picture - if (bkend_use_xrender(ps) && !w->paint.pict) { - xcb_render_create_picture_value_list_t pa = { - .subwindowmode = XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS, - }; - - w->paint.pict = x_create_picture_with_pictfmt_and_pixmap( - &ps->c, w->pictfmt, draw, XCB_RENDER_CP_SUBWINDOW_MODE, &pa); - } - - // GLX: Build texture - // Let glx_bind_pixmap() determine pixmap size, because if the user - // is resizing windows, the width and height we get may not be up-to-date, - // causing the jittering issue M4he reported in #7. - if (!paint_bind_tex(ps, &w->paint, 0, 0, false, 0, w->a.visual, - (!ps->o.glx_no_rebind_pixmap && w->pixmap_damaged))) { - log_error("Failed to bind texture for window %#010x.", w->base.id); - } - w->pixmap_damaged = false; - - if (!paint_isvalid(ps, &w->paint)) { - log_error("Window %#010x is missing painting data.", w->base.id); - return; - } - - const int x = w->g.x; - const int y = w->g.y; - const uint16_t wid = to_u16_checked(w->widthb); - const uint16_t hei = to_u16_checked(w->heightb); - - xcb_render_picture_t pict = w->paint.pict; - - // Invert window color, if required - if (bkend_use_xrender(ps) && w->invert_color) { - xcb_render_picture_t newpict = - x_create_picture_with_pictfmt(&ps->c, wid, hei, w->pictfmt, 0, NULL); - if (newpict) { - // Apply clipping region to save some CPU - if (reg_paint) { - region_t reg; - pixman_region32_init(®); - pixman_region32_copy(®, (region_t *)reg_paint); - pixman_region32_translate(®, -x, -y); - // FIXME XFixesSetPictureClipRegion(ps->dpy, newpict, 0, - // 0, reg); - pixman_region32_fini(®); - } - - xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_SRC, pict, - XCB_NONE, newpict, 0, 0, 0, 0, 0, 0, wid, hei); - xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_DIFFERENCE, - ps->white_picture, XCB_NONE, newpict, 0, 0, - 0, 0, 0, 0, wid, hei); - // We use an extra PictOpInReverse operation to get correct - // pixel alpha. There could be a better solution. - if (win_has_alpha(w)) { - xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_IN_REVERSE, - pict, XCB_NONE, newpict, 0, 0, 0, 0, - 0, 0, wid, hei); - } - pict = newpict; - } - } - - if (w->frame_opacity == 1) { - paint_region(ps, w, 0, 0, wid, hei, w->opacity, reg_paint, pict); - } else { - // Painting parameters - const margin_t extents = win_calc_frame_extents(w); - auto const t = extents.top; - auto const l = extents.left; - auto const b = extents.bottom; - auto const r = extents.right; - -#define COMP_BDR(cx, cy, cwid, chei) \ - paint_region(ps, w, (cx), (cy), (cwid), (chei), w->frame_opacity * w->opacity, \ - reg_paint, pict) - - // Sanitize the margins, in case some broken WM makes - // top_width + bottom_width > height in some cases. - - do { - // top - int body_height = hei; - // ctop = checked top - // Make sure top margin is smaller than height - int ctop = min2(body_height, t); - if (ctop > 0) { - COMP_BDR(0, 0, wid, ctop); - } - - body_height -= ctop; - if (body_height <= 0) { - break; - } - - // bottom - // cbot = checked bottom - // Make sure bottom margin is not too large - int cbot = min2(body_height, b); - if (cbot > 0) { - COMP_BDR(0, hei - cbot, wid, cbot); - } - - // Height of window exclude the margin - body_height -= cbot; - if (body_height <= 0) { - break; - } - - // left - int body_width = wid; - int cleft = min2(body_width, l); - if (cleft > 0) { - COMP_BDR(0, ctop, cleft, body_height); - } - - body_width -= cleft; - if (body_width <= 0) { - break; - } - - // right - int cright = min2(body_width, r); - if (cright > 0) { - COMP_BDR(wid - cright, ctop, cright, body_height); - } - - body_width -= cright; - if (body_width <= 0) { - break; - } - - // body - paint_region(ps, w, cleft, ctop, body_width, body_height, - w->opacity, reg_paint, pict); - } while (0); - } - -#undef COMP_BDR - - if (pict != w->paint.pict) { - x_free_picture(&ps->c, pict); - pict = XCB_NONE; - } - - // Dimming the window if needed - if (w->dim) { - double dim_opacity = ps->o.inactive_dim; - if (!ps->o.inactive_dim_fixed) { - dim_opacity *= w->opacity; - } - - switch (ps->o.backend) { - case BKEND_XRENDER: - case BKEND_XR_GLX_HYBRID: { - auto cval = (uint16_t)(0xffff * dim_opacity); - - // Premultiply color - xcb_render_color_t color = { - .red = 0, - .green = 0, - .blue = 0, - .alpha = cval, - }; - - xcb_rectangle_t rect = { - .x = to_i16_checked(x), - .y = to_i16_checked(y), - .width = wid, - .height = hei, - }; - - xcb_render_fill_rectangles(ps->c.c, XCB_RENDER_PICT_OP_OVER, - ps->tgt_buffer.pict, color, 1, &rect); - } break; -#ifdef CONFIG_OPENGL - case BKEND_GLX: - glx_dim_dst(ps, x, y, wid, hei, (int)(ps->psglx->z - 0.7), - (float)dim_opacity, reg_paint); - break; -#endif - default: assert(false); - } - } -} - -static bool get_root_tile(session_t *ps) { - /* - if (ps->o.paint_on_overlay) { - return ps->root_picture; - } */ - - assert(!ps->root_tile_paint.pixmap); - ps->root_tile_fill = false; - - bool fill = false; - xcb_pixmap_t pixmap = x_get_root_back_pixmap(&ps->c, ps->atoms); - - xcb_get_geometry_reply_t *r; - if (pixmap) { - r = xcb_get_geometry_reply(ps->c.c, xcb_get_geometry(ps->c.c, pixmap), NULL); - } - - // Create a pixmap if there isn't any - xcb_visualid_t visual; - if (!pixmap || !r) { - pixmap = - x_create_pixmap(&ps->c, (uint8_t)ps->c.screen_info->root_depth, 1, 1); - if (pixmap == XCB_NONE) { - log_error("Failed to create pixmaps for root tile."); - return false; - } - visual = ps->c.screen_info->root_visual; - fill = true; - } else { - visual = r->depth == ps->c.screen_info->root_depth - ? ps->c.screen_info->root_visual - : x_get_visual_for_depth(ps->c.screen_info, r->depth); - free(r); - } - - // Create Picture - xcb_render_create_picture_value_list_t pa = { - .repeat = true, - }; - ps->root_tile_paint.pict = x_create_picture_with_visual_and_pixmap( - &ps->c, visual, pixmap, XCB_RENDER_CP_REPEAT, &pa); - - // Fill pixmap if needed - if (fill) { - xcb_render_color_t col; - xcb_rectangle_t rect; - - col.red = col.green = col.blue = 0x8080; - col.alpha = 0xffff; - - rect.x = rect.y = 0; - rect.width = rect.height = 1; - - xcb_render_fill_rectangles(ps->c.c, XCB_RENDER_PICT_OP_SRC, - ps->root_tile_paint.pict, col, 1, &rect); - } - - ps->root_tile_fill = fill; - ps->root_tile_paint.pixmap = pixmap; -#ifdef CONFIG_OPENGL - if (BKEND_GLX == ps->o.backend) { - return paint_bind_tex(ps, &ps->root_tile_paint, 0, 0, true, 0, visual, false); - } -#endif - - return true; -} - -/** - * Paint root window content. - */ -static void paint_root(session_t *ps, const region_t *reg_paint) { - // If there is no root tile pixmap, try getting one. - // If that fails, give up. - if (!ps->root_tile_paint.pixmap && !get_root_tile(ps)) { - return; - } - - paint_region(ps, NULL, 0, 0, ps->root_width, ps->root_height, 1.0, reg_paint, - ps->root_tile_paint.pict); -} - -/** - * Generate shadow Picture for a window. - */ -static bool win_build_shadow(session_t *ps, struct managed_win *w, double opacity) { - const int width = w->widthb; - const int height = w->heightb; - // log_trace("(): building shadow for %s %d %d", w->name, width, height); - - xcb_image_t *shadow_image = NULL; - xcb_pixmap_t shadow_pixmap = XCB_NONE, shadow_pixmap_argb = XCB_NONE; - xcb_render_picture_t shadow_picture = XCB_NONE, shadow_picture_argb = XCB_NONE; - xcb_gcontext_t gc = XCB_NONE; - - shadow_image = - make_shadow(&ps->c, (conv *)ps->shadow_context, opacity, width, height); - if (!shadow_image) { - log_error("failed to make shadow"); - return XCB_NONE; - } - - shadow_pixmap = x_create_pixmap(&ps->c, 8, shadow_image->width, shadow_image->height); - shadow_pixmap_argb = - x_create_pixmap(&ps->c, 32, shadow_image->width, shadow_image->height); - - if (!shadow_pixmap || !shadow_pixmap_argb) { - log_error("failed to create shadow pixmaps"); - goto shadow_picture_err; - } - - shadow_picture = x_create_picture_with_standard_and_pixmap( - &ps->c, XCB_PICT_STANDARD_A_8, shadow_pixmap, 0, NULL); - shadow_picture_argb = x_create_picture_with_standard_and_pixmap( - &ps->c, XCB_PICT_STANDARD_ARGB_32, shadow_pixmap_argb, 0, NULL); - if (!shadow_picture || !shadow_picture_argb) { - goto shadow_picture_err; - } - - gc = x_new_id(&ps->c); - xcb_create_gc(ps->c.c, gc, shadow_pixmap, 0, NULL); - - xcb_image_put(ps->c.c, shadow_pixmap, gc, shadow_image, 0, 0, 0); - xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_SRC, ps->cshadow_picture, - shadow_picture, shadow_picture_argb, 0, 0, 0, 0, 0, 0, - shadow_image->width, shadow_image->height); - - assert(!w->shadow_paint.pixmap); - w->shadow_paint.pixmap = shadow_pixmap_argb; - assert(!w->shadow_paint.pict); - w->shadow_paint.pict = shadow_picture_argb; - - xcb_free_gc(ps->c.c, gc); - xcb_image_destroy(shadow_image); - xcb_free_pixmap(ps->c.c, shadow_pixmap); - x_free_picture(&ps->c, shadow_picture); - - return true; - -shadow_picture_err: - if (shadow_image) { - xcb_image_destroy(shadow_image); - } - if (shadow_pixmap) { - xcb_free_pixmap(ps->c.c, shadow_pixmap); - } - if (shadow_pixmap_argb) { - xcb_free_pixmap(ps->c.c, shadow_pixmap_argb); - } - if (shadow_picture) { - x_free_picture(&ps->c, shadow_picture); - } - if (shadow_picture_argb) { - x_free_picture(&ps->c, shadow_picture_argb); - } - if (gc) { - xcb_free_gc(ps->c.c, gc); - } - - return false; -} - -/** - * Paint the shadow of a window. - */ -static inline void -win_paint_shadow(session_t *ps, struct managed_win *w, region_t *reg_paint) { - // Bind shadow pixmap to GLX texture if needed - paint_bind_tex(ps, &w->shadow_paint, 0, 0, false, 32, 0, false); - - if (!paint_isvalid(ps, &w->shadow_paint)) { - log_error("Window %#010x is missing shadow data.", w->base.id); - return; - } - - xcb_render_picture_t td = XCB_NONE; - bool should_clip = - (w->corner_radius > 0) && (!ps->o.wintype_option[w->window_type].full_shadow); - if (should_clip) { - if (ps->o.backend == BKEND_XRENDER || ps->o.backend == BKEND_XR_GLX_HYBRID) { - uint32_t max_ntraps = to_u32_checked(w->corner_radius); - xcb_render_trapezoid_t traps[4 * max_ntraps + 3]; - uint32_t n = make_rounded_window_shape( - traps, max_ntraps, w->corner_radius, w->widthb, w->heightb); - - td = x_create_picture_with_standard( - &ps->c, w->widthb, w->heightb, XCB_PICT_STANDARD_ARGB_32, 0, 0); - xcb_render_color_t trans = { - .red = 0, .blue = 0, .green = 0, .alpha = 0}; - const xcb_rectangle_t rect = {.x = 0, - .y = 0, - .width = to_u16_checked(w->widthb), - .height = to_u16_checked(w->heightb)}; - xcb_render_fill_rectangles(ps->c.c, XCB_RENDER_PICT_OP_SRC, td, - trans, 1, &rect); - - auto solid = solid_picture(&ps->c, false, 1, 0, 0, 0); - xcb_render_trapezoids( - ps->c.c, XCB_RENDER_PICT_OP_OVER, solid, td, - x_get_pictfmt_for_standard(&ps->c, XCB_PICT_STANDARD_A_8), 0, - 0, n, traps); - x_free_picture(&ps->c, solid); - } else { - // Not implemented - } - } - - clip_t clip = { - .pict = td, - .x = -(w->shadow_dx), - .y = -(w->shadow_dy), - }; - render(ps, 0, 0, w->g.x + w->shadow_dx, w->g.y + w->shadow_dy, w->shadow_width, - w->shadow_height, w->widthb, w->heightb, w->shadow_opacity, true, false, 0, - w->shadow_paint.pict, w->shadow_paint.ptex, reg_paint, NULL, - should_clip ? &clip : NULL); - if (td) { - x_free_picture(&ps->c, td); - } -} - -/** - * @brief Blur an area on a buffer. - * - * @param ps current session - * @param tgt_buffer a buffer as both source and destination - * @param x x pos - * @param y y pos - * @param wid width - * @param hei height - * @param blur_kerns blur kernels, ending with a NULL, guaranteed to have at - * least one kernel - * @param reg_clip a clipping region to be applied on intermediate buffers - * - * @return true if successful, false otherwise - */ -static bool -xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t x, int16_t y, - uint16_t wid, uint16_t hei, struct x_convolution_kernel **blur_kerns, - int nkernels, const region_t *reg_clip, xcb_render_picture_t rounded) { - assert(blur_kerns); - assert(blur_kerns[0]); - - // Directly copying from tgt_buffer to it does not work, so we create a - // Picture in the middle. - xcb_render_picture_t tmp_picture = x_create_picture_with_visual( - &ps->c, wid, hei, ps->c.screen_info->root_visual, 0, NULL); - - if (!tmp_picture) { - log_error("Failed to build intermediate Picture."); - return false; - } - - if (reg_clip && tmp_picture) { - x_set_picture_clip_region(&ps->c, tmp_picture, 0, 0, reg_clip); - } - - xcb_render_picture_t src_pict = tgt_buffer, dst_pict = tmp_picture; - for (int i = 0; i < nkernels; ++i) { - xcb_render_fixed_t *convolution_blur = blur_kerns[i]->kernel; - // `x / 65536.0` converts from X fixed point to double - int kwid = (int)((double)convolution_blur[0] / 65536.0), - khei = (int)((double)convolution_blur[1] / 65536.0); - bool rd_from_tgt = (tgt_buffer == src_pict); - - // Copy from source picture to destination. The filter must - // be applied on source picture, to get the nearby pixels outside the - // window. - xcb_render_set_picture_filter( - ps->c.c, src_pict, strlen(XRFILTER_CONVOLUTION), XRFILTER_CONVOLUTION, - (uint32_t)(kwid * khei + 2), convolution_blur); - xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_SRC, src_pict, XCB_NONE, - dst_pict, (rd_from_tgt ? x : 0), - (rd_from_tgt ? y : 0), 0, 0, (rd_from_tgt ? 0 : x), - (rd_from_tgt ? 0 : y), wid, hei); - xrfilter_reset(ps, src_pict); - - { - xcb_render_picture_t tmp = src_pict; - src_pict = dst_pict; - dst_pict = tmp; - } - } - - if (src_pict != tgt_buffer) { - xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_OVER, src_pict, rounded, - tgt_buffer, 0, 0, 0, 0, x, y, wid, hei); - } - - x_free_picture(&ps->c, tmp_picture); - - return true; -} - -/** - * Blur the background of a window. - */ -static inline void -win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t tgt_buffer, - const region_t *reg_paint) { - const int16_t x = w->g.x; - const int16_t y = w->g.y; - auto const wid = to_u16_checked(w->widthb); - auto const hei = to_u16_checked(w->heightb); - const int cr = w ? w->corner_radius : 0; - - double factor_center = 1.0; - // Adjust blur strength according to window opacity, to make it appear - // better during fading - if (!ps->o.blur_background_fixed) { - double pct = 1.0 - w->opacity * (1.0 - 1.0 / 9.0); - factor_center = pct * 8.0 / (1.1 - pct); - } - - switch (ps->o.backend) { - case BKEND_XRENDER: - case BKEND_XR_GLX_HYBRID: { - // Normalize blur kernels - for (int i = 0; i < ps->o.blur_kernel_count; i++) { - // Note: `x * 65536` converts double `x` to a X fixed point - // representation. `x / 65536` is the other way. - auto kern_src = ps->o.blur_kerns[i]; - auto kern_dst = ps->blur_kerns_cache[i]; - - assert(!kern_dst || (kern_src->w == kern_dst->kernel[0] / 65536 && - kern_src->h == kern_dst->kernel[1] / 65536)); - - // Skip for fixed factor_center if the cache exists already - if (ps->o.blur_background_fixed && kern_dst) { - continue; - } - - x_create_convolution_kernel(kern_src, factor_center, - &ps->blur_kerns_cache[i]); - } - - xcb_render_picture_t td = XCB_NONE; - if (cr) { - uint32_t max_ntraps = to_u32_checked(cr); - xcb_render_trapezoid_t traps[4 * max_ntraps + 3]; - uint32_t n = - make_rounded_window_shape(traps, max_ntraps, cr, wid, hei); - - td = x_create_picture_with_standard( - &ps->c, wid, hei, XCB_PICT_STANDARD_ARGB_32, 0, 0); - xcb_render_color_t trans = { - .red = 0, .blue = 0, .green = 0, .alpha = 0}; - const xcb_rectangle_t rect = {.x = 0, - .y = 0, - .width = to_u16_checked(wid), - .height = to_u16_checked(hei)}; - xcb_render_fill_rectangles(ps->c.c, XCB_RENDER_PICT_OP_SRC, td, - trans, 1, &rect); - - auto solid = solid_picture(&ps->c, false, 1, 0, 0, 0); - - xcb_render_trapezoids( - ps->c.c, XCB_RENDER_PICT_OP_OVER, solid, td, - x_get_pictfmt_for_standard(&ps->c, XCB_PICT_STANDARD_A_8), 0, - 0, n, traps); - x_free_picture(&ps->c, solid); - } - - // Minimize the region we try to blur, if the window itself is not - // opaque, only the frame is. - region_t reg_blur = win_get_bounding_shape_global_by_val(w); - if (w->mode == WMODE_FRAME_TRANS && !ps->o.force_win_blend) { - region_t reg_noframe; - pixman_region32_init(®_noframe); - win_get_region_noframe_local(w, ®_noframe); - pixman_region32_translate(®_noframe, w->g.x, w->g.y); - pixman_region32_subtract(®_blur, ®_blur, ®_noframe); - pixman_region32_fini(®_noframe); - } - - // Translate global coordinates to local ones - pixman_region32_translate(®_blur, -x, -y); - xr_blur_dst(ps, tgt_buffer, x, y, wid, hei, ps->blur_kerns_cache, - ps->o.blur_kernel_count, ®_blur, td); - if (td) { - x_free_picture(&ps->c, td); - } - pixman_region32_clear(®_blur); - } break; -#ifdef CONFIG_OPENGL - case BKEND_GLX: - // TODO(compton) Handle frame opacity - glx_blur_dst(ps, x, y, wid, hei, (float)ps->psglx->z - 0.5F, - (float)factor_center, reg_paint, &w->glx_blur_cache); - break; -#endif - default: assert(0); - } -#ifndef CONFIG_OPENGL - (void)reg_paint; -#endif -} - -/// paint all windows -/// region = ?? -/// region_real = the damage region -void paint_all(session_t *ps, struct managed_win *t) { - if (ps->o.xrender_sync_fence || (ps->drivers & DRIVER_NVIDIA)) { - if (ps->xsync_exists && !x_fence_sync(&ps->c, ps->sync_fence)) { - log_error("x_fence_sync failed, xrender-sync-fence will be " - "disabled from now on."); - xcb_sync_destroy_fence(ps->c.c, ps->sync_fence); - ps->sync_fence = XCB_NONE; - ps->o.xrender_sync_fence = false; - ps->xsync_exists = false; - } - } - - region_t region; - pixman_region32_init(®ion); - int buffer_age = get_buffer_age(ps); - if (buffer_age == -1 || buffer_age > ps->ndamage) { - pixman_region32_copy(®ion, &ps->screen_reg); - } else { - for (int i = 0; i < get_buffer_age(ps); i++) { - auto curr = ((ps->damage - ps->damage_ring) + i) % ps->ndamage; - pixman_region32_union(®ion, ®ion, &ps->damage_ring[curr]); - } - } - - if (!pixman_region32_not_empty(®ion)) { - return; - } - -#ifdef DEBUG_REPAINT - static struct timespec last_paint = {0}; -#endif - - if (ps->o.resize_damage > 0) { - resize_region_in_place(®ion, ps->o.resize_damage, ps->o.resize_damage); - } - - // Remove the damaged area out of screen - pixman_region32_intersect(®ion, ®ion, &ps->screen_reg); - - if (!paint_isvalid(ps, &ps->tgt_buffer)) { - if (!ps->tgt_buffer.pixmap) { - free_paint(ps, &ps->tgt_buffer); - ps->tgt_buffer.pixmap = - x_create_pixmap(&ps->c, ps->c.screen_info->root_depth, - ps->root_width, ps->root_height); - if (ps->tgt_buffer.pixmap == XCB_NONE) { - log_fatal("Failed to allocate a screen-sized pixmap for" - "painting"); - exit(1); - } - } - - if (BKEND_GLX != ps->o.backend) { - ps->tgt_buffer.pict = x_create_picture_with_visual_and_pixmap( - &ps->c, ps->c.screen_info->root_visual, ps->tgt_buffer.pixmap, - 0, 0); - } - } - - if (BKEND_XRENDER == ps->o.backend) { - x_set_picture_clip_region(&ps->c, ps->tgt_picture, 0, 0, ®ion); - } - -#ifdef CONFIG_OPENGL - if (bkend_use_glx(ps)) { - ps->psglx->z = 0; - } -#endif - - region_t reg_tmp, *reg_paint; - pixman_region32_init(®_tmp); - if (t) { - // Calculate the region upon which the root window is to be - // painted based on the ignore region of the lowest window, if - // available - pixman_region32_subtract(®_tmp, ®ion, t->reg_ignore); - reg_paint = ®_tmp; - } else { - reg_paint = ®ion; - } - - // Region on screen we don't want any shadows on - region_t reg_shadow_clip; - pixman_region32_init(®_shadow_clip); - - set_tgt_clip(ps, reg_paint); - paint_root(ps, reg_paint); - - // Windows are sorted from bottom to top - // Each window has a reg_ignore, which is the region obscured by all the - // windows on top of that window. This is used to reduce the number of - // pixels painted. - // - // Whether this is beneficial is to be determined XXX - for (auto w = t; w; w = w->prev_trans) { - region_t bshape_no_corners = - win_get_bounding_shape_global_without_corners_by_val(w); - region_t bshape_corners = win_get_bounding_shape_global_by_val(w); - // Painting shadow - if (w->shadow) { - // Lazy shadow building - if (!w->shadow_paint.pixmap) { - if (!win_build_shadow(ps, w, 1)) { - log_error("build shadow failed"); - } - } - - // Shadow doesn't need to be painted underneath the body - // of the windows above. Because no one can see it - pixman_region32_subtract(®_tmp, ®ion, w->reg_ignore); - - // Mask out the region we don't want shadow on - if (pixman_region32_not_empty(&ps->shadow_exclude_reg)) { - pixman_region32_subtract(®_tmp, ®_tmp, - &ps->shadow_exclude_reg); - } - if (pixman_region32_not_empty(®_shadow_clip)) { - pixman_region32_subtract(®_tmp, ®_tmp, ®_shadow_clip); - } - - // Might be worth while to crop the region to shadow - // border - assert(w->shadow_width >= 0 && w->shadow_height >= 0); - pixman_region32_intersect_rect( - ®_tmp, ®_tmp, w->g.x + w->shadow_dx, w->g.y + w->shadow_dy, - (uint)w->shadow_width, (uint)w->shadow_height); - - // Mask out the body of the window from the shadow if - // needed Doing it here instead of in make_shadow() for - // saving GPU power and handling shaped windows (XXX - // unconfirmed) - if (!ps->o.wintype_option[w->window_type].full_shadow) { - pixman_region32_subtract(®_tmp, ®_tmp, &bshape_no_corners); - } - - if (ps->o.crop_shadow_to_monitor && w->randr_monitor >= 0 && - w->randr_monitor < ps->monitors.count) { - // There can be a window where number of monitors is - // updated, but the monitor number attached to the window - // have not. - // - // Window monitor number will be updated eventually, so - // here we just check to make sure we don't access out of - // bounds. - pixman_region32_intersect( - ®_tmp, ®_tmp, - &ps->monitors.regions[w->randr_monitor]); - } - - // Detect if the region is empty before painting - if (pixman_region32_not_empty(®_tmp)) { - set_tgt_clip(ps, ®_tmp); - win_paint_shadow(ps, w, ®_tmp); - } - } - - // Only clip shadows above visible windows - if (w->opacity * MAX_ALPHA >= 1) { - if (w->clip_shadow_above) { - // Add window bounds to shadow-clip region - pixman_region32_union(®_shadow_clip, ®_shadow_clip, - &bshape_corners); - } else { - // Remove overlapping window bounds from shadow-clip - // region - pixman_region32_subtract( - ®_shadow_clip, ®_shadow_clip, &bshape_corners); - } - } - - // Calculate the paint region based on the reg_ignore of the current - // window and its bounding region. - // Remember, reg_ignore is the union of all windows above the current - // window. - pixman_region32_subtract(®_tmp, ®ion, w->reg_ignore); - pixman_region32_intersect(®_tmp, ®_tmp, &bshape_corners); - pixman_region32_fini(&bshape_corners); - pixman_region32_fini(&bshape_no_corners); - - if (pixman_region32_not_empty(®_tmp)) { - set_tgt_clip(ps, ®_tmp); - -#ifdef CONFIG_OPENGL - // If rounded corners backup the region first - if (w->corner_radius > 0 && ps->o.backend == BKEND_GLX) { - const int16_t x = w->g.x; - const int16_t y = w->g.y; - auto const wid = to_u16_checked(w->widthb); - auto const hei = to_u16_checked(w->heightb); - glx_bind_texture(ps, &w->glx_texture_bg, x, y, wid, hei); - } -#endif - - // Blur window background - if (w->blur_background && - (w->mode == WMODE_TRANS || - (ps->o.blur_background_frame && w->mode == WMODE_FRAME_TRANS) || - ps->o.force_win_blend)) { - win_blur_background(ps, w, ps->tgt_buffer.pict, ®_tmp); - } - - // Painting the window - paint_one(ps, w, ®_tmp); - -#ifdef CONFIG_OPENGL - // Rounded corners for XRender is implemented inside render() - // Round window corners - if (w->corner_radius > 0 && ps->o.backend == BKEND_GLX) { - auto const wid = to_u16_checked(w->widthb); - auto const hei = to_u16_checked(w->heightb); - glx_round_corners_dst(ps, w, w->glx_texture_bg, w->g.x, - w->g.y, wid, hei, - (float)ps->psglx->z - 0.5F, - (float)w->corner_radius, ®_tmp); - } -#endif - } - } - - // Free up all temporary regions - pixman_region32_fini(®_tmp); - pixman_region32_fini(®_shadow_clip); - - // Move the head of the damage ring - ps->damage = ps->damage - 1; - if (ps->damage < ps->damage_ring) { - ps->damage = ps->damage_ring + ps->ndamage - 1; - } - pixman_region32_clear(ps->damage); - - // Do this as early as possible - set_tgt_clip(ps, &ps->screen_reg); - - if (ps->o.vsync) { - // Make sure all previous requests are processed to achieve best - // effect - xcb_aux_sync(ps->c.c); -#ifdef CONFIG_OPENGL - if (glx_has_context(ps)) { - if (ps->o.vsync_use_glfinish) { - glFinish(); - } else { - glFlush(); - } - glXWaitX(); - } -#endif - } - - if (ps->vsync_wait) { - ps->vsync_wait(ps); - } - - auto rwidth = to_u16_checked(ps->root_width); - auto rheight = to_u16_checked(ps->root_height); - switch (ps->o.backend) { - case BKEND_XRENDER: - if (ps->o.monitor_repaint) { - // Copy the screen content to a new picture, and highlight the - // paint region. This is not very efficient, but since it's for - // debug only, we don't really care - - // First we create a new picture, and copy content from the buffer - // to it - auto pictfmt = x_get_pictform_for_visual( - &ps->c, ps->c.screen_info->root_visual); - xcb_render_picture_t new_pict = x_create_picture_with_pictfmt( - &ps->c, rwidth, rheight, pictfmt, 0, NULL); - xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_SRC, - ps->tgt_buffer.pict, XCB_NONE, new_pict, 0, - 0, 0, 0, 0, 0, rwidth, rheight); - - // Next, we set the region of paint and highlight it - x_set_picture_clip_region(&ps->c, new_pict, 0, 0, ®ion); - xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_OVER, ps->white_picture, - ps->alpha_picts[MAX_ALPHA / 2], new_pict, 0, - 0, 0, 0, 0, 0, rwidth, rheight); - - // Finally, clear clip regions of new_pict and the screen, and put - // the whole thing on screen - x_set_picture_clip_region(&ps->c, new_pict, 0, 0, &ps->screen_reg); - x_set_picture_clip_region(&ps->c, ps->tgt_picture, 0, 0, - &ps->screen_reg); - xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_SRC, new_pict, - XCB_NONE, ps->tgt_picture, 0, 0, 0, 0, 0, 0, - rwidth, rheight); - x_free_picture(&ps->c, new_pict); - } else { - xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_SRC, - ps->tgt_buffer.pict, XCB_NONE, ps->tgt_picture, - 0, 0, 0, 0, 0, 0, rwidth, rheight); - } - break; -#ifdef CONFIG_OPENGL - case BKEND_XR_GLX_HYBRID: - xcb_aux_sync(ps->c.c); - if (ps->o.vsync_use_glfinish) { - glFinish(); - } else { - glFlush(); - } - glXWaitX(); - assert(ps->tgt_buffer.pixmap); - paint_bind_tex(ps, &ps->tgt_buffer, ps->root_width, ps->root_height, - false, ps->c.screen_info->root_depth, - ps->c.screen_info->root_visual, !ps->o.glx_no_rebind_pixmap); - if (ps->o.vsync_use_glfinish) { - glFinish(); - } else { - glFlush(); - } - glXWaitX(); - glx_render(ps, ps->tgt_buffer.ptex, 0, 0, 0, 0, ps->root_width, - ps->root_height, 0, 1.0, false, false, ®ion, NULL); - fallthrough(); - case BKEND_GLX: glXSwapBuffers(ps->c.dpy, get_tgt_window(ps)); break; -#endif - default: assert(0); - } - - xcb_aux_sync(ps->c.c); - -#ifdef CONFIG_OPENGL - if (glx_has_context(ps)) { - glFlush(); - glXWaitX(); - } -#endif - -#ifdef DEBUG_REPAINT - struct timespec now = get_time_timespec(); - struct timespec diff = {0}; - timespec_subtract(&diff, &now, &last_paint); - log_trace("[ %5ld:%09ld ] ", diff.tv_sec, diff.tv_nsec); - last_paint = now; - log_trace("paint:"); - for (win *w = t; w; w = w->prev_trans) - log_trace(" %#010lx", w->id); -#endif - - // Free the paint region - pixman_region32_fini(®ion); -} - -/** - * Query needed X Render / OpenGL filters to check for their existence. - */ -static bool xr_init_blur(session_t *ps) { - // Query filters - xcb_render_query_filters_reply_t *pf = xcb_render_query_filters_reply( - ps->c.c, xcb_render_query_filters(ps->c.c, get_tgt_window(ps)), NULL); - if (pf) { - xcb_str_iterator_t iter = xcb_render_query_filters_filters_iterator(pf); - for (; iter.rem; xcb_str_next(&iter)) { - int len = xcb_str_name_length(iter.data); - char *name = xcb_str_name(iter.data); - // Check for the convolution filter - if (strlen(XRFILTER_CONVOLUTION) == len && - !memcmp(XRFILTER_CONVOLUTION, name, strlen(XRFILTER_CONVOLUTION))) { - ps->xrfilter_convolution_exists = true; - } - } - free(pf); - } - - // Turn features off if any required filter is not present - if (!ps->xrfilter_convolution_exists) { - log_error("Xrender convolution filter " - "unsupported by your X server. " - "Background blur is not possible."); - return false; - } - - return true; -} - -/** - * Pregenerate alpha pictures. - */ -static bool init_alpha_picts(session_t *ps) { - ps->alpha_picts = ccalloc(MAX_ALPHA + 1, xcb_render_picture_t); - - for (int i = 0; i <= MAX_ALPHA; ++i) { - double o = (double)i / MAX_ALPHA; - ps->alpha_picts[i] = solid_picture(&ps->c, false, o, 0, 0, 0); - if (ps->alpha_picts[i] == XCB_NONE) { - return false; - } - } - return true; -} - -bool init_render(session_t *ps) { - if (ps->o.backend == BKEND_DUMMY) { - return false; - } - - // Initialize OpenGL as early as possible -#ifdef CONFIG_OPENGL - glxext_init(ps->c.dpy, ps->c.screen); -#endif - if (bkend_use_glx(ps)) { -#ifdef CONFIG_OPENGL - if (!glx_init(ps, true)) { - return false; - } -#else - log_error("GLX backend support not compiled in."); - return false; -#endif - } - - // Initialize VSync - if (!vsync_init(ps)) { - return false; - } - - // Initialize window GL shader - if (BKEND_GLX == ps->o.backend && ps->o.glx_fshader_win_str) { -#ifdef CONFIG_OPENGL - if (!glx_load_prog_main(NULL, ps->o.glx_fshader_win_str, &ps->glx_prog_win)) { - return false; - } -#else - log_error("GLSL supported not compiled in, can't load " - "shader."); - return false; -#endif - } - - if (!init_alpha_picts(ps)) { - log_error("Failed to init alpha pictures."); - return false; - } - - // Blur filter - if (ps->o.blur_method && ps->o.blur_method != BLUR_METHOD_KERNEL) { - log_warn("Old backends only support blur method \"kernel\". Your blur " - "setting will not be applied"); - ps->o.blur_method = BLUR_METHOD_NONE; - } - - if (ps->o.blur_method == BLUR_METHOD_KERNEL) { - ps->blur_kerns_cache = - ccalloc(ps->o.blur_kernel_count, struct x_convolution_kernel *); - - bool ret = false; - if (ps->o.backend == BKEND_GLX) { -#ifdef CONFIG_OPENGL - ret = glx_init_blur(ps); -#else - assert(false); -#endif - } else { - ret = xr_init_blur(ps); - } - if (!ret) { - return ret; - } - } - - ps->black_picture = solid_picture(&ps->c, true, 1, 0, 0, 0); - ps->white_picture = solid_picture(&ps->c, true, 1, 1, 1, 1); - - if (ps->black_picture == XCB_NONE || ps->white_picture == XCB_NONE) { - log_error("Failed to create solid xrender pictures."); - return false; - } - - // Generates another Picture for shadows if the color is modified by - // user - if (ps->o.shadow_red == 0 && ps->o.shadow_green == 0 && ps->o.shadow_blue == 0) { - ps->cshadow_picture = ps->black_picture; - } else { - ps->cshadow_picture = solid_picture(&ps->c, true, 1, ps->o.shadow_red, - ps->o.shadow_green, ps->o.shadow_blue); - if (ps->cshadow_picture == XCB_NONE) { - log_error("Failed to create shadow picture."); - return false; - } - } - - // Initialize our rounded corners fragment shader - if (ps->o.corner_radius > 0 && ps->o.backend == BKEND_GLX) { -#ifdef CONFIG_OPENGL - if (!glx_init_rounded_corners(ps)) { - log_error("Failed to init rounded corners shader."); - return false; - } -#else - assert(false); -#endif - } - return true; -} - -/** - * Free root tile related things. - */ -void free_root_tile(session_t *ps) { - x_free_picture(&ps->c, ps->root_tile_paint.pict); -#ifdef CONFIG_OPENGL - free_texture(ps, &ps->root_tile_paint.ptex); -#else - assert(!ps->root_tile_paint.ptex); -#endif - if (ps->root_tile_fill) { - xcb_free_pixmap(ps->c.c, ps->root_tile_paint.pixmap); - ps->root_tile_paint.pixmap = XCB_NONE; - } - ps->root_tile_paint.pixmap = XCB_NONE; - ps->root_tile_fill = false; -} - -void deinit_render(session_t *ps) { - // Free alpha_picts - for (int i = 0; i <= MAX_ALPHA; ++i) { - x_free_picture(&ps->c, ps->alpha_picts[i]); - } - free(ps->alpha_picts); - ps->alpha_picts = NULL; - - // Free cshadow_picture and black_picture - if (ps->cshadow_picture != ps->black_picture) { - x_free_picture(&ps->c, ps->cshadow_picture); - } - - x_free_picture(&ps->c, ps->black_picture); - x_free_picture(&ps->c, ps->white_picture); - ps->cshadow_picture = ps->black_picture = ps->white_picture = XCB_NONE; - - // Free other X resources - free_root_tile(ps); - -#ifdef CONFIG_OPENGL - ps->root_tile_paint.fbcfg = (struct glx_fbconfig_info){0}; - if (bkend_use_glx(ps)) { - glx_destroy(ps); - } -#endif - - if (ps->o.blur_method != BLUR_METHOD_NONE) { - for (int i = 0; i < ps->o.blur_kernel_count; i++) { - free(ps->blur_kerns_cache[i]); - } - free(ps->blur_kerns_cache); - } -} - -// vim: set ts=8 sw=8 noet : diff --git a/src/render.h b/src/render.h deleted file mode 100644 index 62258f0e..00000000 --- a/src/render.h +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// Copyright (c) Yuxuan Shui -#pragma once - -#include -#include -#include -#ifdef CONFIG_OPENGL -#include "backend/gl/glx.h" -#endif -#include "region.h" - -typedef struct _glx_texture glx_texture_t; -typedef struct glx_prog_main glx_prog_main_t; -typedef struct session session_t; - -struct managed_win; - -typedef struct paint { - xcb_pixmap_t pixmap; - xcb_render_picture_t pict; - glx_texture_t *ptex; -#ifdef CONFIG_OPENGL - struct glx_fbconfig_info fbcfg; -#endif -} paint_t; - -typedef struct clip { - xcb_render_picture_t pict; - int x; - int y; -} clip_t; - -void render(session_t *ps, int x, int y, int dx, int dy, int w, int h, int fullw, - int fullh, double opacity, bool argb, bool neg, int cr, - xcb_render_picture_t pict, glx_texture_t *ptex, const region_t *reg_paint, - const glx_prog_main_t *pprogram, clip_t *clip); -void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint); - -void paint_all(session_t *ps, struct managed_win *const t); - -void free_paint(session_t *ps, paint_t *ppaint); -void free_root_tile(session_t *ps); - -bool init_render(session_t *ps); -void deinit_render(session_t *ps); - -int maximum_buffer_age(session_t *); diff --git a/src/vsync.c b/src/vsync.c deleted file mode 100644 index 57fbb595..00000000 --- a/src/vsync.c +++ /dev/null @@ -1,208 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// Copyright (c) Yuxuan Shui - -/// Function pointers to init VSync modes. - -#include "common.h" -#include "log.h" - -#ifdef CONFIG_OPENGL -#include "backend/gl/glx.h" -#include "opengl.h" -#endif - -#ifdef CONFIG_VSYNC_DRM -#include -#include -#include -#include -#include -#include -#endif - -#include "config.h" -#include "vsync.h" - -#ifdef CONFIG_VSYNC_DRM -/** - * Wait for next VSync, DRM method. - * - * Stolen from: - * https://github.com/MythTV/mythtv/blob/master/mythtv/libs/libmythtv/vsync.cpp - */ -static int vsync_drm_wait(session_t *ps) { - int ret = -1; - drm_wait_vblank_t vbl; - - vbl.request.type = _DRM_VBLANK_RELATIVE, vbl.request.sequence = 1; - - do { - ret = ioctl(ps->drm_fd, DRM_IOCTL_WAIT_VBLANK, &vbl); - vbl.request.type &= ~(uint)_DRM_VBLANK_RELATIVE; - } while (ret && errno == EINTR); - - if (ret) - log_error("VBlank ioctl did not work, unimplemented in this drmver?"); - - return ret; -} - -/** - * Initialize DRM VSync. - * - * @return true for success, false otherwise - */ -static bool vsync_drm_init(session_t *ps) { - // Should we always open card0? - if (ps->drm_fd < 0 && (ps->drm_fd = open("/dev/dri/card0", O_RDWR)) < 0) { - log_error("Failed to open device."); - return false; - } - - if (vsync_drm_wait(ps)) - return false; - - return true; -} -#endif - -#ifdef CONFIG_OPENGL -/** - * Initialize OpenGL VSync. - * - * Stolen from: - * http://git.tuxfamily.org/?p=ccm/cairocompmgr.git;a=commitdiff;h=efa4ceb97da501e8630ca7f12c99b1dce853c73e - * Possible original source: http://www.inb.uni-luebeck.de/~boehme/xvideo_sync.html - * - * @return true for success, false otherwise - */ -static bool vsync_opengl_init(session_t *ps) { - if (!ensure_glx_context(ps)) { - return false; - } - - return glxext.has_GLX_SGI_video_sync; -} - -static bool vsync_opengl_oml_init(session_t *ps) { - if (!ensure_glx_context(ps)) { - return false; - } - - return glxext.has_GLX_OML_sync_control; -} - -static inline bool vsync_opengl_swc_swap_interval(session_t *ps, int interval) { - if (glxext.has_GLX_MESA_swap_control) { - return glXSwapIntervalMESA((uint)interval) == 0; - } - if (glxext.has_GLX_SGI_swap_control) { - return glXSwapIntervalSGI(interval) == 0; - } - if (glxext.has_GLX_EXT_swap_control) { - GLXDrawable d = glXGetCurrentDrawable(); - if (d == None) { - // We don't have a context?? - return false; - } - glXSwapIntervalEXT(ps->c.dpy, glXGetCurrentDrawable(), interval); - return true; - } - return false; -} - -static bool vsync_opengl_swc_init(session_t *ps) { - if (!bkend_use_glx(ps)) { - log_error("OpenGL swap control requires the GLX backend."); - return false; - } - - if (!vsync_opengl_swc_swap_interval(ps, 1)) { - log_error("Failed to load a swap control extension."); - return false; - } - - return true; -} - -/** - * Wait for next VSync, OpenGL method. - */ -static int vsync_opengl_wait(session_t *ps attr_unused) { - unsigned vblank_count = 0; - - glXGetVideoSyncSGI(&vblank_count); - glXWaitVideoSyncSGI(2, (vblank_count + 1) % 2, &vblank_count); - return 0; -} - -/** - * Wait for next VSync, OpenGL OML method. - * - * https://mail.gnome.org/archives/clutter-list/2012-November/msg00031.html - */ -static int vsync_opengl_oml_wait(session_t *ps) { - int64_t ust = 0, msc = 0, sbc = 0; - - glXGetSyncValuesOML(ps->c.dpy, ps->reg_win, &ust, &msc, &sbc); - glXWaitForMscOML(ps->c.dpy, ps->reg_win, 0, 2, (msc + 1) % 2, &ust, &msc, &sbc); - return 0; -} -#endif - -/** - * Initialize current VSync method. - */ -bool vsync_init(session_t *ps) { -#ifdef CONFIG_OPENGL - if (bkend_use_glx(ps)) { - // Mesa turns on swap control by default, undo that - vsync_opengl_swc_swap_interval(ps, 0); - } -#endif -#ifdef CONFIG_VSYNC_DRM - log_warn("The DRM vsync method is deprecated, please don't enable it."); -#endif - - if (!ps->o.vsync) { - return true; - } - -#ifdef CONFIG_OPENGL - if (bkend_use_glx(ps)) { - if (!vsync_opengl_swc_init(ps)) { - return false; - } - ps->vsync_wait = NULL; // glXSwapBuffers will automatically wait - // for vsync, we don't need to do anything. - return true; - } -#endif - - // Oh no, we are not using glx backend. - // Throwing things at wall. -#ifdef CONFIG_OPENGL - if (vsync_opengl_oml_init(ps)) { - log_info("Using the opengl-oml vsync method"); - ps->vsync_wait = vsync_opengl_oml_wait; - return true; - } - - if (vsync_opengl_init(ps)) { - log_info("Using the opengl vsync method"); - ps->vsync_wait = vsync_opengl_wait; - return true; - } -#endif - -#ifdef CONFIG_VSYNC_DRM - if (vsync_drm_init(ps)) { - log_info("Using the drm vsync method"); - ps->vsync_wait = vsync_drm_wait; - return true; - } -#endif - - log_error("No supported vsync method found for this backend"); - return false; -} diff --git a/src/vsync.h b/src/vsync.h deleted file mode 100644 index 076bc260..00000000 --- a/src/vsync.h +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// Copyright (c) Yuxuan Shui -#include - -typedef struct session session_t; - -bool vsync_init(session_t *ps); diff --git a/src/win.c b/src/win.c index e79cce5d..91896c00 100644 --- a/src/win.c +++ b/src/win.c @@ -25,7 +25,6 @@ #include "log.h" #include "picom.h" #include "region.h" -#include "render.h" #include "string_utils.h" #include "types.h" #include "uthash_extra.h" @@ -36,11 +35,6 @@ #include "dbus.h" #endif -#ifdef CONFIG_OPENGL -// TODO(yshui) Get rid of this include -#include "opengl.h" -#endif - #include "win.h" // TODO(yshui) Make more window states internal @@ -1277,7 +1271,6 @@ void win_on_win_size_change(session_t *ps, struct managed_win *w) { win_release_mask(ps->backend_data, w); win_release_shadow(ps->backend_data, w); ps->pending_updates = true; - free_paint(ps, &w->shadow_paint); } /** @@ -1454,9 +1447,6 @@ void free_win_res(session_t *ps, struct managed_win *w) { // finish_unmap_win should've done that for us. // XXX unless we are called by session_destroy // assert(w->win_data == NULL); - free_win_res_glx(ps, w); - free_paint(ps, &w->paint); - free_paint(ps, &w->shadow_paint); // Above should be done during unmapping // Except when we are called by session_destroy @@ -1603,10 +1593,6 @@ struct win *fill_win(session_t *ps, struct win *w) { .class_general = NULL, .role = NULL, - // Initialized during paint - .paint = PAINT_INIT, - .shadow_paint = PAINT_INIT, - .corner_radius = 0, }; @@ -2018,9 +2004,6 @@ void win_update_bounding_shape(session_t *ps, struct managed_win *w) { win_release_mask(ps->backend_data, w); win_release_shadow(ps->backend_data, w); ps->pending_updates = true; - - free_paint(ps, &w->paint); - free_paint(ps, &w->shadow_paint); } /** @@ -2139,9 +2122,6 @@ static void unmap_win_finish(session_t *ps, struct managed_win *w) { assert(!w->shadow_image); } - free_paint(ps, &w->paint); - free_paint(ps, &w->shadow_paint); - // Try again at binding images when the window is mapped next time win_clear_flags(w, WIN_FLAGS_IMAGE_ERROR); } diff --git a/src/win.h b/src/win.h index bd328806..96345a8c 100644 --- a/src/win.h +++ b/src/win.h @@ -15,7 +15,6 @@ #include "compiler.h" #include "list.h" #include "region.h" -#include "render.h" #include "types.h" #include "utils.h" #include "win_defs.h" @@ -23,7 +22,6 @@ struct backend_base; typedef struct session session_t; -typedef struct _glx_texture glx_texture_t; #define win_stack_foreach_managed(w, win_stack) \ list_foreach(struct managed_win, w, win_stack, \ @@ -33,21 +31,6 @@ typedef struct _glx_texture glx_texture_t; list_foreach_safe(struct managed_win, w, win_stack, \ base.stack_neighbour) if ((w)->base.managed) -#ifdef CONFIG_OPENGL -// FIXME this type should be in opengl.h -// it is very unideal for it to be here -typedef struct { - /// Framebuffer used for blurring. - GLuint fbo; - /// Textures used for blurring. - GLuint textures[2]; - /// Width of the textures. - int width; - /// Height of the textures. - int height; -} glx_blur_cache_t; -#endif - /// An entry in the window stack. May or may not correspond to a window we know about. struct window_stack_entry { struct list_node stack_neighbour; @@ -133,8 +116,6 @@ struct managed_win { bool pixmap_damaged; /// Damage of the window. xcb_damage_damage_t damage; - /// Paint info of the window. - paint_t paint; /// bitmap for properties which needs to be updated uint64_t *stale_props; /// number of uint64_ts that has been allocated for stale_props @@ -260,8 +241,6 @@ struct managed_win { int shadow_width; /// Height of shadow. Affected by window size and command line argument. int shadow_height; - /// Picture to render shadow. Affected by window size. - paint_t shadow_paint; /// The value of _COMPTON_SHADOW attribute of the window. Below 0 for /// none. long long prop_shadow; @@ -283,13 +262,6 @@ struct managed_win { /// The custom window shader to use when rendering. struct shader_info *fg_shader; - -#ifdef CONFIG_OPENGL - /// Textures and FBO background blur use. - glx_blur_cache_t glx_blur_cache; - /// Background texture of the window - glx_texture_t *glx_texture_bg; -#endif }; /// Process pending updates/images flags on a window. Has to be called in X critical