st/mesa: handle new GLSL IR enumerants in switch statements
[mesa.git] / src / mesa / state_tracker / st_cb_fbo.c
index 300c3f0eba515ba38a1f44e63e6fcca4076a24f7..d042ebabfd8a6c0fcdbe0c5758a507167d019ff6 100644 (file)
 #include "util/u_surface.h"
 
 
+static GLboolean
+st_renderbuffer_alloc_sw_storage(struct gl_context * ctx,
+                                 struct gl_renderbuffer *rb,
+                                 GLenum internalFormat,
+                                 GLuint width, GLuint height)
+{
+   struct pipe_screen *screen = st_context(ctx)->pipe->screen;
+   struct st_renderbuffer *strb = st_renderbuffer(rb);
+   enum pipe_format format;
+   size_t size;
+
+   free(strb->data);
+   strb->data = NULL;
+
+   if (internalFormat == GL_RGBA16_SNORM) {
+      /* Special case for software accum buffers.  Otherwise, if the
+       * call to st_choose_renderbuffer_format() fails (because the
+       * driver doesn't support signed 16-bit/channel colors) we'd
+       * just return without allocating the software accum buffer.
+       */
+      format = PIPE_FORMAT_R16G16B16A16_SNORM;
+   }
+   else {
+      format = st_choose_renderbuffer_format(screen, internalFormat, 0);
+
+      /* Not setting gl_renderbuffer::Format here will cause
+       * FRAMEBUFFER_UNSUPPORTED and ValidateFramebuffer will not be called.
+       */
+      if (format == PIPE_FORMAT_NONE) {
+         return GL_TRUE;
+      }
+   }
+
+   strb->Base.Format = st_pipe_format_to_mesa_format(format);
+
+   size = _mesa_format_image_size(strb->Base.Format, width, height, 1);
+   strb->data = malloc(size);
+   return strb->data != NULL;
+}
+
+
 /**
  * gl_renderbuffer::AllocStorage()
  * This is called to allocate the original drawing surface, and
@@ -72,100 +113,111 @@ st_renderbuffer_alloc_storage(struct gl_context * ctx,
    struct pipe_context *pipe = st->pipe;
    struct pipe_screen *screen = st->pipe->screen;
    struct st_renderbuffer *strb = st_renderbuffer(rb);
-   enum pipe_format format;
+   enum pipe_format format = PIPE_FORMAT_NONE;
    struct pipe_surface surf_tmpl;
-
-   if (internalFormat == GL_RGBA16_SNORM && strb->software) {
-      /* Special case for software accum buffers.  Otherwise, if the
-       * call to st_choose_renderbuffer_format() fails (because the
-       * driver doesn't support signed 16-bit/channel colors) we'd
-       * just return without allocating the software accum buffer.
-       */
-      format = PIPE_FORMAT_R16G16B16A16_SNORM;
-   }
-   else {
-      format = st_choose_renderbuffer_format(screen, internalFormat,
-                                             rb->NumSamples);
-   }
-
-   if (format == PIPE_FORMAT_NONE) {
-      return FALSE;
-   }
+   struct pipe_resource templ;
 
    /* init renderbuffer fields */
    strb->Base.Width  = width;
    strb->Base.Height = height;
-   strb->Base.Format = st_pipe_format_to_mesa_format(format);
    strb->Base._BaseFormat = _mesa_base_fbo_format(ctx, internalFormat);
-
    strb->defined = GL_FALSE;  /* undefined contents now */
 
    if (strb->software) {
-      size_t size;
-      
-      free(strb->data);
-
-      size = _mesa_format_image_size(strb->Base.Format, width, height, 1);
-      
-      strb->data = malloc(size);
-      
-      return strb->data != NULL;
+      return st_renderbuffer_alloc_sw_storage(ctx, rb, internalFormat,
+                                              width, height);
    }
