dri/nouveau: Implement EXT_texture_from_pixmap.
authorFrancisco Jerez <currojerez@riseup.net>
Sun, 21 Feb 2010 13:23:40 +0000 (14:23 +0100)
committerFrancisco Jerez <currojerez@riseup.net>
Thu, 25 Feb 2010 17:37:38 +0000 (18:37 +0100)
src/mesa/drivers/dri/nouveau/nouveau_context.c
src/mesa/drivers/dri/nouveau/nouveau_context.h
src/mesa/drivers/dri/nouveau/nouveau_driver.c
src/mesa/drivers/dri/nouveau/nouveau_fbo.c
src/mesa/drivers/dri/nouveau/nouveau_screen.c
src/mesa/drivers/dri/nouveau/nouveau_texture.c
src/mesa/drivers/dri/nouveau/nouveau_texture.h

index b1b0e81..2629733 100644 (file)
@@ -168,19 +168,19 @@ nouveau_context_destroy(__DRIcontext *dri_ctx)
        context_drv(ctx)->context_destroy(ctx);
 }
 
-static void
-nouveau_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable,
-                            unsigned int *stamp)
+void
+nouveau_update_renderbuffers(__DRIcontext *dri_ctx, __DRIdrawable *draw)
 {
-       struct nouveau_context *nctx = context->driverPrivate;
-       GLcontext *ctx = &nctx->base;
-       __DRIscreen *screen = context->driScreenPriv;
-       struct gl_framebuffer *fb = drawable->driverPrivate;
+       GLcontext *ctx = dri_ctx->driverPrivate;
+       __DRIscreen *screen = dri_ctx->driScreenPriv;
+       struct gl_framebuffer *fb = draw->driverPrivate;
        unsigned int attachments[10];
        __DRIbuffer *buffers = NULL;
        int i = 0, count, ret;
 
-       *stamp = *drawable->pStamp;
+       if (draw->lastStamp == *draw->pStamp)
+               return;
+       draw->lastStamp = *draw->pStamp;
 
        attachments[i++] = __DRI_BUFFER_FRONT_LEFT;
        if (fb->Visual.doubleBufferMode)
@@ -192,10 +192,9 @@ nouveau_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable,
        else if (fb->Visual.haveStencilBuffer)
                attachments[i++] = __DRI_BUFFER_STENCIL;
 
-       buffers = (*screen->dri2.loader->getBuffers)(drawable,
-                                                    &drawable->w, &drawable->h,
+       buffers = (*screen->dri2.loader->getBuffers)(draw, &draw->w, &draw->h,
                                                     attachments, i, &count,
-                                                    drawable->loaderPrivate);
+                                                    draw->loaderPrivate);
        if (buffers == NULL)
                return;
 
@@ -227,8 +226,8 @@ nouveau_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable,
                rb = fb->Attachment[index].Renderbuffer;
                s = &to_nouveau_renderbuffer(rb)->surface;
 
-               s->width = drawable->w;
-               s->height = drawable->h;
+               s->width = draw->w;
+               s->height = draw->h;
                s->pitch = buffers[i].pitch;
                s->cpp = buffers[i].cpp;
 
@@ -244,12 +243,25 @@ nouveau_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable,
                        ret = nouveau_bo_handle_ref(context_dev(ctx),
                                                    buffers[i].name, &s->bo);
                        assert(!ret);
-
-                       context_dirty(ctx, FRAMEBUFFER);
                }
        }
 
-       _mesa_resize_framebuffer(ctx, fb, drawable->w, drawable->h);
+       _mesa_resize_framebuffer(NULL, fb, draw->w, draw->h);
+}
+
+static void
+update_framebuffer(__DRIcontext *dri_ctx, __DRIdrawable *draw,
+                  int *stamp)
+{
+       GLcontext *ctx = dri_ctx->driverPrivate;
+       struct gl_framebuffer *fb = draw->driverPrivate;
+
+       *stamp = *draw->pStamp;
+
+       nouveau_update_renderbuffers(dri_ctx, draw);
+       _mesa_resize_framebuffer(ctx, fb, draw->w, draw->h);
+
+       context_dirty(ctx, FRAMEBUFFER);
 }
 
 GLboolean
