diff --git a/cogl/cogl/cogl-renderer-private.h b/cogl/cogl/cogl-renderer-private.h index 080bb325d..06aa21320 100644 --- a/cogl/cogl/cogl-renderer-private.h +++ b/cogl/cogl/cogl-renderer-private.h @@ -66,6 +66,7 @@ struct _CoglRenderer #ifdef COGL_HAS_XLIB_SUPPORT Display *foreign_xdpy; CoglBool xlib_enable_event_retrieval; + CoglBool xlib_want_reset_on_video_memory_purge; #endif CoglDriver driver; diff --git a/cogl/cogl/cogl-renderer.c b/cogl/cogl/cogl-renderer.c index fabaf81f2..498a00ff4 100644 --- a/cogl/cogl/cogl-renderer.c +++ b/cogl/cogl/cogl-renderer.c @@ -286,6 +286,16 @@ cogl_xlib_renderer_set_event_retrieval_enabled (CoglRenderer *renderer, renderer->xlib_enable_event_retrieval = enable; } + +void +cogl_xlib_renderer_request_reset_on_video_memory_purge (CoglRenderer *renderer, + CoglBool enable) +{ + _COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer)); + _COGL_RETURN_IF_FAIL (!renderer->connected); + + renderer->xlib_want_reset_on_video_memory_purge = enable; +} #endif /* COGL_HAS_XLIB_SUPPORT */ CoglBool diff --git a/cogl/cogl/cogl-xlib-renderer.h b/cogl/cogl/cogl-xlib-renderer.h index fdce06b03..d33f83052 100644 --- a/cogl/cogl/cogl-xlib-renderer.h +++ b/cogl/cogl/cogl-xlib-renderer.h @@ -173,6 +173,47 @@ cogl_xlib_renderer_get_display (CoglRenderer *renderer); XVisualInfo * cogl_xlib_renderer_get_visual_info (CoglRenderer *renderer); +/** + * cogl_xlib_renderer_request_reset_on_video_memory_purge: + * @renderer: a #CoglRenderer + * @enable: The new value + * + * Sets whether Cogl should make use of the + * NV_robustness_video_memory_purge extension, if exposed by the + * driver, by initializing the GLX context appropriately. + * + * The extension is only useful when running on certain versions of + * the NVIDIA driver. Quoting from the spec: + * + * "The NVIDIA OpenGL driver architecture on Linux has a limitation: + * resources located in video memory are not persistent across certain + * events. VT switches, suspend/resume events, and mode switching + * events may erase the contents of video memory. Any resource that + * is located exclusively in video memory, such as framebuffer objects + * (FBOs), will be lost." + * + * "This extension provides a way for applications to discover when video + * memory content has been lost, so that the application can re-populate + * the video memory content as necessary." + * + * "Any driver that exposes this extension is a driver that considers + * video memory to be volatile. Once the driver stack has been + * improved, the extension will no longer be exposed." + * + * cogl_get_graphics_reset_status() needs to be called at least once + * every frame to find out if video memory was purged. + * + * Note that this doesn't cause Cogl to enable robust buffer access + * but other context reset errors may still happen and be reported via + * cogl_get_graphics_reset_status() if external factors cause the + * driver to trigger them. + * + * This defaults to %FALSE and is effective only if called before + * cogl_display_setup() . + */ +void +cogl_xlib_renderer_request_reset_on_video_memory_purge (CoglRenderer *renderer, + CoglBool enable); COGL_END_DECLS /* The gobject introspection scanner seems to parse public headers in diff --git a/cogl/cogl/cogl.symbols b/cogl/cogl/cogl.symbols index ad4240777..cdac57210 100644 --- a/cogl/cogl/cogl.symbols +++ b/cogl/cogl/cogl.symbols @@ -1042,6 +1042,7 @@ cogl_xlib_renderer_get_foreign_display cogl_xlib_renderer_get_visual_info cogl_xlib_renderer_handle_event cogl_xlib_renderer_remove_filter +cogl_xlib_renderer_request_reset_on_video_memory_purge cogl_xlib_renderer_set_event_retrieval_enabled cogl_xlib_renderer_set_foreign_display cogl_xlib_set_display diff --git a/cogl/cogl/gl-prototypes/cogl-all-functions.h b/cogl/cogl/gl-prototypes/cogl-all-functions.h index 7ac9022b7..0c80fbcd2 100644 --- a/cogl/cogl/gl-prototypes/cogl-all-functions.h +++ b/cogl/cogl/gl-prototypes/cogl-all-functions.h @@ -326,3 +326,11 @@ COGL_EXT_BEGIN (draw_buffers, 2, 0, COGL_EXT_FUNCTION (void, glDrawBuffers, (GLsizei n, const GLenum *bufs)) COGL_EXT_END () + +COGL_EXT_BEGIN (robustness, 255, 255, + 0, + "ARB\0", + "robustness\0") +COGL_EXT_FUNCTION (GLenum, glGetGraphicsResetStatus, + (void)) +COGL_EXT_END () diff --git a/cogl/cogl/winsys/cogl-winsys-glx.c b/cogl/cogl/winsys/cogl-winsys-glx.c index 72d9e5627..f88ee37b5 100644 --- a/cogl/cogl/winsys/cogl-winsys-glx.c +++ b/cogl/cogl/winsys/cogl-winsys-glx.c @@ -71,6 +71,11 @@ #include #include +/* This is a relatively new extension */ +#ifndef GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV +#define GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x20F7 +#endif + #define COGL_ONSCREEN_X11_EVENT_MASK (StructureNotifyMask | ExposureMask) #define MAX_GLX_CONFIG_ATTRIBS 30 @@ -1025,12 +1030,50 @@ create_gl3_context (CoglDisplay *display, GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, None }; + /* NV_robustness_video_memory_purge relies on GLX_ARB_create_context + and in part on ARB_robustness. Namely, it needs the notification + strategy to be set to GLX_LOSE_CONTEXT_ON_RESET_ARB and that the + driver exposes the GetGraphicsResetStatusARB function. This means + we don't actually enable robust buffer access. */ + static const int attrib_list_reset_on_purge[] = + { + GLX_CONTEXT_MAJOR_VERSION_ARB, 3, + GLX_CONTEXT_MINOR_VERSION_ARB, 1, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, + GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV, + GL_TRUE, + GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + GLX_LOSE_CONTEXT_ON_RESET_ARB, + None + }; /* Make sure that the display supports the GLX_ARB_create_context extension */ if (glx_renderer->glXCreateContextAttribs == NULL) return NULL; + /* We can't check the presence of this extension with the usual + COGL_WINSYS_FEATURE machinery because that only gets initialized + later when the CoglContext is created. */ + if (display->renderer->xlib_want_reset_on_video_memory_purge && + strstr (glx_renderer->glXQueryExtensionsString (xlib_renderer->xdpy, + DefaultScreen (xlib_renderer->xdpy)), + "GLX_NV_robustness_video_memory_purge")) + { + CoglXlibTrapState old_state; + GLXContext ctx; + + _cogl_xlib_renderer_trap_errors (display->renderer, &old_state); + ctx = glx_renderer->glXCreateContextAttribs (xlib_renderer->xdpy, + fb_config, + NULL /* share_context */, + True, /* direct */ + attrib_list_reset_on_purge); + if (!_cogl_xlib_renderer_untrap_errors (display->renderer, &old_state) && ctx) + return ctx; + } + return glx_renderer->glXCreateContextAttribs (xlib_renderer->xdpy, fb_config, NULL /* share_context */,