mesa: add support for memory object creation/import/delete
[mesa.git] / src / mesa / main / fbobject.c
index df7cc1775cba5006705077e48c3eaea37461b546..4d6fdfcd6bd90be08c9dbb5b16b65d21c1febe6e 100644 (file)
@@ -1705,11 +1705,6 @@ create_render_buffers(struct gl_context *ctx, GLsizei n, GLuint *renderbuffers,
    GLuint first;
    GLint i;
 
-   if (n < 0) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n<0)", func);
-      return;
-   }
-
    if (!renderbuffers)
       return;
 
@@ -1734,8 +1729,23 @@ create_render_buffers(struct gl_context *ctx, GLsizei n, GLuint *renderbuffers,
 }
 
 
+static void
+create_render_buffers_err(struct gl_context *ctx, GLsizei n,
+                          GLuint *renderbuffers, bool dsa)
+{
+   const char *func = dsa ? "glCreateRenderbuffers" : "glGenRenderbuffers";
+
+   if (n < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n<0)", func);
+      return;
+   }
+
+   create_render_buffers(ctx, n, renderbuffers, dsa);
+}
+
+
 void GLAPIENTRY
-_mesa_GenRenderbuffers(GLsizei n, GLuint *renderbuffers)
+_mesa_GenRenderbuffers_no_error(GLsizei n, GLuint *renderbuffers)
 {
    GET_CURRENT_CONTEXT(ctx);
    create_render_buffers(ctx, n, renderbuffers, false);
@@ -1743,13 +1753,29 @@ _mesa_GenRenderbuffers(GLsizei n, GLuint *renderbuffers)
 
 
 void GLAPIENTRY
-_mesa_CreateRenderbuffers(GLsizei n, GLuint *renderbuffers)
+_mesa_GenRenderbuffers(GLsizei n, GLuint *renderbuffers)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   create_render_buffers_err(ctx, n, renderbuffers, false);
+}
+
+
+void GLAPIENTRY
+_mesa_CreateRenderbuffers_no_error(GLsizei n, GLuint *renderbuffers)
 {
    GET_CURRENT_CONTEXT(ctx);
    create_render_buffers(ctx, n, renderbuffers, true);
 }
 
 
+void GLAPIENTRY
+_mesa_CreateRenderbuffers(GLsizei n, GLuint *renderbuffers)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   create_render_buffers_err(ctx, n, renderbuffers, true);
+}
+
+
 /**
  * Given an internal format token for a render buffer, return the
  * corresponding base format (one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX,
@@ -2822,6 +2848,16 @@ _mesa_check_framebuffer_status(struct gl_context *ctx,
 }
 
 
+GLenum GLAPIENTRY
+_mesa_CheckFramebufferStatus_no_error(GLenum target)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   struct gl_framebuffer *fb = get_framebuffer_target(ctx, target);
+   return _mesa_check_framebuffer_status(ctx, fb);
+}
+
+
 GLenum GLAPIENTRY
 _mesa_CheckFramebufferStatus(GLenum target)
 {
@@ -2910,6 +2946,16 @@ reuse_framebuffer_texture_attachment(struct gl_framebuffer *fb,
 }
 
 
+static struct gl_texture_object *
+get_texture_for_framebuffer(struct gl_context *ctx, GLuint texture)
+{
+   if (!texture)
+      return NULL;
+
+   return _mesa_lookup_texture(ctx, texture);
+}
+
+
 /**
  * Common code called by gl*FramebufferTexture*() to retrieve the correct
  * texture object pointer.
@@ -2920,9 +2966,9 @@ reuse_framebuffer_texture_attachment(struct gl_framebuffer *fb,
  * \return true if no errors, false if errors
  */
 static bool