@@ -260,16 +272,15 @@ nouveau_context_make_current(__DRIcontext *dri_ctx, __DRIdrawable *dri_draw,
                struct nouveau_context *nctx = dri_ctx->driverPrivate;
                GLcontext *ctx = &nctx->base;
 
-               if (dri_draw->driverPrivate == ctx->WinSysDrawBuffer &&
-                   dri_read->driverPrivate == ctx->WinSysReadBuffer)
-                       return GL_TRUE;
-
                /* Ask the X server for new renderbuffers. */
-               nouveau_update_renderbuffers(dri_ctx, dri_draw,
-                                            &nctx->drawable.d_stamp);
-               if (dri_draw != dri_read)
-                       nouveau_update_renderbuffers(dri_ctx, dri_read,
-                                                    &nctx->drawable.r_stamp);
+               if (dri_draw->driverPrivate != ctx->WinSysDrawBuffer)
+                       update_framebuffer(dri_ctx, dri_draw,
+                                          &dri_ctx->dri2.draw_stamp);
+
+               if (dri_draw != dri_read &&
+                   dri_read->driverPrivate != ctx->WinSysReadBuffer)
+                       update_framebuffer(dri_ctx, dri_read,
+                                          &dri_ctx->dri2.read_stamp);
 
                /* Pass it down to mesa. */
                _mesa_make_current(ctx, dri_draw->driverPrivate,
@@ -307,30 +318,20 @@ nouveau_fallback(GLcontext *ctx, enum nouveau_fallback mode)
 void
 nouveau_validate_framebuffer(GLcontext *ctx)
 {
-       struct nouveau_context *nctx = to_nouveau_context(ctx);
        __DRIcontext *dri_ctx = to_nouveau_context(ctx)->dri_context;
        __DRIdrawable *dri_draw = dri_ctx->driDrawablePriv;
        __DRIdrawable *dri_read = dri_ctx->driReadablePriv;
 
-       if ((ctx->DrawBuffer->Name == 0 &&
-            nctx->drawable.d_stamp != *dri_draw->pStamp) ||
-           (dri_draw != dri_read &&
-            ctx->ReadBuffer->Name == 0 &&
-            nctx->drawable.r_stamp != *dri_read->pStamp)) {
-               if (nctx->drawable.dirty)
-                       ctx->Driver.Flush(ctx);
+       if (ctx->DrawBuffer->Name == 0 &&
+           dri_ctx->dri2.draw_stamp != *dri_draw->pStamp)
+               update_framebuffer(dri_ctx, dri_draw,
+                                  &dri_ctx->dri2.draw_stamp);
 
-               /* Ask the X server for new renderbuffers. */
-               nouveau_update_renderbuffers(dri_ctx, dri_draw,
-                                            &nctx->drawable.d_stamp);
-               if (dri_draw != dri_read)
-                       nouveau_update_renderbuffers(dri_ctx, dri_read,
-                                                    &nctx->drawable.r_stamp);
-
-               if (nouveau_next_dirty_state(ctx) >= 0)
-                       FIRE_RING(context_chan(ctx));
-       }
+       if (ctx->ReadBuffer->Name == 0 && dri_draw != dri_read &&
+           dri_ctx->dri2.read_stamp != *dri_read->pStamp)
+               update_framebuffer(dri_ctx, dri_read,
+                                  &dri_ctx->dri2.read_stamp);
 
-       /* Someone's planning to draw something really soon. */
-       nctx->drawable.dirty = GL_TRUE;
+       if (nouveau_next_dirty_state(ctx) >= 0)
+               FIRE_RING(context_chan(ctx));
 }
index efe3e51..682f8a4 100644 (file)
@@ -56,12 +56,6 @@ struct nouveau_hw_state {
        struct nouveau_grobj *sifm;
 };
 
-struct nouveau_drawable_state {
-       GLboolean dirty;
-       unsigned int d_stamp;
-       unsigned int r_stamp;
-};
-
 struct nouveau_context {
        GLcontext base;
        __DRIcontext *dri_context;
@@ -73,7 +67,6 @@ struct nouveau_context {
        struct nouveau_hw_state hw;
        struct nouveau_bo_state bo;
        struct nouveau_render_state render;
-       struct nouveau_drawable_state drawable;
 };
 
 #define to_nouveau_context(ctx)        ((struct nouveau_context *)(ctx))
@@ -107,9 +100,11 @@ nouveau_context_deinit(GLcontext *ctx);
 void
 nouveau_context_destroy(__DRIcontext *dri_ctx);
 
+void
+nouveau_update_renderbuffers(__DRIcontext *dri_ctx, __DRIdrawable *draw);
+
 GLboolean
-nouveau_context_make_current(__DRIcontext *dri_ctx,
-                            __DRIdrawable *ddraw,
+nouveau_context_make_current(__DRIcontext *dri_ctx, __DRIdrawable *ddraw,
                             __DRIdrawable *rdraw);
 
 GLboolean
index afaa8de..1d12f43 100644 (file)
@@ -67,8 +67,6 @@ nouveau_flush(GLcontext *ctx)
 
                dri2->flushFrontBuffer(drawable, drawable->loaderPrivate);
        }
-
-       nctx->drawable.dirty = GL_FALSE;
 }
 
 static void
index c5fb015..1db8c5d 100644 (file)
@@ -142,7 +142,6 @@ nouveau_renderbuffer_dri_storage(GLcontext *ctx, struct gl_renderbuffer *rb,
        rb->Width = width;
        rb->Height = height;
 
-       context_dirty(ctx, FRAMEBUFFER);
        return GL_TRUE;
 }
 
index 71e57e1..18db12f 100644 (file)
@@ -27,6 +27,7 @@
 #include "nouveau_driver.h"
 #include "nouveau_context.h"
 #include "nouveau_fbo.h"
+#include "nouveau_texture.h"
 #include "nouveau_drmif.h"
 #include "nv04_driver.h"
 #include "nv10_driver.h"
@@ -226,8 +227,15 @@ static const struct __DRI2flushExtensionRec nouveau_flush_extension = {
     dri2InvalidateDrawable,
 };
 
+static const struct __DRItexBufferExtensionRec nouveau_texbuffer_extension = {
+    { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION },
+    NULL,
+    nouveau_set_texbuffer,
+};
+
 static const __DRIextension *nouveau_screen_extensions[] = {
     &nouveau_flush_extension.base,
+    &nouveau_texbuffer_extension.base,
     NULL
 };
 
index 840bd6f..c1b0dda 100644 (file)
@@ -27,6 +27,7 @@
 #include "nouveau_driver.h"
 #include "nouveau_context.h"
 #include "nouveau_texture.h"
+#include "nouveau_fbo.h"
 #include "nouveau_util.h"
 
 #include "main/texobj.h"
@@ -36,6 +37,7 @@
 #include "main/texgetimage.h"
 #include "main/mipmap.h"
 #include "main/texfetch.h"
+#include "main/teximage.h"
 
 static struct gl_texture_object *
 nouveau_texture_new(GLcontext *ctx, GLuint name, GLenum target)
@@ -489,6 +491,57 @@ nouveau_bind_texture(GLcontext *ctx, GLenum target,
        context_dirty_i(ctx, TEX_ENV, ctx->Texture.CurrentUnit);
 }
 
+static gl_format
+get_texbuffer_format(struct gl_renderbuffer *rb, GLint format)
+{
+       struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface;
+
+       if (s->cpp < 4)
+               return s->format;
+       else if (format == __DRI_TEXTURE_FORMAT_RGBA)
+               return MESA_FORMAT_ARGB8888;
+       else
+               return MESA_FORMAT_XRGB8888;
+}
+
+void
+nouveau_set_texbuffer(__DRIcontext *dri_ctx,
+                     GLint target, GLint format,
+                     __DRIdrawable *draw)
+{
+       struct nouveau_context *nctx = dri_ctx->driverPrivate;
+       GLcontext *ctx = &nctx->base;
+       struct gl_framebuffer *fb = draw->driverPrivate;
+       struct gl_renderbuffer *rb =
+               fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer;
+       struct gl_texture_object *t = _mesa_get_current_tex_object(ctx, target);
+       struct gl_texture_image *ti;
+       struct nouveau_surface *s;
+
+       _mesa_lock_texture(ctx, t);
+       ti = _mesa_get_tex_image(ctx, t, target, 0);
+       s = &to_nouveau_teximage(ti)->surface;
+
+       /* Update the texture surface with the given drawable. */
+       nouveau_update_renderbuffers(dri_ctx, draw);
+       nouveau_surface_ref(&to_nouveau_renderbuffer(rb)->surface, s);
+
+       /* Update the image fields. */
+       _mesa_init_teximage_fields(ctx, target, ti, s->width, s->height,
+                                  1, 0, s->cpp);
+       ti->RowStride = s->pitch / s->cpp;
+       ti->TexFormat = s->format = get_texbuffer_format(rb, format);
+
+       /* Try to validate it. */
+       if (!validate_teximage(ctx, t, 0, 0, 0, 0, s->width, s->height, 1))
+               nouveau_texture_reallocate(ctx, t);
+
+       context_dirty_i(ctx, TEX_OBJ, ctx->Texture.CurrentUnit);
+       context_dirty_i(ctx, TEX_ENV, ctx->Texture.CurrentUnit);
+
+       _mesa_unlock_texture(ctx, t);
+}
+
 static void
 nouveau_texture_map(GLcontext *ctx, struct gl_texture_object *t)
 {
index 75d8190..b91facb 100644 (file)
@@ -43,6 +43,11 @@ struct nouveau_texture {
 #define texture_dirty(t) \
        to_nouveau_texture(t)->dirty = GL_TRUE;
 
+void
+nouveau_set_texbuffer(__DRIcontext *dri_ctx,
+                     GLint target, GLint format,
+                     __DRIdrawable *draw);
+
 GLboolean
 nouveau_texture_validate(GLcontext *ctx, struct gl_texture_object *t);