gallium: free bitmap fragment shaders, misc clean-up
[mesa.git] / src / mesa / state_tracker / st_cb_fbo.c
index 64ec8022164c61de41a600e2114be57ca4b5d868..5384252a8e511dcf57fcbec24649754741ed747a 100644 (file)
 
 #include "pipe/p_context.h"
 #include "pipe/p_defines.h"
+#include "pipe/p_inlines.h"
+#include "pipe/p_winsys.h"
 #include "st_context.h"
 #include "st_cb_fbo.h"
 #include "st_cb_texture.h"
 #include "st_format.h"
 #include "st_public.h"
+#include "st_texture.h"
 
 
 
+/**
+ * Compute the renderbuffer's Red/Green/EtcBit fields from the pipe format.
+ */
+static int
+init_renderbuffer_bits(struct st_renderbuffer *strb,
+                       enum pipe_format pipeFormat)
+{
+   struct pipe_format_info info;
+
+   if (!st_get_format_info( pipeFormat, &info )) {
+      assert( 0 );
+   }
+
+   strb->Base._ActualFormat = info.base_format;
+   strb->Base.RedBits = info.red_bits;
+   strb->Base.GreenBits = info.green_bits;
+   strb->Base.BlueBits = info.blue_bits;
+   strb->Base.AlphaBits = info.alpha_bits;
+   strb->Base.DepthBits = info.depth_bits;
+   strb->Base.StencilBits = info.stencil_bits;
+   strb->Base.DataType = st_format_datatype(pipeFormat);
+
+   return info.size;
+}
+
+
 /**
  * gl_renderbuffer::AllocStorage()
  */
@@ -59,57 +88,52 @@ st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
 {
    struct pipe_context *pipe = ctx->st->pipe;
    struct st_renderbuffer *strb = st_renderbuffer(rb);
-   const GLuint pipeFormat
-      = st_choose_pipe_format(pipe, internalFormat, GL_NONE, GL_NONE);
-   const struct pipe_format_info *info = st_get_format_info(pipeFormat);
-   GLuint cpp, pitch;
-
-   assert(info);
-   if (!info)
-      return GL_FALSE;
-
-   switch (pipeFormat) {
-   case PIPE_FORMAT_S8_Z24:
-      strb->Base.DataType = GL_UNSIGNED_INT;
-      break;
-   default:
-      strb->Base.DataType = GL_UNSIGNED_BYTE; /* XXX fix */
-   }
-
-   strb->Base._ActualFormat = info->base_format;
-   strb->Base.RedBits = info->red_bits;
-   strb->Base.GreenBits = info->green_bits;
-   strb->Base.BlueBits = info->blue_bits;
-   strb->Base.AlphaBits = info->alpha_bits;
-   strb->Base.DepthBits = info->depth_bits;
-   strb->Base.StencilBits = info->stencil_bits;
-
-   cpp = info->size;
+   enum pipe_format pipeFormat;
+   GLbitfield flags = 0x0; /* XXX needed? */
 
    if (!strb->surface) {
-      strb->surface = pipe->surface_alloc(pipe, pipeFormat);
+      strb->surface = pipe->winsys->surface_alloc(pipe->winsys);
       assert(strb->surface);
+      assert(strb->surface->refcount);
+      assert(strb->surface->winsys);
       if (!strb->surface)
          return GL_FALSE;
    }
 
-   /* free old region */
-   if (strb->surface->region) {
-      pipe->region_release(pipe, &strb->surface->region);
+   if (strb->surface->buffer)
+      pipe_buffer_reference(pipe->winsys, &strb->surface->buffer,
+                           NULL);
+
+   /* Determine surface format here */
+   if (strb->format != PIPE_FORMAT_NONE) {
+      assert(strb->format != 0);
+      /* we'll hit this for front/back color bufs */
+      pipeFormat = strb->format;
+   }
+   else {
+      pipeFormat = st_choose_renderbuffer_format(pipe, internalFormat);
    }
 
-   /* Choose a pitch to match hardware requirements:
-    */
-   pitch = ((cpp * width + 63) & ~63) / cpp; /* XXX fix: device-specific */
+   init_renderbuffer_bits(strb, pipeFormat);
 
-   strb->surface->region = pipe->region_alloc(pipe, cpp, pitch, height);
-   if (!strb->surface->region)
+   pipe->winsys->surface_alloc_storage(pipe->winsys,
+                                       strb->surface,
+                                       width,
+                                       height,
+                                       pipeFormat,
+                                       flags);
+   if (!strb->surface->buffer)
       return GL_FALSE; /* out of memory, try s/w buffer? */
 
-   ASSERT(strb->surface->region->buffer);
+   ASSERT(strb->surface->buffer);
+   ASSERT(strb->surface->format);
+   ASSERT(strb->surface->cpp);
+   ASSERT(strb->surface->width == width);
+   ASSERT(strb->surface->height == height);
+   ASSERT(strb->surface->pitch);
 
-   strb->Base.Width  = strb->surface->width  = width;
-   strb->Base.Height = strb->surface->height = height;
+   strb->Base.Width  = width;
+   strb->Base.Height = height;
 
    return GL_TRUE;
 }
@@ -121,15 +145,11 @@ st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
 static void
 st_renderbuffer_delete(struct gl_renderbuffer *rb)
 {
-   GET_CURRENT_CONTEXT(ctx);
-   struct pipe_context *pipe = ctx->st->pipe;
    struct st_renderbuffer *strb = st_renderbuffer(rb);
    ASSERT(strb);
-   if (strb && strb->surface) {
-      if (strb->surface->region) {
-         pipe->region_release(pipe, &strb->surface->region);
-      }
-      free(strb->surface);
+   if (strb->surface) {
+      struct pipe_winsys *ws = strb->surface->winsys;
+      ws->surface_release(ws, &strb->surface);
    }
    free(strb);
 }
@@ -175,36 +195,19 @@ st_new_renderbuffer(GLcontext *ctx, GLuint name)
       strb->Base.Delete = st_renderbuffer_delete;
       strb->Base.AllocStorage = st_renderbuffer_alloc_storage;
       strb->Base.GetPointer = null_get_pointer;
+      strb->format = PIPE_FORMAT_NONE;
       return &strb->Base;
    }
    return NULL;
 }
 
 