-get_texture_for_framebuffer(struct gl_context *ctx, GLuint texture,
-                            bool layered, const char *caller,
-                            struct gl_texture_object **texObj)
+get_texture_for_framebuffer_err(struct gl_context *ctx, GLuint texture,
+                                bool layered, const char *caller,
+                                struct gl_texture_object **texObj)
 {
    *texObj = NULL; /* This will get returned if texture = 0. */
 
@@ -3188,25 +3234,22 @@ check_level(struct gl_context *ctx, GLenum target, GLint level,
 }
 
 
-void
-_mesa_framebuffer_texture(struct gl_context *ctx, struct gl_framebuffer *fb,
-                          GLenum attachment,
-                          struct gl_texture_object *texObj, GLenum textarget,
-                          GLint level, GLuint layer, GLboolean layered,
-                          const char *caller)
+struct gl_renderbuffer_attachment *
+_mesa_get_and_validate_attachment(struct gl_context *ctx,
+                                  struct gl_framebuffer *fb,
+                                  GLenum attachment, const char *caller)
 {
-   struct gl_renderbuffer_attachment *att;
-   bool is_color_attachment;
-
    /* The window-system framebuffer object is immutable */
    if (_mesa_is_winsys_fbo(fb)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(window-system framebuffer)",
                   caller);
-      return;
+      return NULL;
    }
 
    /* Not a hash lookup, so we can afford to get the attachment here. */
-   att = get_attachment(ctx, fb, attachment, &is_color_attachment);
+   bool is_color_attachment;
+   struct gl_renderbuffer_attachment *att =
+      get_attachment(ctx, fb, attachment, &is_color_attachment);
    if (att == NULL) {
       if (is_color_attachment) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
@@ -3217,9 +3260,20 @@ _mesa_framebuffer_texture(struct gl_context *ctx, struct gl_framebuffer *fb,
                      "%s(invalid attachment %s)", caller,
                      _mesa_enum_to_string(attachment));
       }
-      return;
+      return NULL;
    }
 
+   return att;
+}
+
+
+void
+_mesa_framebuffer_texture(struct gl_context *ctx, struct gl_framebuffer *fb,
+                          GLenum attachment,
+                          struct gl_renderbuffer_attachment *att,
+                          struct gl_texture_object *texObj, GLenum textarget,
+                          GLint level, GLuint layer, GLboolean layered)
+{
    FLUSH_VERTICES(ctx, _NEW_BUFFERS);
 
    mtx_lock(&fb->Mutex);
@@ -3285,6 +3339,28 @@ _mesa_framebuffer_texture(struct gl_context *ctx, struct gl_framebuffer *fb,
 }
 
 
+static void
+framebuffer_texture_with_dims_no_error(GLenum target, GLenum attachment,
+                                       GLenum textarget, GLuint texture,
+                                       GLint level, GLint layer)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   /* Get the framebuffer object */
+   struct gl_framebuffer *fb = get_framebuffer_target(ctx, target);
+
+   /* Get the texture object */
+   struct gl_texture_object *texObj =
+      get_texture_for_framebuffer(ctx, texture);
+
+   struct gl_renderbuffer_attachment *att =
+      get_attachment(ctx, fb, attachment, NULL);
+
+   _mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget,
+                             level, layer, GL_FALSE);
+}
+
+
 static void
 framebuffer_texture_with_dims(int dims, GLenum target,
                               GLenum attachment, GLenum textarget,
@@ -3304,7 +3380,7 @@ framebuffer_texture_with_dims(int dims, GLenum target,
    }
 
    /* Get the texture object */
-   if (!get_texture_for_framebuffer(ctx, texture, false, caller, &texObj))
+   if (!get_texture_for_framebuffer_err(ctx, texture, false, caller, &texObj))
       return;
 
    if (texObj) {
@@ -3318,8 +3394,23 @@ framebuffer_texture_with_dims(int dims, GLenum target,
          return;
    }
 
-   _mesa_framebuffer_texture(ctx, fb, attachment, texObj, textarget, level,
-                             layer, GL_FALSE, caller);
+   struct gl_renderbuffer_attachment *att =
+      _mesa_get_and_validate_attachment(ctx, fb, attachment, caller);
+   if (!att)
+      return;
+
+   _mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget,
+                             level, layer, GL_FALSE);
+}
+
+
+void GLAPIENTRY
+_mesa_FramebufferTexture1D_no_error(GLenum target, GLenum attachment,
+                                    GLenum textarget, GLuint texture,
+                                    GLint level)
+{
+   framebuffer_texture_with_dims_no_error(target, attachment, textarget,
+                                          texture, level, 0);
 }
 
 
