Blob Blame History Raw
From bac385833fddb5dadb3be1eaf7b6071991c4b048 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 15 Jan 2019 11:01:38 -0500
Subject: [PATCH 1/9] cogl: add new UNSTABLE_TEXTURES feature

The proprietary nvidia driver garbles texture memory on suspend.

Before we can address that, we need to be able to detect it.

This commit adds a new UNSTABLE_TEXTURES feature that gets set if
the proprietary nvidia driver is in use.
---
 cogl/cogl/cogl-context.h           |  1 +
 cogl/cogl/cogl-types.h             |  5 ++++-
 cogl/cogl/winsys/cogl-winsys-egl.c | 11 +++++++++++
 cogl/cogl/winsys/cogl-winsys-glx.c | 13 +++++++++++--
 4 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/cogl/cogl/cogl-context.h b/cogl/cogl/cogl-context.h
index add575b49..985ce336d 100644
--- a/cogl/cogl/cogl-context.h
+++ b/cogl/cogl/cogl-context.h
@@ -236,60 +236,61 @@ cogl_is_context (void *object);
  * Since: 1.10
  */
 typedef enum _CoglFeatureID
 {
   COGL_FEATURE_ID_TEXTURE_NPOT_BASIC = 1,
   COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP,
   COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT,
   COGL_FEATURE_ID_TEXTURE_NPOT,
   COGL_FEATURE_ID_TEXTURE_RECTANGLE,
   COGL_FEATURE_ID_TEXTURE_3D,
   COGL_FEATURE_ID_GLSL,
   COGL_FEATURE_ID_ARBFP,
   COGL_FEATURE_ID_OFFSCREEN,
   COGL_FEATURE_ID_OFFSCREEN_MULTISAMPLE,
   COGL_FEATURE_ID_ONSCREEN_MULTIPLE,
   COGL_FEATURE_ID_UNSIGNED_INT_INDICES,
   COGL_FEATURE_ID_DEPTH_RANGE,
   COGL_FEATURE_ID_POINT_SPRITE,
   COGL_FEATURE_ID_MAP_BUFFER_FOR_READ,
   COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE,
   COGL_FEATURE_ID_MIRRORED_REPEAT,
   COGL_FEATURE_ID_SWAP_BUFFERS_EVENT,
   COGL_FEATURE_ID_GLES2_CONTEXT,
   COGL_FEATURE_ID_DEPTH_TEXTURE,
   COGL_FEATURE_ID_PRESENTATION_TIME,
   COGL_FEATURE_ID_FENCE,
   COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE,
   COGL_FEATURE_ID_TEXTURE_RG,
   COGL_FEATURE_ID_BUFFER_AGE,
   COGL_FEATURE_ID_TEXTURE_EGL_IMAGE_EXTERNAL,
+  COGL_FEATURE_ID_UNSTABLE_TEXTURES,
 
   /*< private >*/
   _COGL_N_FEATURE_IDS   /*< skip >*/
 } CoglFeatureID;
 
 
 /**
  * cogl_has_feature:
  * @context: A #CoglContext pointer
  * @feature: A #CoglFeatureID
  *
  * Checks if a given @feature is currently available
  *
  * Cogl does not aim to be a lowest common denominator API, it aims to
  * expose all the interesting features of GPUs to application which
  * means applications have some responsibility to explicitly check
  * that certain features are available before depending on them.
  *
  * Returns: %TRUE if the @feature is currently supported or %FALSE if
  * not.
  *
  * Since: 1.10
  * Stability: unstable
  */
 CoglBool
 cogl_has_feature (CoglContext *context, CoglFeatureID feature);
 
 /**
  * cogl_has_features:
  * @context: A #CoglContext pointer
diff --git a/cogl/cogl/cogl-types.h b/cogl/cogl/cogl-types.h
index f67895dd9..8338e284d 100644
--- a/cogl/cogl/cogl-types.h
+++ b/cogl/cogl/cogl-types.h
@@ -371,91 +371,94 @@ typedef enum { /*< prefix=COGL_PIXEL_FORMAT >*/
  * @COGL_FEATURE_OFFSCREEN_MULTISAMPLE: Multisample support on FBOs
  * @COGL_FEATURE_OFFSCREEN_BLIT: Blit support on FBOs
  * @COGL_FEATURE_FOUR_CLIP_PLANES: At least 4 clip planes available
  * @COGL_FEATURE_STENCIL_BUFFER: Stencil buffer support
  * @COGL_FEATURE_VBOS: VBO support
  * @COGL_FEATURE_PBOS: PBO support
  * @COGL_FEATURE_UNSIGNED_INT_INDICES: Set if
  *     %COGL_INDICES_TYPE_UNSIGNED_INT is supported in
  *     cogl_vertex_buffer_indices_new().
  * @COGL_FEATURE_DEPTH_RANGE: cogl_material_set_depth_range() support
  * @COGL_FEATURE_TEXTURE_NPOT_BASIC: The hardware supports non power
  *     of two textures, but you also need to check the
  *     %COGL_FEATURE_TEXTURE_NPOT_MIPMAP and %COGL_FEATURE_TEXTURE_NPOT_REPEAT
  *     features to know if the hardware supports npot texture mipmaps
  *     or repeat modes other than
  *     %COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE respectively.
  * @COGL_FEATURE_TEXTURE_NPOT_MIPMAP: Mipmapping is supported in
  *     conjuntion with non power of two textures.
  * @COGL_FEATURE_TEXTURE_NPOT_REPEAT: Repeat modes other than
  *     %COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE are supported by the
  *     hardware.
  * @COGL_FEATURE_POINT_SPRITE: Whether
  *     cogl_material_set_layer_point_sprite_coords_enabled() is supported.
  * @COGL_FEATURE_TEXTURE_3D: 3D texture support
  * @COGL_FEATURE_MAP_BUFFER_FOR_READ: Whether cogl_buffer_map() is
  *     supported with CoglBufferAccess including read support.
  * @COGL_FEATURE_MAP_BUFFER_FOR_WRITE: Whether cogl_buffer_map() is
  *     supported with CoglBufferAccess including write support.
  * @COGL_FEATURE_DEPTH_TEXTURE: Whether #CoglFramebuffer support rendering the
  *     depth buffer to a texture.
