mesa: implement glGet for AMD_framebuffer_multisample_advanced
[mesa.git] / src / mesa / main / texobj.c
index ed1eaf9b77b21c28381470e8f6b460fd9b4ee1bd..5dc5cb8e1a962791cc11fde1cbac4656cb7818b9 100644 (file)
@@ -274,7 +274,7 @@ _mesa_initialize_texture_object( struct gl_context *ctx,
 
    memset(obj, 0, sizeof(*obj));
    /* init the non-zero fields */
-   mtx_init(&obj->Mutex, mtx_plain);
+   simple_mtx_init(&obj->Mutex, mtx_plain);
    obj->RefCount = 1;
    obj->Name = name;
    obj->Target = target;
@@ -411,7 +411,7 @@ _mesa_delete_texture_object(struct gl_context *ctx,
    _mesa_reference_buffer_object(ctx, &texObj->BufferObject, NULL);
 
    /* destroy the mutex -- it may have allocated memory (eg on bsd) */
-   mtx_destroy(&texObj->Mutex);
+   simple_mtx_destroy(&texObj->Mutex);
 
    free(texObj->Label);
 
@@ -471,16 +471,19 @@ _mesa_copy_texture_object( struct gl_texture_object *dest,
 
 
 /**
- * Free all texture images of the given texture object.
+ * Free all texture images of the given texture objectm, except for
+ * \p retainTexImage.
  *
  * \param ctx GL context.
- * \param t texture object.
+ * \param texObj texture object.
+ * \param retainTexImage a texture image that will \em not be freed.
  *
  * \sa _mesa_clear_texture_image().
  */
 void
 _mesa_clear_texture_object(struct gl_context *ctx,
-                           struct gl_texture_object *texObj)
+                           struct gl_texture_object *texObj,
+                           struct gl_texture_image *retainTexImage)
 {
    GLuint i, j;
 
@@ -490,7 +493,7 @@ _mesa_clear_texture_object(struct gl_context *ctx,
    for (i = 0; i < MAX_FACES; i++) {
       for (j = 0; j < MAX_TEXTURE_LEVELS; j++) {
          struct gl_texture_image *texImage = texObj->Image[i][j];
-         if (texImage)
+         if (texImage && texImage != retainTexImage)
             _mesa_clear_texture_image(ctx, texImage);
       }
    }
@@ -551,12 +554,12 @@ _mesa_reference_texobj_(struct gl_texture_object **ptr,
       assert(valid_texture_object(oldTex));
       (void) valid_texture_object; /* silence warning in release builds */
 
-      mtx_lock(&oldTex->Mutex);
+      simple_mtx_lock(&oldTex->Mutex);
       assert(oldTex->RefCount > 0);
       oldTex->RefCount--;
 
       deleteFlag = (oldTex->RefCount == 0);
-      mtx_unlock(&oldTex->Mutex);
+      simple_mtx_unlock(&oldTex->Mutex);
 
       if (deleteFlag) {
          /* Passing in the context drastically changes the driver code for
@@ -576,12 +579,12 @@ _mesa_reference_texobj_(struct gl_texture_object **ptr,
    if (tex) {
       /* reference new texture */
       assert(valid_texture_object(tex));
-      mtx_lock(&tex->Mutex);
+      simple_mtx_lock(&tex->Mutex);
       assert(tex->RefCount > 0);
 
       tex->RefCount++;
       *ptr = tex;
-      mtx_unlock(&tex->Mutex);
+      simple_mtx_unlock(&tex->Mutex);
    }
 }
 
@@ -1048,6 +1051,11 @@ _mesa_get_fallback_texture(struct gl_context *ctx, gl_texture_index tex)
       assert(texObj->_MipmapComplete);
 
       ctx->Shared->FallbackTex[tex] = texObj;
+
+      /* Complete the driver's operation in case another context will also
+       * use the same fallback texture. */
+      if (ctx->Driver.Finish)
+         ctx->Driver.Finish(ctx);
    }
    return ctx->Shared->FallbackTex[tex];
 }
@@ -1195,14 +1203,6 @@ create_textures(struct gl_context *ctx, GLenum target,
    GLuint first;
    GLint i;
 
-   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
-      _mesa_debug(ctx, "%s %d\n", caller, n);
-
-   if (n < 0) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", caller);
-      return;
-   }
-
    if (!textures)
       return;
 
@@ -1220,7 +1220,7 @@ create_textures(struct gl_context *ctx, GLenum target,
       texObj = ctx->Driver.NewTextureObject(ctx, name, target);
       if (!texObj) {
          _mesa_HashUnlockMutex(ctx->Shared->TexObjects);
-         _mesa_error(ctx, GL_OUT_OF_MEMORY, "gl%sTextures", caller);
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller);
          return;
       }
 
@@ -1233,6 +1233,22 @@ create_textures(struct gl_context *ctx, GLenum target,
    _mesa_HashUnlockMutex(ctx->Shared->TexObjects);
 }
 
+
+static void
+create_textures_err(struct gl_context *ctx, GLenum target,
+                    GLsizei n, GLuint *textures, const char *caller)
+{
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "%s %d\n", caller, n);
+
+   if (n < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", caller);
+      return;
+   }
+
+   create_textures(ctx, target, n, textures, caller);
+}
+
 /*@}*/
 
 
@@ -1254,12 +1270,20 @@ create_textures(struct gl_context *ctx, GLenum target,
  * objects are also generated.
  */
 void GLAPIENTRY
-_mesa_GenTextures(GLsizei n, GLuint *textures)
+_mesa_GenTextures_no_error(GLsizei n, GLuint *textures)
 {
    GET_CURRENT_CONTEXT(ctx);
    create_textures(ctx, 0, n, textures, "glGenTextures");
 }
 
+
+void GLAPIENTRY
+_mesa_GenTextures(GLsizei n, GLuint *textures)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   create_textures_err(ctx, 0, n, textures, "glGenTextures");
+}
+
 /**
  * Create texture objects.
  *
@@ -1273,6 +1297,14 @@ _mesa_GenTextures(GLsizei n, GLuint *textures)
  * IDs which are stored in \p textures.  Corresponding empty texture
  * objects are also generated.
  */
+void GLAPIENTRY
+_mesa_CreateTextures_no_error(GLenum target, GLsizei n, GLuint *textures)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   create_textures(ctx, target, n, textures, "glCreateTextures");
+}
+
+
 void GLAPIENTRY
 _mesa_CreateTextures(GLenum target, GLsizei n, GLuint *textures)
 {
@@ -1290,7 +1322,7 @@ _mesa_CreateTextures(GLenum target, GLsizei n, GLuint *textures)
       return;
    }
 