@@ -3332,6 +3423,16 @@ _mesa_FramebufferTexture1D(GLenum target, GLenum attachment,
 }
 
 
+void GLAPIENTRY
+_mesa_FramebufferTexture2D_no_error(GLenum target, GLenum attachment,
+                                    GLenum textarget, GLuint texture,
+                                    GLint level)
+{
+   framebuffer_texture_with_dims_no_error(target, attachment, textarget,
+                                          texture, level, 0);
+}
+
+
 void GLAPIENTRY
 _mesa_FramebufferTexture2D(GLenum target, GLenum attachment,
                            GLenum textarget, GLuint texture, GLint level)
@@ -3341,6 +3442,16 @@ _mesa_FramebufferTexture2D(GLenum target, GLenum attachment,
 }
 
 
+void GLAPIENTRY
+_mesa_FramebufferTexture3D_no_error(GLenum target, GLenum attachment,
+                                    GLenum textarget, GLuint texture,
+                                    GLint level, GLint layer)
+{
+   framebuffer_texture_with_dims_no_error(target, attachment, textarget,
+                                          texture, level, layer);
+}
+
+
 void GLAPIENTRY
 _mesa_FramebufferTexture3D(GLenum target, GLenum attachment,
                            GLenum textarget, GLuint texture,
@@ -3351,91 +3462,140 @@ _mesa_FramebufferTexture3D(GLenum target, GLenum attachment,
 }
 
 
-void GLAPIENTRY
-_mesa_FramebufferTextureLayer(GLenum target, GLenum attachment,
-                              GLuint texture, GLint level, GLint layer)
+static ALWAYS_INLINE void
+frame_buffer_texture(GLuint framebuffer, GLenum target,
+                     GLenum attachment, GLuint texture,
+                     GLint level, GLint layer, const char *func,
+                     bool dsa, bool no_error, bool check_layered)
 {
    GET_CURRENT_CONTEXT(ctx);
-   struct gl_framebuffer *fb;
-   struct gl_texture_object *texObj;
-   GLenum textarget = 0;
+   GLboolean layered = GL_FALSE;
 
-   const char *func = "glFramebufferTextureLayer";
+   if (!no_error && check_layered) {
+      if (!_mesa_has_geometry_shaders(ctx)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "unsupported function (%s) called", func);
+         return;
+      }
+   }
 
    /* Get the framebuffer object */
-   fb = get_framebuffer_target(ctx, target);
-   if (!fb) {
-      _mesa_error(ctx, GL_INVALID_ENUM,
-                  "glFramebufferTextureLayer(invalid target %s)",
-                  _mesa_enum_to_string(target));
-      return;
+   struct gl_framebuffer *fb;
+   if (no_error) {
+      if (dsa) {
+         fb = _mesa_lookup_framebuffer(ctx, framebuffer);
+      } else {
+         fb = get_framebuffer_target(ctx, target);
+      }
+   } else {
+      if (dsa) {
+         fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, func);
+         if (!fb)
+            return;
+      } else {
+         fb = get_framebuffer_target(ctx, target);
+         if (!fb) {
+            _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)",
+                        func, _mesa_enum_to_string(target));
+            return;
+         }
+      }
    }
 