-#if 000
-struct gl_renderbuffer *
-st_new_renderbuffer_fb(struct pipe_region *region, GLuint width, GLuint height)
-{
-   struct st_renderbuffer *strb = CALLOC_STRUCT(st_renderbuffer);
-   if (!strb)
-      return;
-
-   _mesa_init_renderbuffer(&strb->Base, name);
-   strb->Base.Delete = st_renderbuffer_delete;
-   strb->Base.AllocStorage = st_renderbuffer_alloc_storage;
-   strb->Base.GetPointer = null_get_pointer;
-   strb->Base.Width = width;
-   strb->Base.Heigth = height;
-
-   strb->region = region;
-
-   return &strb->Base;
-}
-
-#else
-
+/**
+ * Allocate a renderbuffer for a an on-screen window (not a user-created
+ * renderbuffer).  The window system code determines the format.
+ */
 struct gl_renderbuffer *
-st_new_renderbuffer_fb(GLenum intFormat)
+st_new_renderbuffer_fb(enum pipe_format format)
 {
    struct st_renderbuffer *strb;
 
@@ -215,24 +218,42 @@ st_new_renderbuffer_fb(GLenum intFormat)
    }
 
    _mesa_init_renderbuffer(&strb->Base, 0);
-   strb->Base.ClassID = 0x42; /* XXX temp */
-   strb->Base.InternalFormat = intFormat;
-
-   switch (intFormat) {
-   case GL_RGB5:
-   case GL_RGBA8:
+   strb->Base.ClassID = 0x4242; /* just a unique value */
+   strb->format = format;
+
+   switch (format) {
+   case PIPE_FORMAT_A8R8G8B8_UNORM:
+   case PIPE_FORMAT_B8G8R8A8_UNORM:
+   case PIPE_FORMAT_A1R5G5B5_UNORM:
+   case PIPE_FORMAT_A4R4G4B4_UNORM:
+   case PIPE_FORMAT_R5G6B5_UNORM:
+      strb->Base.InternalFormat = GL_RGBA;
       strb->Base._BaseFormat = GL_RGBA;
       break;
-   case GL_DEPTH_COMPONENT16:
-   case GL_DEPTH_COMPONENT32:
+   case PIPE_FORMAT_Z16_UNORM:
+      strb->Base.InternalFormat = GL_DEPTH_COMPONENT16;
       strb->Base._BaseFormat = GL_DEPTH_COMPONENT;
       break;
-   case GL_DEPTH24_STENCIL8_EXT:
+   case PIPE_FORMAT_Z32_UNORM:
+      strb->Base.InternalFormat = GL_DEPTH_COMPONENT32;
+      strb->Base._BaseFormat = GL_DEPTH_COMPONENT;
+      break;
+   case PIPE_FORMAT_S8Z24_UNORM:
+   case PIPE_FORMAT_Z24S8_UNORM:
+      strb->Base.InternalFormat = GL_DEPTH24_STENCIL8_EXT;
       strb->Base._BaseFormat = GL_DEPTH_STENCIL_EXT;
       break;
+   case PIPE_FORMAT_S8_UNORM:
+      strb->Base.InternalFormat = GL_STENCIL_INDEX8_EXT;
+      strb->Base._BaseFormat = GL_STENCIL_INDEX;
+      break;
+   case PIPE_FORMAT_R16G16B16A16_SNORM:
+      strb->Base.InternalFormat = GL_RGBA16;
+      strb->Base._BaseFormat = GL_RGBA;
+      break;
    default:
       _mesa_problem(NULL,
-                   "Unexpected intFormat in st_new_renderbuffer");
+                   "Unexpected format in st_new_renderbuffer_fb");
       return NULL;
    }
 
