[PATCH] gl/msaa: Share the depth/stencil buffer among all surfaces

Martin Robinson <[email protected]>
Newsgroups gmane.comp.lib.cairo
Message-ID <[email protected]>
From a7d684e6fe4bbeea2262276aaa57bb2a47c401df Mon Sep 17 00:00:00 2001
From: Martin Robinson <[email protected]>
Date: Mon, 5 Mar 2012 23:11:19 -0800
Subject: [PATCH] gl/msaa: Share the depth/stencil buffer among all surfaces

Instead of allocating a depth/stencil buffer for all surfaces, share a
common buffer that's the size of the largest surface. This reduces
video memory usage when there are many GL surfaces.
---
 src/cairo-gl-device.c  |  118 ++++++++++++++++++++++++++++++++++--------------
 src/cairo-gl-private.h |   13 ++++++
 src/cairo-gl-surface.c |   31 +++++++++++--
 3 files changed, 124 insertions(+), 38 deletions(-)

diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 37c837d..b6a9c15 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -112,6 +112,11 @@ _gl_finish (void *device)
     for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
 	_cairo_gl_glyph_cache_fini (ctx, &ctx->glyph_cache[n]);
 
+    if (ctx->depth_stencil_info.id)
+	ctx->dispatch.DeleteRenderbuffers (1, &ctx->depth_stencil_info.id);
+    if (ctx->msaa_depth_stencil_info.id)
+	ctx->dispatch.DeleteRenderbuffers (1, &ctx->msaa_depth_stencil_info.id);
+
     _gl_unlock (device);
 }
 
@@ -453,36 +458,59 @@ _cairo_gl_ensure_multisampling (cairo_gl_context_t *ctx,
 }
 #endif
 
+static void
+_cairo_gl_replace_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
+					     int width,
+					     int height)
+{
+    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+
+    if (ctx->msaa_depth_stencil_info.id)
+	dispatch->DeleteRenderbuffers (1, &ctx->msaa_depth_stencil_info.id);
+
+    dispatch->GenRenderbuffers (1, &ctx->msaa_depth_stencil_info.id);
+    dispatch->BindRenderbuffer (GL_RENDERBUFFER, ctx->msaa_depth_stencil_info.id);
+    dispatch->RenderbufferStorageMultisample (GL_RENDERBUFFER, ctx->num_samples,
+					      _get_depth_stencil_format (ctx),
+					      width, height);
+    ctx->msaa_depth_stencil_info.width = width;
+    ctx->msaa_depth_stencil_info.height = height;
+    ctx->msaa_depth_stencil_info.surfaces_with_same_size = 0;
+}
+
 static cairo_bool_t
 _cairo_gl_ensure_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
 					    cairo_gl_surface_t *surface)
 {
     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-    if (surface->msaa_depth_stencil)
-	return TRUE;
-
     _cairo_gl_ensure_framebuffer (ctx, surface);
 #if CAIRO_HAS_GL_SURFACE
     if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
 	_cairo_gl_ensure_multisampling (ctx, surface);
 #endif
 
-    dispatch->GenRenderbuffers (1, &surface->msaa_depth_stencil);
-    dispatch->BindRenderbuffer (GL_RENDERBUFFER,
-			        surface->msaa_depth_stencil);
+    if (! ctx->msaa_depth_stencil_info.id ||
+        ctx->msaa_depth_stencil_info.width < surface->width ||
+        ctx->msaa_depth_stencil_info.height < surface->height) {
+	_cairo_gl_replace_msaa_depth_stencil_buffer (ctx,
+						     surface->width,
+						     surface->height);
+    }
 
-    dispatch->RenderbufferStorageMultisample (GL_RENDERBUFFER,
-					      ctx->num_samples,
-					      _get_depth_stencil_format (ctx),
-					      surface->width,
-					      surface->height);
+    assert (ctx->msaa_depth_stencil_info.id);
+    if (surface->msaa_depth_stencil == ctx->msaa_depth_stencil_info.id)
+	return TRUE;
+
+    if (ctx->msaa_depth_stencil_info.width == surface->width &&
+	ctx->msaa_depth_stencil_info.height == surface->height)
+    ctx->msaa_depth_stencil_info.surfaces_with_same_size++;
 
 #if CAIRO_HAS_GL_SURFACE
     if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
 	dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
 					   GL_DEPTH_STENCIL_ATTACHMENT,
 					   GL_RENDERBUFFER,
-					   surface->msaa_depth_stencil);
+					   ctx->msaa_depth_stencil_info.id);
     }
 #endif
 
