summaryrefslogtreecommitdiff
path: root/src/glitz_framebuffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/glitz_framebuffer.c')
-rw-r--r--src/glitz_framebuffer.c393
1 files changed, 360 insertions, 33 deletions
diff --git a/src/glitz_framebuffer.c b/src/glitz_framebuffer.c
index 87edbe4..69e7381 100644
--- a/src/glitz_framebuffer.c
+++ b/src/glitz_framebuffer.c
@@ -1,6 +1,6 @@
/*
* Copyright © 2005 Novell, Inc.
- *
+ *
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
@@ -12,11 +12,11 @@
* software for any purpose. It is provided "as is" without express or
* implied warranty.
*
- * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
* NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
- * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
@@ -29,48 +29,375 @@
#include "glitzint.h"
-void
-glitz_framebuffer_init (glitz_framebuffer_t *framebuffer)
+typedef struct _glitz_fbo_drawable {
+ glitz_drawable_t base;
+ glitz_drawable_t *other;
+ int width;
+ int height;
+ glitz_gl_uint_t fb;
+ glitz_gl_uint_t front;
+ glitz_gl_uint_t back;
+ glitz_gl_uint_t depth;
+ glitz_gl_uint_t stencil;
+ glitz_gl_uint_t front_texture;
+ glitz_gl_uint_t back_texture;
+ glitz_gl_enum_t internal_format;
+} glitz_fbo_drawable_t;
+
+static glitz_bool_t
+_glitz_fbo_bind (glitz_fbo_drawable_t *drawable)
{
- framebuffer->name = 0;
+ glitz_bool_t update = 0;
+ glitz_gl_enum_t status;
+
+ GLITZ_GL_DRAWABLE (drawable->other);
+
+ if (!drawable->fb)
+ {
+ gl->gen_framebuffers (1, &drawable->fb);
+
+ drawable->width = drawable->base.width;
+ drawable->height = drawable->base.height;
+ update = 1;
+ }
+ else if (drawable->width != drawable->base.width ||
+ drawable->height != drawable->base.height)
+ {
+ drawable->width = drawable->base.width;
+ drawable->height = drawable->base.height;
+ update = 1;
+ }
+
+ gl->bind_framebuffer (GLITZ_GL_FRAMEBUFFER, drawable->fb);
+
+ if (drawable->base.front &&
+ drawable->front_texture != drawable->base.front->texture.name)
+ {
+ gl->framebuffer_texture_2d (GLITZ_GL_FRAMEBUFFER,
+ GLITZ_GL_COLOR_ATTACHMENT0,
+ drawable->base.front->texture.target,
+ drawable->base.front->texture.name,
+ 0);
+
+ drawable->front_texture = drawable->base.front->texture.name;
+
+ if (drawable->front)
+ {
+ gl->delete_renderbuffers (1, &drawable->front);
+ drawable->front = 0;
+ }
+ }
+
+ if (!drawable->front_texture && !drawable->front)
+ {
+ gl->gen_renderbuffers (1, &drawable->front);
+ gl->bind_renderbuffer (GLITZ_GL_RENDERBUFFER, drawable->front);
+ gl->renderbuffer_storage (GLITZ_GL_RENDERBUFFER,
+ drawable->internal_format,
+ drawable->base.width,
+ drawable->base.height);
+ gl->bind_renderbuffer (GLITZ_GL_RENDERBUFFER, 0);
+ gl->framebuffer_renderbuffer (GLITZ_GL_FRAMEBUFFER,
+ GLITZ_GL_COLOR_ATTACHMENT0,
+ GLITZ_GL_RENDERBUFFER,
+ drawable->front);
+ }
+
+ if (drawable->base.format->d.doublebuffer)
+ {
+ if (drawable->base.back &&
+ drawable->back_texture != drawable->base.back->texture.name)
+ {
+ gl->framebuffer_texture_2d (GLITZ_GL_FRAMEBUFFER,
+ GLITZ_GL_COLOR_ATTACHMENT1,
+ drawable->base.back->texture.target,
+ drawable->base.back->texture.name,
+ 0);
+
+ drawable->back_texture = drawable->base.back->texture.name;
+
+ if (drawable->back)
+ {
+ gl->delete_renderbuffers (1, &drawable->back);
+ drawable->back = 0;
+ }
+ }
+
+ if (!drawable->back_texture && !drawable->back)
+ {
+ gl->gen_renderbuffers (1, &drawable->back);
+ gl->bind_renderbuffer (GLITZ_GL_RENDERBUFFER,
+ drawable->back);
+ gl->renderbuffer_storage (GLITZ_GL_RENDERBUFFER,
+ drawable->internal_format,
+ drawable->base.width,
+ drawable->base.height);
+ gl->bind_renderbuffer (GLITZ_GL_RENDERBUFFER, 0);
+ gl->framebuffer_renderbuffer (GLITZ_GL_FRAMEBUFFER,
+ GLITZ_GL_COLOR_ATTACHMENT1,
+ GLITZ_GL_RENDERBUFFER,
+ drawable->back);
+ }
+ }
+
+ if (update)
+ {
+ if (drawable->base.format->d.depth_size)
+ {
+ if (!drawable->depth)
+ gl->gen_renderbuffers (1, &drawable->depth);
+
+ gl->bind_renderbuffer (GLITZ_GL_RENDERBUFFER, drawable->depth);
+ gl->renderbuffer_storage (GLITZ_GL_RENDERBUFFER,
+ GLITZ_GL_DEPTH_COMPONENT,
+ drawable->base.width,
+ drawable->base.height);
+ gl->bind_renderbuffer (GLITZ_GL_RENDERBUFFER, 0);
+
+ gl->framebuffer_renderbuffer (GLITZ_GL_FRAMEBUFFER,
+ GLITZ_GL_DEPTH_ATTACHMENT,
+ GLITZ_GL_RENDERBUFFER,
+ drawable->depth);
+ }
+
+ if (drawable->base.format->d.stencil_size)
+ {
+ if (!drawable->stencil)
+ gl->gen_renderbuffers (1, &drawable->stencil);
+
+ gl->bind_renderbuffer (GLITZ_GL_RENDERBUFFER,
+ drawable->stencil);
+ gl->renderbuffer_storage (GLITZ_GL_RENDERBUFFER,
+ GLITZ_GL_STENCIL_INDEX,
+ drawable->base.width,
+ drawable->base.height);
+ gl->bind_renderbuffer (GLITZ_GL_RENDERBUFFER, 0);
+
+ gl->framebuffer_renderbuffer (GLITZ_GL_FRAMEBUFFER,
+ GLITZ_GL_STENCIL_ATTACHMENT,
+ GLITZ_GL_RENDERBUFFER,
+ drawable->stencil);
+ }
+ }
+
+ status = gl->check_framebuffer_status (GLITZ_GL_FRAMEBUFFER);
+ if (status == GLITZ_GL_FRAMEBUFFER_COMPLETE)
+ return 1;
+
+ return 0;
}
-void
-glitz_framebuffer_fini (glitz_gl_proc_address_list_t *gl,
- glitz_framebuffer_t *framebuffer)
+static void
+_glitz_fbo_attach_notify (void *abstract_drawable,
+ glitz_surface_t *surface)
{
- if (framebuffer->name)
- gl->delete_framebuffers (1, &framebuffer->name);
+ glitz_fbo_drawable_t *drawable = (glitz_fbo_drawable_t *)
+ abstract_drawable;
+ glitz_texture_t *texture;
+
+ GLITZ_GL_DRAWABLE (drawable->other);
+
+ texture = &surface->texture;
+ if (!TEXTURE_ALLOCATED (texture))
+ {
+ drawable->other->backend->push_current (drawable->other, NULL,
+ GLITZ_ANY_CONTEXT_CURRENT);
+ glitz_texture_allocate (gl, texture);
+ drawable->other->backend->pop_current (drawable->other);
+
+ if (!TEXTURE_ALLOCATED (texture))
+ return;
+ }
+
+ REGION_EMPTY (&surface->drawable_damage);
}
-void
-glitz_framebuffer_unbind (glitz_gl_proc_address_list_t *gl)
+static void
+_glitz_fbo_detach_notify (void *abstract_drawable,
+ glitz_surface_t *surface)
{
+ glitz_fbo_drawable_t *drawable = (glitz_fbo_drawable_t *)
+ abstract_drawable;
+
+ if (surface->texture.name == drawable->front_texture ||
+ surface->texture.name == drawable->back_texture)
+ {
+ GLITZ_GL_DRAWABLE (drawable->other);
+
+ drawable->other->backend->push_current (drawable->other, NULL,
+ GLITZ_ANY_CONTEXT_CURRENT);
+
+ gl->bind_framebuffer (GLITZ_GL_FRAMEBUFFER, drawable->fb);
+
+ if (surface->texture.name == drawable->front_texture)
+ {
+ gl->framebuffer_texture_2d (GLITZ_GL_FRAMEBUFFER,
+ GLITZ_GL_COLOR_ATTACHMENT0,
+ surface->texture.target,
+ 0, 0);
+ drawable->front_texture = 0;
+ }
+
+ if (surface->texture.name == drawable->back_texture)
+ {
+ gl->framebuffer_texture_2d (GLITZ_GL_FRAMEBUFFER,
+ GLITZ_GL_COLOR_ATTACHMENT1,
+ surface->texture.target,
+ 0, 0);
+ drawable->back_texture = 0;
+ }
+
+ gl->bind_framebuffer (GLITZ_GL_FRAMEBUFFER, 0);
+
+ surface->fb = 0;
+
+ drawable->other->backend->pop_current (drawable->other);
+ }
+}
+
+static glitz_bool_t
+_glitz_fbo_push_current (void *abstract_drawable,
+ glitz_surface_t *surface,
+ glitz_constraint_t constraint)
+{
+ glitz_fbo_drawable_t *drawable = (glitz_fbo_drawable_t *)
+ abstract_drawable;
+
+ drawable->other->backend->push_current (drawable->other, surface,
+ constraint);
+
+ if (constraint == GLITZ_DRAWABLE_CURRENT)
+ {
+ if (_glitz_fbo_bind (drawable))
+ {
+ drawable->base.update_all = drawable->other->update_all = 1;
+ surface->fb = drawable->fb;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static glitz_surface_t *
+_glitz_fbo_pop_current (void *abstract_drawable)
+{
+ glitz_fbo_drawable_t *drawable = (glitz_fbo_drawable_t *)
+ abstract_drawable;
+
+ GLITZ_GL_DRAWABLE (drawable->other);
+
gl->bind_framebuffer (GLITZ_GL_FRAMEBUFFER, 0);
+
+ return drawable->other->backend->pop_current (drawable->other);
+}
+
+static void
+_glitz_fbo_make_current (void *abstract_drawable,
+ void *abstract_context)
+{
+ glitz_fbo_drawable_t *drawable = (glitz_fbo_drawable_t *)
+ abstract_drawable;
+
+ drawable->other->backend->make_current (drawable->other, abstract_context);
+
+ _glitz_fbo_bind (drawable);
+}
+
+static glitz_bool_t
+_glitz_fbo_swap_buffers (void *abstract_drawable)
+{
+ glitz_fbo_drawable_t *drawable = (glitz_fbo_drawable_t *)
+ abstract_drawable;
+
+ if (!drawable->fb)
+ return 1;
+
+ return 0;
}
-glitz_bool_t
-glitz_framebuffer_complete (glitz_gl_proc_address_list_t *gl,
- glitz_framebuffer_t *framebuffer,
- glitz_texture_t *texture)
-{
- if (!framebuffer->name)
+static void
+_glitz_fbo_destroy (void *abstract_drawable)
+{
+ glitz_fbo_drawable_t *drawable = (glitz_fbo_drawable_t *)
+ abstract_drawable;
+
+ if (drawable->fb)
{
- if (!TEXTURE_ALLOCATED (texture))
- glitz_texture_allocate (gl, texture);
-
- gl->gen_framebuffers (1, &framebuffer->name);
-
- gl->bind_framebuffer (GLITZ_GL_FRAMEBUFFER, framebuffer->name);
-
- gl->framebuffer_texture_2d (GLITZ_GL_FRAMEBUFFER,
- GLITZ_GL_COLOR_ATTACHMENT0,
- GLITZ_GL_TEXTURE_2D, texture->name,
- 0);
+ GLITZ_GL_DRAWABLE (drawable->other);
+
+ drawable->other->backend->push_current (drawable->other, NULL,
+ GLITZ_ANY_CONTEXT_CURRENT);
+
+ gl->delete_framebuffers (1, &drawable->fb);
+
+ if (drawable->front)
+ gl->delete_renderbuffers (1, &drawable->front);
+
+ if (drawable->back)
+ gl->delete_renderbuffers (1, &drawable->back);
+
+ if (drawable->depth)
+ gl->delete_renderbuffers (1, &drawable->depth);
+
+ if (drawable->stencil)
+ gl->delete_renderbuffers (1, &drawable->stencil);
+
+ drawable->other->backend->pop_current (drawable->other);
}
+
+ glitz_drawable_destroy (drawable->other);
+
+ free (drawable);
+}
+
+glitz_drawable_t *
+_glitz_fbo_drawable_create (glitz_drawable_t *other,
+ glitz_int_drawable_format_t *format,
+ int width,
+ int height)
+{
+ glitz_fbo_drawable_t *drawable;
+ glitz_backend_t *backend;
+
+ drawable = malloc (sizeof (glitz_fbo_drawable_t) +
+ sizeof (glitz_backend_t));
+ if (!drawable)
+ return NULL;
+
+ glitz_drawable_reference (other);
+ drawable->other = other;
+ backend = (glitz_backend_t *) (drawable + 1);
+ *backend = *other->backend;
+
+ backend->destroy = _glitz_fbo_destroy;
+ backend->push_current = _glitz_fbo_push_current;
+ backend->pop_current = _glitz_fbo_pop_current;
+ backend->attach_notify = _glitz_fbo_attach_notify;
+ backend->detach_notify = _glitz_fbo_detach_notify;
+ backend->swap_buffers = _glitz_fbo_swap_buffers;
+ backend->make_current = _glitz_fbo_make_current;
+
+ drawable->fb = 0;
+
+ drawable->width = 0;
+ drawable->height = 0;
+
+ drawable->front = 0;
+ drawable->back = 0;
+ drawable->depth = 0;
+ drawable->stencil = 0;
+
+ drawable->front_texture = 0;
+ drawable->back_texture = 0;
+
+ /* XXX: temporary solution until we have proper format validation */
+ if (format->d.color.alpha_size)
+ drawable->internal_format = GLITZ_GL_RGBA;
else
- gl->bind_framebuffer (GLITZ_GL_FRAMEBUFFER, framebuffer->name);
+ drawable->internal_format = GLITZ_GL_RGB;
+
+ _glitz_drawable_init (&drawable->base, format, backend, width, height);
- return (gl->check_framebuffer_status (GLITZ_GL_FRAMEBUFFER) ==
- GLITZ_GL_FRAMEBUFFER_COMPLETE);
+ return &drawable->base;
}