-   /* Get the texture object */
-   if (!get_texture_for_framebuffer(ctx, texture, false, func, &texObj))
-      return;
-
-   if (texObj) {
-      if (!check_texture_target(ctx, texObj->Target, func))
+   /* Get the texture object and framebuffer attachment*/
+   struct gl_renderbuffer_attachment *att;
+   struct gl_texture_object *texObj;
+   if (no_error) {
+      texObj = get_texture_for_framebuffer(ctx, texture);
+      att = get_attachment(ctx, fb, attachment, NULL);
+   } else {
+      if (!get_texture_for_framebuffer_err(ctx, texture, check_layered, func,
+                                           &texObj))
          return;
 
-      if (!check_layer(ctx, texObj->Target, layer, func))
+      att = _mesa_get_and_validate_attachment(ctx, fb, attachment, func);
+      if (!att)
          return;
+   }
 
-      if (!check_level(ctx, texObj->Target, level, func))
-         return;
+   GLenum textarget = 0;
+   if (texObj) {
+      if (check_layered) {
+         /* We do this regardless of no_error because this sets layered */
+         if (!check_layered_texture_target(ctx, texObj->Target, func,
+                                           &layered))
+            return;
+      }
 
-      if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
+      if (!no_error) {
+         if (!check_layered) {
+            if (!check_texture_target(ctx, texObj->Target, func))
+               return;
+
+            if (!check_layer(ctx, texObj->Target, layer, func))
+               return;
+         }
+
+         if (!check_level(ctx, texObj->Target, level, func))
+            return;
+      }
+
+      if (!check_layered && texObj->Target == GL_TEXTURE_CUBE_MAP) {
          assert(layer >= 0 && layer < 6);
          textarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;
          layer = 0;
       }
    }
 
-   _mesa_framebuffer_texture(ctx, fb, attachment, texObj, textarget, level,
-                             layer, GL_FALSE, func);
+   _mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget,
+                             level, layer, layered);
 }
 
-
 void GLAPIENTRY
-_mesa_NamedFramebufferTextureLayer(GLuint framebuffer, GLenum attachment,
-                                   GLuint texture, GLint level, GLint layer)
+_mesa_FramebufferTextureLayer_no_error(GLenum target, GLenum attachment,
+                                       GLuint texture, GLint level,
+                                       GLint layer)
 {
-   GET_CURRENT_CONTEXT(ctx);
-   struct gl_framebuffer *fb;
-   struct gl_texture_object *texObj;
-   GLenum textarget = 0;
+   frame_buffer_texture(0, target, attachment, texture, level, layer,
+                        "glFramebufferTextureLayer", false, true, false);
+}
 
-   const char *func = "glNamedFramebufferTextureLayer";
 
-   /* Get the framebuffer object */
-   fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, func);
-   if (!fb)
-      return;
+void GLAPIENTRY
+_mesa_FramebufferTextureLayer(GLenum target, GLenum attachment,
+                              GLuint texture, GLint level, GLint layer)
+{
+   frame_buffer_texture(0, target, attachment, texture, level, layer,
+                        "glFramebufferTextureLayer", false, false, false);
+}
 
-   /* Get the texture object */
-   if (!get_texture_for_framebuffer(ctx, texture, false, func, &texObj))
-      return;
 
-   if (texObj) {
-      if (!check_texture_target(ctx, texObj->Target, func))
-         return;
+void GLAPIENTRY
+_mesa_NamedFramebufferTextureLayer_no_error(GLuint framebuffer,
+                                            GLenum attachment,
+                                            GLuint texture, GLint level,
+                                            GLint layer)
+{
+   frame_buffer_texture(framebuffer, 0, attachment, texture, level, layer,
+                        "glNamedFramebufferTextureLayer", true, true, false);
+}
 
-      if (!check_layer(ctx, texObj->Target, layer, func))
-         return;
 
-      if (!check_level(ctx, texObj->Target, level, func))
-         return;
+void GLAPIENTRY
+_mesa_NamedFramebufferTextureLayer(GLuint framebuffer, GLenum attachment,
+                                   GLuint texture, GLint level, GLint layer)
+{
+   frame_buffer_texture(framebuffer, 0, attachment, texture, level, layer,
+                        "glNamedFramebufferTextureLayer", true, false, false);
+}
 
-      if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
-         assert(layer >= 0 && layer < 6);
-         textarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;
-         layer = 0;
-      }
-   }
 