-   create_textures(ctx, target, n, textures, "glCreateTextures");
+   create_textures_err(ctx, target, n, textures, "glCreateTextures");
 }
 
 /**
@@ -1423,31 +1455,15 @@ unbind_textures_from_unit(struct gl_context *ctx, GLuint unit)
  * Recall that texture objects can be shared among several rendering
  * contexts.
  */
-void GLAPIENTRY
-_mesa_DeleteTextures( GLsizei n, const GLuint *textures)
+static void
+delete_textures(struct gl_context *ctx, GLsizei n, const GLuint *textures)
 {
-   GET_CURRENT_CONTEXT(ctx);
-   GLint i;
-
-   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
-      _mesa_debug(ctx, "glDeleteTextures %d\n", n);
-
-   if (n < 0) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteTextures(n < 0)");
-      return;
-   }
-
    FLUSH_VERTICES(ctx, 0); /* too complex */
 
-   if (n < 0) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteTextures(n)");
-      return;
-   }
-
    if (!textures)
       return;
 
-   for (i = 0; i < n; i++) {
+   for (GLsizei i = 0; i < n; i++) {
       if (textures[i] > 0) {
          struct gl_texture_object *delObj
             = _mesa_lookup_texture(ctx, textures[i]);
@@ -1537,6 +1553,31 @@ _mesa_delete_nameless_texture(struct gl_context *ctx,
 }
 
 
+void GLAPIENTRY
+_mesa_DeleteTextures_no_error(GLsizei n, const GLuint *textures)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   delete_textures(ctx, n, textures);
+}
+
+
+void GLAPIENTRY
+_mesa_DeleteTextures(GLsizei n, const GLuint *textures)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "glDeleteTextures %d\n", n);
+
+   if (n < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteTextures(n < 0)");
+      return;
+   }
+
+   delete_textures(ctx, n, textures);
+}
+
+
 /**
  * Convert a GL texture target enum such as GL_TEXTURE_2D or GL_TEXTURE_3D
  * into the corresponding Mesa texture target index.
@@ -1598,9 +1639,8 @@ _mesa_tex_target_to_index(const struct gl_context *ctx, GLenum target)
  * \param texObj  the new texture object (cannot be NULL)
  */
 static void
