diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c index 37c837d27..b6a9c15f3 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); - - 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; } diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h index 7c97c49a6..088a87444 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 c0ee79f8a..7c9332270 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);