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.
This commit is contained in:
Martin Robinson 2012-03-05 23:11:19 -08:00
parent ba4a4eae05
commit a7d684e6fe
3 changed files with 126 additions and 40 deletions

View file

@ -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);
dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, surface->depth_stencil);
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;
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, ctx->depth_stencil_info.id);
dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
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;
}

View file

@ -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);

View file

@ -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);