-bind_texture(struct gl_context *ctx,
-             unsigned unit,
-             struct gl_texture_object *texObj)
+bind_texture_object(struct gl_context *ctx, unsigned unit,
+                    struct gl_texture_object *texObj)
 {
    struct gl_texture_unit *texUnit;
    int targetIndex;
@@ -1621,10 +1661,10 @@ bind_texture(struct gl_context *ctx,
     */
    if (targetIndex != TEXTURE_EXTERNAL_INDEX) {
       bool early_out;
-      mtx_lock(&ctx->Shared->Mutex);
+      simple_mtx_lock(&ctx->Shared->Mutex);
       early_out = ((ctx->Shared->RefCount == 1)
                    && (texObj == texUnit->CurrentTex[targetIndex]));
-      mtx_unlock(&ctx->Shared->Mutex);
+      simple_mtx_unlock(&ctx->Shared->Mutex);
       if (early_out) {
          return;
       }
@@ -1652,6 +1692,29 @@ bind_texture(struct gl_context *ctx,
    }
 }
 
+/**
+ * Light-weight bind texture for internal users
+ *
+ * This is really just \c finish_texture_init plus \c bind_texture_object.
+ * This is intended to be used by internal Mesa functions that use
+ * \c _mesa_CreateTexture and need to bind textures (e.g., meta).
+ */
+void
+_mesa_bind_texture(struct gl_context *ctx, GLenum target,
+                   struct gl_texture_object *tex_obj)
+{
+   const GLint targetIndex = _mesa_tex_target_to_index(ctx, target);
+
+   assert(targetIndex >= 0 && targetIndex < NUM_TEXTURE_TARGETS);
+
+   if (tex_obj->Target == 0)
+      finish_texture_init(ctx, target, tex_obj, targetIndex);
+
+   assert(tex_obj->Target == target);
+   assert(tex_obj->TargetIndex == targetIndex);
+
+   bind_texture_object(ctx, ctx->Texture.CurrentUnit, tex_obj);
+}
 
 /**
  * Implement glBindTexture().  Do error checking, look-up or create a new
@@ -1660,18 +1723,15 @@ bind_texture(struct gl_context *ctx,
  * \param target texture target.
  * \param texName texture name.
  */
-void GLAPIENTRY
-_mesa_BindTexture( GLenum target, GLuint texName )
+static ALWAYS_INLINE void
+bind_texture(struct gl_context *ctx, GLenum target, GLuint texName,
+             bool no_error)
 {
-   GET_CURRENT_CONTEXT(ctx);
    struct gl_texture_object *newTexObj = NULL;
+   int targetIndex;
 
-   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
-      _mesa_debug(ctx, "glBindTexture %s %d\n",
-                  _mesa_enum_to_string(target), (GLint) texName);
-
-   int targetIndex = _mesa_tex_target_to_index(ctx, target);
-   if (targetIndex < 0) {
+   targetIndex = _mesa_tex_target_to_index(ctx, target);
+   if (!no_error && targetIndex < 0) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glBindTexture(target = %s)",
                   _mesa_enum_to_string(target));
       return;
@@ -1684,13 +1744,13 @@ _mesa_BindTexture( GLenum target, GLuint texName )
    if (texName == 0) {
       /* Use a default texture object */
       newTexObj = ctx->Shared->DefaultTex[targetIndex];
-   }
-   else {
+   } else {
       /* non-default texture object */
       newTexObj = _mesa_lookup_texture(ctx, texName);
       if (newTexObj) {
          /* error checking */
-         if (newTexObj->Target != 0 && newTexObj->Target != target) {
+         if (!no_error &&
+             newTexObj->Target != 0 && newTexObj->Target != target) {
             /* The named texture object's target doesn't match the
              * given target
              */
@@ -1703,7 +1763,7 @@ _mesa_BindTexture( GLenum target, GLuint texName )
          }
       }
       else {
-         if (ctx->API == API_OPENGL_CORE) {
+         if (!no_error && ctx->API == API_OPENGL_CORE) {
             _mesa_error(ctx, GL_INVALID_OPERATION,
                         "glBindTexture(non-gen name)");
             return;
@@ -1724,7 +1784,27 @@ _mesa_BindTexture( GLenum target, GLuint texName )
    assert(newTexObj->Target == target);
    assert(newTexObj->TargetIndex == targetIndex);
 
-   bind_texture(ctx, ctx->Texture.CurrentUnit, newTexObj);
+   bind_texture_object(ctx, ctx->Texture.CurrentUnit, newTexObj);
+}
+
+void GLAPIENTRY
+_mesa_BindTexture_no_error(GLenum target, GLuint texName)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   bind_texture(ctx, target, texName, true);
+}
+
+
+void GLAPIENTRY
+_mesa_BindTexture(GLenum target, GLuint texName)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "glBindTexture %s %d\n",
+                  _mesa_enum_to_string(target), (GLint) texName);
+
+   bind_texture(ctx, target, texName, false);
 }
 
 
@@ -1741,21 +1821,12 @@ _mesa_BindTexture( GLenum target, GLuint texName )
  * If the named texture is not 0 or a recognized texture name, this throws
  * GL_INVALID_OPERATION.
  */
-void GLAPIENTRY
-_mesa_BindTextureUnit(GLuint unit, GLuint texture)
+static ALWAYS_INLINE void
+bind_texture_unit(struct gl_context *ctx, GLuint unit, GLuint texture,
+                  bool no_error)
 {
-   GET_CURRENT_CONTEXT(ctx);
    struct gl_texture_object *texObj;
 
-   if (unit >= _mesa_max_tex_unit(ctx)) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glBindTextureUnit(unit=%u)", unit);
-      return;
-   }
-
-   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
-      _mesa_debug(ctx, "glBindTextureUnit %s %d\n",
-                  _mesa_enum_to_string(GL_TEXTURE0+unit), (GLint) texture);
-
    /* Section 8.1 (Texture Objects) of the OpenGL 4.5 core profile spec
     * (20141030) says:
     *    "When texture is zero, each of the targets enumerated at the
@@ -1769,47 +1840,62 @@ _mesa_BindTextureUnit(GLuint unit, GLuint texture)
 
    /* Get the non-default texture object */
    texObj = _mesa_lookup_texture(ctx, texture);
+   if (!no_error) {
+      /* Error checking */
+      if (!texObj) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glBindTextureUnit(non-gen name)");
+         return;
+      }
 
-   /* Error checking */
-   if (!texObj) {
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "glBindTextureUnit(non-gen name)");
-      return;
-   }
-   if (texObj->Target == 0) {
-      /* Texture object was gen'd but never bound so the target is not set */
-      _mesa_error(ctx, GL_INVALID_OPERATION, "glBindTextureUnit(target)");
-      return;
+      if (texObj->Target == 0) {
+         /* Texture object was gen'd but never bound so the target is not set */
+         _mesa_error(ctx, GL_INVALID_OPERATION, "glBindTextureUnit(target)");
+         return;
+      }
    }
+
    assert(valid_texture_object(texObj));
 
-   bind_texture(ctx, unit, texObj);
+   bind_texture_object(ctx, unit, texObj);
 }
 
 
-/**
- * OpenGL 4.4 / GL_ARB_multi_bind glBindTextures().
- */
 void GLAPIENTRY
-_mesa_BindTextures(GLuint first, GLsizei count, const GLuint *textures)
+_mesa_BindTextureUnit_no_error(GLuint unit, GLuint texture)
 {
    GET_CURRENT_CONTEXT(ctx);
-   GLint i;
+   bind_texture_unit(ctx, unit, texture, true);
+}
 
-   /* The ARB_multi_bind spec says:
-    *
-    *     "An INVALID_OPERATION error is generated if <first> + <count>
-    *      is greater than the number of texture image units supported
-    *      by the implementation."
-    */
-   if (first + count > ctx->Const.MaxCombinedTextureImageUnits) {
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "glBindTextures(first=%u + count=%d > the value of "
-                  "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS=%u)",
-                  first, count, ctx->Const.MaxCombinedTextureImageUnits);
+
+void GLAPIENTRY
+_mesa_BindTextureUnit(GLuint unit, GLuint texture)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (unit >= _mesa_max_tex_unit(ctx)) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glBindTextureUnit(unit=%u)", unit);
       return;
    }
 
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "glBindTextureUnit %s %d\n",
+                  _mesa_enum_to_string(GL_TEXTURE0+unit), (GLint) texture);
+
+   bind_texture_unit(ctx, unit, texture, false);
+}
+
+
+/**
+ * OpenGL 4.4 / GL_ARB_multi_bind glBindTextures().
+ */
+static ALWAYS_INLINE void
+bind_textures(struct gl_context *ctx, GLuint first, GLsizei count,
+              const GLuint *textures, bool no_error)
+{
+   GLsizei i;
+
    if (textures) {
       /* Note that the error semantics for multi-bind commands differ from
        * those of other GL commands.
@@ -1844,8 +1930,8 @@ _mesa_BindTextures(GLuint first, GLsizei count, const GLuint *textures)
                texObj = _mesa_lookup_texture_locked(ctx, textures[i]);
 
             if (texObj && texObj->Target != 0) {
-               bind_texture(ctx, first + i, texObj);
-            } else {
+               bind_texture_object(ctx, first + i, texObj);
+            } else if (!no_error) {
                /* The ARB_multi_bind spec says:
                 *
                 *     "An INVALID_OPERATION error is generated if any value
@@ -1871,6 +1957,37 @@ _mesa_BindTextures(GLuint first, GLsizei count, const GLuint *textures)
 }
 
 
+void GLAPIENTRY
+_mesa_BindTextures_no_error(GLuint first, GLsizei count, const GLuint *textures)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   bind_textures(ctx, first, count, textures, true);
+}
+
+
+void GLAPIENTRY
+_mesa_BindTextures(GLuint first, GLsizei count, const GLuint *textures)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   /* The ARB_multi_bind spec says:
+    *
+    *     "An INVALID_OPERATION error is generated if <first> + <count>
+    *      is greater than the number of texture image units supported
+    *      by the implementation."
+    */
+   if (first + count > ctx->Const.MaxCombinedTextureImageUnits) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glBindTextures(first=%u + count=%d > the value of "
+                  "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS=%u)",
+                  first, count, ctx->Const.MaxCombinedTextureImageUnits);
+      return;
+   }
+
+   bind_textures(ctx, first, count, textures, false);
+}
+
+
 /**
  * Set texture priorities.
  *
@@ -2030,6 +2147,16 @@ _mesa_unlock_context_textures( struct gl_context *ctx )
 }
 
 
+void GLAPIENTRY
+_mesa_InvalidateTexSubImage_no_error(GLuint texture, GLint level, GLint xoffset,
+                                     GLint yoffset, GLint zoffset,
+                                     GLsizei width, GLsizei height,
+                                     GLsizei depth)
+{
+   /* no-op */
+}
+
+
 void GLAPIENTRY
 _mesa_InvalidateTexSubImage(GLuint texture, GLint level, GLint xoffset,
                             GLint yoffset, GLint zoffset, GLsizei width,
@@ -2177,6 +2304,13 @@ _mesa_InvalidateTexSubImage(GLuint texture, GLint level, GLint xoffset,
 }
 
 
+void GLAPIENTRY
+_mesa_InvalidateTexImage_no_error(GLuint texture, GLint level)
+{
+   /* no-op */
+}
+
+
 void GLAPIENTRY
 _mesa_InvalidateTexImage(GLuint texture, GLint level)
 {