-   else {
-      struct pipe_resource template;
-    
-      /* Free the old surface and texture
-       */
-      pipe_surface_reference( &strb->surface, NULL );
-      pipe_resource_reference( &strb->texture, NULL );
 
-      if (width == 0 || height == 0) {
-         /* if size is zero, nothing to allocate */
-         return GL_TRUE;
-      }
+   /* Free the old surface and texture
+    */
+   pipe_surface_reference( &strb->surface, NULL );
+   pipe_resource_reference( &strb->texture, NULL );
+
+   /* Handle multisample renderbuffers first.
+    *
+    * From ARB_framebuffer_object:
+    *   If <samples> is zero, then RENDERBUFFER_SAMPLES is set to zero.
+    *   Otherwise <samples> represents a request for a desired minimum
+    *   number of samples. Since different implementations may support
+    *   different sample counts for multisampled rendering, the actual
+    *   number of samples allocated for the renderbuffer image is
+    *   implementation dependent.  However, the resulting value for
+    *   RENDERBUFFER_SAMPLES is guaranteed to be greater than or equal
+    *   to <samples> and no more than the next larger sample count supported
+    *   by the implementation.
+    *
+    * So let's find the supported number of samples closest to NumSamples.
+    * (NumSamples == 1) is treated the same as (NumSamples == 0).
+    */
+   if (rb->NumSamples > 1) {
+      unsigned i;
 
-      /* Setup new texture template.
-       */
-      memset(&template, 0, sizeof(template));
-      template.target = st->internal_target;
-      template.format = format;
-      template.width0 = width;
-      template.height0 = height;
-      template.depth0 = 1;
-      template.array_size = 1;
-      template.last_level = 0;
-      template.nr_samples = rb->NumSamples;
-      if (util_format_is_depth_or_stencil(format)) {
-         template.bind = PIPE_BIND_DEPTH_STENCIL;
-      }
-      else if (strb->Base.Name != 0) {
-         /* this is a user-created renderbuffer */
-         template.bind = PIPE_BIND_RENDER_TARGET;
-      }
-      else {
-         /* this is a window-system buffer */
-         template.bind = (PIPE_BIND_DISPLAY_TARGET |
-                          PIPE_BIND_RENDER_TARGET);
+      for (i = rb->NumSamples; i <= ctx->Const.MaxSamples; i++) {
+         format = st_choose_renderbuffer_format(screen, internalFormat, i);
+
+         if (format != PIPE_FORMAT_NONE) {
+            rb->NumSamples = i;
+            break;
+         }
       }
+   } else {
+      format = st_choose_renderbuffer_format(screen, internalFormat, 0);
+   }
 
-      strb->texture = screen->resource_create(screen, &template);
+   /* Not setting gl_renderbuffer::Format here will cause
+    * FRAMEBUFFER_UNSUPPORTED and ValidateFramebuffer will not be called.
+    */
+   if (format == PIPE_FORMAT_NONE) {
+      return GL_TRUE;
+   }
 
-      if (!strb->texture) 
-         return FALSE;
+   strb->Base.Format = st_pipe_format_to_mesa_format(format);
 
-      u_surface_default_template(&surf_tmpl, strb->texture, template.bind);
-      strb->surface = pipe->create_surface(pipe,
-                                           strb->texture,
-                                           &surf_tmpl);
-      if (strb->surface) {
-         assert(strb->surface->texture);
-         assert(strb->surface->format);
-         assert(strb->surface->width == width);
-         assert(strb->surface->height == height);
-      }
+   if (width == 0 || height == 0) {
+      /* if size is zero, nothing to allocate */
+      return GL_TRUE;
+   }
 
-      return strb->surface != NULL;
+   /* Setup new texture template.
+    */
+   memset(&templ, 0, sizeof(templ));
+   templ.target = st->internal_target;
+   templ.format = format;
+   templ.width0 = width;
+   templ.height0 = height;
+   templ.depth0 = 1;
+   templ.array_size = 1;
+   templ.nr_samples = rb->NumSamples;
+   if (util_format_is_depth_or_stencil(format)) {
+      templ.bind = PIPE_BIND_DEPTH_STENCIL;
+   }
+   else if (strb->Base.Name != 0) {
+      /* this is a user-created renderbuffer */
+      templ.bind = PIPE_BIND_RENDER_TARGET;
+   }
+   else {
+      /* this is a window-system buffer */
+      templ.bind = (PIPE_BIND_DISPLAY_TARGET |
+                    PIPE_BIND_RENDER_TARGET);
    }
+
+   strb->texture = screen->resource_create(screen, &templ);
+
+   if (!strb->texture)
+      return FALSE;
+
+   u_surface_default_template(&surf_tmpl, strb->texture);
+   strb->surface = pipe->create_surface(pipe,
+                                        strb->texture,
+                                        &surf_tmpl);
+   if (strb->surface) {
+      assert(strb->surface->texture);
+      assert(strb->surface->format);
+      assert(strb->surface->width == width);
+      assert(strb->surface->height == height);
+   }
+
+   return strb->surface != NULL;
 }
 
 
@@ -173,14 +225,16 @@ st_renderbuffer_alloc_storage(struct gl_context * ctx,
  * gl_renderbuffer::Delete()
  */
 static void
-st_renderbuffer_delete(struct gl_renderbuffer *rb)
+st_renderbuffer_delete(struct gl_context *ctx, struct gl_renderbuffer *rb)
 {
    struct st_renderbuffer *strb = st_renderbuffer(rb);
-   ASSERT(strb);
-   pipe_surface_reference(&strb->surface, NULL);
+   if (ctx) {
+      struct st_context *st = st_context(ctx);
+      pipe_surface_release(st->pipe, &strb->surface);
+   }
    pipe_resource_reference(&strb->texture, NULL);
    free(strb->data);
-   free(strb);
+   _mesa_delete_renderbuffer(ctx, rb);
 }
 
 
@@ -239,13 +293,21 @@ st_new_renderbuffer_fb(enum pipe_format format, int samples, boolean sw)
    case PIPE_FORMAT_R8G8B8A8_UNORM:
    case PIPE_FORMAT_B8G8R8A8_UNORM:
    case PIPE_FORMAT_A8R8G8B8_UNORM:
+      strb->Base.InternalFormat = GL_RGBA8;
+      break;
    case PIPE_FORMAT_R8G8B8X8_UNORM:
    case PIPE_FORMAT_B8G8R8X8_UNORM:
    case PIPE_FORMAT_X8R8G8B8_UNORM:
+      strb->Base.InternalFormat = GL_RGB8;
+      break;
    case PIPE_FORMAT_B5G5R5A1_UNORM:
+      strb->Base.InternalFormat = GL_RGB5_A1;
+      break;
    case PIPE_FORMAT_B4G4R4A4_UNORM:
+      strb->Base.InternalFormat = GL_RGBA4;
+      break;
    case PIPE_FORMAT_B5G6R5_UNORM:
-      strb->Base.InternalFormat = GL_RGBA;
+      strb->Base.InternalFormat = GL_RGB565;
       break;
    case PIPE_FORMAT_Z16_UNORM:
       strb->Base.InternalFormat = GL_DEPTH_COMPONENT16;
@@ -255,9 +317,11 @@ st_new_renderbuffer_fb(enum pipe_format format, int samples, boolean sw)
       break;
    case PIPE_FORMAT_Z24_UNORM_S8_UINT:
    case PIPE_FORMAT_S8_UINT_Z24_UNORM:
+      strb->Base.InternalFormat = GL_DEPTH24_STENCIL8_EXT;
+      break;
    case PIPE_FORMAT_Z24X8_UNORM:
    case PIPE_FORMAT_X8Z24_UNORM:
-      strb->Base.InternalFormat = GL_DEPTH24_STENCIL8_EXT;
+      strb->Base.InternalFormat = GL_DEPTH_COMPONENT24;
       break;
    case PIPE_FORMAT_S8_UINT:
       strb->Base.InternalFormat = GL_STENCIL_INDEX8_EXT;
@@ -278,9 +342,16 @@ st_new_renderbuffer_fb(enum pipe_format format, int samples, boolean sw)
    case PIPE_FORMAT_R16G16_UNORM:
       strb->Base.InternalFormat = GL_RG16;
       break;
+   case PIPE_FORMAT_R32G32B32A32_FLOAT:
+      strb->Base.InternalFormat = GL_RGBA32F;
+      break;
+   case PIPE_FORMAT_R16G16B16A16_FLOAT:
+      strb->Base.InternalFormat = GL_RGBA16F;
+      break;
    default:
       _mesa_problem(NULL,
-                   "Unexpected format in st_new_renderbuffer_fb");
+                   "Unexpected format %s in st_new_renderbuffer_fb",
+                    util_format_name(format));
       free(strb);
       return NULL;
    }