+ * @COGL_FEATURE_UNSTABLE_TEXTURES: Whether textures require redrawing on
+ *     resume or not.
  *
  * Flags for the supported features.
  *
  * Since: 0.8
  */
 typedef enum
 {
   COGL_FEATURE_TEXTURE_RECTANGLE      = (1 << 1),
   COGL_FEATURE_TEXTURE_NPOT           = (1 << 2),
   COGL_FEATURE_TEXTURE_YUV            = (1 << 3),
   COGL_FEATURE_TEXTURE_READ_PIXELS    = (1 << 4),
   COGL_FEATURE_SHADERS_GLSL           = (1 << 5),
   COGL_FEATURE_OFFSCREEN              = (1 << 6),
   COGL_FEATURE_OFFSCREEN_MULTISAMPLE  = (1 << 7),
   COGL_FEATURE_OFFSCREEN_BLIT         = (1 << 8),
   COGL_FEATURE_FOUR_CLIP_PLANES       = (1 << 9),
   COGL_FEATURE_STENCIL_BUFFER         = (1 << 10),
   COGL_FEATURE_VBOS		      = (1 << 11),
   COGL_FEATURE_PBOS		      = (1 << 12),
   COGL_FEATURE_UNSIGNED_INT_INDICES   = (1 << 13),
   COGL_FEATURE_DEPTH_RANGE            = (1 << 14),
   COGL_FEATURE_TEXTURE_NPOT_BASIC     = (1 << 15),
   COGL_FEATURE_TEXTURE_NPOT_MIPMAP    = (1 << 16),
   COGL_FEATURE_TEXTURE_NPOT_REPEAT    = (1 << 17),
   COGL_FEATURE_POINT_SPRITE           = (1 << 18),
   COGL_FEATURE_TEXTURE_3D             = (1 << 19),
   COGL_FEATURE_SHADERS_ARBFP          = (1 << 20),
   COGL_FEATURE_MAP_BUFFER_FOR_READ    = (1 << 21),
   COGL_FEATURE_MAP_BUFFER_FOR_WRITE   = (1 << 22),
   COGL_FEATURE_ONSCREEN_MULTIPLE      = (1 << 23),
-  COGL_FEATURE_DEPTH_TEXTURE          = (1 << 24)
+  COGL_FEATURE_DEPTH_TEXTURE          = (1 << 24),
+  COGL_FEATURE_UNSTABLE_TEXTURES      = (1 << 25)
 } CoglFeatureFlags;
 
 /**
  * CoglBufferTarget:
  * @COGL_WINDOW_BUFFER: FIXME
  * @COGL_OFFSCREEN_BUFFER: FIXME
  *
  * Target flags for FBOs.
  *
  * Since: 0.8
  */
 typedef enum
 {
   COGL_WINDOW_BUFFER      = (1 << 1),
   COGL_OFFSCREEN_BUFFER   = (1 << 2)
 } CoglBufferTarget;
 
 /**
  * CoglColor:
  * @red: amount of red
  * @green: amount of green
  * @blue: amount of green
  * @alpha: alpha
  *
  * A structure for holding a color definition. The contents of
  * the CoglColor structure are private and should never by accessed
  * directly.
  *
  * Since: 1.0
  */
