diff --git a/common.h b/common.h index 9f72badc8..c1bae4223 100644 --- a/common.h +++ b/common.h @@ -443,7 +443,6 @@ struct _glx_texture { unsigned depth; bool y_inverted; }; -#endif #ifdef CONFIG_VSYNC_OPENGL_GLSL typedef struct { @@ -488,6 +487,7 @@ typedef struct { .unifm_tex = -1, \ } +#endif #endif typedef struct { @@ -584,6 +584,10 @@ typedef struct _options_t { switch_t redirected_force; /// Whether to stop painting. Controlled through D-Bus. switch_t stoppaint_force; + /// Whether to re-redirect screen on root size change. + bool reredir_on_root_change; + /// Whether to reinitialize GLX on root size change. + bool glx_reinit_on_root_change; /// Whether to enable D-Bus support. bool dbus; /// Path to log file. @@ -721,6 +725,65 @@ typedef struct _options_t { bool track_leader; } options_t; +#ifdef CONFIG_VSYNC_OPENGL +/// Structure containing GLX-dependent data for a compton session. +typedef struct { + // === OpenGL related === + /// GLX context. + GLXContext context; + /// Whether we have GL_ARB_texture_non_power_of_two. + bool has_texture_non_power_of_two; + /// Pointer to glXGetVideoSyncSGI function. + f_GetVideoSync glXGetVideoSyncSGI; + /// Pointer to glXWaitVideoSyncSGI function. + f_WaitVideoSync glXWaitVideoSyncSGI; + /// Pointer to glXGetSyncValuesOML function. + f_GetSyncValuesOML glXGetSyncValuesOML; + /// Pointer to glXWaitForMscOML function. + f_WaitForMscOML glXWaitForMscOML; + /// Pointer to glXSwapIntervalSGI function. + f_SwapIntervalSGI glXSwapIntervalProc; + /// Pointer to glXSwapIntervalMESA function. + f_SwapIntervalMESA glXSwapIntervalMESAProc; + /// Pointer to glXBindTexImageEXT function. + f_BindTexImageEXT glXBindTexImageProc; + /// Pointer to glXReleaseTexImageEXT function. + f_ReleaseTexImageEXT glXReleaseTexImageProc; + /// Pointer to glXCopySubBufferMESA function. + f_CopySubBuffer glXCopySubBufferProc; +#ifdef CONFIG_GLX_SYNC + /// Pointer to the glFenceSync() function. + f_FenceSync glFenceSyncProc; + /// Pointer to the glIsSync() function. + f_IsSync glIsSyncProc; + /// Pointer to the glDeleteSync() function. + f_DeleteSync glDeleteSyncProc; + /// Pointer to the glClientWaitSync() function. + f_ClientWaitSync glClientWaitSyncProc; + /// Pointer to the glWaitSync() function. + f_WaitSync glWaitSyncProc; + /// Pointer to the glImportSyncEXT() function. + f_ImportSyncEXT glImportSyncEXT; +#endif +#ifdef DEBUG_GLX_MARK + /// Pointer to StringMarkerGREMEDY function. + f_StringMarkerGREMEDY glStringMarkerGREMEDY; + /// Pointer to FrameTerminatorGREMEDY function. + f_FrameTerminatorGREMEDY glFrameTerminatorGREMEDY; +#endif + /// Current GLX Z value. + int z; + /// FBConfig-s for GLX pixmap of different depths. + glx_fbconfig_t *fbconfigs[OPENGL_MAX_DEPTH + 1]; +#ifdef CONFIG_VSYNC_OPENGL_GLSL + glx_blur_pass_t blur_passes[MAX_BLUR_PASS]; +#endif +} glx_session_t; + +#define CGLX_SESSION_INIT { .context = NULL } + +#endif + /// Structure containing all necessary data for a compton session. typedef struct _session_t { // === Display related === @@ -762,6 +825,10 @@ typedef struct _session_t { XdbeBackBuffer root_dbe; /// Window ID of the window we register as a symbol. Window reg_win; +#ifdef CONFIG_VSYNC_OPENGL + /// Pointer to GLX data. + glx_session_t *psglx; +#endif // === Operation related === /// Program options. @@ -804,10 +871,6 @@ typedef struct _session_t { /// Pointer to the next member of tail element of the error /// ignore linked list. ignore_t **ignore_tail; -#ifdef CONFIG_VSYNC_OPENGL - /// Current GLX Z value. - int glx_z; -#endif // Cached blur convolution kernels. XFixed *blur_kerns_cache[MAX_BLUR_PASS]; /// Reset program after next paint. @@ -867,57 +930,6 @@ typedef struct _session_t { int drm_fd; #endif -#ifdef CONFIG_VSYNC_OPENGL - // === OpenGL related === - /// GLX context. - GLXContext glx_context; - /// Whether we have GL_ARB_texture_non_power_of_two. - bool glx_has_texture_non_power_of_two; - /// Pointer to glXGetVideoSyncSGI function. - f_GetVideoSync glXGetVideoSyncSGI; - /// Pointer to glXWaitVideoSyncSGI function. - f_WaitVideoSync glXWaitVideoSyncSGI; - /// Pointer to glXGetSyncValuesOML function. - f_GetSyncValuesOML glXGetSyncValuesOML; - /// Pointer to glXWaitForMscOML function. - f_WaitForMscOML glXWaitForMscOML; - /// Pointer to glXSwapIntervalSGI function. - f_SwapIntervalSGI glXSwapIntervalProc; - /// Pointer to glXSwapIntervalMESA function. - f_SwapIntervalMESA glXSwapIntervalMESAProc; - /// Pointer to glXBindTexImageEXT function. - f_BindTexImageEXT glXBindTexImageProc; - /// Pointer to glXReleaseTexImageEXT function. - f_ReleaseTexImageEXT glXReleaseTexImageProc; - /// Pointer to glXCopySubBufferMESA function. - f_CopySubBuffer glXCopySubBufferProc; -#ifdef CONFIG_GLX_SYNC - /// Pointer to the glFenceSync() function. - f_FenceSync glFenceSyncProc; - /// Pointer to the glIsSync() function. - f_IsSync glIsSyncProc; - /// Pointer to the glDeleteSync() function. - f_DeleteSync glDeleteSyncProc; - /// Pointer to the glClientWaitSync() function. - f_ClientWaitSync glClientWaitSyncProc; - /// Pointer to the glWaitSync() function. - f_WaitSync glWaitSyncProc; - /// Pointer to the glImportSyncEXT() function. - f_ImportSyncEXT glImportSyncEXT; -#endif -#ifdef DEBUG_GLX_MARK - /// Pointer to StringMarkerGREMEDY function. - f_StringMarkerGREMEDY glStringMarkerGREMEDY; - /// Pointer to FrameTerminatorGREMEDY function. - f_FrameTerminatorGREMEDY glFrameTerminatorGREMEDY; -#endif - /// FBConfig-s for GLX pixmap of different depths. - glx_fbconfig_t *glx_fbconfigs[OPENGL_MAX_DEPTH + 1]; -#ifdef CONFIG_VSYNC_OPENGL_GLSL - glx_blur_pass_t glx_blur_passes[MAX_BLUR_PASS]; -#endif -#endif - // === X extension related === /// Event base number for X Fixes extension. int xfixes_event; @@ -1891,6 +1903,18 @@ bkend_use_glx(session_t *ps) { || BKEND_XR_GLX_HYBRID == ps->o.backend; } +/** + * Check if there's a GLX context. + */ +static inline bool +glx_has_context(session_t *ps) { +#ifdef CONFIG_VSYNC_OPENGL + return ps->psglx && ps->psglx->context; +#else + return false; +#endif +} + /** * Check if a window is really focused. */ @@ -2106,6 +2130,9 @@ glx_init(session_t *ps, bool need_render); void glx_destroy(session_t *ps); +bool +glx_reinit(session_t *ps, bool need_render); + void glx_on_root_change(session_t *ps); @@ -2185,7 +2212,7 @@ 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); + const char *frag_shader_str); #endif /** @@ -2194,7 +2221,7 @@ glx_create_program_from_str(const char *vert_shader_str, static inline void free_texture_r(session_t *ps, GLuint *ptexture) { if (*ptexture) { - assert(ps->glx_context); + assert(glx_has_context(ps)); glDeleteTextures(1, ptexture); *ptexture = 0; } @@ -2260,20 +2287,40 @@ free_texture(session_t *ps, glx_texture_t **pptex) { 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, win *w) { + free_paint_glx(ps, &w->paint); + free_paint_glx(ps, &w->shadow_paint); +#ifdef CONFIG_VSYNC_OPENGL_GLSL + free_glx_bc(ps, &w->glx_blur_cache); +#endif +} + /** * Add a OpenGL debugging marker. */ static inline void glx_mark_(session_t *ps, const char *func, XID xid, bool start) { #ifdef DEBUG_GLX_MARK - if (bkend_use_glx(ps) && ps->glStringMarkerGREMEDY) { + if (glx_has_context(ps) && ps->psglx->glStringMarkerGREMEDY) { if (!func) func = "(unknown)"; const char *postfix = (start ? " (start)": " (end)"); char *str = malloc((strlen(func) + 12 + 2 + strlen(postfix) + 5) * sizeof(char)); strcpy(str, func); sprintf(str + strlen(str), "(%#010lx)%s", xid, postfix); - ps->glStringMarkerGREMEDY(strlen(str), str); + ps->psglx->glStringMarkerGREMEDY(strlen(str), str); free(str); } #endif @@ -2287,8 +2334,8 @@ glx_mark_(session_t *ps, const char *func, XID xid, bool start) { static inline void glx_mark_frame(session_t *ps) { #ifdef DEBUG_GLX_MARK - if (bkend_use_glx(ps) && ps->glFrameTerminatorGREMEDY) - ps->glFrameTerminatorGREMEDY(); + if (glx_has_context(ps) && ps->psglx->glFrameTerminatorGREMEDY) + ps->psglx->glFrameTerminatorGREMEDY(); #endif } diff --git a/compton.c b/compton.c index fb1d0b5cd..f4f7244a5 100644 --- a/compton.c +++ b/compton.c @@ -492,14 +492,12 @@ win_build_shadow(session_t *ps, win *w, double opacity) { // Sync it once and only once xr_sync(ps, w->shadow_paint.pixmap, NULL); - bool success = paint_bind_tex(ps, &w->shadow_paint, shadow_image->width, shadow_image->height, 32, true); - XFreeGC(ps->dpy, gc); XDestroyImage(shadow_image); XFreePixmap(ps->dpy, shadow_pixmap); XRenderFreePicture(ps->dpy, shadow_picture); - return success; + return true; shadow_picture_err: if (shadow_image) @@ -1309,6 +1307,9 @@ paint_preprocess(session_t *ps, win *list) { static inline void win_paint_shadow(session_t *ps, win *w, XserverRegion reg_paint, const reg_data_t *pcache_reg) { + // Bind shadow pixmap to GLX texture if needed + paint_bind_tex(ps, &w->shadow_paint, 0, 0, 32, false); + if (!paint_isvalid(ps, &w->shadow_paint)) { printf_errf("(%#010lx): Missing painting data. This is a bad sign.", w->id); return; @@ -1486,7 +1487,7 @@ win_blur_background(session_t *ps, win *w, Picture tgt_buffer, #ifdef CONFIG_VSYNC_OPENGL_GLSL case BKEND_GLX: // TODO: Handle frame opacity - glx_blur_dst(ps, x, y, wid, hei, ps->glx_z - 0.5, factor_center, + glx_blur_dst(ps, x, y, wid, hei, ps->psglx->z - 0.5, factor_center, reg_paint, pcache_reg, &w->glx_blur_cache); break; #endif @@ -1519,8 +1520,8 @@ render_(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, #ifdef CONFIG_VSYNC_OPENGL case BKEND_GLX: glx_render(ps, ptex, x, y, dx, dy, wid, hei, - ps->glx_z, opacity, argb, neg, reg_paint, pcache_reg, pprogram); - ps->glx_z += 1; + ps->psglx->z, opacity, argb, neg, reg_paint, pcache_reg, pprogram); + ps->psglx->z += 1; break; #endif default: @@ -1701,7 +1702,7 @@ win_paint_win(session_t *ps, win *w, XserverRegion reg_paint, break; #ifdef CONFIG_VSYNC_OPENGL case BKEND_GLX: - glx_dim_dst(ps, x, y, wid, hei, ps->glx_z - 0.7, dim_opacity, + glx_dim_dst(ps, x, y, wid, hei, ps->psglx->z - 0.7, dim_opacity, reg_paint, pcache_reg); break; #endif @@ -1940,7 +1941,7 @@ paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t // effect XSync(ps->dpy, False); #ifdef CONFIG_VSYNC_OPENGL - if (ps->glx_context) { + if (glx_has_context(ps)) { if (ps->o.vsync_use_glfinish) glFinish(); else @@ -2017,7 +2018,7 @@ paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t XFlush(ps->dpy); #ifdef CONFIG_VSYNC_OPENGL - if (ps->glx_context) { + if (glx_has_context(ps)) { glFlush(); glXWaitX(); } @@ -3050,6 +3051,9 @@ restack_win(session_t *ps, win *w, Window new_above) { } } +static bool +init_filters(session_t *ps); + static void configure_win(session_t *ps, XConfigureEvent *ce) { // On root window changes @@ -3063,11 +3067,28 @@ configure_win(session_t *ps, XConfigureEvent *ce) { rebuild_shadow_exclude_reg(ps); free_all_damage_last(ps); + // Re-redirect screen if required + if (ps->o.reredir_on_root_change && ps->redirected) { + redir_stop(ps); + redir_start(ps); + } + #ifdef CONFIG_VSYNC_OPENGL + // Reinitialize GLX on root change + if (ps->o.glx_reinit_on_root_change && ps->psglx) { + if (!glx_reinit(ps, bkend_use_glx(ps))) + printf_errf("(): Failed to reinitialize GLX, troubles ahead."); + if (BKEND_GLX == ps->o.backend && !init_filters(ps)) + printf_errf("(): Failed to initialize filters."); + } + + // GLX root change callback if (BKEND_GLX == ps->o.backend) glx_on_root_change(ps); #endif + force_repaint(ps); + return; } @@ -4807,7 +4828,7 @@ fork_after(session_t *ps) { #ifdef CONFIG_VSYNC_OPENGL // GLX context must be released and reattached on fork - if (ps->glx_context && !glXMakeCurrent(ps->dpy, None, NULL)) { + if (glx_has_context(ps) && !glXMakeCurrent(ps->dpy, None, NULL)) { printf_errf("(): Failed to detach GLx context."); return false; } @@ -4825,8 +4846,8 @@ fork_after(session_t *ps) { setsid(); #ifdef CONFIG_VSYNC_OPENGL - if (ps->glx_context - && !glXMakeCurrent(ps->dpy, get_tgt_window(ps), ps->glx_context)) { + if (glx_has_context(ps) + && !glXMakeCurrent(ps->dpy, get_tgt_window(ps), ps->psglx->context)) { printf_errf("(): Failed to make GLX context current."); return false; } @@ -5617,6 +5638,8 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) { { "glx-fshader-win", required_argument, NULL, 317 }, { "version", no_argument, NULL, 318 }, { "no-x-selection", no_argument, NULL, 319 }, + { "reredir-on-root-change", no_argument, NULL, 731 }, + { "glx-reinit-on-root-change", no_argument, NULL, 732 }, // Must terminate with a NULL entry { NULL, 0, NULL, 0 }, }; @@ -5883,6 +5906,8 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) { ps->o.glx_fshader_win_str = mstrcpy(optarg); break; P_CASEBOOL(319, no_x_selection); + P_CASEBOOL(731, reredir_on_root_change); + P_CASEBOOL(732, glx_reinit_on_root_change); default: usage(1); break; @@ -6166,13 +6191,13 @@ vsync_opengl_init(session_t *ps) { return false; // Get video sync functions - if (!ps->glXGetVideoSyncSGI) - ps->glXGetVideoSyncSGI = (f_GetVideoSync) + if (!ps->psglx->glXGetVideoSyncSGI) + ps->psglx->glXGetVideoSyncSGI = (f_GetVideoSync) glXGetProcAddress((const GLubyte *) "glXGetVideoSyncSGI"); - if (!ps->glXWaitVideoSyncSGI) - ps->glXWaitVideoSyncSGI = (f_WaitVideoSync) + if (!ps->psglx->glXWaitVideoSyncSGI) + ps->psglx->glXWaitVideoSyncSGI = (f_WaitVideoSync) glXGetProcAddress((const GLubyte *) "glXWaitVideoSyncSGI"); - if (!ps->glXWaitVideoSyncSGI || !ps->glXGetVideoSyncSGI) { + if (!ps->psglx->glXWaitVideoSyncSGI || !ps->psglx->glXGetVideoSyncSGI) { printf_errf("(): Failed to get glXWait/GetVideoSyncSGI function."); return false; } @@ -6191,13 +6216,13 @@ vsync_opengl_oml_init(session_t *ps) { return false; // Get video sync functions - if (!ps->glXGetSyncValuesOML) - ps->glXGetSyncValuesOML = (f_GetSyncValuesOML) + if (!ps->psglx->glXGetSyncValuesOML) + ps->psglx->glXGetSyncValuesOML = (f_GetSyncValuesOML) glXGetProcAddress ((const GLubyte *) "glXGetSyncValuesOML"); - if (!ps->glXWaitForMscOML) - ps->glXWaitForMscOML = (f_WaitForMscOML) + if (!ps->psglx->glXWaitForMscOML) + ps->psglx->glXWaitForMscOML = (f_WaitForMscOML) glXGetProcAddress ((const GLubyte *) "glXWaitForMscOML"); - if (!ps->glXGetSyncValuesOML || !ps->glXWaitForMscOML) { + if (!ps->psglx->glXGetSyncValuesOML || !ps->psglx->glXWaitForMscOML) { printf_errf("(): Failed to get OML_sync_control functions."); return false; } @@ -6221,14 +6246,14 @@ vsync_opengl_swc_init(session_t *ps) { } // Get video sync functions - if (!ps->glXSwapIntervalProc) - ps->glXSwapIntervalProc = (f_SwapIntervalSGI) + if (!ps->psglx->glXSwapIntervalProc) + ps->psglx->glXSwapIntervalProc = (f_SwapIntervalSGI) glXGetProcAddress ((const GLubyte *) "glXSwapIntervalSGI"); - if (!ps->glXSwapIntervalProc) { + if (!ps->psglx->glXSwapIntervalProc) { printf_errf("(): Failed to get SGI_swap_control function."); return false; } - ps->glXSwapIntervalProc(1); + ps->psglx->glXSwapIntervalProc(1); return true; #else @@ -6249,14 +6274,14 @@ vsync_opengl_mswc_init(session_t *ps) { } // Get video sync functions - if (!ps->glXSwapIntervalMESAProc) - ps->glXSwapIntervalMESAProc = (f_SwapIntervalMESA) + if (!ps->psglx->glXSwapIntervalMESAProc) + ps->psglx->glXSwapIntervalMESAProc = (f_SwapIntervalMESA) glXGetProcAddress ((const GLubyte *) "glXSwapIntervalMESA"); - if (!ps->glXSwapIntervalMESAProc) { + if (!ps->psglx->glXSwapIntervalMESAProc) { printf_errf("(): Failed to get MESA_swap_control function."); return false; } - ps->glXSwapIntervalMESAProc(1); + ps->psglx->glXSwapIntervalMESAProc(1); return true; #else @@ -6273,8 +6298,8 @@ static int vsync_opengl_wait(session_t *ps) { unsigned vblank_count = 0; - ps->glXGetVideoSyncSGI(&vblank_count); - ps->glXWaitVideoSyncSGI(2, (vblank_count + 1) % 2, &vblank_count); + ps->psglx->glXGetVideoSyncSGI(&vblank_count); + ps->psglx->glXWaitVideoSyncSGI(2, (vblank_count + 1) % 2, &vblank_count); // I see some code calling glXSwapIntervalSGI(1) afterwards, is it required? return 0; @@ -6289,8 +6314,8 @@ static int vsync_opengl_oml_wait(session_t *ps) { int64_t ust = 0, msc = 0, sbc = 0; - ps->glXGetSyncValuesOML(ps->dpy, ps->reg_win, &ust, &msc, &sbc); - ps->glXWaitForMscOML(ps->dpy, ps->reg_win, 0, 2, (msc + 1) % 2, + ps->psglx->glXGetSyncValuesOML(ps->dpy, ps->reg_win, &ust, &msc, &sbc); + ps->psglx->glXWaitForMscOML(ps->dpy, ps->reg_win, 0, 2, (msc + 1) % 2, &ust, &msc, &sbc); return 0; @@ -6299,14 +6324,14 @@ vsync_opengl_oml_wait(session_t *ps) { static void vsync_opengl_swc_deinit(session_t *ps) { // The standard says it doesn't accept 0, but in fact it probably does - if (ps->glx_context && ps->glXSwapIntervalProc) - ps->glXSwapIntervalProc(0); + if (glx_has_context(ps) && ps->psglx->glXSwapIntervalProc) + ps->psglx->glXSwapIntervalProc(0); } static void vsync_opengl_mswc_deinit(session_t *ps) { - if (ps->glx_context && ps->glXSwapIntervalMESAProc) - ps->glXSwapIntervalMESAProc(0); + if (glx_has_context(ps) && ps->psglx->glXSwapIntervalMESAProc) + ps->psglx->glXSwapIntervalMESAProc(0); } #endif @@ -6343,7 +6368,6 @@ void vsync_deinit(session_t *ps) { if (ps->o.vsync && VSYNC_FUNCS_DEINIT[ps->o.vsync]) VSYNC_FUNCS_DEINIT[ps->o.vsync](ps); - ps->o.vsync = VSYNC_NONE; } /** @@ -6383,7 +6407,7 @@ init_dbe(session_t *ps) { /** * Initialize X composite overlay window. */ -static void +static bool init_overlay(session_t *ps) { ps->overlay = XCompositeGetOverlayWindow(ps->dpy, ps->root); if (ps->overlay) { @@ -6411,6 +6435,11 @@ init_overlay(session_t *ps) { "back to painting on root window.\n"); ps->o.paint_on_overlay = false; } +#ifdef DEBUG_REDIR + printf_dbgf("(): overlay = %#010lx\n", ps->overlay); +#endif + + return ps->overlay; } /** @@ -6940,15 +6969,6 @@ session_init(session_t *ps_old, int argc, char **argv) { .drm_fd = -1, #endif -#ifdef CONFIG_VSYNC_OPENGL - .glx_context = None, - .glx_has_texture_non_power_of_two = false, - .glXGetVideoSyncSGI = NULL, - .glXWaitVideoSyncSGI = NULL, - .glXGetSyncValuesOML = NULL, - .glXWaitForMscOML = NULL, -#endif - .xfixes_event = 0, .xfixes_error = 0, .damage_event = 0, @@ -6996,14 +7016,6 @@ session_init(session_t *ps_old, int argc, char **argv) { // Allocate a session and copy default values into it session_t *ps = malloc(sizeof(session_t)); memcpy(ps, &s_def, sizeof(session_t)); -#ifdef CONFIG_VSYNC_OPENGL_GLSL - for (int i = 0; i < MAX_BLUR_PASS; ++i) { - glx_blur_pass_t *ppass = &ps->glx_blur_passes[i]; - ppass->unifm_factor_center = -1; - ppass->unifm_offset_x = -1; - ppass->unifm_offset_y = -1; - } -#endif ps_g = ps; ps->ignore_tail = &ps->ignore_head; gettimeofday(&ps->time_start, NULL); diff --git a/compton.h b/compton.h index 524e81ed9..637d13f34 100644 --- a/compton.h +++ b/compton.h @@ -270,7 +270,7 @@ free_reg_data(reg_data_t *pregd) { */ static inline void free_paint(session_t *ps, paint_t *ppaint) { - free_texture(ps, &ppaint->ptex); + free_paint_glx(ps, ppaint); free_picture(ps, &ppaint->pict); free_pixmap(ps, &ppaint->pixmap); } @@ -289,6 +289,7 @@ free_wpaint(session_t *ps, win *w) { */ static inline void free_win_res(session_t *ps, win *w) { + free_win_res_glx(ps, w); free_region(ps, &w->extents); free_paint(ps, &w->paint); free_region(ps, &w->border_size); @@ -299,9 +300,6 @@ free_win_res(session_t *ps, win *w) { free(w->class_instance); free(w->class_general); free(w->role); -#ifdef CONFIG_VSYNC_OPENGL_GLSL - free_glx_bc(ps, &w->glx_blur_cache); -#endif } /** @@ -1224,10 +1222,10 @@ swopti_handle_timeout(session_t *ps, struct timeval *ptv); static inline bool ensure_glx_context(session_t *ps) { // Create GLX context - if (!ps->glx_context) + if (!glx_has_context(ps)) glx_init(ps, false); - return ps->glx_context; + return ps->psglx->context; } #endif @@ -1274,7 +1272,7 @@ init_alpha_picts(session_t *ps); static bool init_dbe(session_t *ps); -static void +static bool init_overlay(session_t *ps); static void diff --git a/opengl.c b/opengl.c index 424407f9f..965356593 100644 --- a/opengl.c +++ b/opengl.c @@ -14,15 +14,15 @@ void xr_glx_sync(session_t *ps, Drawable d, XSyncFence *pfence) { if (*pfence) { - // GLsync sync = ps->glFenceSyncProc(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - GLsync sync = ps->glImportSyncEXT(GL_SYNC_X11_FENCE_EXT, *pfence, 0); - /* GLenum ret = ps->glClientWaitSyncProc(sync, GL_SYNC_FLUSH_COMMANDS_BIT, + // GLsync sync = ps->psglx->glFenceSyncProc(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + GLsync sync = ps->psglx->glImportSyncEXT(GL_SYNC_X11_FENCE_EXT, *pfence, 0); + /* GLenum ret = ps->psglx->glClientWaitSyncProc(sync, GL_SYNC_FLUSH_COMMANDS_BIT, 1000); assert(GL_CONDITION_SATISFIED == ret); */ XSyncTriggerFence(ps->dpy, *pfence); XFlush(ps->dpy); - ps->glWaitSyncProc(sync, 0, GL_TIMEOUT_IGNORED); - // ps->glDeleteSyncProc(sync); + ps->psglx->glWaitSyncProc(sync, 0, GL_TIMEOUT_IGNORED); + // ps->psglx->glDeleteSyncProc(sync); // XSyncResetFence(ps->dpy, *pfence); } glx_check_err(ps); @@ -98,10 +98,26 @@ glx_init(session_t *ps, bool need_render) { if (need_render && !glx_hasglxext(ps, "GLX_EXT_texture_from_pixmap")) goto glx_init_end; - if (!ps->glx_context) { + // Initialize GLX data structure + if (!ps->psglx) { + static const glx_session_t CGLX_SESSION_DEF = CGLX_SESSION_INIT; + ps->psglx = cmalloc(1, glx_session_t); + memcpy(ps->psglx, &CGLX_SESSION_DEF, sizeof(glx_session_t)); + + for (int i = 0; i < MAX_BLUR_PASS; ++i) { + glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i]; + ppass->unifm_factor_center = -1; + ppass->unifm_offset_x = -1; + ppass->unifm_offset_y = -1; + } + } + + glx_session_t *psglx = ps->psglx; + + if (!psglx->context) { // Get GLX context #ifndef DEBUG_GLX_DEBUG_CONTEXT - ps->glx_context = glXCreateContext(ps->dpy, pvis, None, GL_TRUE); + psglx->context = glXCreateContext(ps->dpy, pvis, None, GL_TRUE); #else { GLXFBConfig fbconfig = get_fbconfig_from_visualinfo(ps, pvis); @@ -123,18 +139,18 @@ glx_init(session_t *ps, bool need_render) { GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, None }; - ps->glx_context = p_glXCreateContextAttribsARB(ps->dpy, fbconfig, NULL, + psglx->context = p_glXCreateContextAttribsARB(ps->dpy, fbconfig, NULL, GL_TRUE, attrib_list); } #endif - if (!ps->glx_context) { + if (!psglx->context) { printf_errf("(): Failed to get GLX context."); goto glx_init_end; } // Attach GLX context - if (!glXMakeCurrent(ps->dpy, get_tgt_window(ps), ps->glx_context)) { + if (!glXMakeCurrent(ps->dpy, get_tgt_window(ps), psglx->context)) { printf_errf("(): Failed to attach GLX context."); goto glx_init_end; } @@ -169,52 +185,52 @@ glx_init(session_t *ps, bool need_render) { // Check GL_ARB_texture_non_power_of_two, requires a GLX context and // must precede FBConfig fetching if (need_render) - ps->glx_has_texture_non_power_of_two = glx_hasglext(ps, + psglx->has_texture_non_power_of_two = glx_hasglext(ps, "GL_ARB_texture_non_power_of_two"); // Acquire function addresses if (need_render) { #ifdef DEBUG_GLX_MARK - ps->glStringMarkerGREMEDY = (f_StringMarkerGREMEDY) + psglx->glStringMarkerGREMEDY = (f_StringMarkerGREMEDY) glXGetProcAddress((const GLubyte *) "glStringMarkerGREMEDY"); - ps->glFrameTerminatorGREMEDY = (f_FrameTerminatorGREMEDY) + psglx->glFrameTerminatorGREMEDY = (f_FrameTerminatorGREMEDY) glXGetProcAddress((const GLubyte *) "glFrameTerminatorGREMEDY"); #endif - ps->glXBindTexImageProc = (f_BindTexImageEXT) + psglx->glXBindTexImageProc = (f_BindTexImageEXT) glXGetProcAddress((const GLubyte *) "glXBindTexImageEXT"); - ps->glXReleaseTexImageProc = (f_ReleaseTexImageEXT) + psglx->glXReleaseTexImageProc = (f_ReleaseTexImageEXT) glXGetProcAddress((const GLubyte *) "glXReleaseTexImageEXT"); - if (!ps->glXBindTexImageProc || !ps->glXReleaseTexImageProc) { + if (!psglx->glXBindTexImageProc || !psglx->glXReleaseTexImageProc) { printf_errf("(): Failed to acquire glXBindTexImageEXT() / glXReleaseTexImageEXT()."); goto glx_init_end; } if (ps->o.glx_use_copysubbuffermesa) { - ps->glXCopySubBufferProc = (f_CopySubBuffer) + psglx->glXCopySubBufferProc = (f_CopySubBuffer) glXGetProcAddress((const GLubyte *) "glXCopySubBufferMESA"); - if (!ps->glXCopySubBufferProc) { + if (!psglx->glXCopySubBufferProc) { printf_errf("(): Failed to acquire glXCopySubBufferMESA()."); goto glx_init_end; } } #ifdef CONFIG_GLX_SYNC - ps->glFenceSyncProc = (f_FenceSync) + psglx->glFenceSyncProc = (f_FenceSync) glXGetProcAddress((const GLubyte *) "glFenceSync"); - ps->glIsSyncProc = (f_IsSync) + psglx->glIsSyncProc = (f_IsSync) glXGetProcAddress((const GLubyte *) "glIsSync"); - ps->glDeleteSyncProc = (f_DeleteSync) + psglx->glDeleteSyncProc = (f_DeleteSync) glXGetProcAddress((const GLubyte *) "glDeleteSync"); - ps->glClientWaitSyncProc = (f_ClientWaitSync) + psglx->glClientWaitSyncProc = (f_ClientWaitSync) glXGetProcAddress((const GLubyte *) "glClientWaitSync"); - ps->glWaitSyncProc = (f_WaitSync) + psglx->glWaitSyncProc = (f_WaitSync) glXGetProcAddress((const GLubyte *) "glWaitSync"); - ps->glImportSyncEXT = (f_ImportSyncEXT) + psglx->glImportSyncEXT = (f_ImportSyncEXT) glXGetProcAddress((const GLubyte *) "glImportSyncEXT"); - if (!ps->glFenceSyncProc || !ps->glIsSyncProc || !ps->glDeleteSyncProc - || !ps->glClientWaitSyncProc || !ps->glWaitSyncProc - || !ps->glImportSyncEXT) { + if (!psglx->glFenceSyncProc || !psglx->glIsSyncProc || !psglx->glDeleteSyncProc + || !psglx->glClientWaitSyncProc || !psglx->glWaitSyncProc + || !psglx->glImportSyncEXT) { printf_errf("(): Failed to acquire GLX sync functions."); goto glx_init_end; } @@ -281,10 +297,17 @@ glx_free_prog_main(session_t *ps, glx_prog_main_t *pprogram) { */ void glx_destroy(session_t *ps) { + if (!ps->psglx) + return; + + // Free all GLX resources of windows + for (win *w = ps->list; w; w = w->next) + free_win_res_glx(ps, w); + #ifdef CONFIG_VSYNC_OPENGL_GLSL // Free GLSL shaders/programs for (int i = 0; i < MAX_BLUR_PASS; ++i) { - glx_blur_pass_t *ppass = &ps->glx_blur_passes[i]; + glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i]; if (ppass->frag_shader) glDeleteShader(ppass->frag_shader); if (ppass->prog) @@ -298,15 +321,40 @@ glx_destroy(session_t *ps) { // Free FBConfigs for (int i = 0; i <= OPENGL_MAX_DEPTH; ++i) { - free(ps->glx_fbconfigs[i]); - ps->glx_fbconfigs[i] = NULL; + free(ps->psglx->fbconfigs[i]); + ps->psglx->fbconfigs[i] = NULL; } // Destroy GLX context - if (ps->glx_context) { - glXDestroyContext(ps->dpy, ps->glx_context); - ps->glx_context = NULL; + if (ps->psglx->context) { + glXDestroyContext(ps->dpy, ps->psglx->context); + ps->psglx->context = NULL; } + + free(ps->psglx); + ps->psglx = NULL; +} + +/** + * Reinitialize GLX. + */ +bool +glx_reinit(session_t *ps, bool need_render) { + // Reinitialize VSync as well + vsync_deinit(ps); + + glx_destroy(ps); + if (!glx_init(ps, need_render)) { + printf_errf("(): Failed to initialize GLX."); + return false; + } + + if (!vsync_init(ps)) { + printf_errf("(): Failed to initialize VSync."); + return false; + } + + return true; } /** @@ -376,7 +424,7 @@ glx_init_blur(session_t *ps) { " gl_FragColor = sum / (factor_center + float(%.7g));\n" "}\n"; - const bool use_texture_rect = !ps->glx_has_texture_non_power_of_two; + 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 ? @@ -395,7 +443,7 @@ glx_init_blur(session_t *ps) { if (!kern) break; - glx_blur_pass_t *ppass = &ps->glx_blur_passes[i]; + glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i]; // Build shader { @@ -527,15 +575,15 @@ glx_update_fbconfig_bydepth(session_t *ps, int depth, glx_fbconfig_t *pfbcfg) { return; // Compare new FBConfig with current one - if (glx_cmp_fbconfig(ps, ps->glx_fbconfigs[depth], pfbcfg) < 0) { + if (glx_cmp_fbconfig(ps, ps->psglx->fbconfigs[depth], pfbcfg) < 0) { #ifdef DEBUG_GLX - printf_dbgf("(%d): %#x overrides %#x, target %#x.\n", depth, (unsigned) pfbcfg->cfg, (ps->glx_fbconfigs[depth] ? (unsigned) ps->glx_fbconfigs[depth]->cfg: 0), pfbcfg->texture_tgts); + printf_dbgf("(%d): %#x overrides %#x, target %#x.\n", depth, (unsigned) pfbcfg->cfg, (ps->psglx->fbconfigs[depth] ? (unsigned) ps->psglx->fbconfigs[depth]->cfg: 0), pfbcfg->texture_tgts); #endif - if (!ps->glx_fbconfigs[depth]) { - ps->glx_fbconfigs[depth] = malloc(sizeof(glx_fbconfig_t)); - allocchk(ps->glx_fbconfigs[depth]); + if (!ps->psglx->fbconfigs[depth]) { + ps->psglx->fbconfigs[depth] = malloc(sizeof(glx_fbconfig_t)); + allocchk(ps->psglx->fbconfigs[depth]); } - (*ps->glx_fbconfigs[depth]) = *pfbcfg; + (*ps->psglx->fbconfigs[depth]) = *pfbcfg; } } @@ -617,19 +665,19 @@ glx_update_fbconfig(session_t *ps) { cxfree(pfbcfgs); // Sanity checks - if (!ps->glx_fbconfigs[ps->depth]) { + if (!ps->psglx->fbconfigs[ps->depth]) { printf_errf("(): No FBConfig found for default depth %d.", ps->depth); return false; } - if (!ps->glx_fbconfigs[32]) { + if (!ps->psglx->fbconfigs[32]) { printf_errf("(): No FBConfig found for depth 32. Expect crazy things."); } #ifdef DEBUG_GLX printf_dbgf("(): %d-bit: %#3x, 32-bit: %#3x\n", - ps->depth, (int) ps->glx_fbconfigs[ps->depth]->cfg, - (int) ps->glx_fbconfigs[32]->cfg); + ps->depth, (int) ps->psglx->fbconfigs[ps->depth]->cfg, + (int) ps->psglx->fbconfigs[32]->cfg); #endif return true; @@ -733,7 +781,7 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap, } } - const glx_fbconfig_t *pcfg = ps->glx_fbconfigs[depth]; + const glx_fbconfig_t *pcfg = ps->psglx->fbconfigs[depth]; if (!pcfg) { printf_errf("(%d): Couldn't find FBConfig with requested depth.", depth); return false; @@ -744,7 +792,7 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap, // pixmap-specific parameters, and this may change in the future GLenum tex_tgt = 0; if (GLX_TEXTURE_2D_BIT_EXT & pcfg->texture_tgts - && ps->glx_has_texture_non_power_of_two) + && ps->psglx->has_texture_non_power_of_two) tex_tgt = GLX_TEXTURE_2D_EXT; else if (GLX_TEXTURE_RECTANGLE_BIT_EXT & pcfg->texture_tgts) tex_tgt = GLX_TEXTURE_RECTANGLE_EXT; @@ -809,9 +857,9 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap, // The specification requires rebinding whenever the content changes... // We can't follow this, too slow. if (need_release) - ps->glXReleaseTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT); + ps->psglx->glXReleaseTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT); - ps->glXBindTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT, NULL); + ps->psglx->glXBindTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT, NULL); // Cleanup glBindTexture(ptex->target, 0); @@ -830,7 +878,7 @@ glx_release_pixmap(session_t *ps, glx_texture_t *ptex) { // Release binding if (ptex->glpixmap && ptex->texture) { glBindTexture(ptex->target, ptex->texture); - ps->glXReleaseTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT); + ps->psglx->glXReleaseTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT); glBindTexture(ptex->target, 0); } @@ -848,7 +896,7 @@ glx_release_pixmap(session_t *ps, glx_texture_t *ptex) { */ void glx_paint_pre(session_t *ps, XserverRegion *preg) { - ps->glx_z = 0.0; + ps->psglx->z = 0.0; // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Get buffer age @@ -1116,8 +1164,8 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, GLfloat factor_center, XserverRegion reg_tgt, const reg_data_t *pcache_reg, glx_blur_cache_t *pbc) { - assert(ps->glx_blur_passes[0].prog); - const bool more_passes = ps->glx_blur_passes[1].prog; + assert(ps->psglx->blur_passes[0].prog); + const bool more_passes = ps->psglx->blur_passes[1].prog; const bool have_scissors = glIsEnabled(GL_SCISSOR_TEST); const bool have_stencil = glIsEnabled(GL_STENCIL_TEST); bool ret = false; @@ -1154,7 +1202,7 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, */ GLenum tex_tgt = GL_TEXTURE_RECTANGLE; - if (ps->glx_has_texture_non_power_of_two) + if (ps->psglx->has_texture_non_power_of_two) tex_tgt = GL_TEXTURE_2D; // Free textures if size inconsistency discovered @@ -1217,9 +1265,9 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, bool last_pass = false; for (int i = 0; !last_pass; ++i) { - last_pass = !ps->glx_blur_passes[i + 1].prog; + last_pass = !ps->psglx->blur_passes[i + 1].prog; assert(i < MAX_BLUR_PASS - 1); - const glx_blur_pass_t *ppass = &ps->glx_blur_passes[i]; + const glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i]; assert(ppass->prog); assert(tex_scr); @@ -1392,7 +1440,7 @@ glx_render_(session_t *ps, const glx_texture_t *ptex, #endif argb = argb || (GLX_TEXTURE_FORMAT_RGBA_EXT == - ps->glx_fbconfigs[ptex->depth]->texture_fmt); + ps->psglx->fbconfigs[ptex->depth]->texture_fmt); #ifdef CONFIG_VSYNC_OPENGL_GLSL const bool has_prog = pprogram && pprogram->prog; #endif @@ -1695,7 +1743,7 @@ glx_swap_copysubbuffermesa(session_t *ps, XserverRegion reg) { #ifdef DEBUG_GLX printf_dbgf("(): %d, %d, %d, %d\n", x, y, wid, hei); #endif - ps->glXCopySubBufferProc(ps->dpy, get_tgt_window(ps), x, y, wid, hei); + ps->psglx->glXCopySubBufferProc(ps->dpy, get_tgt_window(ps), x, y, wid, hei); } } diff --git a/opengl.h b/opengl.h index 35ccf6878..b4e04440a 100644 --- a/opengl.h +++ b/opengl.h @@ -41,7 +41,7 @@ glx_dump_err_str(GLenum err) { */ static inline void glx_check_err_(session_t *ps, const char *func, int line) { - if (!ps->glx_context) return; + if (!ps->psglx->context) return; GLenum err = GL_NO_ERROR;