@@ -241,12 +262,12 @@ st_new_renderbuffer_fb(GLenum intFormat)
    strb->Base.AllocStorage = st_renderbuffer_alloc_storage;
    strb->Base.GetPointer = null_get_pointer;
 
-   /* surface is allocate in alloc_renderbuffer_storage() */
+   /* surface is allocated in st_renderbuffer_alloc_storage() */
    strb->surface = NULL;
 
    return &strb->Base;
 }
-#endif
+
 
 
 
@@ -283,27 +304,54 @@ st_render_texture(GLcontext *ctx,
                   struct gl_renderbuffer_attachment *att)
 {
    struct st_context *st = ctx->st;
-   struct st_renderbuffer *strb = st_renderbuffer(att->Renderbuffer);
+   struct st_renderbuffer *strb;
+   struct gl_renderbuffer *rb;
    struct pipe_context *pipe = st->pipe;
-   struct pipe_framebuffer_state framebuffer;
-   struct pipe_mipmap_tree *mt;
-
-   mt = st_get_texobj_mipmap_tree(att->Texture);
-
-   /* the renderbuffer's surface is inside the mipmap_tree: */
-   strb->surface = pipe->get_tex_surface(pipe, mt,
-                                         att->CubeMapFace,
-                                         att->TextureLevel,
-                                         att->Zoffset);
-
-   /* update pipe's framebuffer state */
-   memset(&framebuffer, 0, sizeof(framebuffer));
-   framebuffer.num_cbufs = 1;
-   framebuffer.cbufs[0] = strb->surface;
-   if (memcmp(&framebuffer, &st->state.framebuffer, sizeof(framebuffer)) != 0) {
-      st->state.framebuffer = framebuffer;
-      st->pipe->set_framebuffer_state( st->pipe, &framebuffer );
+   struct pipe_screen *screen = pipe->screen;
+   struct pipe_texture *pt;
+
+   assert(!att->Renderbuffer);
+
+   /* create new renderbuffer which wraps the texture image */
+   rb = st_new_renderbuffer(ctx, 0);
+   if (!rb) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()");
+      return;
    }
+
+   _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
+   assert(rb->RefCount == 1);
+   rb->AllocStorage = NULL; /* should not get called */
+   strb = st_renderbuffer(rb);
+
+   /* get the texture for the texture object */
+   pt = st_get_texobj_texture(att->Texture);
+   assert(pt);
+   assert(pt->width[att->TextureLevel]);
+
+   rb->Width = pt->width[att->TextureLevel];
+   rb->Height = pt->height[att->TextureLevel];
+
+   /* the renderbuffer's surface is inside the texture */
+   strb->surface = screen->get_tex_surface(screen, pt,
+                                           att->CubeMapFace,
+                                           att->TextureLevel,
+                                           att->Zoffset);
+   assert(strb->surface);
+
+   init_renderbuffer_bits(strb, pt->format);
+
+   /*
+   printf("RENDER TO TEXTURE obj=%p pt=%p surf=%p  %d x %d\n",
+          att->Texture, pt, strb->surface, rb->Width, rb->Height);
+   */
+
+   /* Invalidate buffer state so that the pipe's framebuffer state
+    * gets updated.
+    * That's where the new renderbuffer (which we just created) gets
+    * passed to the pipe as a (color/depth) render target.
+    */
+   st_invalidate_state(ctx, _NEW_BUFFERS);
 }
 
 
@@ -316,7 +364,17 @@ st_finish_render_texture(GLcontext *ctx,
 {
    struct st_renderbuffer *strb = st_renderbuffer(att->Renderbuffer);
 
-   pipe_surface_unreference(&strb->surface);
+   assert(strb);
+
+   ctx->st->pipe->flush(ctx->st->pipe, PIPE_FLUSH_RENDER_CACHE);
+
+   /*
+   printf("FINISH RENDER TO TEXTURE surf=%p\n", strb->surface);
+   */
+
+   pipe_surface_reference(&strb->surface, NULL);
+
+   _mesa_reference_renderbuffer(&att->Renderbuffer, NULL);
 
    /* restore previous framebuffer state */
    st_invalidate_state(ctx, _NEW_BUFFERS);