-   _mesa_framebuffer_texture(ctx, fb, attachment, texObj, textarget, level,
-                             layer, GL_FALSE, func);
+void GLAPIENTRY
+_mesa_FramebufferTexture_no_error(GLenum target, GLenum attachment,
+                                  GLuint texture, GLint level)
+{
+   frame_buffer_texture(0, target, attachment, texture, level, 0,
+                        "glFramebufferTexture", false, true, true);
 }
 
 
@@ -3443,42 +3603,16 @@ void GLAPIENTRY
 _mesa_FramebufferTexture(GLenum target, GLenum attachment,
                          GLuint texture, GLint level)
 {
-   GET_CURRENT_CONTEXT(ctx);
-   struct gl_framebuffer *fb;
-   struct gl_texture_object *texObj;
-   GLboolean layered = GL_FALSE;
-
-   const char *func = "FramebufferTexture";
-
-   if (!_mesa_has_geometry_shaders(ctx)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "unsupported function (glFramebufferTexture) called");
-      return;
-   }
-
-   /* Get the framebuffer object */
-   fb = get_framebuffer_target(ctx, target);
-   if (!fb) {
-      _mesa_error(ctx, GL_INVALID_ENUM,
-                  "glFramebufferTexture(invalid target %s)",
-                  _mesa_enum_to_string(target));
-      return;
-   }
-
-   /* Get the texture object */
-   if (!get_texture_for_framebuffer(ctx, texture, true, func, &texObj))
-      return;
-
-   if (texObj) {
-      if (!check_layered_texture_target(ctx, texObj->Target, func, &layered))
-         return;
-
-      if (!check_level(ctx, texObj->Target, level, func))
-         return;
-   }
+   frame_buffer_texture(0, target, attachment, texture, level, 0,
+                        "glFramebufferTexture", false, false, true);
+}
 
-   _mesa_framebuffer_texture(ctx, fb, attachment, texObj, 0, level,
-                             0, layered, func);
+void GLAPIENTRY
+_mesa_NamedFramebufferTexture_no_error(GLuint framebuffer, GLenum attachment,
+                                       GLuint texture, GLint level)
+{
+   frame_buffer_texture(framebuffer, 0, attachment, texture, level, 0,
+                        "glNamedFramebufferTexture", true, true, true);
 }
 
 
@@ -3486,39 +3620,8 @@ void GLAPIENTRY
 _mesa_NamedFramebufferTexture(GLuint framebuffer, GLenum attachment,
                               GLuint texture, GLint level)
 {
-   GET_CURRENT_CONTEXT(ctx);
-   struct gl_framebuffer *fb;
-   struct gl_texture_object *texObj;
-   GLboolean layered = GL_FALSE;
-
-   const char *func = "glNamedFramebufferTexture";
-
-   if (!_mesa_has_geometry_shaders(ctx)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "unsupported function (glNamedFramebufferTexture) called");
-      return;
-   }
-
-   /* Get the framebuffer object */
-   fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, func);
-   if (!fb)
-      return;
-
-   /* Get the texture object */
-   if (!get_texture_for_framebuffer(ctx, texture, true, func, &texObj))
-      return;
-
-   if (texObj) {
-      if (!check_layered_texture_target(ctx, texObj->Target, func,
-                                        &layered))
-         return;
-
-      if (!check_level(ctx, texObj->Target, level, func))
-         return;
-   }
-
-   _mesa_framebuffer_texture(ctx, fb, attachment, texObj, 0, level,
-                             0, layered, func);
+   frame_buffer_texture(framebuffer, 0, attachment, texture, level, 0,
+                        "glNamedFramebufferTexture", true, false, true);
 }
 
 