diff --git a/cogl/cogl/winsys/cogl-winsys-egl.c b/cogl/cogl/winsys/cogl-winsys-egl.c
index 73648f663..66c2661b3 100644
--- a/cogl/cogl/winsys/cogl-winsys-egl.c
+++ b/cogl/cogl/winsys/cogl-winsys-egl.c
@@ -475,72 +475,83 @@ _cogl_winsys_display_setup (CoglDisplay *display,
       CoglRendererEGL *egl_renderer = display->renderer->winsys;
 
       if (egl_renderer->pf_eglBindWaylandDisplay)
 	egl_renderer->pf_eglBindWaylandDisplay (egl_renderer->edpy,
 						wayland_display);
     }
 #endif
 
   if (egl_renderer->platform_vtable->display_setup &&
       !egl_renderer->platform_vtable->display_setup (display, error))
     goto error;
 
   if (!try_create_context (display, error))
     goto error;
 
   egl_display->found_egl_config = TRUE;
 
   return TRUE;
 
 error:
   _cogl_winsys_display_destroy (display);
   return FALSE;
 }
 
 static CoglBool
 _cogl_winsys_context_init (CoglContext *context, CoglError **error)
 {
   CoglRenderer *renderer = context->display->renderer;
   CoglDisplayEGL *egl_display = context->display->winsys;
   CoglRendererEGL *egl_renderer = renderer->winsys;
+  CoglGpuInfo *info;
 
   context->winsys = g_new0 (CoglContextEGL, 1);
 
   _COGL_RETURN_VAL_IF_FAIL (egl_display->egl_context, FALSE);
 
   memset (context->winsys_features, 0, sizeof (context->winsys_features));
 
   check_egl_extensions (renderer);
 
   if (!_cogl_context_update_features (context, error))
     return FALSE;
 
+  info = &context->gpu;
+
+  if (info->vendor == COGL_GPU_INFO_VENDOR_NVIDIA)
+    {
+      context->feature_flags |= COGL_FEATURE_UNSTABLE_TEXTURES;
+      COGL_FLAGS_SET (context->features,
+                      COGL_FEATURE_ID_UNSTABLE_TEXTURES,
+                      TRUE);
+    }
+
   if (egl_renderer->private_features & COGL_EGL_WINSYS_FEATURE_SWAP_REGION)
     {
       COGL_FLAGS_SET (context->winsys_features,
                       COGL_WINSYS_FEATURE_SWAP_REGION, TRUE);
       COGL_FLAGS_SET (context->winsys_features,
                       COGL_WINSYS_FEATURE_SWAP_REGION_THROTTLE, TRUE);
     }
 
   if ((egl_renderer->private_features & COGL_EGL_WINSYS_FEATURE_FENCE_SYNC) &&
       _cogl_has_private_feature (context, COGL_PRIVATE_FEATURE_OES_EGL_SYNC))
     COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_FENCE, TRUE);
 
   if (egl_renderer->private_features & COGL_EGL_WINSYS_FEATURE_BUFFER_AGE)
     {
       COGL_FLAGS_SET (context->winsys_features,
                       COGL_WINSYS_FEATURE_BUFFER_AGE,
                       TRUE);
       COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_BUFFER_AGE, TRUE);
     }
 
   /* NB: We currently only support creating standalone GLES2 contexts
    * for offscreen rendering and so we need a dummy (non-visible)
    * surface to be able to bind those contexts */
   if (egl_display->dummy_surface != EGL_NO_SURFACE &&
       context->driver == COGL_DRIVER_GLES2)
     COGL_FLAGS_SET (context->features,
                     COGL_FEATURE_ID_GLES2_CONTEXT, TRUE);
 
   if (egl_renderer->platform_vtable->context_init &&
       !egl_renderer->platform_vtable->context_init (context, error))
