main: Added entry point for glGenerateTextureMipmap.
[mesa.git] / src / mesa / main / texobj.c
index a17aaa662e8562adb0e83828404307f248088d18..0ff271769e6dde115245fa83cfad8e9f62200fbc 100644 (file)
@@ -502,6 +502,9 @@ _mesa_reference_texobj_(struct gl_texture_object **ptr,
       mtx_unlock(&oldTex->Mutex);
 
       if (deleteFlag) {
+         /* Passing in the context drastically changes the driver code for
+          * framebuffer deletion.
+          */
          GET_CURRENT_CONTEXT(ctx);
          if (ctx)
             ctx->Driver.DeleteTexture(ctx, oldTex);
@@ -1118,38 +1121,46 @@ invalidate_tex_image_error_check(struct gl_context *ctx, GLuint texture,
    return t;
 }
 
-/*@}*/
+/**
+ * Wrapper for the driver function. Need this because _mesa_new_texture_object
+ * permits a target of 0 and does not initialize targetIndex.
+ */
+struct gl_texture_object *
+_mesa_create_nameless_texture(struct gl_context *ctx, GLenum target)
+{
+      struct gl_texture_object *texObj = NULL;
+      GLint targetIndex;
 
+      if (target == 0)
+         return texObj;
 
-/***********************************************************************/
-/** \name API functions */
-/*@{*/
+      texObj = ctx->Driver.NewTextureObject(ctx, 0, target);
+      targetIndex = _mesa_tex_target_to_index(ctx, texObj->Target);
+      assert(targetIndex < NUM_TEXTURE_TARGETS);
+      texObj->TargetIndex = targetIndex;
 
+      return texObj;
+}
 
 /**
- * Generate texture names.
- *
- * \param n number of texture names to be generated.
- * \param textures an array in which will hold the generated texture names.
- *
- * \sa glGenTextures().
- *
- * Calls _mesa_HashFindFreeKeyBlock() to find a block of free texture
- * IDs which are stored in \p textures.  Corresponding empty texture
- * objects are also generated.
+ * Helper function for glCreateTextures and glGenTextures. Need this because
+ * glCreateTextures should throw errors if target = 0. This is not exposed to
+ * the rest of Mesa to encourage Mesa internals to use nameless textures,
+ * which do not require expensive hash lookups.
  */
-void GLAPIENTRY
-_mesa_GenTextures( GLsizei n, GLuint *textures )
+static void
+create_textures(struct gl_context *ctx, GLenum target,
+                GLsizei n, GLuint *textures, bool dsa)
 {
-   GET_CURRENT_CONTEXT(ctx);
    GLuint first;
    GLint i;
+   const char *func = dsa ? "Create" : "Gen";
 
    if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
-      _mesa_debug(ctx, "glGenTextures %d\n", n);
+      _mesa_debug(ctx, "gl%sTextures %d\n", func, n);
 
    if (n < 0) {
-      _mesa_error( ctx, GL_INVALID_VALUE, "glGenTextures" );
+      _mesa_error( ctx, GL_INVALID_VALUE, "gl%sTextures(n < 0)", func );
       return;
    }
 
@@ -1166,15 +1177,28 @@ _mesa_GenTextures( GLsizei n, GLuint *textures )
    /* Allocate new, empty texture objects */
    for (i = 0; i < n; i++) {
       struct gl_texture_object *texObj;
+      GLint targetIndex;
       GLuint name = first + i;
-      GLenum target = 0;
       texObj = ctx->Driver.NewTextureObject(ctx, name, target);
       if (!texObj) {
          mtx_unlock(&ctx->Shared->Mutex);
-         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTextures");
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "gl%sTextures", func);
          return;
       }
 
+      /* Initialize the target index if target is non-zero. */
+      if (target != 0) {
+         targetIndex = _mesa_tex_target_to_index(ctx, texObj->Target);
+         if (targetIndex < 0) { /* Bad Target */
+            mtx_unlock(&ctx->Shared->Mutex);
+            _mesa_error(ctx, GL_INVALID_ENUM, "gl%sTextures(target = %s)",
+                        func, _mesa_lookup_enum_by_nr(texObj->Target));
+            return;
+         }
+         assert(targetIndex < NUM_TEXTURE_TARGETS);
+         texObj->TargetIndex = targetIndex;
+      }
+
       /* insert into hash table */
       _mesa_HashInsert(ctx->Shared->TexObjects, texObj->Name, texObj);
 
@@ -1184,6 +1208,65 @@ _mesa_GenTextures( GLsizei n, GLuint *textures )
    mtx_unlock(&ctx->Shared->Mutex);
 }
 
+/*@}*/
+
+
+/***********************************************************************/
+/** \name API functions */
+/*@{*/
+
+
+/**
+ * Generate texture names.
+ *
+ * \param n number of texture names to be generated.
+ * \param textures an array in which will hold the generated texture names.
+ *
+ * \sa glGenTextures(), glCreateTextures().
+ *
+ * Calls _mesa_HashFindFreeKeyBlock() to find a block of free texture
+ * IDs which are stored in \p textures.  Corresponding empty texture
+ * objects are also generated.
+ */
+void GLAPIENTRY
+_mesa_GenTextures(GLsizei n, GLuint *textures)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   create_textures(ctx, 0, n, textures, false);
+}
+
+/**
+ * Create texture objects.
+ *
+ * \param target the texture target for each name to be generated.
+ * \param n number of texture names to be generated.
+ * \param textures an array in which will hold the generated texture names.
+ *
+ * \sa glCreateTextures(), glGenTextures().
+ *
+ * Calls _mesa_HashFindFreeKeyBlock() to find a block of free texture
+ * IDs which are stored in \p textures.  Corresponding empty texture
+ * objects are also generated.
+ */
+void GLAPIENTRY
+_mesa_CreateTextures(GLenum target, GLsizei n, GLuint *textures)
+{
+   GLint targetIndex;
+   GET_CURRENT_CONTEXT(ctx);
+
+   /*
+    * The 4.5 core profile spec (30.10.2014) doesn't specify what
+    * glCreateTextures should do with invalid targets, which was probably an
+    * oversight.  This conforms to the spec for glBindTexture.
+    */
+   targetIndex = _mesa_tex_target_to_index(ctx, target);
+   if (targetIndex < 0) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glCreateTextures(target)");
+      return;
+   }
+
+   create_textures(ctx, target, n, textures, true);
+}
 
 /**
  * Check if the given texture object is bound to the current draw or
@@ -1368,6 +1451,47 @@ _mesa_DeleteTextures( GLsizei n, const GLuint *textures)
    }
 }
 
+/**
+ * This deletes a texObj without altering the hash table.
+ */
+void
+_mesa_delete_nameless_texture(struct gl_context *ctx,
+                              struct gl_texture_object *texObj)
+{
+   if (!texObj)
+      return;
+
+   FLUSH_VERTICES(ctx, 0);
+
+   _mesa_lock_texture(ctx, texObj);
+   {
+      /* Check if texture is bound to any framebuffer objects.
+       * If so, unbind.
+       * See section 4.4.2.3 of GL_EXT_framebuffer_object.
+       */
+      unbind_texobj_from_fbo(ctx, texObj);
+
+      /* Check if this texture is currently bound to any texture units.
+       * If so, unbind it.
+       */
+      unbind_texobj_from_texunits(ctx, texObj);
+
+      /* Check if this texture is currently bound to any shader
+       * image unit.  If so, unbind it.
+       * See section 3.9.X of GL_ARB_shader_image_load_store.
+       */
+      unbind_texobj_from_image_units(ctx, texObj);
+   }
+   _mesa_unlock_texture(ctx, texObj);
+
+   ctx->NewState |= _NEW_TEXTURE;
+
+   /* Unreference the texobj.  If refcount hits zero, the texture
+    * will be deleted.
+    */
+   _mesa_reference_texobj(&texObj, NULL);
+}
+
 
 /**
  * Convert a GL texture target enum such as GL_TEXTURE_2D or GL_TEXTURE_3D
@@ -1539,6 +1663,107 @@ _mesa_BindTexture( GLenum target, GLuint texName )
       ctx->Driver.BindTexture(ctx, ctx->Texture.CurrentUnit, target, newTexObj);
 }
 
+/**
+ * Do the actual binding to a numbered texture unit.
+ * The refcount on the previously bound
+ * texture object will be decremented.  It'll be deleted if the
+ * count hits zero.
+ */
+void
+_mesa_bind_texture_unit(struct gl_context *ctx,
+                        GLuint unit,
+                        struct gl_texture_object *texObj)
+{
+   struct gl_texture_unit *texUnit;
+
+   /* Get the texture unit (this is an array look-up) */
+   texUnit = _mesa_get_tex_unit_err(ctx, unit, "glBindTextureUnit");
+   if (!texUnit)
+      return;
+
+   /* Check if this texture is only used by this context and is already bound.
+    * If so, just return.
+    */
+   {
+      bool early_out;
+      mtx_lock(&ctx->Shared->Mutex);
+      early_out = ((ctx->Shared->RefCount == 1)
+                   && (texObj == texUnit->CurrentTex[texObj->TargetIndex]));
+      mtx_unlock(&ctx->Shared->Mutex);
+      if (early_out) {
+         return;
+      }
+   }
+
+   /* flush before changing binding */
+   FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+
+   _mesa_reference_texobj(&texUnit->CurrentTex[texObj->TargetIndex],
+                          texObj);
+   ASSERT(texUnit->CurrentTex[texObj->TargetIndex]);
+   ctx->Texture.NumCurrentTexUsed = MAX2(ctx->Texture.NumCurrentTexUsed,
+                                         unit + 1);
+   texUnit->_BoundTextures |= (1 << texObj->TargetIndex);
+
+
+   /* Pass BindTexture call to device driver */
+   if (ctx->Driver.BindTexture) {
+      ctx->Driver.BindTexture(ctx, unit, texObj->Target, texObj);
+   }
+}
+
+/**
+ * Bind a named texture to the specified texture unit.
+ *
+ * \param unit texture unit.
+ * \param texture texture name.
+ *
+ * \sa glBindTexture().
+ *
+ * If the named texture is 0, this will reset each target for the specified
+ * texture unit to its default texture.
+ * 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)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_texture_object *texObj;
+
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "glBindTextureUnit %s %d\n",
+                  _mesa_lookup_enum_by_nr(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
+    *    beginning of this section is reset to its default texture for the
+    *    corresponding texture image unit."
+    */
+   if (texture == 0) {
+      unbind_textures_from_unit(ctx, unit);
+      return;
+   }
+
+   /* Get the non-default texture object */
+   texObj = _mesa_lookup_texture(ctx, texture);
+
+   /* Error checking */
+   if (!texObj) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+         "glBindTextureUnit(non-gen name)");
+      return;
+   }
+   if (texObj->Target == 0) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glBindTextureUnit(target)");
+      return;
+   }
+   assert(valid_texture_object(texObj));
+
+   _mesa_bind_texture_unit(ctx, unit, texObj);
+}
+
 
 void GLAPIENTRY
 _mesa_BindTextures(GLuint first, GLsizei count, const GLuint *textures)