@@ -3541,70 +3644,121 @@ _mesa_framebuffer_renderbuffer(struct gl_context *ctx,
    _mesa_update_framebuffer_visual(ctx, fb);
 }
 
-static void
-framebuffer_renderbuffer(struct gl_context *ctx,
-                         struct gl_framebuffer *fb,
-                         GLenum attachment,
-                         struct gl_renderbuffer *rb,
-                         const char *func)
+static ALWAYS_INLINE void
+framebuffer_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
+                         GLenum attachment, GLenum renderbuffertarget,
+                         GLuint renderbuffer, const char *func, bool no_error)
 {
    struct gl_renderbuffer_attachment *att;
+   struct gl_renderbuffer *rb;
    bool is_color_attachment;
 
-   if (_mesa_is_winsys_fbo(fb)) {
-      /* Can't attach new renderbuffers to a window system framebuffer */
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "%s(window-system framebuffer)", func);
+   if (!no_error && renderbuffertarget != GL_RENDERBUFFER) {
+      _mesa_error(ctx, GL_INVALID_ENUM,
+                  "%s(renderbuffertarget is not GL_RENDERBUFFER)", func);
       return;
    }
 
-   att = get_attachment(ctx, fb, attachment, &is_color_attachment);
-   if (att == NULL) {
-      /*
-       * From OpenGL 4.5 spec, section 9.2.7 "Attaching Renderbuffer Images to
-       * a Framebuffer":
-       *
-       *    "An INVALID_OPERATION error is generated if attachment is COLOR_-
-       *     ATTACHMENTm where m is greater than or equal to the value of
-       *     MAX_COLOR_- ATTACHMENTS ."
-       *
-       * If we are at this point, is because the attachment is not valid, so
-       * if is_color_attachment is true, is because of the previous reason.
-       */
-      if (is_color_attachment) {
-         _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "%s(invalid color attachment %s)", func,
-                     _mesa_enum_to_string(attachment));
+   if (renderbuffer) {
+      if (!no_error) {
+         rb = _mesa_lookup_renderbuffer_err(ctx, renderbuffer, func);
+         if (!rb)
+            return;
       } else {
-         _mesa_error(ctx, GL_INVALID_ENUM,
-                     "%s(invalid attachment %s)", func,
-                     _mesa_enum_to_string(attachment));
+         rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
       }
-
-      return;
+   } else {
+      /* remove renderbuffer attachment */
+      rb = NULL;
    }
 
-   if (attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
-       rb && rb->Format != MESA_FORMAT_NONE) {
-      /* make sure the renderbuffer is a depth/stencil format */
-      const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
-      if (baseFormat != GL_DEPTH_STENCIL) {
+   if (!no_error) {
+      if (_mesa_is_winsys_fbo(fb)) {
+         /* Can't attach new renderbuffers to a window system framebuffer */
          _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "%s(renderbuffer is not DEPTH_STENCIL format)", func);
+                     "%s(window-system framebuffer)", func);
+         return;
+      }
+
+      att = get_attachment(ctx, fb, attachment, &is_color_attachment);
+      if (att == NULL) {
+         /*
+          * From OpenGL 4.5 spec, section 9.2.7 "Attaching Renderbuffer Images
+          * to a Framebuffer":
+          *
+          *    "An INVALID_OPERATION error is generated if attachment is
+          *    COLOR_- ATTACHMENTm where m is greater than or equal to the
+          *    value of MAX_COLOR_- ATTACHMENTS ."
+          *
+          * If we are at this point, is because the attachment is not valid, so
+          * if is_color_attachment is true, is because of the previous reason.
+          */
+         if (is_color_attachment) {
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "%s(invalid color attachment %s)", func,
+                        _mesa_enum_to_string(attachment));
+         } else {
+            _mesa_error(ctx, GL_INVALID_ENUM,
+                        "%s(invalid attachment %s)", func,
+                        _mesa_enum_to_string(attachment));
+         }
+
          return;
       }
+
+      if (attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
+          rb && rb->Format != MESA_FORMAT_NONE) {
+         /* make sure the renderbuffer is a depth/stencil format */
+         const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
+         if (baseFormat != GL_DEPTH_STENCIL) {
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "%s(renderbuffer is not DEPTH_STENCIL format)", func);
+            return;
+         }
+      }
    }
 
    _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb);
 }
 