@@ -367,7 +438,7 @@ st_render_texture(struct gl_context *ctx,
 
    pipe_resource_reference( &strb->texture, pt );
 
-   pipe_surface_reference(&strb->surface, NULL);
+   pipe_surface_release(pipe, &strb->surface);
 
    assert(strb->rtt_level <= strb->texture->last_level);
 
@@ -375,7 +446,6 @@ st_render_texture(struct gl_context *ctx,
    memset(&surf_tmpl, 0, sizeof(surf_tmpl));
    surf_tmpl.format = ctx->Color.sRGBEnabled
       ? strb->texture->format : util_format_linear(strb->texture->format);
-   surf_tmpl.usage = PIPE_BIND_RENDER_TARGET;
    surf_tmpl.u.tex.level = strb->rtt_level;
    surf_tmpl.u.tex.first_layer = strb->rtt_face + strb->rtt_slice;
    surf_tmpl.u.tex.last_layer = strb->rtt_face + strb->rtt_slice;
@@ -391,6 +461,12 @@ st_render_texture(struct gl_context *ctx,
     * passed to the pipe as a (color/depth) render target.
     */
    st_invalidate_state(ctx, _NEW_BUFFERS);
+
+
+   /* Need to trigger a call to update_framebuffer() since we just
+    * attached a new renderbuffer.
+    */
+   ctx->NewState |= _NEW_BUFFERS;
 }
 
 
@@ -413,6 +489,16 @@ st_finish_render_texture(struct gl_context *ctx,
 }
 
 
+/** Debug helper */
+static void
+st_fbo_invalid(const char *reason)
+{
+   if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) {
+      _mesa_debug(NULL, "Invalid FBO: %s\n", reason);
+   }
+}
+
+
 /**
  * Validate a renderbuffer attachment for a particular set of bindings.
  */
@@ -425,6 +511,7 @@ st_validate_attachment(struct gl_context *ctx,
    const struct st_texture_object *stObj = st_texture_object(att->Texture);
    enum pipe_format format;
    gl_format texFormat;
+   GLboolean valid;
 
    /* Only validate texture attachments for now, since
     * st_renderbuffer_alloc_storage makes sure that
@@ -448,9 +535,14 @@ st_validate_attachment(struct gl_context *ctx,
       format = st_mesa_format_to_pipe_format(linearFormat);
    }
 
-   return screen->is_format_supported(screen, format,
+   valid = screen->is_format_supported(screen, format,
                                       PIPE_TEXTURE_2D,
                                       stObj->pt->nr_samples, bindings);
+   if (!valid) {
+      st_fbo_invalid("Invalid format");
+   }
+
+   return valid;
 }
 
 
@@ -499,12 +591,14 @@ st_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb)
          screen->get_param(screen, PIPE_CAP_MIXED_COLORBUFFER_FORMATS) != 0;
 
    if (depth->Type && stencil->Type && depth->Type != stencil->Type) {
+      st_fbo_invalid("Different Depth/Stencil buffer formats");
       fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
       return;
    }
    if (depth->Type == GL_RENDERBUFFER_EXT &&
        stencil->Type == GL_RENDERBUFFER_EXT &&
        depth->Renderbuffer != stencil->Renderbuffer) {
+      st_fbo_invalid("Separate Depth/Stencil buffers");
       fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
       return;
    }
@@ -512,6 +606,7 @@ st_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb)
        stencil->Type == GL_TEXTURE &&
        depth->Texture != stencil->Texture) {
       fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
+      st_fbo_invalid("Different Depth/Stencil textures");
       return;
    }
 
@@ -554,6 +649,7 @@ st_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb)
             first_format = format;
          } else if (format != first_format) {
             fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
+            st_fbo_invalid("Mixed color formats");
             return;
          }
       }
@@ -615,6 +711,7 @@ st_MapRenderbuffer(struct gl_context *ctx,
    const GLboolean invert = rb->Name == 0;
    unsigned usage;
    GLuint y2;
+   GLubyte *map;
 
    if (strb->software) {
       /* software-allocated renderbuffer (probably an accum buffer) */
@@ -649,15 +746,14 @@ st_MapRenderbuffer(struct gl_context *ctx,
    else
       y2 = y;
 
-   strb->transfer = pipe_get_transfer(pipe,
-                                      strb->texture,
-                                      strb->rtt_level,
-                                      strb->rtt_face + strb->rtt_slice,
-                                      usage, x, y2, w, h);
-   if (strb->transfer) {
-      GLubyte *map = pipe_transfer_map(pipe, strb->transfer);
+    map = pipe_transfer_map(pipe,
+                            strb->texture,
+                            strb->rtt_level,
+                            strb->rtt_face + strb->rtt_slice,
+                            usage, x, y2, w, h, &strb->transfer);
+   if (map) {
       if (invert) {
-         *rowStrideOut = -strb->transfer->stride;
+         *rowStrideOut = -(int) strb->transfer->stride;
          map += (h - 1) * strb->transfer->stride;
       }
       else {
@@ -689,7 +785,6 @@ st_UnmapRenderbuffer(struct gl_context *ctx,
    }
 
    pipe_transfer_unmap(pipe, strb->transfer);
-   pipe->transfer_destroy(pipe, strb->transfer);
    strb->transfer = NULL;
 }
 
@@ -697,7 +792,6 @@ st_UnmapRenderbuffer(struct gl_context *ctx,
 
 void st_init_fbo_functions(struct dd_function_table *functions)
 {
-#if FEATURE_EXT_framebuffer_object
    functions->NewFramebuffer = st_new_framebuffer;
    functions->NewRenderbuffer = st_new_renderbuffer;
    functions->BindFramebuffer = st_bind_framebuffer;
@@ -705,7 +799,6 @@ void st_init_fbo_functions(struct dd_function_table *functions)
    functions->RenderTexture = st_render_texture;
    functions->FinishRenderTexture = st_finish_render_texture;
    functions->ValidateFramebuffer = st_validate_framebuffer;
-#endif
 
    functions->DrawBuffers = st_DrawBuffers;
    functions->ReadBuffer = st_ReadBuffer;