@@ -491,50 +519,72 @@ _cairo_gl_ensure_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
 	dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
 					   GL_DEPTH_ATTACHMENT,
 					   GL_RENDERBUFFER,
-					   surface->msaa_depth_stencil);
+					   ctx->msaa_depth_stencil_info.id);
 	dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
 					   GL_STENCIL_ATTACHMENT,
 					   GL_RENDERBUFFER,
-					   surface->msaa_depth_stencil);
+					   ctx->msaa_depth_stencil_info.id);
     }
 #endif
 
-    if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
-	dispatch->DeleteRenderbuffers (1, &surface->msaa_depth_stencil);
-	surface->msaa_depth_stencil = 0;
-	return FALSE;
-    }
+    surface->msaa_depth_stencil = ctx->msaa_depth_stencil_info.id;
 
+    if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+	return FALSE;
     return TRUE;
 }
 
+static void
+_cairo_gl_replace_depth_stencil_buffer (cairo_gl_context_t *ctx,
+					int width,
+					int height)
+{
+    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+
+    if (ctx->depth_stencil_info.id)
+	dispatch->DeleteRenderbuffers (1, &ctx->depth_stencil_info.id);
+
+    dispatch->GenRenderbuffers (1, &ctx->depth_stencil_info.id);
+    dispatch->BindRenderbuffer (GL_RENDERBUFFER, ctx->depth_stencil_info.id);
+    dispatch->RenderbufferStorage (GL_RENDERBUFFER,
+				   _get_depth_stencil_format (ctx),
+				   width, height);
+    ctx->depth_stencil_info.width = width;
+    ctx->depth_stencil_info.height = height;
+    ctx->depth_stencil_info.surfaces_with_same_size = 0;
+}
+
 static cairo_bool_t
 _cairo_gl_ensure_depth_stencil_buffer (cairo_gl_context_t *ctx,
 				       cairo_gl_surface_t *surface)
 {
     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
 
-    if (surface->depth_stencil)
-	return TRUE;
-
     _cairo_gl_ensure_framebuffer (ctx, surface);
 
-    dispatch->GenRenderbuffers (1, &surface->depth_stencil);
-    dispatch->BindRenderbuffer (GL_RENDERBUFFER, surface->depth_stencil);
-    dispatch->RenderbufferStorage (GL_RENDERBUFFER,
-				   _get_depth_stencil_format (ctx),
-				   surface->width, surface->height);
+    if (! ctx->depth_stencil_info.id ||
+        ctx->depth_stencil_info.width < surface->width ||
+        ctx->depth_stencil_info.height < surface->height) {
+	_cairo_gl_replace_depth_stencil_buffer (ctx,
+						surface->width,
+						surface->height);
+    }
+
+    if (surface->depth_stencil == ctx->depth_stencil_info.id)
+	return TRUE;
+
+    if (ctx->depth_stencil_info.width == surface->width &&
+	ctx->depth_stencil_info.height == surface->height)
+    ctx->depth_stencil_info.surfaces_with_same_size++;
 
     dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
-				       GL_RENDERBUFFER, surface->depth_stencil);
+				       GL_RENDERBUFFER, ctx->depth_stencil_info.id);
     dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