+static void
+framebuffer_renderbuffer_error(struct gl_context *ctx,
+                               struct gl_framebuffer *fb, GLenum attachment,
+                               GLenum renderbuffertarget,
+                               GLuint renderbuffer, const char *func)
+{
+   framebuffer_renderbuffer(ctx, fb, attachment, renderbuffertarget,
+                            renderbuffer, func, false);
+}
+
+static void
+framebuffer_renderbuffer_no_error(struct gl_context *ctx,
+                                  struct gl_framebuffer *fb, GLenum attachment,
+                                  GLenum renderbuffertarget,
+                                  GLuint renderbuffer, const char *func)
+{
+   framebuffer_renderbuffer(ctx, fb, attachment, renderbuffertarget,
+                            renderbuffer, func, true);
+}
+
+void GLAPIENTRY
+_mesa_FramebufferRenderbuffer_no_error(GLenum target, GLenum attachment,
+                                       GLenum renderbuffertarget,
+                                       GLuint renderbuffer)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   struct gl_framebuffer *fb = get_framebuffer_target(ctx, target);
+   framebuffer_renderbuffer_no_error(ctx, fb, attachment, renderbuffertarget,
+                                     renderbuffer, "glFramebufferRenderbuffer");
+}
+
 void GLAPIENTRY
 _mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment,
                               GLenum renderbuffertarget,
                               GLuint renderbuffer)
 {
    struct gl_framebuffer *fb;
-   struct gl_renderbuffer *rb;
    GET_CURRENT_CONTEXT(ctx);
 
    fb = get_framebuffer_target(ctx, target);
@@ -3615,36 +3769,30 @@ _mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment,
       return;
    }
 
-   if (renderbuffertarget != GL_RENDERBUFFER) {
-      _mesa_error(ctx, GL_INVALID_ENUM,
-                  "glFramebufferRenderbuffer(renderbuffertarget is not "
-                  "GL_RENDERBUFFER)");
-      return;
-   }
+   framebuffer_renderbuffer_error(ctx, fb, attachment, renderbuffertarget,
+                                  renderbuffer, "glFramebufferRenderbuffer");
+}
 
-   if (renderbuffer) {
-      rb = _mesa_lookup_renderbuffer_err(ctx, renderbuffer,
-                                         "glFramebufferRenderbuffer");
-      if (!rb)
-         return;
-   }
-   else {
-      /* remove renderbuffer attachment */
-      rb = NULL;
-   }
+void GLAPIENTRY
+_mesa_NamedFramebufferRenderbuffer_no_error(GLuint framebuffer,
+                                            GLenum attachment,
+                                            GLenum renderbuffertarget,
+                                            GLuint renderbuffer)
+{
+   GET_CURRENT_CONTEXT(ctx);
 
-   framebuffer_renderbuffer(ctx, fb, attachment, rb,
-                            "glFramebufferRenderbuffer");
+   struct gl_framebuffer *fb = _mesa_lookup_framebuffer(ctx, framebuffer);
+   framebuffer_renderbuffer_no_error(ctx, fb, attachment, renderbuffertarget,
+                                     renderbuffer,
+                                     "glNamedFramebufferRenderbuffer");
 }
 