diff --git a/cogl/cogl/winsys/cogl-winsys-glx.c b/cogl/cogl/winsys/cogl-winsys-glx.c
index 74b0895d1..4a033c0c6 100644
--- a/cogl/cogl/winsys/cogl-winsys-glx.c
+++ b/cogl/cogl/winsys/cogl-winsys-glx.c
@@ -805,149 +805,158 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
   /* XXX: Note: For a long time Mesa exported a hybrid GLX, exporting
    * extensions specified to require GLX 1.3, but still reporting 1.2
    * via glXQueryVersion. */
   if (!glx_renderer->glXQueryVersion (xlib_renderer->xdpy,
                                       &glx_renderer->glx_major,
                                       &glx_renderer->glx_minor)
       || !(glx_renderer->glx_major == 1 && glx_renderer->glx_minor >= 2))
     {
       _cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_INIT,
                    "XServer appears to lack required GLX 1.2 support");
       goto error;
     }
 
   update_base_winsys_features (renderer);
 
   glx_renderer->dri_fd = -1;
 
   return TRUE;
 
 error:
   _cogl_winsys_renderer_disconnect (renderer);
   return FALSE;
 }
 
 static CoglBool
 update_winsys_features (CoglContext *context, CoglError **error)
 {
   CoglGLXDisplay *glx_display = context->display->winsys;
   CoglGLXRenderer *glx_renderer = context->display->renderer->winsys;
+  CoglGpuInfo *info;
 
   _COGL_RETURN_VAL_IF_FAIL (glx_display->glx_context, FALSE);
 
   if (!_cogl_context_update_features (context, error))
     return FALSE;
 
+  info = &context->gpu;
+
   memcpy (context->winsys_features,
           glx_renderer->base_winsys_features,
           sizeof (context->winsys_features));
 
   context->feature_flags |= glx_renderer->legacy_feature_flags;
 
   context->feature_flags |= COGL_FEATURE_ONSCREEN_MULTIPLE;
   COGL_FLAGS_SET (context->features,
                   COGL_FEATURE_ID_ONSCREEN_MULTIPLE, TRUE);
 
   if (glx_renderer->glXCopySubBuffer || context->glBlitFramebuffer)
     {
-      CoglGpuInfo *info = &context->gpu;
       CoglGpuInfoArchitecture arch = info->architecture;
 
       COGL_FLAGS_SET (context->winsys_features, COGL_WINSYS_FEATURE_SWAP_REGION, TRUE);
 
       /*
        * "The "drisw" binding in Mesa for loading sofware renderers is
        * broken, and neither glBlitFramebuffer nor glXCopySubBuffer
        * work correctly."
        * - ajax
        * - https://bugzilla.gnome.org/show_bug.cgi?id=674208
        *
        * This is broken in software Mesa at least as of 7.10 and got
        * fixed in Mesa 10.1
        */
 
       if (info->driver_package == COGL_GPU_INFO_DRIVER_PACKAGE_MESA &&
           info->driver_package_version < COGL_VERSION_ENCODE (10, 1, 0) &&
           (arch == COGL_GPU_INFO_ARCHITECTURE_LLVMPIPE ||
            arch == COGL_GPU_INFO_ARCHITECTURE_SOFTPIPE ||
            arch == COGL_GPU_INFO_ARCHITECTURE_SWRAST))
 	{
 	  COGL_FLAGS_SET (context->winsys_features,
 			  COGL_WINSYS_FEATURE_SWAP_REGION, FALSE);
 	}
     }
 
   /* Note: glXCopySubBuffer and glBlitFramebuffer won't be throttled
    * by the SwapInterval so we have to throttle swap_region requests
    * manually... */
   if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION) &&
       (glx_display->have_vblank_counter || glx_display->can_vblank_wait))
     COGL_FLAGS_SET (context->winsys_features,
                     COGL_WINSYS_FEATURE_SWAP_REGION_THROTTLE, TRUE);
 
   if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT))
     {
       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);
     }
   else
     {
-      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,
                           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);
         }
     }
 
+  if (info->vendor == COGL_GPU_INFO_VENDOR_NVIDIA)
+    {
+      context->feature_flags |= COGL_FEATURE_UNSTABLE_TEXTURES;
+      COGL_FLAGS_SET (context->features,
+                      COGL_FEATURE_ID_UNSTABLE_TEXTURES,
+                      TRUE);
+    }
+
   /* We'll manually handle queueing dirty events in response to
    * Expose events from X */
   COGL_FLAGS_SET (context->private_features,
                   COGL_PRIVATE_FEATURE_DIRTY_EVENTS,
                   TRUE);
 
   if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE))
     COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_BUFFER_AGE, TRUE);
 
   return TRUE;
 }
 
 static void
 glx_attributes_from_framebuffer_config (CoglDisplay *display,
                                         CoglFramebufferConfig *config,
                                         int *attributes)
 {
   CoglGLXRenderer *glx_renderer = display->renderer->winsys;
   int i = 0;
 
   attributes[i++] = GLX_DRAWABLE_TYPE;
   attributes[i++] = GLX_WINDOW_BIT;
 
   attributes[i++] = GLX_RENDER_TYPE;
   attributes[i++] = GLX_RGBA_BIT;
 
   attributes[i++] = GLX_DOUBLEBUFFER;
   attributes[i++] = GL_TRUE;
 
   attributes[i++] = GLX_RED_SIZE;
-- 
2.18.1