mesa: Prefix main includes with dir to avoid conflicts.
[mesa.git] / src / mesa / state_tracker / st_atom_framebuffer.c
index c8fa0cbdfb6150d65d3fe0197b103317e56325a8..80df3b0506d5d2269878b4279d0517769aaa6c9a 100644 (file)
 #include "st_context.h"
 #include "st_atom.h"
 #include "st_cb_fbo.h"
+#include "st_texture.h"
 #include "pipe/p_context.h"
+#include "pipe/p_inlines.h"
 #include "cso_cache/cso_context.h"
 
 
+
+/**
+ * When doing GL render to texture, we have to be sure that finalize_texture()
+ * didn't yank out the pipe_texture that we earlier created a surface for.
+ * Check for that here and create a new surface if needed.
+ */
+static void
+update_renderbuffer_surface(struct st_context *st,
+                            struct st_renderbuffer *strb)
+{
+   struct pipe_screen *screen = st->pipe->screen;
+   struct pipe_texture *texture = strb->rtt->pt;
+   int rtt_width = strb->Base.Width;
+   int rtt_height = strb->Base.Height;
+
+   if (!strb->surface ||
+       strb->surface->texture != texture ||
+       strb->surface->width != rtt_width ||
+       strb->surface->height != rtt_height) {
+      GLuint level;
+      /* find matching mipmap level size */
+      for (level = 0; level <= texture->last_level; level++) {
+         if (texture->width[level] == rtt_width &&
+             texture->height[level] == rtt_height) {
+
+            pipe_surface_reference(&strb->surface, NULL);
+
+            strb->surface = screen->get_tex_surface(screen,
+                                              texture,
+                                              strb->rtt_face,
+                                              level,
+                                              strb->rtt_slice,
+                                              PIPE_BUFFER_USAGE_GPU_READ |
+                                              PIPE_BUFFER_USAGE_GPU_WRITE);
+#if 0
+            printf("-- alloc new surface %d x %d into tex %p\n",
+                   strb->surface->width, strb->surface->height,
+                   texture);
+#endif
+            break;
+         }
+      }
+   }
+}
+
+
 /**
  * Update framebuffer state (color, depth, stencil, etc. buffers)
- * XXX someday: separate draw/read buffers.
  */
 static void
 update_framebuffer_state( struct st_context *st )
 {
-   struct pipe_framebuffer_state framebuffer;
+   struct pipe_framebuffer_state *framebuffer = &st->state.framebuffer;
    struct gl_framebuffer *fb = st->ctx->DrawBuffer;
    struct st_renderbuffer *strb;
-   GLuint i;
+   GLuint i, j;
 
-   memset(&framebuffer, 0, sizeof(framebuffer));
+   memset(framebuffer, 0, sizeof(*framebuffer));
+
+   framebuffer->width = fb->Width;
+   framebuffer->height = fb->Height;
+
+   /*printf("------ fb size %d x %d\n", fb->Width, fb->Height);*/
 
    /* Examine Mesa's ctx->DrawBuffer->_ColorDrawBuffers state
     * to determine which surfaces to draw to
     */
-   framebuffer.num_cbufs = fb->_NumColorDrawBuffers[0];
-   for (i = 0; i < framebuffer.num_cbufs; i++) {
-      strb = st_renderbuffer(fb->_ColorDrawBuffers[0][i]);
-      assert(strb->surface);
-      framebuffer.cbufs[i] = strb->surface;
+   framebuffer->num_cbufs = 0;
+   for (j = 0; j < MAX_DRAW_BUFFERS; j++) {
+      for (i = 0; i < fb->_NumColorDrawBuffers[j]; i++) {
+         strb = st_renderbuffer(fb->_ColorDrawBuffers[j][i]);
+
+         /*printf("--------- framebuffer surface rtt %p\n", strb->rtt);*/
+         if (strb->rtt) {
+            /* rendering to a GL texture, may have to update surface */
+            update_renderbuffer_surface(st, strb);
+         }
+
+         assert(strb->surface);
+         framebuffer->cbufs[framebuffer->num_cbufs] = strb->surface;
+         framebuffer->num_cbufs++;
+      }
    }
 
    strb = st_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer);
    if (strb) {
       strb = st_renderbuffer(strb->Base.Wrapped);
+      if (strb->rtt) {
+         /* rendering to a GL texture, may have to update surface */
+         update_renderbuffer_surface(st, strb);
+      }
+
       assert(strb->surface);
-      framebuffer.zsbuf = strb->surface;
+      framebuffer->zsbuf = strb->surface;
    }
    else {
       strb = st_renderbuffer(fb->Attachment[BUFFER_STENCIL].Renderbuffer);
       if (strb) {
          strb = st_renderbuffer(strb->Base.Wrapped);
          assert(strb->surface);
-         framebuffer.zsbuf = strb->surface;
+         framebuffer->zsbuf = strb->surface;
       }
    }
 
-   cso_set_framebuffer(st->cso_context, &framebuffer);
+   cso_set_framebuffer(st->cso_context, framebuffer);
+
+   if (fb->_ColorDrawBufferMask[0] & BUFFER_BIT_FRONT_LEFT) {
+      if (st->frontbuffer_status == FRONT_STATUS_COPY_OF_BACK) {
+         /* XXX copy back buf to front? */
+      }
+      /* we're assuming we'll really draw to the front buffer */
+      st->frontbuffer_status = FRONT_STATUS_DIRTY;
+   }
 }
 
 
 const struct st_tracked_state st_update_framebuffer = {
-   .name = "st_update_framebuffer",
-   .dirty = {
-      .mesa = _NEW_BUFFERS,
-      .st  = 0,
+   "st_update_framebuffer",                            /* name */
+   {                                                   /* dirty */
+      _NEW_BUFFERS,                                    /* mesa */
+      ST_NEW_FRAMEBUFFER,                              /* st */
    },
-   .update = update_framebuffer_state
+   update_framebuffer_state                            /* update */
 };