-
 void GLAPIENTRY
 _mesa_NamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment,
                                    GLenum renderbuffertarget,
                                    GLuint renderbuffer)
 {
    struct gl_framebuffer *fb;
-   struct gl_renderbuffer *rb;
    GET_CURRENT_CONTEXT(ctx);
 
    fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
@@ -3652,34 +3800,17 @@ _mesa_NamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment,
    if (!fb)
       return;
 
-   if (renderbuffertarget != GL_RENDERBUFFER) {
-      _mesa_error(ctx, GL_INVALID_ENUM,
-                  "glNamedFramebufferRenderbuffer(renderbuffertarget is not "
-                  "GL_RENDERBUFFER)");
-      return;
-   }
-
-   if (renderbuffer) {
-      rb = _mesa_lookup_renderbuffer_err(ctx, renderbuffer,
-                                         "glNamedFramebufferRenderbuffer");
-      if (!rb)
-         return;
-   }
-   else {
-      /* remove renderbuffer attachment */
-      rb = NULL;
-   }
-
-   framebuffer_renderbuffer(ctx, fb, attachment, rb,
-                            "glNamedFramebufferRenderbuffer");
+   framebuffer_renderbuffer_error(ctx, fb, attachment, renderbuffertarget,
+                                  renderbuffer,
+                                  "glNamedFramebufferRenderbuffer");
 }
 
 
-void
-_mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx,
-                                           struct gl_framebuffer *buffer,
-                                           GLenum attachment, GLenum pname,
-                                           GLint *params, const char *caller)
+static void
+get_framebuffer_attachment_parameter(struct gl_context *ctx,
+                                     struct gl_framebuffer *buffer,
+                                     GLenum attachment, GLenum pname,
+                                     GLint *params, const char *caller)
 {
    const struct gl_renderbuffer_attachment *att;
    bool is_color_attachment = false;
@@ -3966,10 +4097,6 @@ _mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx,
           && !_mesa_is_gles3(ctx)) {
          goto invalid_pname_enum;
       }
-      else if (att->Type == GL_NONE) {
-         _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
-                     _mesa_enum_to_string(pname));
-      }
       else if (att->Texture) {
          const struct gl_texture_image *texImage =
             _mesa_select_tex_image(att->Texture, att->Texture->Target,
@@ -3987,7 +4114,9 @@ _mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx,
                                       att->Renderbuffer->Format);
       }
       else {
-         _mesa_problem(ctx, "%s: invalid FBO attachment structure", caller);
+         assert(att->Type == GL_NONE);
+         _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
+                     _mesa_enum_to_string(pname));
       }
       return;
    case GL_FRAMEBUFFER_ATTACHMENT_LAYERED:
@@ -4030,8 +4159,8 @@ _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment,
       return;
    }
 
-   _mesa_get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname,
-                                              params,
+   get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname,
+                                        params,
                                     "glGetFramebufferAttachmentParameteriv");
 }
 
@@ -4060,8 +4189,8 @@ _mesa_GetNamedFramebufferAttachmentParameteriv(GLuint framebuffer,
       buffer = ctx->WinSysDrawBuffer;
    }
 
-   _mesa_get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname,
-                                              params,
+   get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname,
+                                        params,
                               "glGetNamedFramebufferAttachmentParameteriv");
 }
 
@@ -4248,6 +4377,15 @@ invalid_enum:
 }
 
 
+void GLAPIENTRY
+_mesa_InvalidateSubFramebuffer_no_error(GLenum target, GLsizei numAttachments,
+                                        const GLenum *attachments, GLint x,
+                                        GLint y, GLsizei width, GLsizei height)
+{
+   /* no-op */
+}
+
+
 void GLAPIENTRY
 _mesa_InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments,
                                const GLenum *attachments, GLint x, GLint y,
@@ -4299,6 +4437,14 @@ _mesa_InvalidateNamedFramebufferSubData(GLuint framebuffer,
 }
 
 
+void GLAPIENTRY
+_mesa_InvalidateFramebuffer_no_error(GLenum target, GLsizei numAttachments,
+                                     const GLenum *attachments)
+{
+   /* no-op */
+}
+
+
 void GLAPIENTRY
 _mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments,
                             const GLenum *attachments)