diff --git a/SOURCES/0001-examples-cogl-crate.c-fix-bug-when-waiting-for-next-.patch b/SOURCES/0001-examples-cogl-crate.c-fix-bug-when-waiting-for-next-.patch new file mode 100644 index 0000000..6c1e9f4 --- /dev/null +++ b/SOURCES/0001-examples-cogl-crate.c-fix-bug-when-waiting-for-next-.patch @@ -0,0 +1,27 @@ +From 9d33312a2b78960d2cb840f60d2e5d6eb6ac87da Mon Sep 17 00:00:00 2001 +From: "Owen W. Taylor" +Date: Wed, 10 Feb 2016 17:20:00 -0500 +Subject: [PATCH 1/6] examples/cogl-crate.c: fix bug when waiting for next + frame + +The swap_ready variable was never reset, meaning that we weren't +effectively waiting for SYNC events that signal frame completion. +--- + examples/cogl-crate.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/examples/cogl-crate.c b/examples/cogl-crate.c +index 0836b82..1933c7c 100644 +--- a/examples/cogl-crate.c ++++ b/examples/cogl-crate.c +@@ -285,6 +285,7 @@ main (int argc, char **argv) + { + paint (&data); + cogl_onscreen_swap_buffers (COGL_ONSCREEN (fb)); ++ data.swap_ready = FALSE; + } + + cogl_poll_renderer_get_info (cogl_context_get_renderer (ctx), +-- +1.8.3.1 + diff --git a/SOURCES/0002-CoglGPUInfo-fix-check-for-NVIDIA.patch b/SOURCES/0002-CoglGPUInfo-fix-check-for-NVIDIA.patch new file mode 100644 index 0000000..dde2625 --- /dev/null +++ b/SOURCES/0002-CoglGPUInfo-fix-check-for-NVIDIA.patch @@ -0,0 +1,28 @@ +From 30ee61a38eb9098cb45e566bef6c4d5a3a35f14b Mon Sep 17 00:00:00 2001 +From: "Owen W. Taylor" +Date: Thu, 11 Feb 2016 15:06:23 -0500 +Subject: [PATCH 2/6] CoglGPUInfo - fix check for NVIDIA + +NVIDIA drivers have a vendor of "NVIDIA Corporation" not "NVIDIA". +Check for both in case older drivers did use "NVIDIA" +--- + cogl/cogl-gpu-info.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/cogl/cogl-gpu-info.c b/cogl/cogl-gpu-info.c +index 54dfe18..d91830d 100644 +--- a/cogl/cogl-gpu-info.c ++++ b/cogl/cogl-gpu-info.c +@@ -169,7 +169,8 @@ check_qualcomm_vendor (const CoglGpuInfoStrings *strings) + static CoglBool + check_nvidia_vendor (const CoglGpuInfoStrings *strings) + { +- if (strcmp (strings->vendor_string, "NVIDIA") != 0) ++ if (strcmp (strings->vendor_string, "NVIDIA") != 0 && ++ strcmp (strings->vendor_string, "NVIDIA Corporation") != 0) + return FALSE; + + return TRUE; +-- +1.8.3.1 + diff --git a/SOURCES/0003-CoglWinsysGLX-factor-out-some-duplicated-code.patch b/SOURCES/0003-CoglWinsysGLX-factor-out-some-duplicated-code.patch new file mode 100644 index 0000000..be73758 --- /dev/null +++ b/SOURCES/0003-CoglWinsysGLX-factor-out-some-duplicated-code.patch @@ -0,0 +1,82 @@ +From 603f16c96b2f1e5040d819277602086cc9e03699 Mon Sep 17 00:00:00 2001 +From: "Owen W. Taylor" +Date: Thu, 11 Feb 2016 16:33:03 -0500 +Subject: [PATCH 3/7] CoglWinsysGLX: factor out some duplicated code + +Add a helper function for repeated calls to clock_gettime(CLOCK_MONOTONIC) +--- + cogl/winsys/cogl-winsys-glx.c | 24 ++++++++++++------------ + 1 file changed, 12 insertions(+), 12 deletions(-) + +diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c +index 34fb071..ed20e81 100644 +--- a/cogl/winsys/cogl-winsys-glx.c ++++ b/cogl/winsys/cogl-winsys-glx.c +@@ -187,6 +187,15 @@ find_onscreen_for_xid (CoglContext *context, uint32_t xid) + return NULL; + } + ++static int64_t ++get_monotonic_time_ns (void) ++{ ++ struct timespec ts; ++ ++ clock_gettime (CLOCK_MONOTONIC, &ts); ++ return ts.tv_sec * G_GINT64_CONSTANT (1000000000) + ts.tv_nsec; ++} ++ + static void + ensure_ust_type (CoglRenderer *renderer, + GLXDrawable drawable) +@@ -197,7 +206,6 @@ ensure_ust_type (CoglRenderer *renderer, + int64_t msc; + int64_t sbc; + struct timeval tv; +- struct timespec ts; + int64_t current_system_time; + int64_t current_monotonic_time; + +@@ -227,9 +235,7 @@ ensure_ust_type (CoglRenderer *renderer, + + /* This is the time source that the newer (fixed) linux drm + * drivers use (Linux >= 3.8) */ +- clock_gettime (CLOCK_MONOTONIC, &ts); +- current_monotonic_time = (ts.tv_sec * G_GINT64_CONSTANT (1000000)) + +- (ts.tv_nsec / G_GINT64_CONSTANT (1000)); ++ current_monotonic_time = get_monotonic_time_ns () / 1000; + + if (current_monotonic_time > ust - 1000000 && + current_monotonic_time < ust + 1000000) +@@ -305,10 +311,7 @@ _cogl_winsys_get_clock_time (CoglContext *context) + } + case COGL_GLX_UST_IS_MONOTONIC_TIME: + { +- struct timespec ts; +- +- clock_gettime (CLOCK_MONOTONIC, &ts); +- return ts.tv_sec * G_GINT64_CONSTANT (1000000000) + ts.tv_nsec; ++ return get_monotonic_time_ns (); + } + } + +@@ -1636,16 +1639,13 @@ _cogl_winsys_wait_for_vblank (CoglOnscreen *onscreen) + else + { + uint32_t current_count; +- struct timespec ts; + + glx_renderer->glXGetVideoSync (¤t_count); + glx_renderer->glXWaitVideoSync (2, + (current_count + 1) % 2, + ¤t_count); + +- clock_gettime (CLOCK_MONOTONIC, &ts); +- info->presentation_time = +- ts.tv_sec * G_GINT64_CONSTANT (1000000000) + ts.tv_nsec; ++ info->presentation_time = get_monotonic_time_ns (); + } + } + } +-- +1.8.3.1 + diff --git a/SOURCES/0004-Usability-of-SGI_video_sync-is-per-display-not-per-r.patch b/SOURCES/0004-Usability-of-SGI_video_sync-is-per-display-not-per-r.patch new file mode 100644 index 0000000..b8a59b7 --- /dev/null +++ b/SOURCES/0004-Usability-of-SGI_video_sync-is-per-display-not-per-r.patch @@ -0,0 +1,177 @@ +From 34419e3631d1e7e22441e611f686f6f9ca27b12a Mon Sep 17 00:00:00 2001 +From: "Owen W. Taylor" +Date: Thu, 11 Feb 2016 17:04:08 -0500 +Subject: [PATCH 4/6] Usability of SGI_video_sync is per-display not + per-renderer + +As previously commented in the code, SGI_video_sync is per-display, rather +than per-renderer. The is_direct flag for the renderer was tested before +it was initialized (per-display) and that resulted in SGI_video_sync +never being used. +--- + cogl/cogl-glx-display-private.h | 3 +++ + cogl/cogl-glx-renderer-private.h | 2 -- + cogl/winsys/cogl-winsys-glx.c | 52 +++++++++++++++++++++------------------- + 3 files changed, 31 insertions(+), 26 deletions(-) + +diff --git a/cogl/cogl-glx-display-private.h b/cogl/cogl-glx-display-private.h +index 133c118..1d1afc0 100644 +--- a/cogl/cogl-glx-display-private.h ++++ b/cogl/cogl-glx-display-private.h +@@ -51,6 +51,9 @@ typedef struct _CoglGLXDisplay + + CoglBool found_fbconfig; + CoglBool fbconfig_has_rgba_visual; ++ CoglBool is_direct; ++ CoglBool have_vblank_counter; ++ CoglBool can_vblank_wait; + GLXFBConfig fbconfig; + + /* Single context for all wins */ +diff --git a/cogl/cogl-glx-renderer-private.h b/cogl/cogl-glx-renderer-private.h +index cb8ff97..061f2cc 100644 +--- a/cogl/cogl-glx-renderer-private.h ++++ b/cogl/cogl-glx-renderer-private.h +@@ -43,8 +43,6 @@ typedef struct _CoglGLXRenderer + int glx_error_base; + int glx_event_base; + +- CoglBool is_direct; +- + /* Vblank stuff */ + int dri_fd; + +diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c +index 4450365..cd0b211 100644 +--- a/cogl/winsys/cogl-winsys-glx.c ++++ b/cogl/winsys/cogl-winsys-glx.c +@@ -710,23 +710,25 @@ update_base_winsys_features (CoglRenderer *renderer) + + g_strfreev (split_extensions); + +- /* Note: the GLX_SGI_video_sync spec explicitly states this extension +- * only works for direct contexts. */ +- if (!glx_renderer->is_direct) +- { +- glx_renderer->glXGetVideoSync = NULL; +- glx_renderer->glXWaitVideoSync = NULL; +- COGL_FLAGS_SET (glx_renderer->base_winsys_features, +- COGL_WINSYS_FEATURE_VBLANK_COUNTER, +- FALSE); +- } ++ /* The GLX_SGI_video_sync spec explicitly states this extension ++ * only works for direct contexts; we don't know per-renderer ++ * if the context is direct or not, so we turn off the feature ++ * flag; we still use the extension within this file looking ++ * instead at glx_display->have_vblank_counter. ++ */ ++ COGL_FLAGS_SET (glx_renderer->base_winsys_features, ++ COGL_WINSYS_FEATURE_VBLANK_COUNTER, ++ FALSE); ++ + + COGL_FLAGS_SET (glx_renderer->base_winsys_features, + COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN, + TRUE); + +- if (glx_renderer->glXWaitVideoSync || +- glx_renderer->glXWaitForMsc) ++ /* Because of the direct-context dependency, the VBLANK_WAIT feature ++ * doesn't reflect the presence of GLX_SGI_video_sync. ++ */ ++ if (glx_renderer->glXWaitForMsc) + COGL_FLAGS_SET (glx_renderer->base_winsys_features, + COGL_WINSYS_FEATURE_VBLANK_WAIT, + TRUE); +@@ -859,7 +861,7 @@ update_winsys_features (CoglContext *context, CoglError **error) + * by the SwapInterval so we have to throttle swap_region requests + * manually... */ + if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION) && +- _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_WAIT)) ++ (glx_display->have_vblank_counter || glx_display->can_vblank_wait)) + COGL_FLAGS_SET (context->winsys_features, + COGL_WINSYS_FEATURE_SWAP_REGION_THROTTLE, TRUE); + +@@ -1096,11 +1098,13 @@ create_context (CoglDisplay *display, CoglError **error) + return FALSE; + } + +- glx_renderer->is_direct = ++ glx_display->is_direct = + glx_renderer->glXIsDirect (xlib_renderer->xdpy, glx_display->glx_context); ++ glx_display->have_vblank_counter = glx_display->is_direct && glx_renderer->glXWaitVideoSync; ++ glx_display->can_vblank_wait = glx_renderer->glXWaitForMsc || glx_display->have_vblank_counter; + + COGL_NOTE (WINSYS, "Setting %s context", +- glx_renderer->is_direct ? "direct" : "indirect"); ++ glx_display->is_direct ? "direct" : "indirect"); + + /* XXX: GLX doesn't let us make a context current without a window + * so we create a dummy window that we can use while no CoglOnscreen +@@ -1612,12 +1616,13 @@ _cogl_winsys_wait_for_vblank (CoglOnscreen *onscreen) + CoglContext *ctx = framebuffer->context; + CoglGLXRenderer *glx_renderer; + CoglXlibRenderer *xlib_renderer; ++ CoglGLXDisplay *glx_display; + + glx_renderer = ctx->display->renderer->winsys; + xlib_renderer = _cogl_xlib_renderer_get_data (ctx->display->renderer); ++ glx_display = ctx->display->winsys; + +- if (glx_renderer->glXWaitForMsc || +- glx_renderer->glXGetVideoSync) ++ if (glx_display->can_vblank_wait) + { + CoglFrameInfo *info = g_queue_peek_tail (&onscreen->pending_frame_infos); + +@@ -1713,6 +1718,7 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen, + CoglXlibRenderer *xlib_renderer = + _cogl_xlib_renderer_get_data (context->display->renderer); + CoglGLXRenderer *glx_renderer = context->display->renderer->winsys; ++ CoglGLXDisplay *glx_display = context->display->winsys; + CoglOnscreenXlib *xlib_onscreen = onscreen->winsys; + CoglOnscreenGLX *glx_onscreen = onscreen->winsys; + GLXDrawable drawable = +@@ -1769,9 +1775,8 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen, + + if (framebuffer->config.swap_throttled) + { +- have_counter = +- _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_COUNTER); +- can_wait = _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_WAIT); ++ have_counter = glx_display->have_vblank_counter; ++ can_wait = glx_display->can_vblank_wait; + } + else + { +@@ -1928,6 +1933,7 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, + CoglXlibRenderer *xlib_renderer = + _cogl_xlib_renderer_get_data (context->display->renderer); + CoglGLXRenderer *glx_renderer = context->display->renderer->winsys; ++ CoglGLXDisplay *glx_display = context->display->winsys; + CoglOnscreenXlib *xlib_onscreen = onscreen->winsys; + CoglOnscreenGLX *glx_onscreen = onscreen->winsys; + CoglBool have_counter; +@@ -1947,8 +1953,7 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, + { + uint32_t end_frame_vsync_counter = 0; + +- have_counter = +- _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_COUNTER); ++ have_counter = glx_display->have_vblank_counter; + + /* If the swap_region API is also being used then we need to track + * the vsync counter for each swap request so we can manually +@@ -1958,8 +1963,7 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, + + if (!glx_renderer->glXSwapInterval) + { +- CoglBool can_wait = +- _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_VBLANK_WAIT); ++ CoglBool can_wait = glx_display->can_vblank_wait; + + /* If we are going to wait for VBLANK manually, we not only + * need to flush out pending drawing to the GPU before we +-- +1.8.3.1 + diff --git a/SOURCES/0005-Fix-the-get_clock_time-without-GLX_OML_sync_control.patch b/SOURCES/0005-Fix-the-get_clock_time-without-GLX_OML_sync_control.patch new file mode 100644 index 0000000..b174544 --- /dev/null +++ b/SOURCES/0005-Fix-the-get_clock_time-without-GLX_OML_sync_control.patch @@ -0,0 +1,29 @@ +From 9259fc8ce95e38771e3501bd3936582f9a85b3a0 Mon Sep 17 00:00:00 2001 +From: "Owen W. Taylor" +Date: Thu, 11 Feb 2016 17:12:09 -0500 +Subject: [PATCH 5/6] Fix the get_clock_time() without GLX_OML_sync_control + +When we don't have GLX_OML_sync_control, we still can set the +frame presentation time, but we always use the system monotonic time, +so return that from get_clock_time(). +--- + cogl/winsys/cogl-winsys-glx.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c +index cd0b211..8ce1e37 100644 +--- a/cogl/winsys/cogl-winsys-glx.c ++++ b/cogl/winsys/cogl-winsys-glx.c +@@ -291,6 +291,9 @@ _cogl_winsys_get_clock_time (CoglContext *context) + { + CoglGLXRenderer *glx_renderer = context->display->renderer->winsys; + ++ if (!glx_renderer->glXWaitForMsc) ++ return get_monotonic_time_ns (); ++ + /* We don't call ensure_ust_type() because we don't have a drawable + * to work with. cogl_get_clock_time() is documented to only work + * once a valid, non-zero, timestamp has been retrieved from Cogl. +-- +1.8.3.1 + diff --git a/SOURCES/0006-For-NVIDIA-proprietary-drivers-implement-sync-events.patch b/SOURCES/0006-For-NVIDIA-proprietary-drivers-implement-sync-events.patch new file mode 100644 index 0000000..445fc23 --- /dev/null +++ b/SOURCES/0006-For-NVIDIA-proprietary-drivers-implement-sync-events.patch @@ -0,0 +1,404 @@ +From 062fd3cc6bf40990f748af9244728060f5330109 Mon Sep 17 00:00:00 2001 +From: "Owen W. Taylor" +Date: Thu, 11 Feb 2016 17:15:13 -0500 +Subject: [PATCH 6/7] For NVIDIA proprietary drivers, implement sync events + with a thread + +It's a good guess that the buffer swap will occur at the next vblank, +so use glXWaitVideoSync in a separate thread to deliver a sync event +rather than just letting the client block when frame drawing, which +can signficantly change app logic as compared to the INTEL_swap_event +case. +--- + cogl/cogl-private.h | 3 + + cogl/winsys/cogl-winsys-glx.c | 294 ++++++++++++++++++++++++++++++++++++++++-- + examples/cogl-crate.c | 3 + + 3 files changed, 289 insertions(+), 11 deletions(-) + +diff -up cogl-1.18.2/cogl/cogl-private.h.threaded-sync-events cogl-1.18.2/cogl/cogl-private.h +--- cogl-1.18.2/cogl/cogl-private.h.threaded-sync-events 2014-07-02 19:31:31.000000000 -0400 ++++ cogl-1.18.2/cogl/cogl-private.h 2016-06-30 15:44:39.823352236 -0400 +@@ -77,6 +77,9 @@ typedef enum + COGL_PRIVATE_FEATURE_GL_PROGRAMMABLE, + COGL_PRIVATE_FEATURE_GL_EMBEDDED, + COGL_PRIVATE_FEATURE_GL_WEB, ++ /* This is currently only implemented for GLX, but isn't actually ++ * that winsys dependent */ ++ COGL_PRIVATE_FEATURE_THREADED_SWAP_WAIT, + + COGL_N_PRIVATE_FEATURES + } CoglPrivateFeature; +diff -up cogl-1.18.2/cogl/winsys/cogl-winsys-glx.c.threaded-sync-events cogl-1.18.2/cogl/winsys/cogl-winsys-glx.c +--- cogl-1.18.2/cogl/winsys/cogl-winsys-glx.c.threaded-sync-events 2016-06-30 15:44:39.822352220 -0400 ++++ cogl-1.18.2/cogl/winsys/cogl-winsys-glx.c 2016-06-30 15:48:22.371948425 -0400 +@@ -65,12 +65,16 @@ + #include + #include + #include ++#include + #include + #include ++#include + + #include + #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 +@@ -100,6 +104,14 @@ typedef struct _CoglOnscreenGLX + CoglBool pending_sync_notify; + CoglBool pending_complete_notify; + CoglBool pending_resize_notify; ++ ++ GThread *swap_wait_thread; ++ GQueue *swap_wait_queue; ++ GCond swap_wait_cond; ++ GMutex swap_wait_mutex; ++ int swap_wait_pipe[2]; ++ GLXContext swap_wait_context; ++ CoglBool closing_down; + } CoglOnscreenGLX; + + typedef struct _CoglPixmapTextureEyeGLX +@@ -885,6 +897,28 @@ update_winsys_features (CoglContext *con + COGL_FEATURE_ID_PRESENTATION_TIME, + TRUE); + } ++ else ++ { ++ CoglGpuInfo *info = &context->gpu; ++ if (glx_display->have_vblank_counter && ++ info->vendor == COGL_GPU_INFO_VENDOR_NVIDIA) ++ { ++ COGL_FLAGS_SET (context->winsys_features, ++ COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT, TRUE); ++ COGL_FLAGS_SET (context->winsys_features, ++ COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT, TRUE); ++ /* TODO: remove this deprecated feature */ ++ COGL_FLAGS_SET (context->features, ++ COGL_FEATURE_ID_SWAP_BUFFERS_EVENT, ++ TRUE); ++ COGL_FLAGS_SET (context->features, ++ COGL_FEATURE_ID_PRESENTATION_TIME, ++ TRUE); ++ COGL_FLAGS_SET (context->private_features, ++ COGL_PRIVATE_FEATURE_THREADED_SWAP_WAIT, ++ TRUE); ++ } ++ } + + /* We'll manually handle queueing dirty events in response to + * Expose events from X */ +@@ -1481,7 +1515,8 @@ _cogl_winsys_onscreen_init (CoglOnscreen + } + + #ifdef GLX_INTEL_swap_event +- if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT)) ++ if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT) && ++ !_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_THREADED_SWAP_WAIT)) + { + GLXDrawable drawable = + glx_onscreen->glxwin ? glx_onscreen->glxwin : xlib_onscreen->xwin; +@@ -1524,6 +1559,31 @@ _cogl_winsys_onscreen_deinit (CoglOnscre + xlib_onscreen->output = NULL; + } + ++ if (glx_onscreen->swap_wait_thread) ++ { ++ g_mutex_lock (&glx_onscreen->swap_wait_mutex); ++ glx_onscreen->closing_down = TRUE; ++ g_cond_signal (&glx_onscreen->swap_wait_cond); ++ g_mutex_unlock (&glx_onscreen->swap_wait_mutex); ++ g_thread_join (glx_onscreen->swap_wait_thread); ++ glx_onscreen->swap_wait_thread = NULL; ++ ++ g_cond_clear (&glx_onscreen->swap_wait_cond); ++ g_mutex_clear (&glx_onscreen->swap_wait_mutex); ++ ++ g_queue_free (glx_onscreen->swap_wait_queue); ++ glx_onscreen->swap_wait_queue = NULL; ++ ++ _cogl_poll_renderer_remove_fd (context->display->renderer, ++ glx_onscreen->swap_wait_pipe[0]); ++ ++ close (glx_onscreen->swap_wait_pipe[0]); ++ close (glx_onscreen->swap_wait_pipe[1]); ++ ++ glx_renderer->glXDestroyContext (xlib_renderer->xdpy, ++ glx_onscreen->swap_wait_context); ++ } ++ + _cogl_xlib_renderer_trap_errors (context->display->renderer, &old_state); + + drawable = +@@ -1759,6 +1819,199 @@ set_frame_info_output (CoglOnscreen *ons + } + } + ++static gpointer ++threaded_swap_wait (gpointer data) ++{ ++ CoglOnscreen *onscreen = data; ++ ++ CoglOnscreenGLX *glx_onscreen = onscreen->winsys; ++ ++ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); ++ CoglContext *context = framebuffer->context; ++ CoglDisplay *display = context->display; ++ CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (display->renderer); ++ CoglGLXDisplay *glx_display = display->winsys; ++ CoglGLXRenderer *glx_renderer = display->renderer->winsys; ++ GLXDrawable dummy_drawable; ++ ++ if (glx_display->dummy_glxwin) ++ dummy_drawable = glx_display->dummy_glxwin; ++ else ++ dummy_drawable = glx_display->dummy_xwin; ++ ++ glx_renderer->glXMakeContextCurrent (xlib_renderer->xdpy, ++ dummy_drawable, ++ dummy_drawable, ++ glx_onscreen->swap_wait_context); ++ ++ g_mutex_lock (&glx_onscreen->swap_wait_mutex); ++ ++ while (TRUE) ++ { ++ gpointer queue_element; ++ uint32_t vblank_counter; ++ ++ while (!glx_onscreen->closing_down && glx_onscreen->swap_wait_queue->length == 0) ++ g_cond_wait (&glx_onscreen->swap_wait_cond, &glx_onscreen->swap_wait_mutex); ++ ++ if (glx_onscreen->closing_down) ++ break; ++ ++ queue_element = g_queue_pop_tail (glx_onscreen->swap_wait_queue); ++ vblank_counter = GPOINTER_TO_UINT(queue_element); ++ ++ g_mutex_unlock (&glx_onscreen->swap_wait_mutex); ++ glx_renderer->glXWaitVideoSync (2, ++ (vblank_counter + 1) % 2, ++ &vblank_counter); ++ g_mutex_lock (&glx_onscreen->swap_wait_mutex); ++ ++ if (!glx_onscreen->closing_down) ++ { ++ int bytes_written = 0; ++ ++ union { ++ char bytes[8]; ++ int64_t presentation_time; ++ } u; ++ ++ u.presentation_time = get_monotonic_time_ns (); ++ ++ while (bytes_written < 8) ++ { ++ int res = write (glx_onscreen->swap_wait_pipe[1], u.bytes + bytes_written, 8 - bytes_written); ++ if (res == -1) ++ { ++ if (errno != EINTR) ++ g_error ("Error writing to swap notification pipe: %s\n", ++ g_strerror (errno)); ++ } ++ else ++ { ++ bytes_written += res; ++ } ++ } ++ } ++ } ++ ++ g_mutex_unlock (&glx_onscreen->swap_wait_mutex); ++ ++ glx_renderer->glXMakeContextCurrent (xlib_renderer->xdpy, ++ None, ++ None, ++ NULL); ++ ++ return NULL; ++} ++ ++static int64_t ++threaded_swap_wait_pipe_prepare (void *user_data) ++{ ++ return -1; ++} ++ ++static void ++threaded_swap_wait_pipe_dispatch (void *user_data, int revents) ++{ ++ CoglOnscreen *onscreen = user_data; ++ CoglOnscreenGLX *glx_onscreen = onscreen->winsys; ++ ++ CoglFrameInfo *info; ++ ++ if ((revents & COGL_POLL_FD_EVENT_IN)) ++ { ++ int bytes_read = 0; ++ ++ union { ++ char bytes[8]; ++ int64_t presentation_time; ++ } u; ++ ++ while (bytes_read < 8) ++ { ++ int res = read (glx_onscreen->swap_wait_pipe[0], u.bytes + bytes_read, 8 - bytes_read); ++ if (res == -1) ++ { ++ if (errno != EINTR) ++ g_error ("Error reading from swap notification pipe: %s\n", ++ g_strerror (errno)); ++ } ++ else ++ { ++ bytes_read += res; ++ } ++ } ++ ++ set_sync_pending (onscreen); ++ set_complete_pending (onscreen); ++ ++ info = g_queue_peek_head (&onscreen->pending_frame_infos); ++ info->presentation_time = u.presentation_time; ++ } ++} ++ ++static void ++start_threaded_swap_wait (CoglOnscreen *onscreen, ++ uint32_t vblank_counter) ++{ ++ CoglOnscreenGLX *glx_onscreen = onscreen->winsys; ++ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); ++ CoglContext *context = framebuffer->context; ++ ++ if (glx_onscreen->swap_wait_thread == NULL) ++ { ++ CoglDisplay *display = context->display; ++ CoglGLXRenderer *glx_renderer = display->renderer->winsys; ++ CoglGLXDisplay *glx_display = display->winsys; ++ CoglOnscreenXlib *xlib_onscreen = onscreen->winsys; ++ CoglXlibRenderer *xlib_renderer = ++ _cogl_xlib_renderer_get_data (display->renderer); ++ ++ GLXDrawable drawable = ++ glx_onscreen->glxwin ? glx_onscreen->glxwin : xlib_onscreen->xwin; ++ int i; ++ ++ ensure_ust_type (display->renderer, drawable); ++ ++ if ((pipe (glx_onscreen->swap_wait_pipe) == -1)) ++ g_error ("Couldn't create pipe for swap notification: %s\n", ++ g_strerror (errno)); ++ ++ for (i = 0; i < 2; i++) ++ { ++ if (fcntl(glx_onscreen->swap_wait_pipe[i], F_SETFD, ++ fcntl(glx_onscreen->swap_wait_pipe[i], F_GETFD, 0) | FD_CLOEXEC) == -1) ++ g_error ("Couldn't set swap notification pipe CLOEXEC: %s\n", ++ g_strerror (errno)); ++ } ++ ++ _cogl_poll_renderer_add_fd (display->renderer, ++ glx_onscreen->swap_wait_pipe[0], ++ COGL_POLL_FD_EVENT_IN, ++ threaded_swap_wait_pipe_prepare, ++ threaded_swap_wait_pipe_dispatch, ++ onscreen); ++ ++ glx_onscreen->swap_wait_queue = g_queue_new (); ++ g_mutex_init (&glx_onscreen->swap_wait_mutex); ++ g_cond_init (&glx_onscreen->swap_wait_cond); ++ glx_onscreen->swap_wait_context = ++ glx_renderer->glXCreateNewContext (xlib_renderer->xdpy, ++ glx_display->fbconfig, ++ GLX_RGBA_TYPE, ++ glx_display->glx_context, ++ True); ++ glx_onscreen->swap_wait_thread = g_thread_new ("cogl_glx_swap_wait", ++ threaded_swap_wait, ++ onscreen); ++ } ++ ++ g_mutex_lock (&glx_onscreen->swap_wait_mutex); ++ g_queue_push_head (glx_onscreen->swap_wait_queue, GUINT_TO_POINTER(vblank_counter)); ++ g_cond_signal (&glx_onscreen->swap_wait_cond); ++ g_mutex_unlock (&glx_onscreen->swap_wait_mutex); ++} ++ + static void + _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen, + const int *user_rectangles, +@@ -2002,19 +2255,38 @@ _cogl_winsys_onscreen_swap_buffers_with_ + + if (framebuffer->config.swap_throttled) + { +- uint32_t end_frame_vsync_counter = 0; +- + have_counter = glx_display->have_vblank_counter; + +- /* If the swap_region API is also being used then we need to track +- * the vsync counter for each swap request so we can manually +- * throttle swap_region requests. */ +- if (have_counter) +- end_frame_vsync_counter = _cogl_winsys_get_vsync_counter (context); +- +- if (!glx_renderer->glXSwapInterval) ++ if (glx_renderer->glXSwapInterval) + { +- CoglBool can_wait = glx_display->can_vblank_wait; ++ if (_cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_THREADED_SWAP_WAIT)) ++ { ++ /* If we didn't wait for the GPU here, then it's easy to get the case ++ * where there is a VBlank between the point where we get the vsync counter ++ * and the point where the GPU is ready to actually perform the glXSwapBuffers(), ++ * and the swap wait terminates at the first VBlank rather than the one ++ * where the swap buffers happens. Calling glFinish() here makes this a ++ * rare race since the GPU is already ready to swap when we call glXSwapBuffers(). ++ * The glFinish() also prevents any serious damage if the rare race happens, ++ * since it will wait for the preceding glXSwapBuffers() and prevent us from ++ * getting premanently ahead. (For NVIDIA drivers, glFinish() after glXSwapBuffers() ++ * waits for the buffer swap to happen.) ++ */ ++ _cogl_winsys_wait_for_gpu (onscreen); ++ start_threaded_swap_wait (onscreen, _cogl_winsys_get_vsync_counter (context)); ++ } ++ } ++ else ++ { ++ CoglBool can_wait = have_counter || glx_display->can_vblank_wait; ++ ++ uint32_t end_frame_vsync_counter = 0; ++ ++ /* If the swap_region API is also being used then we need to track ++ * the vsync counter for each swap request so we can manually ++ * throttle swap_region requests. */ ++ if (have_counter) ++ end_frame_vsync_counter = _cogl_winsys_get_vsync_counter (context); + + /* If we are going to wait for VBLANK manually, we not only + * need to flush out pending drawing to the GPU before we +diff -up cogl-1.18.2/examples/cogl-crate.c.threaded-sync-events cogl-1.18.2/examples/cogl-crate.c +--- cogl-1.18.2/examples/cogl-crate.c.threaded-sync-events 2016-06-30 15:44:39.804351929 -0400 ++++ cogl-1.18.2/examples/cogl-crate.c 2016-06-30 15:44:39.824352252 -0400 +@@ -1,5 +1,6 @@ + #include + #include ++#include + + /* The state for this example... */ + typedef struct _Data +@@ -153,6 +154,8 @@ main (int argc, char **argv) + float fovy, aspect, z_near, z_2d, z_far; + CoglDepthState depth_state; + ++ XInitThreads (); ++ + ctx = cogl_context_new (NULL, &error); + if (!ctx) { + fprintf (stderr, "Failed to create context: %s\n", error->message); diff --git a/SOURCES/0007-Add-cogl_xlib_renderer_set_threaded_swap_wait_enable.patch b/SOURCES/0007-Add-cogl_xlib_renderer_set_threaded_swap_wait_enable.patch new file mode 100644 index 0000000..3141576 --- /dev/null +++ b/SOURCES/0007-Add-cogl_xlib_renderer_set_threaded_swap_wait_enable.patch @@ -0,0 +1,159 @@ +From e31a4722c43db908e1831f77559d7a721cc08c1d Mon Sep 17 00:00:00 2001 +From: "Owen W. Taylor" +Date: Wed, 29 Jun 2016 13:52:59 -0400 +Subject: [PATCH] Add cogl_xlib_renderer_set_threaded_swap_wait_enabled() + +Because the threaded-swap-wait functionality requires XInitThreads(), +and because it isn't clear that it is a win for all applications, +add a API function to conditionally enable it. + +Fix the cogl-crate example not to just have a hard-coded dependency +on libX11. +--- + cogl/cogl-renderer-private.h | 1 + + cogl/cogl-renderer.c | 11 +++++++++++ + cogl/cogl-xlib-renderer.h | 30 ++++++++++++++++++++++++++++++ + cogl/winsys/cogl-winsys-glx.c | 4 +++- + examples/cogl-crate.c | 32 ++++++++++++++++++++++++++++++-- + 5 files changed, 75 insertions(+), 3 deletions(-) + +diff -up cogl-1.18.2/cogl/cogl-renderer.c.swap-wait-setter cogl-1.18.2/cogl/cogl-renderer.c +--- cogl-1.18.2/cogl/cogl-renderer.c.swap-wait-setter 2016-06-30 15:58:16.047534998 -0400 ++++ cogl-1.18.2/cogl/cogl-renderer.c 2016-06-30 15:58:16.084535595 -0400 +@@ -357,6 +357,17 @@ cogl_xlib_renderer_request_reset_on_vide + + renderer->xlib_want_reset_on_video_memory_purge = enable; + } ++ ++void ++cogl_xlib_renderer_set_threaded_swap_wait_enabled (CoglRenderer *renderer, ++ CoglBool enable) ++{ ++ _COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer)); ++ /* NB: Renderers are considered immutable once connected */ ++ _COGL_RETURN_IF_FAIL (!renderer->connected); ++ ++ renderer->xlib_enable_threaded_swap_wait = enable; ++} + #endif /* COGL_HAS_XLIB_SUPPORT */ + + CoglBool +diff -up cogl-1.18.2/cogl/cogl-renderer-private.h.swap-wait-setter cogl-1.18.2/cogl/cogl-renderer-private.h +--- cogl-1.18.2/cogl/cogl-renderer-private.h.swap-wait-setter 2016-06-30 15:58:16.047534998 -0400 ++++ cogl-1.18.2/cogl/cogl-renderer-private.h 2016-06-30 15:58:16.084535595 -0400 +@@ -71,6 +71,7 @@ struct _CoglRenderer + Display *foreign_xdpy; + CoglBool xlib_enable_event_retrieval; + CoglBool xlib_want_reset_on_video_memory_purge; ++ CoglBool xlib_enable_threaded_swap_wait; + #endif + + #ifdef COGL_HAS_WIN32_SUPPORT +diff -up cogl-1.18.2/cogl/cogl-xlib-renderer.h.swap-wait-setter cogl-1.18.2/cogl/cogl-xlib-renderer.h +--- cogl-1.18.2/cogl/cogl-xlib-renderer.h.swap-wait-setter 2016-06-30 15:58:16.047534998 -0400 ++++ cogl-1.18.2/cogl/cogl-xlib-renderer.h 2016-06-30 15:58:16.084535595 -0400 +@@ -166,6 +166,36 @@ void + cogl_xlib_renderer_set_event_retrieval_enabled (CoglRenderer *renderer, + CoglBool enable); + ++/** ++ * cogl_xlib_renderer_set_threaded_swap_wait_enabled: ++ * @renderer: a #CoglRenderer ++ * @enable: The new value ++ * ++ * Sets whether Cogl is allowed to use a separate threaded to wait for the ++ * completion of glXSwapBuffers() and call the frame callback for the ++ * corresponding #CoglOnscreen. This is a way of emulating the ++ * INTEL_swap_event extension, and will only ever be used if ++ * INTEL_swap_event is not present; it will also only be used for ++ * specific white-listed drivers that are known to work correctly with ++ * multiple contexts sharing state between threads. ++ * ++ * The advantage of enabling this is that it will allow your main loop ++ * to do other work while waiting for the system to be ready to draw ++ * the next frame, instead of blocking in glXSwapBuffers(). A disadvantage ++ * is that the driver will be prevented from buffering up multiple frames ++ * even if it thinks that it would be advantageous. In general, this ++ * will work best for something like a system compositor that is doing ++ * simple drawing but handling lots of other complex tasks. ++ * ++ * If you enable this, you must call XInitThreads() before any other ++ * X11 calls in your program. (See the documentation for XInitThreads()) ++ * ++ * Stability: unstable ++ */ ++void ++cogl_xlib_renderer_set_threaded_swap_wait_enabled (CoglRenderer *renderer, ++ CoglBool enable); ++ + Display * + cogl_xlib_renderer_get_display (CoglRenderer *renderer); + +diff -up cogl-1.18.2/cogl/winsys/cogl-winsys-glx.c.swap-wait-setter cogl-1.18.2/cogl/winsys/cogl-winsys-glx.c +--- cogl-1.18.2/cogl/winsys/cogl-winsys-glx.c.swap-wait-setter 2016-06-30 15:58:16.085535611 -0400 ++++ cogl-1.18.2/cogl/winsys/cogl-winsys-glx.c 2016-06-30 15:58:55.708175372 -0400 +@@ -901,6 +901,7 @@ update_winsys_features (CoglContext *con + { + CoglGpuInfo *info = &context->gpu; + if (glx_display->have_vblank_counter && ++ context->display->renderer->xlib_enable_threaded_swap_wait && + info->vendor == COGL_GPU_INFO_VENDOR_NVIDIA) + { + COGL_FLAGS_SET (context->winsys_features, +diff -up cogl-1.18.2/examples/cogl-crate.c.swap-wait-setter cogl-1.18.2/examples/cogl-crate.c +--- cogl-1.18.2/examples/cogl-crate.c.swap-wait-setter 2016-06-30 15:58:16.082535563 -0400 ++++ cogl-1.18.2/examples/cogl-crate.c 2016-06-30 15:58:16.085535611 -0400 +@@ -1,6 +1,9 @@ + #include + #include ++#ifdef COGL_HAS_XLIB_SUPPORT + #include ++#include ++#endif /* COGL_HAS_XLIB_SUPPORT */ + + /* The state for this example... */ + typedef struct _Data +@@ -145,6 +148,8 @@ frame_event_cb (CoglOnscreen *onscreen, + int + main (int argc, char **argv) + { ++ CoglRenderer *renderer; ++ CoglDisplay *display; + CoglContext *ctx; + CoglOnscreen *onscreen; + CoglFramebuffer *fb; +@@ -154,9 +159,32 @@ main (int argc, char **argv) + float fovy, aspect, z_near, z_2d, z_far; + CoglDepthState depth_state; + +- XInitThreads (); ++ renderer = cogl_renderer_new (); + +- ctx = cogl_context_new (NULL, &error); ++#ifdef COGL_HAS_XLIB_SUPPORT ++ /* Guess if we're using the GLX renderer; we could just blindly ++ * call XInitThreads() as long as we're linked against Xlib ++ * but it's a bit cleaner not to if we're not going to even ++ * open a display. ++ */ ++ if (g_getenv("DISPLAY") != NULL) ++ { ++ const char *renderer_environment = g_getenv("COGL_RENDERER_NEW"); ++ if (renderer_environment == NULL || g_strcmp0 (renderer_environment, "GLX") == 0) ++ { ++ XInitThreads (); ++ cogl_xlib_renderer_set_threaded_swap_wait_enabled (renderer, TRUE); ++ } ++ } ++#endif /* COGL_HAS_XLIB_SUPPORT */ ++ ++ if (!cogl_renderer_connect (renderer, &error)) { ++ fprintf (stderr, "Failed to connect CoglRenderer: %s\n", error->message); ++ return 1; ++ } ++ ++ display = cogl_display_new (renderer, NULL); ++ ctx = cogl_context_new (display, &error); + if (!ctx) { + fprintf (stderr, "Failed to create context: %s\n", error->message); + return 1; diff --git a/SOURCES/video-memory-purge.patch b/SOURCES/video-memory-purge.patch new file mode 100644 index 0000000..619e6eb --- /dev/null +++ b/SOURCES/video-memory-purge.patch @@ -0,0 +1,962 @@ +From c0bc9bef7fb7bb416acff6160338664a17874773 Mon Sep 17 00:00:00 2001 +From: Adel Gadllah +Date: Sun, 26 Jul 2015 11:27:00 +0200 +Subject: [PATCH 1/5] winsys-glx: Add error traps in create_context + +Both create_gl3_context and glXCreateNewContext can fail with an X error. + +https://bugzilla.gnome.org/show_bug.cgi?id=742678 +--- + cogl/winsys/cogl-winsys-glx.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c +index 0487b79..4f7abfb 100644 +--- a/cogl/winsys/cogl-winsys-glx.c ++++ b/cogl/winsys/cogl-winsys-glx.c +@@ -1075,6 +1075,8 @@ create_context (CoglDisplay *display, CoglError **error) + COGL_NOTE (WINSYS, "Creating GLX Context (display: %p)", + xlib_renderer->xdpy); + ++ _cogl_xlib_renderer_trap_errors (display->renderer, &old_state); ++ + if (display->renderer->driver == COGL_DRIVER_GL3) + glx_display->glx_context = create_gl3_context (display, config); + else +@@ -1085,7 +1087,8 @@ create_context (CoglDisplay *display, CoglError **error) + NULL, + True); + +- if (glx_display->glx_context == NULL) ++ if (_cogl_xlib_renderer_untrap_errors (display->renderer, &old_state) || ++ glx_display->glx_context == NULL) + { + _cogl_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_CONTEXT, +-- +2.7.4 + + +From 55af12d4ec146c610dd3c05d777f1ae33738c218 Mon Sep 17 00:00:00 2001 +From: Emmanuele Bassi +Date: Thu, 6 Aug 2015 12:19:52 +0100 +Subject: [PATCH 2/5] gl: Do not use deprecated constants with the GL3 driver + +glGetIntegerv (GL_DEPTH_BITS, ...) and friends are deprecated in GL3; we +have to use glGetFramebufferAttachmentParameteriv() instead, like we do +for offscreen framebuffers. + +Based on a patch by: Adel Gadllah +Signed-off-by: Emmanuele Bassi + +https://bugzilla.gnome.org/show_bug.cgi?id=753295 +--- + cogl/driver/gl/cogl-framebuffer-gl.c | 46 ++++++++++++++++++++---------------- + 1 file changed, 26 insertions(+), 20 deletions(-) + +diff --git a/cogl/driver/gl/cogl-framebuffer-gl.c b/cogl/driver/gl/cogl-framebuffer-gl.c +index 793b10b..26bcc5f 100644 +--- a/cogl/driver/gl/cogl-framebuffer-gl.c ++++ b/cogl/driver/gl/cogl-framebuffer-gl.c +@@ -1028,29 +1028,35 @@ _cogl_framebuffer_init_bits (CoglFramebuffer *framebuffer) + COGL_FRAMEBUFFER_STATE_BIND); + + #ifdef HAVE_COGL_GL +- if (_cogl_has_private_feature +- (ctx, COGL_PRIVATE_FEATURE_QUERY_FRAMEBUFFER_BITS) && +- framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN) ++ if ((ctx->driver == COGL_DRIVER_GL3 && ++ framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN) || ++ (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_QUERY_FRAMEBUFFER_BITS) && ++ framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN)) + { +- static const struct +- { ++ gboolean is_offscreen = framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN; ++ const struct { + GLenum attachment, pname; + size_t offset; +- } params[] = +- { +- { GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, +- offsetof (CoglFramebufferBits, red) }, +- { GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE, +- offsetof (CoglFramebufferBits, green) }, +- { GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE, +- offsetof (CoglFramebufferBits, blue) }, +- { GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE, +- offsetof (CoglFramebufferBits, alpha) }, +- { GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE, +- offsetof (CoglFramebufferBits, depth) }, +- { GL_STENCIL_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, +- offsetof (CoglFramebufferBits, stencil) }, +- }; ++ } params[] = { ++ { is_offscreen ? GL_COLOR_ATTACHMENT0 : GL_BACK_LEFT, ++ GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, ++ offsetof (CoglFramebufferBits, red) }, ++ { is_offscreen ? GL_COLOR_ATTACHMENT0 : GL_BACK_LEFT, ++ GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE, ++ offsetof (CoglFramebufferBits, green) }, ++ { is_offscreen ? GL_COLOR_ATTACHMENT0 : GL_BACK_LEFT, ++ GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE, ++ offsetof (CoglFramebufferBits, blue) }, ++ { is_offscreen ? GL_COLOR_ATTACHMENT0 : GL_BACK_LEFT, ++ GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE, ++ offsetof (CoglFramebufferBits, alpha) }, ++ { is_offscreen ? GL_DEPTH_ATTACHMENT : GL_DEPTH, ++ GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE, ++ offsetof (CoglFramebufferBits, depth) }, ++ { is_offscreen ? GL_STENCIL_ATTACHMENT : GL_STENCIL, ++ GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, ++ offsetof (CoglFramebufferBits, stencil) }, ++ }; + int i; + + for (i = 0; i < G_N_ELEMENTS (params); i++) +-- +2.7.4 + + +From 067d3cb0f8a67a1c5ba144505c124ec42f409aaf Mon Sep 17 00:00:00 2001 +From: Rui Matos +Date: Wed, 29 Jun 2016 15:37:14 +0200 +Subject: [PATCH 3/5] cogl-winsys-glx: Add support for + NV_robustness_video_memory_purge + +This adds API to allow callers to specify that they're interested in +video memory purge errors. + +https://bugzilla.gnome.org/show_bug.cgi?id=739178 +--- + cogl/cogl-renderer-private.h | 1 + + cogl/cogl-renderer.c | 10 ++++++++ + cogl/cogl-xlib-renderer.h | 41 +++++++++++++++++++++++++++++++ + cogl/cogl.symbols | 1 + + cogl/gl-prototypes/cogl-all-functions.h | 8 ++++++ + cogl/winsys/cogl-winsys-glx.c | 43 +++++++++++++++++++++++++++++++++ + 6 files changed, 104 insertions(+) + +diff --git a/cogl/cogl-renderer-private.h b/cogl/cogl-renderer-private.h +index 3871d91..4a2fa6e 100644 +--- a/cogl/cogl-renderer-private.h ++++ b/cogl/cogl-renderer-private.h +@@ -70,6 +70,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 + + #ifdef COGL_HAS_WIN32_SUPPORT +diff --git a/cogl/cogl-renderer.c b/cogl/cogl-renderer.c +index ef6e900..52a4732 100644 +--- a/cogl/cogl-renderer.c ++++ b/cogl/cogl-renderer.c +@@ -347,6 +347,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-xlib-renderer.h b/cogl/cogl-xlib-renderer.h +index 6318957..a81f275 100644 +--- a/cogl/cogl-xlib-renderer.h ++++ b/cogl/cogl-xlib-renderer.h +@@ -169,6 +169,47 @@ cogl_xlib_renderer_set_event_retrieval_enabled (CoglRenderer *renderer, + Display * + cogl_xlib_renderer_get_display (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.symbols b/cogl/cogl.symbols +index c48314a..feb9e65 100644 +--- a/cogl/cogl.symbols ++++ b/cogl/cogl.symbols +@@ -1065,6 +1065,7 @@ cogl_xlib_renderer_get_display + cogl_xlib_renderer_get_foreign_display + 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/gl-prototypes/cogl-all-functions.h b/cogl/gl-prototypes/cogl-all-functions.h +index dda08f7..c1c5462 100644 +--- a/cogl/gl-prototypes/cogl-all-functions.h ++++ b/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/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c +index 4f7abfb..097589f 100644 +--- a/cogl/winsys/cogl-winsys-glx.c ++++ b/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 */, +-- +2.7.4 + + +From e91a1f5217d28e8e181e4fd98b78ec180d601228 Mon Sep 17 00:00:00 2001 +From: Rui Matos +Date: Sun, 29 May 2016 20:30:36 +0200 +Subject: [PATCH 4/5] cogl-context: Add a cogl_get_graphics_reset_status API + +If the driver supports the GL_ARB_robustness extension we can expose +the graphics reset status this way. + +https://bugzilla.gnome.org/show_bug.cgi?id=739178 +--- + cogl/cogl-context.c | 30 ++++++++++++++++++++++++++++++ + cogl/cogl-context.h | 42 ++++++++++++++++++++++++++++++++++++++++++ + cogl/cogl.symbols | 1 + + 3 files changed, 73 insertions(+) + +diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c +index a7eed29..4b1af61 100644 +--- a/cogl/cogl-context.c ++++ b/cogl/cogl-context.c +@@ -76,6 +76,11 @@ + #define GL_NUM_EXTENSIONS 0x821D + #endif + ++/* This is a relatively new extension */ ++#ifndef GL_PURGED_CONTEXT_RESET_NV ++#define GL_PURGED_CONTEXT_RESET_NV 0x92BB ++#endif ++ + static void _cogl_context_free (CoglContext *context); + + COGL_OBJECT_DEFINE (Context, context); +@@ -784,3 +789,28 @@ cogl_get_clock_time (CoglContext *context) + else + return 0; + } ++ ++CoglGraphicsResetStatus ++cogl_get_graphics_reset_status (CoglContext *context) ++{ ++ if (!context->glGetGraphicsResetStatus) ++ return COGL_GRAPHICS_RESET_STATUS_NO_ERROR; ++ ++ switch (context->glGetGraphicsResetStatus ()) ++ { ++ case GL_GUILTY_CONTEXT_RESET_ARB: ++ return COGL_GRAPHICS_RESET_STATUS_GUILTY_CONTEXT_RESET; ++ ++ case GL_INNOCENT_CONTEXT_RESET_ARB: ++ return COGL_GRAPHICS_RESET_STATUS_INNOCENT_CONTEXT_RESET; ++ ++ case GL_UNKNOWN_CONTEXT_RESET_ARB: ++ return COGL_GRAPHICS_RESET_STATUS_UNKNOWN_CONTEXT_RESET; ++ ++ case GL_PURGED_CONTEXT_RESET_NV: ++ return COGL_GRAPHICS_RESET_STATUS_PURGED_CONTEXT_RESET; ++ ++ default: ++ return COGL_GRAPHICS_RESET_STATUS_NO_ERROR; ++ } ++} +diff --git a/cogl/cogl-context.h b/cogl/cogl-context.h +index 07badeb..cab586b 100644 +--- a/cogl/cogl-context.h ++++ b/cogl/cogl-context.h +@@ -393,6 +393,48 @@ cogl_foreach_feature (CoglContext *context, + int64_t + cogl_get_clock_time (CoglContext *context); + ++/** ++ * CoglGraphicsResetStatus: ++ * @COGL_GRAPHICS_RESET_STATUS_NO_ERROR: ++ * @COGL_GRAPHICS_RESET_STATUS_GUILTY_CONTEXT_RESET: ++ * @COGL_GRAPHICS_RESET_STATUS_INNOCENT_CONTEXT_RESET: ++ * @COGL_GRAPHICS_RESET_STATUS_UNKNOWN_CONTEXT_RESET: ++ * @COGL_GRAPHICS_RESET_STATUS_PURGED_CONTEXT_RESET: ++ * ++ * All the error values that might be returned by ++ * cogl_get_graphics_reset_status(). Each value's meaning corresponds ++ * to the similarly named value defined in the ARB_robustness and ++ * NV_robustness_video_memory_purge extensions. ++ */ ++typedef enum _CoglGraphicsResetStatus ++{ ++ COGL_GRAPHICS_RESET_STATUS_NO_ERROR, ++ COGL_GRAPHICS_RESET_STATUS_GUILTY_CONTEXT_RESET, ++ COGL_GRAPHICS_RESET_STATUS_INNOCENT_CONTEXT_RESET, ++ COGL_GRAPHICS_RESET_STATUS_UNKNOWN_CONTEXT_RESET, ++ COGL_GRAPHICS_RESET_STATUS_PURGED_CONTEXT_RESET, ++} CoglGraphicsResetStatus; ++ ++/** ++ * cogl_get_graphics_reset_status: ++ * @context: a #CoglContext pointer ++ * ++ * Returns the graphics reset status as reported by ++ * GetGraphicsResetStatusARB defined in the ARB_robustness extension. ++ * ++ * Note that Cogl doesn't normally enable the ARB_robustness ++ * extension in which case this will only ever return ++ * #COGL_GRAPHICS_RESET_STATUS_NO_ERROR. ++ * ++ * Applications must explicitly use a backend specific method to ++ * request that errors get reported such as X11's ++ * cogl_xlib_renderer_request_reset_on_video_memory_purge(). ++ * ++ * Return value: a #CoglGraphicsResetStatus ++ */ ++CoglGraphicsResetStatus ++cogl_get_graphics_reset_status (CoglContext *context); ++ + #endif /* COGL_ENABLE_EXPERIMENTAL_API */ + + COGL_END_DECLS +diff --git a/cogl/cogl.symbols b/cogl/cogl.symbols +index feb9e65..eb72407 100644 +--- a/cogl/cogl.symbols ++++ b/cogl/cogl.symbols +@@ -334,6 +334,7 @@ cogl_get_clock_time + cogl_get_depth_test_enabled + cogl_get_draw_framebuffer + cogl_get_features ++cogl_get_graphics_reset_status + cogl_get_modelview_matrix + cogl_get_option_group + cogl_get_proc_address +-- +2.7.4 + + +From 6361d971c0775b4d7c20e3c2deb8c87ce546a94d Mon Sep 17 00:00:00 2001 +From: Rui Matos +Date: Tue, 24 May 2016 19:37:02 +0200 +Subject: [PATCH 5/5] cogl: Ignore GL_CONTEXT_LOST when checking for GL errors + +When using a context with robustness, glGetError() may return +GL_CONTEXT_LOST at any time and this error doesn't get cleared until +the application calls glGetGraphicsResetStatus() . This means that our +error checking can't call glGetError() in a loop without checking for +that return value and returning in that case. + +https://bugzilla.gnome.org/show_bug.cgi?id=739178 +--- + cogl/cogl-texture-3d.c | 4 +--- + cogl/cogl-texture-rectangle.c | 10 +++------- + cogl/deprecated/cogl-shader.c | 5 ++--- + cogl/driver/gl/cogl-buffer-gl.c | 15 ++++----------- + cogl/driver/gl/cogl-pipeline-opengl.c | 7 ++----- + cogl/driver/gl/cogl-texture-2d-gl.c | 16 +++++----------- + cogl/driver/gl/cogl-util-gl-private.h | 10 ++++++++-- + cogl/driver/gl/cogl-util-gl.c | 22 +++++++++++++++++++++- + cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp.c | 6 ++---- + cogl/driver/gl/gl/cogl-texture-driver-gl.c | 12 +++--------- + cogl/driver/gl/gles/cogl-texture-driver-gles.c | 18 +++++------------- + 11 files changed, 56 insertions(+), 69 deletions(-) + +diff --git a/cogl/cogl-texture-3d.c b/cogl/cogl-texture-3d.c +index 8e2ff08..31d2941 100644 +--- a/cogl/cogl-texture-3d.c ++++ b/cogl/cogl-texture-3d.c +@@ -361,7 +361,6 @@ allocate_with_size (CoglTexture3D *tex_3d, + GLenum gl_intformat; + GLenum gl_format; + GLenum gl_type; +- GLenum gl_error; + GLenum gl_texture; + + internal_format = +@@ -387,8 +386,7 @@ allocate_with_size (CoglTexture3D *tex_3d, + gl_texture, + FALSE); + /* Clear any GL errors */ +- while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) +- ; ++ _cogl_gl_util_clear_gl_errors (ctx); + + ctx->glTexImage3D (GL_TEXTURE_3D, 0, gl_intformat, + width, height, depth, +diff --git a/cogl/cogl-texture-rectangle.c b/cogl/cogl-texture-rectangle.c +index 65d2f06..da5f1f0 100644 +--- a/cogl/cogl-texture-rectangle.c ++++ b/cogl/cogl-texture-rectangle.c +@@ -228,7 +228,6 @@ allocate_with_size (CoglTextureRectangle *tex_rect, + GLenum gl_intformat; + GLenum gl_format; + GLenum gl_type; +- GLenum gl_error; + GLenum gl_texture; + + internal_format = +@@ -256,8 +255,7 @@ allocate_with_size (CoglTextureRectangle *tex_rect, + tex_rect->is_foreign); + + /* Clear any GL errors */ +- while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) +- ; ++ _cogl_gl_util_clear_gl_errors (ctx); + + ctx->glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, gl_intformat, + width, height, 0, gl_format, gl_type, NULL); +@@ -361,7 +359,6 @@ allocate_from_gl_foreign (CoglTextureRectangle *tex_rect, + CoglTexture *tex = COGL_TEXTURE (tex_rect); + CoglContext *ctx = tex->context; + CoglPixelFormat format = loader->src.gl_foreign.format; +- GLenum gl_error = 0; + GLint gl_compressed = GL_FALSE; + GLenum gl_int_format = 0; + +@@ -377,12 +374,11 @@ allocate_from_gl_foreign (CoglTextureRectangle *tex_rect, + } + + /* Make sure binding succeeds */ +- while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) +- ; ++ _cogl_gl_util_clear_gl_errors (ctx); + + _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB, + loader->src.gl_foreign.gl_handle, TRUE); +- if (ctx->glGetError () != GL_NO_ERROR) ++ if (_cogl_gl_util_get_error (ctx) != GL_NO_ERROR) + { + _cogl_set_error (error, + COGL_SYSTEM_ERROR, +diff --git a/cogl/deprecated/cogl-shader.c b/cogl/deprecated/cogl-shader.c +index 08dcb82..d4b687c 100644 +--- a/cogl/deprecated/cogl-shader.c ++++ b/cogl/deprecated/cogl-shader.c +@@ -213,15 +213,14 @@ _cogl_shader_compile_real (CoglHandle handle, + g_message ("user ARBfp program:\n%s", shader->source); + + #ifdef COGL_GL_DEBUG +- while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) +- ; ++ _cogl_gl_util_clear_gl_errors (ctx); + #endif + ctx->glProgramString (GL_FRAGMENT_PROGRAM_ARB, + GL_PROGRAM_FORMAT_ASCII_ARB, + strlen (shader->source), + shader->source); + #ifdef COGL_GL_DEBUG +- gl_error = ctx->glGetError (); ++ gl_error = _cogl_gl_util_get_error (ctx); + if (gl_error != GL_NO_ERROR) + { + g_warning ("%s: GL error (%d): Failed to compile ARBfp:\n%s\n%s", +diff --git a/cogl/driver/gl/cogl-buffer-gl.c b/cogl/driver/gl/cogl-buffer-gl.c +index 0f98406..b8cd03f 100644 +--- a/cogl/driver/gl/cogl-buffer-gl.c ++++ b/cogl/driver/gl/cogl-buffer-gl.c +@@ -142,7 +142,6 @@ recreate_store (CoglBuffer *buffer, + CoglContext *ctx = buffer->context; + GLenum gl_target; + GLenum gl_enum; +- GLenum gl_error; + + /* This assumes the buffer is already bound */ + +@@ -150,8 +149,7 @@ recreate_store (CoglBuffer *buffer, + gl_enum = update_hints_to_gl_enum (buffer); + + /* Clear any GL errors */ +- while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) +- ; ++ _cogl_gl_util_clear_gl_errors (ctx); + + ctx->glBufferData (gl_target, + buffer->size, +@@ -216,7 +214,6 @@ _cogl_buffer_gl_map_range (CoglBuffer *buffer, + CoglBufferBindTarget target; + GLenum gl_target; + CoglContext *ctx = buffer->context; +- GLenum gl_error; + + if (((access & COGL_BUFFER_ACCESS_READ) && + !cogl_has_feature (ctx, COGL_FEATURE_ID_MAP_BUFFER_FOR_READ)) || +@@ -282,8 +279,7 @@ _cogl_buffer_gl_map_range (CoglBuffer *buffer, + } + + /* Clear any GL errors */ +- while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) +- ; ++ _cogl_gl_util_clear_gl_errors (ctx); + + data = ctx->glMapBufferRange (gl_target, + offset, +@@ -314,8 +310,7 @@ _cogl_buffer_gl_map_range (CoglBuffer *buffer, + } + + /* Clear any GL errors */ +- while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) +- ; ++ _cogl_gl_util_clear_gl_errors (ctx); + + data = ctx->glMapBuffer (gl_target, + _cogl_buffer_access_to_gl_enum (access)); +@@ -363,7 +358,6 @@ _cogl_buffer_gl_set_data (CoglBuffer *buffer, + CoglBufferBindTarget target; + GLenum gl_target; + CoglContext *ctx = buffer->context; +- GLenum gl_error; + CoglBool status = TRUE; + CoglError *internal_error = NULL; + +@@ -384,8 +378,7 @@ _cogl_buffer_gl_set_data (CoglBuffer *buffer, + gl_target = convert_bind_target_to_gl_target (target); + + /* Clear any GL errors */ +- while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) +- ; ++ _cogl_gl_util_clear_gl_errors (ctx); + + ctx->glBufferSubData (gl_target, offset, size, data); + +diff --git a/cogl/driver/gl/cogl-pipeline-opengl.c b/cogl/driver/gl/cogl-pipeline-opengl.c +index c7b44ee..52c2392 100644 +--- a/cogl/driver/gl/cogl-pipeline-opengl.c ++++ b/cogl/driver/gl/cogl-pipeline-opengl.c +@@ -253,12 +253,9 @@ set_glsl_program (GLuint gl_program) + + if (ctx->current_gl_program != gl_program) + { +- GLenum gl_error; +- +- while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) +- ; ++ _cogl_gl_util_clear_gl_errors (ctx); + ctx->glUseProgram (gl_program); +- if (ctx->glGetError () == GL_NO_ERROR) ++ if (_cogl_gl_util_get_error (ctx) == GL_NO_ERROR) + ctx->current_gl_program = gl_program; + else + { +diff --git a/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/driver/gl/cogl-texture-2d-gl.c +index 8675f52..1cae680 100644 +--- a/cogl/driver/gl/cogl-texture-2d-gl.c ++++ b/cogl/driver/gl/cogl-texture-2d-gl.c +@@ -116,7 +116,6 @@ allocate_with_size (CoglTexture2D *tex_2d, + GLenum gl_intformat; + GLenum gl_format; + GLenum gl_type; +- GLenum gl_error; + GLenum gl_texture; + + internal_format = +@@ -149,8 +148,7 @@ allocate_with_size (CoglTexture2D *tex_2d, + tex_2d->is_foreign); + + /* Clear any GL errors */ +- while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) +- ; ++ _cogl_gl_util_clear_gl_errors (ctx); + + ctx->glTexImage2D (GL_TEXTURE_2D, 0, gl_intformat, + width, height, 0, gl_format, gl_type, NULL); +@@ -286,18 +284,16 @@ allocate_from_egl_image (CoglTexture2D *tex_2d, + CoglTexture *tex = COGL_TEXTURE (tex_2d); + CoglContext *ctx = tex->context; + CoglPixelFormat internal_format = loader->src.egl_image.format; +- GLenum gl_error; + + tex_2d->gl_texture = + ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, internal_format); + _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, + tex_2d->gl_texture, + FALSE); ++ _cogl_gl_util_clear_gl_errors (ctx); + +- while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) +- ; + ctx->glEGLImageTargetTexture2D (GL_TEXTURE_2D, loader->src.egl_image.image); +- if (ctx->glGetError () != GL_NO_ERROR) ++ if (_cogl_gl_util_get_error (ctx) != GL_NO_ERROR) + { + _cogl_set_error (error, + COGL_TEXTURE_ERROR, +@@ -327,7 +323,6 @@ allocate_from_gl_foreign (CoglTexture2D *tex_2d, + CoglTexture *tex = COGL_TEXTURE (tex_2d); + CoglContext *ctx = tex->context; + CoglPixelFormat format = loader->src.gl_foreign.format; +- GLenum gl_error = 0; + GLint gl_compressed = GL_FALSE; + GLenum gl_int_format = 0; + +@@ -342,12 +337,11 @@ allocate_from_gl_foreign (CoglTexture2D *tex_2d, + } + + /* Make sure binding succeeds */ +- while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) +- ; ++ _cogl_gl_util_clear_gl_errors (ctx); + + _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, + loader->src.gl_foreign.gl_handle, TRUE); +- if (ctx->glGetError () != GL_NO_ERROR) ++ if (_cogl_gl_util_get_error (ctx) != GL_NO_ERROR) + { + _cogl_set_error (error, + COGL_SYSTEM_ERROR, +diff --git a/cogl/driver/gl/cogl-util-gl-private.h b/cogl/driver/gl/cogl-util-gl-private.h +index dcc61c0..1407e0f 100644 +--- a/cogl/driver/gl/cogl-util-gl-private.h ++++ b/cogl/driver/gl/cogl-util-gl-private.h +@@ -45,7 +45,7 @@ _cogl_gl_error_to_string (GLenum error_code); + #define GE(ctx, x) G_STMT_START { \ + GLenum __err; \ + (ctx)->x; \ +- while ((__err = (ctx)->glGetError ()) != GL_NO_ERROR) \ ++ while ((__err = (ctx)->glGetError ()) != GL_NO_ERROR && __err != GL_CONTEXT_LOST) \ + { \ + g_warning ("%s: GL error (%d): %s\n", \ + G_STRLOC, \ +@@ -56,7 +56,7 @@ _cogl_gl_error_to_string (GLenum error_code); + #define GE_RET(ret, ctx, x) G_STMT_START { \ + GLenum __err; \ + ret = (ctx)->x; \ +- while ((__err = (ctx)->glGetError ()) != GL_NO_ERROR) \ ++ while ((__err = (ctx)->glGetError ()) != GL_NO_ERROR && __err != GL_CONTEXT_LOST) \ + { \ + g_warning ("%s: GL error (%d): %s\n", \ + G_STRLOC, \ +@@ -71,6 +71,12 @@ _cogl_gl_error_to_string (GLenum error_code); + + #endif /* COGL_GL_DEBUG */ + ++GLenum ++_cogl_gl_util_get_error (CoglContext *ctx); ++ ++void ++_cogl_gl_util_clear_gl_errors (CoglContext *ctx); ++ + CoglBool + _cogl_gl_util_catch_out_of_memory (CoglContext *ctx, CoglError **error); + +diff --git a/cogl/driver/gl/cogl-util-gl.c b/cogl/driver/gl/cogl-util-gl.c +index 814621a..f136673 100644 +--- a/cogl/driver/gl/cogl-util-gl.c ++++ b/cogl/driver/gl/cogl-util-gl.c +@@ -77,13 +77,33 @@ _cogl_gl_error_to_string (GLenum error_code) + } + #endif /* COGL_GL_DEBUG */ + ++GLenum ++_cogl_gl_util_get_error (CoglContext *ctx) ++{ ++ GLenum gl_error = ctx->glGetError (); ++ ++ if (gl_error != GL_NO_ERROR && gl_error != GL_CONTEXT_LOST) ++ return gl_error; ++ else ++ return GL_NO_ERROR; ++} ++ ++void ++_cogl_gl_util_clear_gl_errors (CoglContext *ctx) ++{ ++ GLenum gl_error; ++ ++ while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR && gl_error != GL_CONTEXT_LOST) ++ ; ++} ++ + CoglBool + _cogl_gl_util_catch_out_of_memory (CoglContext *ctx, CoglError **error) + { + GLenum gl_error; + CoglBool out_of_memory = FALSE; + +- while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) ++ while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR && gl_error != GL_CONTEXT_LOST) + { + if (gl_error == GL_OUT_OF_MEMORY) + out_of_memory = TRUE; +diff --git a/cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp.c b/cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp.c +index 16b13be..7be4a3f 100644 +--- a/cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp.c ++++ b/cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp.c +@@ -837,7 +837,6 @@ _cogl_pipeline_fragend_arbfp_end (CoglPipeline *pipeline, + + if (shader_state->source) + { +- GLenum gl_error; + COGL_STATIC_COUNTER (fragend_arbfp_compile_counter, + "arbfp compile counter", + "Increments each time a new ARBfp " +@@ -857,14 +856,13 @@ _cogl_pipeline_fragend_arbfp_end (CoglPipeline *pipeline, + + GE (ctx, glBindProgram (GL_FRAGMENT_PROGRAM_ARB, + shader_state->gl_program)); ++ _cogl_gl_util_clear_gl_errors (ctx); + +- while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) +- ; + ctx->glProgramString (GL_FRAGMENT_PROGRAM_ARB, + GL_PROGRAM_FORMAT_ASCII_ARB, + shader_state->source->len, + shader_state->source->str); +- if (ctx->glGetError () != GL_NO_ERROR) ++ if (_cogl_gl_util_get_error (ctx) != GL_NO_ERROR) + { + g_warning ("\n%s\n%s", + shader_state->source->str, +diff --git a/cogl/driver/gl/gl/cogl-texture-driver-gl.c b/cogl/driver/gl/gl/cogl-texture-driver-gl.c +index 109af81..1113966 100644 +--- a/cogl/driver/gl/gl/cogl-texture-driver-gl.c ++++ b/cogl/driver/gl/gl/cogl-texture-driver-gl.c +@@ -207,7 +207,6 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx, + uint8_t *data; + CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); + int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); +- GLenum gl_error; + CoglBool status = TRUE; + CoglError *internal_error = NULL; + int level_width; +@@ -237,8 +236,7 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx, + _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); + + /* Clear any GL errors */ +- while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) +- ; ++ _cogl_gl_util_clear_gl_errors (ctx); + + _cogl_texture_get_level_size (texture, + level, +@@ -315,7 +313,6 @@ _cogl_texture_driver_upload_to_gl (CoglContext *ctx, + uint8_t *data; + CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); + int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); +- GLenum gl_error; + CoglBool status = TRUE; + CoglError *internal_error = NULL; + +@@ -341,8 +338,7 @@ _cogl_texture_driver_upload_to_gl (CoglContext *ctx, + _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); + + /* Clear any GL errors */ +- while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) +- ; ++ _cogl_gl_util_clear_gl_errors (ctx); + + ctx->glTexImage2D (gl_target, 0, + internal_gl_format, +@@ -377,7 +373,6 @@ _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx, + uint8_t *data; + CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); + int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); +- GLenum gl_error; + CoglBool status = TRUE; + + data = _cogl_bitmap_gl_bind (source_bmp, COGL_BUFFER_ACCESS_READ, 0, error); +@@ -394,8 +389,7 @@ _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx, + _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); + + /* Clear any GL errors */ +- while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) +- ; ++ _cogl_gl_util_clear_gl_errors (ctx); + + ctx->glTexImage3D (gl_target, + 0, /* level */ +diff --git a/cogl/driver/gl/gles/cogl-texture-driver-gles.c b/cogl/driver/gl/gles/cogl-texture-driver-gles.c +index f87f1e9..85412a8 100644 +--- a/cogl/driver/gl/gles/cogl-texture-driver-gles.c ++++ b/cogl/driver/gl/gles/cogl-texture-driver-gles.c +@@ -201,7 +201,6 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx, + int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format); + CoglBitmap *slice_bmp; + int rowstride; +- GLenum gl_error; + CoglBool status = TRUE; + CoglError *internal_error = NULL; + int level_width; +@@ -265,8 +264,7 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx, + _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); + + /* Clear any GL errors */ +- while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) +- ; ++ _cogl_gl_util_clear_gl_errors (ctx); + + _cogl_texture_get_level_size (texture, + level, +@@ -348,7 +346,6 @@ _cogl_texture_driver_upload_to_gl (CoglContext *ctx, + int bmp_height = cogl_bitmap_get_height (source_bmp); + CoglBitmap *bmp; + uint8_t *data; +- GLenum gl_error; + CoglError *internal_error = NULL; + CoglBool status = TRUE; + +@@ -379,8 +376,7 @@ _cogl_texture_driver_upload_to_gl (CoglContext *ctx, + } + + /* Clear any GL errors */ +- while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) +- ; ++ _cogl_gl_util_clear_gl_errors (ctx); + + ctx->glTexImage2D (gl_target, 0, + internal_gl_format, +@@ -419,7 +415,6 @@ _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx, + int bmp_width = cogl_bitmap_get_width (source_bmp); + int bmp_height = cogl_bitmap_get_height (source_bmp); + uint8_t *data; +- GLenum gl_error; + + _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign); + +@@ -440,8 +435,7 @@ _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx, + image with a sub-region update */ + + /* Clear any GL errors */ +- while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) +- ; ++ _cogl_gl_util_clear_gl_errors (ctx); + + ctx->glTexImage3D (gl_target, + 0, /* level */ +@@ -488,8 +482,7 @@ _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx, + } + + /* Clear any GL errors */ +- while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) +- ; ++ _cogl_gl_util_clear_gl_errors (ctx); + + ctx->glTexSubImage3D (gl_target, + 0, /* level */ +@@ -524,8 +517,7 @@ _cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx, + _cogl_texture_driver_prep_gl_for_pixels_upload (ctx, rowstride, bpp); + + /* Clear any GL errors */ +- while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR) +- ; ++ _cogl_gl_util_clear_gl_errors (ctx); + + ctx->glTexImage3D (gl_target, + 0, /* level */ +-- +2.7.4 + diff --git a/SPECS/cogl.spec b/SPECS/cogl.spec index dab5c64..0cbb489 100644 --- a/SPECS/cogl.spec +++ b/SPECS/cogl.spec @@ -6,7 +6,7 @@ Name: cogl Version: 1.18.2 -Release: 10%{?dist} +Release: 12%{?dist} Summary: A library for using 3D graphics hardware to draw pretty pictures Group: Development/Libraries @@ -18,6 +18,16 @@ Source0: http://download.gnome.org/sources/cogl/1.18/cogl-%{version}.tar.x # development branch) Patch10: Add-support-for-setting-up-stereo-CoglOnscreens.patch Patch11: CoglTexturePixmapX11-add-support-for-stereo-content.patch +Patch12: video-memory-purge.patch + +# See https://bugzilla.gnome.org/show_bug.cgi?id=768190 +Patch21: 0001-examples-cogl-crate.c-fix-bug-when-waiting-for-next-.patch +Patch22: 0002-CoglGPUInfo-fix-check-for-NVIDIA.patch +Patch23: 0003-CoglWinsysGLX-factor-out-some-duplicated-code.patch +Patch24: 0004-Usability-of-SGI_video_sync-is-per-display-not-per-r.patch +Patch25: 0005-Fix-the-get_clock_time-without-GLX_OML_sync_control.patch +Patch26: 0006-For-NVIDIA-proprietary-drivers-implement-sync-events.patch +Patch27: 0007-Add-cogl_xlib_renderer_set_threaded_swap_wait_enable.patch BuildRequires: autoconf automake libtool gettext-devel @@ -98,6 +108,15 @@ This package contains the installable tests for %{cogl}. %patch10 -p1 %patch11 -p1 +%patch12 -p1 + +%patch21 -p1 -b .cogl-crate +%patch22 -p1 -b .gpuinfo +%patch23 -p1 -b .duplicated-code +%patch24 -p1 -b .video-sync +%patch25 -p1 -b .clock-time +%patch26 -p1 -b .threaded-sync-events +%patch27 -p1 -b .swap-wait-setter %build CFLAGS="$RPM_OPT_FLAGS -fPIC" @@ -160,6 +179,24 @@ chrpath --delete $RPM_BUILD_ROOT%{_libdir}/libcogl-pango.so %endif %changelog +* Wed Jun 29 2016 Owen Taylor - 1.18.2-12 +- Add patches to improve display synchronization on NVIDIA + + When testing quadbuffer stereo patches, GNOME Shell would sometimes + hang up on restart. This turned out to be a problem with display + synchronization on NVIDIA. The patches added here make display + synchronization work much more similarly with the NVIDIA drivers + and the open source drivers, which not only fixes this bug, but should + reduce future bugs. + + Resolves: #1305076 + +- Add patches improving frame completion events in Cogl + +* Wed Jun 15 2016 Rui Matos - 1.18.2-11 +- Add patch to support NV_robustness_video_memory_purge + Resolves: rhbz#1330488 + * Thu Apr 9 2015 Rui Matos - 1.18.2-10 - Rebase to 1.18.2 - Resolves: rhbz#1174508