diff --git a/README.md b/README.md index c5ef8e0463..84cc7a586c 100644 --- a/README.md +++ b/README.md @@ -11,20 +11,6 @@ We also try to fix bugs. The original README can be found [here](README_orig.md) -## Call for testers - -### `--experimental-backends` - -This flag enables the refactored/partially rewritten backends. - -Currently new backends features better vsync with the xrender backend, improved input lag with the glx backend (for non-NVIDIA users). The performance should be on par with the old backends. - -New backend features will only be implemented on the new backends from now on, and the old backends will eventually be phased out after the new backends stabilizes. - -To test the new backends, add the `--experimental-backends` flag to the command line you used to run compton. This flag is not available from the configuration file. - -To report issues with the new backends, please state explicitly you are using the new backends in your report. - ## Change Log See [Releases](https://github.com/yshui/compton/releases) diff --git a/man/compton.1.asciidoc b/man/compton.1.asciidoc index dc77fbd4f3..af51ebd2d7 100644 --- a/man/compton.1.asciidoc +++ b/man/compton.1.asciidoc @@ -76,9 +76,6 @@ OPTIONS *--log-file*:: Set the log file. If *--log-file* is never specified, logs will be written to stderr. Otherwise, logs will to written to the given file, though some of the early logs might still be written to the stderr. When setting this option from the config file, it is recommended to use an absolute path. -*--experimental-backends*:: - Use the new, reimplemented version of the backends. The new backends are HIGHLY UNSTABLE at this point, you have been warned. This option is not available in the config file. - *--show-all-xerrors*:: Show all X errors (for debugging). @@ -395,7 +392,6 @@ Available options of the 'blur' section are: :: *method*::: A string. Controls the blur method. Corresponds to the `--blur-method` command line option. Available choices are: 'none' to disable blurring; 'gaussian' for gaussian blur; 'box' for box blur; 'kernel' for convolution blur with a custom kernel. - Note: 'gaussian' and 'box' blur methods are only supported by the experimental backends. *size*::: An integer. The size of the blur kernel, required by 'gaussian' and 'box' blur methods. For the 'kernel' method, the size is included in the kernel. Corresponds to the `--blur-size` command line option. diff --git a/meson_options.txt b/meson_options.txt index d0790a3ea3..75abf32a20 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -2,8 +2,6 @@ option('sanitize', type: 'boolean', value: false, description: 'Compile compton option('config_file', type: 'boolean', value: true, description: 'Enable config file support') option('regex', type: 'boolean', value: true, description: 'Enable regex support in window conditions') -option('vsync_drm', type: 'boolean', value: false, description: 'Enable support for using drm for vsync') - option('opengl', type: 'boolean', value: true, description: 'Enable features that require opengl (opengl backend, and opengl vsync methods)') option('dbus', type: 'boolean', value: true, description: 'Enable support for D-Bus remote control') diff --git a/src/backend/meson.build b/src/backend/meson.build index 9318b78f5d..2bdc9cea77 100644 --- a/src/backend/meson.build +++ b/src/backend/meson.build @@ -4,4 +4,6 @@ srcs += [ files('backend_common.c', 'xrender/xrender.c', 'backend.c', 'driver.c' # enable opengl if get_option('opengl') srcs += [ files('gl/gl_common.c', 'gl/glx.c') ] + cflags += ['-DCONFIG_OPENGL', '-DGL_GLEXT_PROTOTYPES'] + deps += [ dependency('gl', required: true) ] endif diff --git a/src/common.h b/src/common.h index f2ddd19a43..da00464052 100644 --- a/src/common.h +++ b/src/common.h @@ -38,9 +38,6 @@ #include #include "uthash_extra.h" -#ifdef CONFIG_OPENGL -#include "backend/gl/glx.h" -#endif // X resource checker #ifdef DEBUG_XRC @@ -81,37 +78,6 @@ typedef struct _ignore { unsigned long sequence; } ignore_t; -#ifdef CONFIG_OPENGL -#ifdef DEBUG_GLX_DEBUG_CONTEXT -typedef GLXContext (*f_glXCreateContextAttribsARB)(Display *dpy, GLXFBConfig config, - GLXContext share_context, Bool direct, - const int *attrib_list); -typedef void (*GLDEBUGPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, - GLsizei length, const GLchar *message, GLvoid *userParam); -typedef void (*f_DebugMessageCallback)(GLDEBUGPROC, void *userParam); -#endif - -typedef struct glx_prog_main { - /// GLSL program. - GLuint prog; - /// Location of uniform "opacity" in window GLSL program. - GLint unifm_opacity; - /// Location of uniform "invert_color" in blur GLSL program. - GLint unifm_invert_color; - /// Location of uniform "tex" in window GLSL program. - GLint unifm_tex; -} glx_prog_main_t; - -#define GLX_PROG_MAIN_INIT \ - { .prog = 0, .unifm_opacity = -1, .unifm_invert_color = -1, .unifm_tex = -1, } - -#else -struct glx_prog_main {}; -#endif - -#define PAINT_INIT \ - { .pixmap = XCB_NONE, .pict = XCB_NONE } - /// Linked list type of atoms. typedef struct _latom { xcb_atom_t atom; @@ -175,28 +141,12 @@ typedef struct session { xcb_window_t debug_window; /// Whether the root tile is filled by compton. bool root_tile_fill; - /// Picture of the root window background. - paint_t root_tile_paint; /// The backend data the root pixmap bound to void *root_image; /// A region of the size of the screen. region_t screen_reg; - /// Picture of root window. Destination of painting in no-DBE painting - /// mode. - 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 - /// Pointer to GLX data. - struct glx_session *psglx; - /// Custom GLX program used for painting window. - // XXX should be in struct glx_session - glx_prog_main_t glx_prog_win; -#endif /// Sync fence to sync draw operations xcb_sync_fence_t sync_fence; @@ -280,12 +230,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; @@ -319,14 +263,6 @@ typedef struct session { int randr_error; /// Whether X Present extension exists. bool present_exists; -#ifdef CONFIG_OPENGL - /// Whether X GLX extension exists. - bool glx_exists; - /// Event base number for X GLX extension. - int glx_event; - /// Error base number for X GLX extension. - int glx_error; -#endif /// Whether X Xinerama extension exists. bool xinerama_exists; /// Xinerama screen regions. @@ -353,8 +289,6 @@ typedef struct session { // === DBus related === void *dbus_data; #endif - - int (*vsync_wait)(session_t *); } session_t; /// Enumeration for window event hints. diff --git a/src/compton.c b/src/compton.c index 924388d7b2..37e7ca2a1a 100644 --- a/src/compton.c +++ b/src/compton.c @@ -34,16 +34,12 @@ #include "config.h" #include "err.h" #include "kernel.h" -#ifdef CONFIG_OPENGL -#include "opengl.h" -#endif #include "backend/backend.h" #include "c2.h" #include "config.h" #include "diagnostic.h" #include "log.h" #include "region.h" -#include "render.h" #include "types.h" #include "utils.h" #include "win.h" @@ -497,11 +493,6 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) { rc_region_unref(&w->reg_ignore); } - // Clear flags if we are not using experimental backends - if (!ps->o.experimental_backends) { - w->flags = 0; - } - // log_trace("%d %d %s", w->a.map_state, w->ever_damaged, w->name); // Give up if it's not damaged or invisible, or it's unmapped and its @@ -649,6 +640,7 @@ static void rebuild_shadow_exclude_reg(session_t *ps) { /// Free up all the images and deinit the backend static void destroy_backend(session_t *ps) { + assert(ps->backend_data); win_stack_foreach_managed_safe(w, &ps->window_stack) { // Wrapping up fading in progress win_skip_fading(ps, &w); @@ -658,32 +650,27 @@ static void destroy_backend(session_t *ps) { continue; } - if (ps->backend_data) { - if (w->state == WSTATE_MAPPED) { - win_release_image(ps->backend_data, w); - } else { - assert(!w->win_image); - assert(!w->shadow_image); - } + if (w->state == WSTATE_MAPPED) { + win_release_image(ps->backend_data, w); + } else { + assert(!w->win_image); + assert(!w->shadow_image); } - free_paint(ps, &w->paint); } - if (ps->backend_data && ps->root_image) { + if (ps->root_image) { ps->backend_data->ops->release_image(ps->backend_data, ps->root_image); ps->root_image = NULL; } - if (ps->backend_data) { - // deinit backend - if (ps->backend_blur_context) { - ps->backend_data->ops->destroy_blur_context( - ps->backend_data, ps->backend_blur_context); - ps->backend_blur_context = NULL; - } - ps->backend_data->ops->deinit(ps->backend_data); - ps->backend_data = NULL; + // deinit backend + if (ps->backend_blur_context) { + ps->backend_data->ops->destroy_blur_context( + ps->backend_data, ps->backend_blur_context); + ps->backend_blur_context = NULL; } + ps->backend_data->ops->deinit(ps->backend_data); + ps->backend_data = NULL; } static bool initialize_blur(session_t *ps) { @@ -717,35 +704,33 @@ 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.experimental_backends) { - assert(!ps->backend_data); - // Reinitialize win_data - ps->backend_data = backend_list[ps->o.backend]->init(ps); - if (!ps->backend_data) { - log_fatal("Failed to initialize backend, aborting..."); - quit_compton(ps); - return false; - } - ps->backend_data->ops = backend_list[ps->o.backend]; + assert(!ps->backend_data); + // Reinitialize win_data + ps->backend_data = backend_list[ps->o.backend]->init(ps); + if (!ps->backend_data) { + log_fatal("Failed to initialize backend, aborting..."); + quit_compton(ps); + return false; + } + ps->backend_data->ops = backend_list[ps->o.backend]; - if (!initialize_blur(ps)) { - log_fatal("Failed to prepare for background blur, aborting..."); - quit_compton(ps); - return false; - } + if (!initialize_blur(ps)) { + log_fatal("Failed to prepare for background blur, aborting..."); + quit_compton(ps); + return false; + } - // 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; - if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) { - if (!win_bind_image(ps, w)) { - w->flags |= WIN_FLAGS_IMAGE_ERROR; - } + // 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; + if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) { + if (!win_bind_image(ps, w)) { + w->flags |= WIN_FLAGS_IMAGE_ERROR; } } } @@ -760,20 +745,14 @@ void configure_root(session_t *ps, int width, int height) { bool has_root_change = false; if (ps->redirected) { // On root window changes - if (ps->o.experimental_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 = width; @@ -794,16 +773,8 @@ void configure_root(session_t *ps, int width, int height) { 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.experimental_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); - } + ps->backend_data->ops->root_change(ps->backend_data, ps); // Old backend's root_change is not a specific function } else { if (!initialize_backend(ps)) { @@ -823,26 +794,20 @@ void configure_root(session_t *ps, int width, int height) { } void root_damaged(session_t *ps) { - if (ps->root_tile_paint.pixmap) { - free_root_tile(ps); - } - if (!ps->redirected) { return; } - if (ps->backend_data) { - if (ps->root_image) { - ps->backend_data->ops->release_image(ps->backend_data, ps->root_image); - } - auto pixmap = x_get_root_back_pixmap(ps); - if (pixmap != XCB_NONE) { - ps->root_image = ps->backend_data->ops->bind_pixmap( - ps->backend_data, pixmap, x_get_visual_info(ps->c, ps->vis), false); - ps->backend_data->ops->image_op( - ps->backend_data, IMAGE_OP_RESIZE_TILE, ps->root_image, NULL, - NULL, (int[]){ps->root_width, ps->root_height}); - } + if (ps->root_image) { + ps->backend_data->ops->release_image(ps->backend_data, ps->root_image); + } + auto pixmap = x_get_root_back_pixmap(ps); + if (pixmap != XCB_NONE) { + ps->root_image = ps->backend_data->ops->bind_pixmap( + ps->backend_data, pixmap, x_get_visual_info(ps->c, ps->vis), false); + ps->backend_data->ops->image_op( + ps->backend_data, IMAGE_OP_RESIZE_TILE, ps->root_image, NULL, + NULL, (int[]){ps->root_width, ps->root_height}); } // Mark screen damaged @@ -1170,12 +1135,8 @@ static bool redir_start(session_t *ps) { return false; } - if (ps->o.experimental_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; @@ -1388,11 +1349,7 @@ static void _draw_callback(EV_P_ session_t *ps, int revents attr_unused) { // If the screen is unredirected, free all_damage to stop painting if (ps->redirected && ps->o.stoppaint_force != ON) { static int paint = 0; - if (ps->o.experimental_backends) { - paint_all_new(ps, bottom, false); - } else { - paint_all(ps, bottom, false); - } + paint_all_new(ps, bottom, false); paint++; if (ps->o.benchmark && paint >= ps->o.benchmark) @@ -1509,13 +1466,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, -#endif .redirected = false, .alpha_picts = NULL, .fade_time = 0L, @@ -1540,10 +1491,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy, .refresh_intv = 0UL, .paint_tm_offset = 0L, -#ifdef CONFIG_VSYNC_DRM - .drm_fd = -1, -#endif - .xfixes_event = 0, .xfixes_error = 0, .damage_event = 0, @@ -1559,11 +1506,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy, .randr_exists = 0, .randr_event = 0, .randr_error = 0, -#ifdef CONFIG_OPENGL - .glx_exists = false, - .glx_event = 0, - .glx_error = 0, -#endif .xrfilter_convolution_exists = false, .atoms_wintypes = {0}, @@ -1716,11 +1658,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy, } } - if (ps->o.debug_mode && !ps->o.experimental_backends) { - log_fatal("Debug mode only works with the experimental backends."); - return NULL; - } - ps->atoms = init_atoms(ps->c); ps->atoms_wintypes[WINTYPE_UNKNOWN] = 0; #define SET_WM_TYPE_ATOM(x) \ @@ -1861,12 +1798,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy, ps->drivers = detect_driver(ps->c, ps->backend_data, ps->root); - // Initialize filters, must be preceded by OpenGL context creation - if (!ps->o.experimental_backends && !init_render(ps)) { - log_fatal("Failed to initialize the backend"); - exit(1); - } - if (ps->o.print_diagnostics) { print_diagnostics(ps, config_file); free(config_file_to_free); @@ -1874,20 +1805,10 @@ static session_t *session_init(int argc, char **argv, Display *dpy, } free(config_file_to_free); - if (bkend_use_glx(ps) && !ps->o.experimental_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.experimental_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; } // Initialize software optimization @@ -1902,20 +1823,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy, cxinerama_upd_scrs(ps); - { - xcb_render_create_picture_value_list_t pa = { - .subwindowmode = IncludeInferiors, - }; - - ps->root_picture = x_create_picture_with_visual_and_pixmap( - ps->c, ps->vis, ps->root, XCB_RENDER_CP_SUBWINDOW_MODE, &pa); - if (ps->overlay != XCB_NONE) { - ps->tgt_picture = x_create_picture_with_visual_and_pixmap( - ps->c, ps->vis, ps->overlay, XCB_RENDER_CP_SUBWINDOW_MODE, &pa); - } else - ps->tgt_picture = ps->root_picture; - } - ev_io_init(&ps->xiow, x_event_callback, ConnectionNumber(ps->dpy), EV_READ); ev_io_start(ps->loop, &ps->xiow); ev_init(&ps->unredir_timer, tmout_unredir_callback); @@ -2101,18 +2008,6 @@ static void session_destroy(session_t *ps) { ps->ignore_tail = &ps->ignore_head; } - // 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) - ps->tgt_picture = XCB_NONE; - else - free_picture(ps->c, &ps->tgt_picture); - - free_picture(ps->c, &ps->root_picture); - free_paint(ps, &ps->tgt_buffer); - pixman_region32_fini(&ps->screen_reg); free(ps->expose_rects); @@ -2125,14 +2020,6 @@ static void session_destroy(session_t *ps) { free(ps->o.glx_fshader_win_str); free_xinerama_info(ps); -#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, ps->overlay); @@ -2155,19 +2042,8 @@ static void session_destroy(session_t *ps) { ps->debug_window = XCB_NONE; } - if (ps->o.experimental_backends) { - // backend is deinitialized in redir_stop - 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 redir_stop + assert(ps->backend_data == NULL); // Flush all events x_sync(ps->c); diff --git a/src/compton.h b/src/compton.h index 121a2f2eac..ef7a6c25eb 100644 --- a/src/compton.h +++ b/src/compton.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" @@ -97,14 +96,6 @@ static inline void free_wincondlst(c2_lptr_t **pcondlst) { continue; } -#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 - /** * Create a XTextProperty of a single string. */ diff --git a/src/config.h b/src/config.h index f8e1dd0509..8b801b7082 100644 --- a/src/config.h +++ b/src/config.h @@ -65,8 +65,6 @@ typedef struct options { /// Render to a separate window instead of taking over the screen bool debug_mode; // === General === - /// Use the experimental new backends? - bool experimental_backends; /// Path to write PID to. char *write_pid_path; /// The backend in use. diff --git a/src/dbus.c b/src/dbus.c index 3f2d50fa09..214f9c1706 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -1039,11 +1039,7 @@ static bool cdbus_process_opts_get(session_t *ps, DBusMessage *msg) { cdbus_m_opts_get_do(detect_transient, cdbus_reply_bool); cdbus_m_opts_get_do(detect_client_leader, cdbus_reply_bool); -#ifdef CONFIG_OPENGL - cdbus_m_opts_get_do(glx_no_stencil, cdbus_reply_bool); - cdbus_m_opts_get_do(glx_no_rebind_pixmap, cdbus_reply_bool); cdbus_m_opts_get_do(use_damage, cdbus_reply_bool); -#endif cdbus_m_opts_get_stub(track_focus, cdbus_reply_bool, true); cdbus_m_opts_get_do(track_wdata, cdbus_reply_bool); diff --git a/src/log.c b/src/log.c index 2fb62c06e8..d4360b0cfb 100644 --- a/src/log.c +++ b/src/log.c @@ -327,6 +327,7 @@ struct log_target *stderr_logger_new(void) { return &ret->tgt; } +// TODO: move this to gl_common.c #ifdef CONFIG_OPENGL /// An opengl logger that can be used for logging into opengl debugging tools, /// such as apitrace diff --git a/src/meson.build b/src/meson.build index 644688fd5c..f8e9e98261 100644 --- a/src/meson.build +++ b/src/meson.build @@ -8,8 +8,8 @@ base_deps = [ dependency('xcb', version: '>=1.9.2'), ] -srcs = [ files('compton.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('compton.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') ] compton_inc = include_directories('.') @@ -48,17 +48,6 @@ 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', '-DGL_GLEXT_PROTOTYPES'] - deps += [dependency('gl', required: true)] - srcs += [ 'opengl.c' ] -endif - if get_option('dbus') cflags += ['-DCONFIG_DBUS'] deps += [dependency('dbus-1', required: true)] diff --git a/src/opengl.c b/src/opengl.c deleted file mode 100644 index e5a57ca8e1..0000000000 --- a/src/opengl.c +++ /dev/null @@ -1,1127 +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 "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->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) { - if (glXQueryExtension(ps->dpy, &ps->glx_event, &ps->glx_error)) - ps->glx_exists = true; - else { - log_error("No GLX extension."); - goto glx_init_end; - } - } - - // Get XVisualInfo - pvis = get_visualinfo_from_visual(ps, ps->vis); - 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->dpy, pvis, GLX_USE_GL, &value) || !value) { - log_error("Root visual is not a GL visual."); - goto glx_init_end; - } - - if (Success != glXGetConfig(ps->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; - } - } - - glx_session_t *psglx = ps->psglx; - - if (!psglx->context) { - // Get GLX context -#ifndef DEBUG_GLX_DEBUG_CONTEXT - psglx->context = glXCreateContext(ps->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->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->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 = - gl_has_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->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_free_prog_main(&ps->glx_prog_win); - - gl_check_err(); - - // Destroy GLX context - if (ps->psglx->context) { - glXDestroyContext(ps->dpy, ps->psglx->context); - ps->psglx->context = NULL; - } - - free(ps->psglx); - ps->psglx = NULL; -} - -/** - * 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; -} - -/** - * 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); -#undef P_GET_UNIFM_LOC - - 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, xcb_get_geometry(ps->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->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->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT); - - glXBindTexImageEXT(ps->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->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT); - glBindTexture(ptex->target, 0); - } - - // Free GLX Pixmap - if (ptex->glpixmap) { - glXDestroyPixmap(ps->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); - -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; -} - -static inline void glx_copy_region_to_tex(session_t *ps, GLenum tex_tgt, int basex, - int basey, int dx, int dy, int width, int height) { - if (width > 0 && height > 0) - glCopyTexSubImage2D(tex_tgt, 0, dx - basex, dy - basey, dx, - ps->root_height - dy - height, width, height); -} - -/** - * Blur contents in a particular region. - * - * 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; -} - -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); - 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); - } - - // 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) { - // XXX explain these variables - 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; - } - 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 da304b682e..0000000000 --- a/src/opengl.h +++ /dev/null @@ -1,210 +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 - -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; - -/// Structure containing GLX-dependent data for a compton 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_session_t; - -/// @brief Wrapper of a binded GLX texture. -typedef struct _glx_texture { - GLuint texture; - GLXPixmap glpixmap; - xcb_pixmap_t pixmap; - GLenum target; - int width; - int height; - bool y_inverted; -} glx_texture_t; - -#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); - -#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); - -void glx_paint_pre(session_t *ps, region_t *preg) attr_nonnull(1, 2); - -/** - * Check if a texture is binded, or is binded to the given pixmap. - */ -static inline bool glx_tex_binded(const glx_texture_t *ptex, xcb_pixmap_t pixmap) { - return ptex && ptex->glpixmap && ptex->texture && (!pixmap || pixmap == ptex->pixmap); -} - -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); - -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 ps->psglx->context; -} - -/** - * Free a GLX texture. - */ -static inline void free_texture_r(session_t *ps, 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; - assert(!*pptex); -} - -/** - * Free GLX part of paint_t. - */ -static inline void free_paint_glx(session_t *ps, paint_t *ppaint) { - free_texture(ps, &ppaint->ptex); -} - -/** - * 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(w->paint.fbcfg); -#endif -} diff --git a/src/options.c b/src/options.c index 74556fb44a..42faaabd05 100644 --- a/src/options.c +++ b/src/options.c @@ -412,7 +412,6 @@ static const struct option longopts[] = { {"log-level", required_argument, NULL, 321}, {"log-file", required_argument, NULL, 322}, {"use-damage", no_argument, NULL, 323}, - {"experimental-backends", no_argument, NULL, 733}, {"monitor-repaint", no_argument, NULL, 800}, {"diagnostics", no_argument, NULL, 801}, {"debug-mode", no_argument, NULL, 802}, @@ -785,7 +784,6 @@ void get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, } P_CASEBOOL(319, no_x_selection); P_CASEBOOL(323, use_damage); - P_CASEBOOL(733, experimental_backends); P_CASEBOOL(800, monitor_repaint); case 801: opt->print_diagnostics = true; break; P_CASEBOOL(802, debug_mode); @@ -800,11 +798,6 @@ void get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, setlocale(LC_NUMERIC, lc_numeric_old); free(lc_numeric_old); - if (opt->monitor_repaint && opt->backend != BKEND_XRENDER && - !opt->experimental_backends) { - log_warn("--monitor-repaint has no effect when backend is not xrender"); - } - // Range checking and option assignments opt->fade_delta = max2(opt->fade_delta, 1); opt->shadow_radius = max2(opt->shadow_radius, 0); diff --git a/src/render.c b/src/render.c deleted file mode 100644 index c2f9262e3a..0000000000 --- a/src/render.c +++ /dev/null @@ -1,1225 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// Copyright (c) Yuxuan Shui - -#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_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. - static thread_local struct glx_fbconfig_info *argb_fbconfig = NULL; - if (!ppaint->pixmap) - return false; - - struct glx_fbconfig_info *fbcfg; - if (!visual) { - assert(depth == 32); - if (!argb_fbconfig) { - argb_fbconfig = - glx_find_fbconfig(ps->dpy, ps->scr, - (struct xvisual_info){.red_size = 8, - .green_size = 8, - .blue_size = 8, - .alpha_size = 8, - .visual_depth = 32}); - } - if (!argb_fbconfig) { - log_error("Failed to find appropriate FBConfig for 32 bit depth"); - return false; - } - fbcfg = 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) { - ppaint->fbcfg = glx_find_fbconfig(ps->dpy, ps->scr, m); - } - if (!ppaint->fbcfg) { - log_error("Failed to find appropriate FBConfig for X pixmap"); - return false; - } - fbcfg = ppaint->fbcfg; - } - - if (force || !glx_tex_binded(ppaint->ptex, ppaint->pixmap)) - return glx_bind_pixmap(ps, &ppaint->ptex, ppaint->pixmap, wid, hei, - 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->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, 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); - } -} - -/** - * Destroy a Picture. - */ -void free_picture(xcb_connection_t *c, xcb_render_picture_t *p) { - if (*p) { - xcb_render_free_picture(c, *p); - *p = XCB_NONE; - } -} - -/** - * Free paint_t. - */ -void free_paint(session_t *ps, paint_t *ppaint) { -#ifdef CONFIG_OPENGL - free_paint_glx(ps, ppaint); -#endif - free_picture(ps->c, &ppaint->pict); - if (ppaint->pixmap) - xcb_free_pixmap(ps->c, ppaint->pixmap); - ppaint->pixmap = XCB_NONE; -} - -void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, double opacity, - bool argb, bool neg, xcb_render_picture_t pict, glx_texture_t *ptex, - const region_t *reg_paint, const glx_prog_main_t *pprogram) { - 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) { - uint8_t op = ((!argb && !alpha_pict) ? XCB_RENDER_PICT_OP_SRC - : XCB_RENDER_PICT_OP_OVER); - xcb_render_composite( - ps->c, op, pict, alpha_pict, 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)); - } - 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 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, opacity, argb, neg, pict, - (w ? w->paint.ptex : ps->root_tile_paint.ptex), reg_paint, -#ifdef CONFIG_OPENGL - w ? &ps->glx_prog_win : NULL -#else - NULL -#endif - ); -} - -/** - * 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_binded(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, xcb_composite_name_window_pixmap(ps->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, ps->root, 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, XCB_RENDER_PICT_OP_SRC, pict, XCB_NONE, - newpict, 0, 0, 0, 0, 0, 0, wid, hei); - xcb_render_composite(ps->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, 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); - const auto t = extents.top; - const auto l = extents.left; - const auto b = extents.bottom; - const auto 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) - free_picture(ps->c, &pict); - - // 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, 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); - } - } -} - -extern const char *background_props_str[]; - -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); - - // Make sure the pixmap we got is valid - if (pixmap && !x_validate_pixmap(ps->c, pixmap)) - pixmap = XCB_NONE; - - // Create a pixmap if there isn't any - if (!pixmap) { - pixmap = x_create_pixmap(ps->c, (uint8_t)ps->depth, ps->root, 1, 1); - if (pixmap == XCB_NONE) { - log_error("Failed to create pixmaps for root tile."); - return false; - } - fill = true; - } - - // 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, ps->vis, 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, 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, ps->vis, 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, ps->gaussian_map, opacity, width, height); - if (!shadow_image) { - log_error("failed to make shadow"); - return XCB_NONE; - } - - shadow_pixmap = - x_create_pixmap(ps->c, 8, ps->root, shadow_image->width, shadow_image->height); - shadow_pixmap_argb = - x_create_pixmap(ps->c, 32, ps->root, 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, gc, shadow_pixmap, 0, NULL); - - xcb_image_put(ps->c, shadow_pixmap, gc, shadow_image, 0, 0, 0); - xcb_render_composite(ps->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, gc); - xcb_image_destroy(shadow_image); - xcb_free_pixmap(ps->c, shadow_pixmap); - xcb_render_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, shadow_pixmap); - if (shadow_pixmap_argb) - xcb_free_pixmap(ps->c, shadow_pixmap_argb); - if (shadow_picture) - xcb_render_free_picture(ps->c, shadow_picture); - if (shadow_picture_argb) - xcb_render_free_picture(ps->c, shadow_picture_argb); - if (gc) - xcb_free_gc(ps->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; - } - - render(ps, 0, 0, w->g.x + w->shadow_dx, w->g.y + w->shadow_dy, w->shadow_width, - w->shadow_height, w->shadow_opacity, true, false, w->shadow_paint.pict, - w->shadow_paint.ptex, reg_paint, NULL); -} - -/** - * @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) { - 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, ps->root, wid, hei, ps->vis, 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, src_pict, strlen(XRFILTER_CONVOLUTION), XRFILTER_CONVOLUTION, - (uint32_t)(kwid * khei + 2), convolution_blur); - xcb_render_composite(ps->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, XCB_RENDER_PICT_OP_SRC, src_pict, XCB_NONE, - tgt_buffer, 0, 0, 0, 0, x, y, wid, hei); - - 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; - const auto wid = to_u16_checked(w->widthb); - const auto hei = to_u16_checked(w->heightb); - - 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]); - } - - // 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); - pixman_region32_clear(®_blur); - } break; -#ifdef CONFIG_OPENGL - case BKEND_GLX: - // TODO: 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, bool ignore_damage) { - 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, 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 || ignore_damage) { - 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, (uint8_t)ps->depth, ps->root, - 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->vis, 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.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; - } - - 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 = 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); - - // 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); - - if (ps->o.xinerama_shadow_crop && w->xinerama_scr >= 0 && - w->xinerama_scr < ps->xinerama_nscrs) - // There can be a window where number of screens - // is updated, but the screen number attached to - // the windows have not. - // - // Window screen 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->xinerama_scr_regs[w->xinerama_scr]); - - // 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); - } - } - - // 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); - pixman_region32_fini(&bshape); - - if (pixman_region32_not_empty(®_tmp)) { - set_tgt_clip(ps, ®_tmp); - // 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); - } - } - - // Free up all temporary regions - pixman_region32_fini(®_tmp); - - // 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 - x_sync(ps->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->vis); - xcb_render_picture_t new_pict = x_create_picture_with_pictfmt( - ps->c, ps->root, rwidth, rheight, pictfmt, 0, NULL); - xcb_render_composite(ps->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, 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, XCB_RENDER_PICT_OP_SRC, new_pict, - XCB_NONE, ps->tgt_picture, 0, 0, 0, 0, 0, 0, - rwidth, rheight); - xcb_render_free_picture(ps->c, new_pict); - } else - xcb_render_composite(ps->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: - x_sync(ps->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->depth, ps->vis, !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); - // falls through - case BKEND_GLX: glXSwapBuffers(ps->dpy, get_tgt_window(ps)); break; -#endif - default: assert(0); - } - - x_sync(ps->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, xcb_render_query_filters(ps->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, ps->root, false, o, 0, 0, 0); - if (ps->alpha_picts[i] == XCB_NONE) - return false; - } - return true; -} - -bool init_render(session_t *ps) { - // Initialize OpenGL as early as possible -#ifdef CONFIG_OPENGL - glxext_init(ps->dpy, ps->scr); -#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, ps->root, true, 1, 0, 0, 0); - ps->white_picture = solid_picture(ps->c, ps->root, 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, ps->root, 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; - } - } - return true; -} - -/** - * Free root tile related things. - */ -void free_root_tile(session_t *ps) { - 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, 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) - 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) - ps->cshadow_picture = XCB_NONE; - else - free_picture(ps->c, &ps->cshadow_picture); - - free_picture(ps->c, &ps->black_picture); - free_picture(ps->c, &ps->white_picture); - - // Free other X resources - free_root_tile(ps); - -#ifdef CONFIG_OPENGL - free(ps->root_tile_paint.fbcfg); - if (bkend_use_glx(ps)) { - glx_destroy(ps); - } -#endif - - 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 92b71c8e01..0000000000 --- a/src/render.h +++ /dev/null @@ -1,43 +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; - -void render(session_t *ps, int x, int y, int dx, int dy, int w, int h, double opacity, - bool argb, bool neg, xcb_render_picture_t pict, glx_texture_t *ptex, - const region_t *reg_paint, const glx_prog_main_t *pprogram); -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, bool ignore_damage); - -void free_picture(xcb_connection_t *c, xcb_render_picture_t *p); - -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 5980155837..0000000000 --- a/src/vsync.c +++ /dev/null @@ -1,204 +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; - else if (glxext.has_GLX_SGI_swap_control) - return glXSwapIntervalSGI(interval) == 0; - else if (glxext.has_GLX_EXT_swap_control) { - GLXDrawable d = glXGetCurrentDrawable(); - if (d == None) { - // We don't have a context?? - return false; - } - glXSwapIntervalEXT(ps->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->dpy, ps->reg_win, &ust, &msc, &sbc); - glXWaitForMscOML(ps->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 076bc260c3..0000000000 --- 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 6f14e35068..7d9f59241c 100644 --- a/src/win.c +++ b/src/win.c @@ -25,7 +25,6 @@ #include "list.h" #include "log.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 remove this include -#include "opengl.h" -#endif - #include "win.h" #define OPAQUE (0xffffffff) @@ -822,7 +816,6 @@ void win_on_win_size_change(session_t *ps, struct managed_win *w) { } else { assert(w->state == WSTATE_UNMAPPED); } - free_paint(ps, &w->shadow_paint); } /** @@ -966,12 +959,6 @@ void free_win_res(session_t *ps, struct managed_win *w) { // No need to call backend release_image here because // 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 pixman_region32_fini(&w->bounding_shape); // BadDamage may be thrown if the window is destroyed @@ -1104,10 +1091,6 @@ struct win *fill_win(session_t *ps, struct win *w) { .class_instance = NULL, .class_general = NULL, .role = NULL, - - // Initialized during paint - .paint = PAINT_INIT, - .shadow_paint = PAINT_INIT, }; assert(!w->destroyed); @@ -1499,8 +1482,6 @@ void win_update_bounding_shape(session_t *ps, struct managed_win *w) { w->flags |= WIN_FLAGS_IMAGE_STALE; ps->pending_updates = true; } - free_paint(ps, &w->paint); - free_paint(ps, &w->shadow_paint); win_on_factor_change(ps, w); } @@ -1601,8 +1582,6 @@ static void finish_unmap_win(session_t *ps, struct managed_win **_w) { if (ps->backend_data) { win_release_image(ps->backend_data, w); } - free_paint(ps, &w->paint); - free_paint(ps, &w->shadow_paint); w->flags = 0; } diff --git a/src/win.h b/src/win.h index 90e6af40f6..c96cc45f4b 100644 --- a/src/win.h +++ b/src/win.h @@ -9,17 +9,11 @@ #include "uthash_extra.h" -// FIXME shouldn't need this -#ifdef CONFIG_OPENGL -#include -#endif - #include "backend/backend.h" #include "c2.h" #include "compiler.h" #include "list.h" #include "region.h" -#include "render.h" #include "types.h" #include "utils.h" #include "x.h" @@ -34,21 +28,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 - typedef enum { WINTYPE_UNKNOWN, WINTYPE_DESKTOP, @@ -194,8 +173,6 @@ struct managed_win { bool pixmap_damaged; /// Damage of the window. xcb_damage_damage_t damage; - /// Paint info of the window. - paint_t paint; /// Bounding shape of the window. In local coordinates. /// See above about coordinate systems. @@ -299,8 +276,6 @@ struct managed_win { int shadow_width; /// Height of shadow. Affected by window size and commandline 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 prop_shadow; @@ -317,11 +292,6 @@ struct managed_win { /// Whether to blur window background. bool blur_background; - -#ifdef CONFIG_OPENGL - /// Textures and FBO background blur use. - glx_blur_cache_t glx_blur_cache; -#endif }; void win_release_image(backend_t *base, struct managed_win *w); diff --git a/src/x.c b/src/x.c index ed6668a88b..84d2fb80ba 100644 --- a/src/x.c +++ b/src/x.c @@ -356,21 +356,6 @@ void x_print_error(unsigned long serial, uint8_t major, uint16_t minor, uint8_t CASESTRRET2(XCB_RENDER_GLYPH); } -#ifdef CONFIG_OPENGL - if (ps->glx_exists) { - o = error_code - ps->glx_error; - switch (o) { - CASESTRRET2(GLX_BAD_SCREEN); - CASESTRRET2(GLX_BAD_ATTRIBUTE); - CASESTRRET2(GLX_NO_EXTENSION); - CASESTRRET2(GLX_BAD_VISUAL); - CASESTRRET2(GLX_BAD_CONTEXT); - CASESTRRET2(GLX_BAD_VALUE); - CASESTRRET2(GLX_BAD_ENUM); - } - } -#endif - if (ps->xsync_exists) { o = error_code - ps->xsync_error; switch (o) {