mirror of
https://github.com/brl/mutter.git
synced 2025-06-14 01:09:30 +00:00
framebuffer: Support texture based depth buffers
This commit introduces some new framebuffer api to be able to enable texture based depth buffers for a framebuffer (currently only supported for offscreen framebuffers) and once allocated to be able to retrieve the depth buffer as a texture for further usage, say, to implement shadow mapping. The API works as follow: * Before the framebuffer is allocated, you can request that a depth texture is created with cogl_framebuffer_set_depth_texture_enabled() * cogl_framebuffer_get_depth_texture() can then be used to grab a CoglTexture once the framebuffer has been allocated.
This commit is contained in:

committed by
Robert Bragg

parent
58bbf8499a
commit
87bc616d34
@ -817,9 +817,83 @@ _cogl_offscreen_free (CoglOffscreen *offscreen)
|
||||
if (offscreen->texture != NULL)
|
||||
cogl_object_unref (offscreen->texture);
|
||||
|
||||
if (offscreen->depth_texture != NULL)
|
||||
cogl_object_unref (offscreen->depth_texture);
|
||||
|
||||
g_free (offscreen);
|
||||
}
|
||||
|
||||
static CoglTexture *
|
||||
create_depth_texture (CoglContext *ctx,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
CoglPixelFormat format;
|
||||
CoglTexture2D *depth_texture;
|
||||
|
||||
if (ctx->private_feature_flags &
|
||||
(COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL |
|
||||
COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL))
|
||||
{
|
||||
format = COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8;
|
||||
}
|
||||
else
|
||||
format = COGL_PIXEL_FORMAT_DEPTH_16;
|
||||
|
||||
depth_texture = cogl_texture_2d_new_with_size (ctx,
|
||||
width, height,
|
||||
format,
|
||||
NULL);
|
||||
|
||||
return COGL_TEXTURE (depth_texture);
|
||||
}
|
||||
|
||||
static CoglTexture *
|
||||
attach_depth_texture (CoglContext *ctx,
|
||||
CoglTexture *depth_texture,
|
||||
CoglOffscreenAllocateFlags flags)
|
||||
{
|
||||
GLuint tex_gl_handle;
|
||||
GLenum tex_gl_target;
|
||||
|
||||
if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL)
|
||||
{
|
||||
/* attach a GL_DEPTH_STENCIL texture to the GL_DEPTH_ATTACHMENT and
|
||||
* GL_STENCIL_ATTACHMENT attachement points */
|
||||
g_assert (cogl_texture_get_format (depth_texture) ==
|
||||
COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8);
|
||||
|
||||
cogl_texture_get_gl_texture (depth_texture,
|
||||
&tex_gl_handle, &tex_gl_target);
|
||||
|
||||
GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER,
|
||||
GL_DEPTH_ATTACHMENT,
|
||||
tex_gl_target, tex_gl_handle,
|
||||
0));
|
||||
GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER,
|
||||
GL_STENCIL_ATTACHMENT,
|
||||
tex_gl_target, tex_gl_handle,
|
||||
0));
|
||||
}
|
||||
else if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH)
|
||||
{
|
||||
/* attach a newly created GL_DEPTH_COMPONENT16 texture to the
|
||||
* GL_DEPTH_ATTACHMENT attachement point */
|
||||
g_assert (cogl_texture_get_format (depth_texture) ==
|
||||
COGL_PIXEL_FORMAT_DEPTH_16);
|
||||
|
||||
cogl_texture_get_gl_texture (COGL_TEXTURE (depth_texture),
|
||||
&tex_gl_handle, &tex_gl_target);
|
||||
|
||||
GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER,
|
||||
GL_DEPTH_ATTACHMENT,
|
||||
tex_gl_target, tex_gl_handle,
|
||||
0));
|
||||
}
|
||||
|
||||
return COGL_TEXTURE (depth_texture);
|
||||
}
|
||||
|
||||
static GList *
|
||||
try_creating_renderbuffers (CoglContext *ctx,
|
||||
int width,
|
||||
@ -937,6 +1011,7 @@ try_creating_fbo (CoglContext *ctx,
|
||||
int texture_level,
|
||||
int texture_level_width,
|
||||
int texture_level_height,
|
||||
CoglTexture *depth_texture,
|
||||
CoglFramebufferConfig *config,
|
||||
CoglOffscreenAllocateFlags flags,
|
||||
CoglGLFramebuffer *gl_framebuffer)
|
||||
@ -987,12 +1062,31 @@ try_creating_fbo (CoglContext *ctx,
|
||||
tex_gl_target, tex_gl_handle,
|
||||
texture_level));
|
||||
|
||||
gl_framebuffer->renderbuffers =
|
||||
try_creating_renderbuffers (ctx,
|
||||
texture_level_width,
|
||||
texture_level_height,
|
||||
flags,
|
||||
n_samples);
|
||||
/* attach either a depth/stencil texture, a depth texture or render buffers
|
||||
* depending on what we've been asked to provide */
|
||||
|
||||
if (depth_texture &&
|
||||
flags & (COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL |
|
||||
COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH))
|
||||
{
|
||||
attach_depth_texture (ctx, depth_texture, flags);
|
||||
|
||||
/* Let's clear the flags that are now fulfilled as we might need to
|
||||
* create renderbuffers (for the ALLOCATE_FLAG_DEPTH |
|
||||
* ALLOCATE_FLAG_STENCIL case) */
|
||||
flags &= ~(COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL |
|
||||
COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH);
|
||||
}
|
||||
|
||||
if (flags)
|
||||
{
|
||||
gl_framebuffer->renderbuffers =
|
||||
try_creating_renderbuffers (ctx,
|
||||
texture_level_width,
|
||||
texture_level_height,
|
||||
flags,
|
||||
n_samples);
|
||||
}
|
||||
|
||||
/* Make sure it's complete */
|
||||
status = ctx->glCheckFramebufferStatus (GL_FRAMEBUFFER);
|
||||
@ -1031,6 +1125,7 @@ _cogl_framebuffer_try_creating_gl_fbo (CoglContext *ctx,
|
||||
int texture_level,
|
||||
int texture_level_width,
|
||||
int texture_level_height,
|
||||
CoglTexture *depth_texture,
|
||||
CoglFramebufferConfig *config,
|
||||
CoglOffscreenAllocateFlags flags,
|
||||
CoglGLFramebuffer *gl_framebuffer)
|
||||
@ -1040,6 +1135,7 @@ _cogl_framebuffer_try_creating_gl_fbo (CoglContext *ctx,
|
||||
texture_level,
|
||||
texture_level_width,
|
||||
texture_level_height,
|
||||
depth_texture,
|
||||
config,
|
||||
flags,
|
||||
gl_framebuffer);
|
||||
@ -1054,6 +1150,24 @@ _cogl_offscreen_allocate (CoglOffscreen *offscreen,
|
||||
CoglOffscreenAllocateFlags flags;
|
||||
CoglGLFramebuffer *gl_framebuffer = &offscreen->gl_framebuffer;
|
||||
|
||||
if (fb->config.depth_texture_enabled &&
|
||||
offscreen->depth_texture == NULL)
|
||||
{
|
||||
offscreen->depth_texture =
|
||||
create_depth_texture (ctx,
|
||||
offscreen->texture_level_width,
|
||||
offscreen->texture_level_height);
|
||||
|
||||
if (offscreen->depth_texture)
|
||||
_cogl_texture_associate_framebuffer (offscreen->depth_texture, fb);
|
||||
else
|
||||
{
|
||||
g_set_error (error, COGL_FRAMEBUFFER_ERROR,
|
||||
COGL_FRAMEBUFFER_ERROR_ALLOCATE,
|
||||
"Failed to allocate depth texture for framebuffer");
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX: The framebuffer_object spec isn't clear in defining whether attaching
|
||||
* a texture as a renderbuffer with mipmap filtering enabled while the
|
||||
* mipmaps have not been uploaded should result in an incomplete framebuffer
|
||||
@ -1072,6 +1186,7 @@ _cogl_offscreen_allocate (CoglOffscreen *offscreen,
|
||||
offscreen->texture_level,
|
||||
offscreen->texture_level_width,
|
||||
offscreen->texture_level_height,
|
||||
offscreen->depth_texture,
|
||||
&fb->config,
|
||||
flags = 0,
|
||||
gl_framebuffer)) ||
|
||||
@ -1082,6 +1197,7 @@ _cogl_offscreen_allocate (CoglOffscreen *offscreen,
|
||||
offscreen->texture_level,
|
||||
offscreen->texture_level_width,
|
||||
offscreen->texture_level_height,
|
||||
offscreen->depth_texture,
|
||||
&fb->config,
|
||||
flags = ctx->last_offscreen_allocate_flags,
|
||||
gl_framebuffer)) ||
|
||||
@ -1094,6 +1210,7 @@ _cogl_offscreen_allocate (CoglOffscreen *offscreen,
|
||||
offscreen->texture_level,
|
||||
offscreen->texture_level_width,
|
||||
offscreen->texture_level_height,
|
||||
offscreen->depth_texture,
|
||||
&fb->config,
|
||||
flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL,
|
||||
gl_framebuffer)) ||
|
||||
@ -1103,6 +1220,7 @@ _cogl_offscreen_allocate (CoglOffscreen *offscreen,
|
||||
offscreen->texture_level,
|
||||
offscreen->texture_level_width,
|
||||
offscreen->texture_level_height,
|
||||
offscreen->depth_texture,
|
||||
&fb->config,
|
||||
flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH |
|
||||
COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL,
|
||||
@ -1113,6 +1231,7 @@ _cogl_offscreen_allocate (CoglOffscreen *offscreen,
|
||||
offscreen->texture_level,
|
||||
offscreen->texture_level_width,
|
||||
offscreen->texture_level_height,
|
||||
offscreen->depth_texture,
|
||||
&fb->config,
|
||||
flags = COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL,
|
||||
gl_framebuffer) ||
|
||||
@ -1122,6 +1241,7 @@ _cogl_offscreen_allocate (CoglOffscreen *offscreen,
|
||||
offscreen->texture_level,
|
||||
offscreen->texture_level_width,
|
||||
offscreen->texture_level_height,
|
||||
offscreen->depth_texture,
|
||||
&fb->config,
|
||||
flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH,
|
||||
gl_framebuffer) ||
|
||||
@ -1131,6 +1251,7 @@ _cogl_offscreen_allocate (CoglOffscreen *offscreen,
|
||||
offscreen->texture_level,
|
||||
offscreen->texture_level_width,
|
||||
offscreen->texture_level_height,
|
||||
offscreen->depth_texture,
|
||||
&fb->config,
|
||||
flags = 0,
|
||||
gl_framebuffer))
|
||||
@ -1145,7 +1266,7 @@ _cogl_offscreen_allocate (CoglOffscreen *offscreen,
|
||||
ctx->have_last_offscreen_allocate_flags = TRUE;
|
||||
}
|
||||
|
||||
/* Save the flags we managed so successfully allocate the
|
||||
/* Save the flags we managed to successfully allocate the
|
||||
* renderbuffers with in case we need to make renderbuffers for a
|
||||
* GLES2 context later */
|
||||
offscreen->allocation_flags = flags;
|
||||
@ -1173,6 +1294,15 @@ cogl_framebuffer_allocate (CoglFramebuffer *framebuffer,
|
||||
|
||||
if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
|
||||
{
|
||||
if (framebuffer->config.depth_texture_enabled)
|
||||
{
|
||||
g_set_error (error, COGL_FRAMEBUFFER_ERROR,
|
||||
COGL_FRAMEBUFFER_ERROR_ALLOCATE,
|
||||
"Can't allocate onscreen framebuffer with a "
|
||||
"texture based depth buffer");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!winsys->onscreen_init (onscreen, error))
|
||||
return FALSE;
|
||||
}
|
||||
@ -1928,6 +2058,32 @@ cogl_framebuffer_get_color_format (CoglFramebuffer *framebuffer)
|
||||
return framebuffer->format;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_framebuffer_set_depth_texture_enabled (CoglFramebuffer *framebuffer,
|
||||
CoglBool enabled)
|
||||
{
|
||||
_COGL_RETURN_IF_FAIL (!framebuffer->allocated);
|
||||
|
||||
framebuffer->config.depth_texture_enabled = enabled;
|
||||
}
|
||||
|
||||
CoglBool
|
||||
cogl_framebuffer_get_depth_texture_enabled (CoglFramebuffer *framebuffer)
|
||||
{
|
||||
return framebuffer->config.depth_texture_enabled;
|
||||
}
|
||||
|
||||
CoglTexture *
|
||||
cogl_framebuffer_get_depth_texture (CoglFramebuffer *framebuffer)
|
||||
{
|
||||
/* lazily allocate the framebuffer... */
|
||||
if (!cogl_framebuffer_allocate (framebuffer, NULL))
|
||||
return NULL;
|
||||
|
||||
_COGL_RETURN_VAL_IF_FAIL (cogl_is_offscreen (framebuffer), NULL);
|
||||
return COGL_OFFSCREEN(framebuffer)->depth_texture;
|
||||
}
|
||||
|
||||
int
|
||||
cogl_framebuffer_get_samples_per_pixel (CoglFramebuffer *framebuffer)
|
||||
{
|
||||
|
Reference in New Issue
Block a user