-				       GL_RENDERBUFFER, surface->depth_stencil);
-    if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
-	dispatch->DeleteRenderbuffers (1, &surface->depth_stencil);
-	surface->depth_stencil = 0;
-	return FALSE;
-    }
+				       GL_RENDERBUFFER, ctx->depth_stencil_info.id);
+    surface->depth_stencil = ctx->depth_stencil_info.id;
 
+    if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+	return FALSE;
     return TRUE;
 }
 
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 7c97c49..088a874 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -301,6 +301,13 @@ typedef struct _cairo_gl_dispatch {
 					     GLint level, GLsizei samples);
 } cairo_gl_dispatch_t;
 
+typedef struct _cairo_gl_shared_depth_stencil_info {
+    GLuint id;
+    int width;
+    int height;
+    unsigned surfaces_with_same_size;
+} cairo_gl_shared_depth_stencil_info_t;
+
 struct _cairo_gl_context {
     cairo_device_t base;
 
@@ -353,6 +360,12 @@ struct _cairo_gl_context {
 
     cairo_bool_t thread_aware;
 
+    /* GL stencil and depth buffers are shared among all surfaces
+       to preserve memory. In the future this could be a pool of renderbuffers
+       with an eviction policy. */
+    cairo_gl_shared_depth_stencil_info_t depth_stencil_info;
+    cairo_gl_shared_depth_stencil_info_t msaa_depth_stencil_info;
+
     void (*acquire) (void *ctx);
     void (*release) (void *ctx);
 
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index c0ee79f..7c93322 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -946,6 +946,23 @@ static int _cairo_gl_surface_flavor (cairo_gl_surface_t *surface)
     return ctx->gl_flavor;
 }
 
+static void
+_cairo_gl_shrink_shared_renderbuffer (cairo_gl_context_t *ctx,
+				      cairo_gl_shared_depth_stencil_info_t *info,
+				      int surface_width,
+				      int surface_height)
+{
+    if (info->width != surface_width || info->height != surface_height)
+	return;
+
+    /* Force the creation of a new shared renderbuffer if we are the
+     * last surface that has the same size as our old shared buffer. */
+    ctx->dispatch.DeleteRenderbuffers (1, &info->id);
+    info->height = 0;
+    info->width = 0;
+    info->id = 0;
+}
+
 static cairo_status_t
 _cairo_gl_surface_finish (void *abstract_surface)
 {
@@ -968,18 +985,24 @@ _cairo_gl_surface_finish (void *abstract_surface)
 
     if (surface->fb)
         ctx->dispatch.DeleteFramebuffers (1, &surface->fb);
-    if (surface->depth_stencil)
-        ctx->dispatch.DeleteRenderbuffers (1, &surface->depth_stencil);
     if (surface->owns_tex)
 	glDeleteTextures (1, &surface->tex);
 
+    if (surface->depth_stencil) {
+	_cairo_gl_shrink_shared_renderbuffer (ctx, &ctx->depth_stencil_info,
+					      surface->width, surface->height);
+    }
+
 #if CAIRO_HAS_GL_SURFACE
-    if (surface->msaa_depth_stencil)
-	ctx->dispatch.DeleteRenderbuffers (1, &surface->msaa_depth_stencil);
     if (surface->msaa_fb)
 	ctx->dispatch.DeleteFramebuffers (1, &surface->msaa_fb);
     if (surface->msaa_rb)
 	ctx->dispatch.DeleteRenderbuffers (1, &surface->msaa_rb);
+
+    if (surface->msaa_depth_stencil) {
+	_cairo_gl_shrink_shared_renderbuffer (ctx, &ctx->msaa_depth_stencil_info,
+					      surface->width, surface->height);
+    }
 #endif
 
     return _cairo_gl_context_release (ctx, status);
-- 
1.7.10.4

-- 
cairo mailing list
[email protected]
http://lists.cairographics.org/mailman/listinfo/cairo
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.