glsl/linker: add DisableTransformFeedbackPacking workaround
[mesa.git] / src / mesa / main / texobj.c
index 1978898b8b9ab048cb19c72fa86be34f1c44fcdd..c5459f4540f6475dc0d114908f497fde26067152 100644 (file)
@@ -218,6 +218,42 @@ _mesa_get_current_tex_object(struct gl_context *ctx, GLenum target)
 }
 
 
+/**
+ * Get the texture object for given target and texunit
+ * Proxy targets are accepted only allowProxyTarget is true.
+ * Return NULL if any error (and record the error).
+ */
+struct gl_texture_object *
+_mesa_get_texobj_by_target_and_texunit(struct gl_context *ctx, GLenum target,
+                                       GLuint texunit, bool allowProxyTarget,
+                                       const char* caller)
+{
+   struct gl_texture_unit *texUnit;
+   int targetIndex;
+
+   if (_mesa_is_proxy_texture(target) && allowProxyTarget) {
+      return _mesa_get_current_tex_object(ctx, target);
+   }
+
+   if (texunit >= ctx->Const.MaxCombinedTextureImageUnits) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "%s(texunit=%d)", caller, texunit);
+      return NULL;
+   }
+
+   texUnit = _mesa_get_tex_unit(ctx, texunit);
+
+   targetIndex = _mesa_tex_target_to_index(ctx, target);
+   if (targetIndex < 0 || targetIndex == TEXTURE_BUFFER_INDEX) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", caller);
+      return NULL;
+   }
+   assert(targetIndex < NUM_TEXTURE_TARGETS);
+
+   return texUnit->CurrentTex[targetIndex];
+}
+
+
 /**
  * Allocate and initialize a new texture object.  But don't put it into the
  * texture object hash table.
@@ -274,7 +310,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 +447,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);
 
@@ -554,12 +590,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
@@ -579,12 +615,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);
    }
 }
 
@@ -703,33 +739,8 @@ _mesa_test_texobj_completeness( const struct gl_context *ctx,
       return;
    }
 
-   /* Compute _MaxLevel (the maximum mipmap level we'll sample from given the
-    * mipmap image sizes and GL_TEXTURE_MAX_LEVEL state).
-    */
-   switch (t->Target) {
-   case GL_TEXTURE_1D:
-   case GL_TEXTURE_1D_ARRAY_EXT:
-      maxLevels = ctx->Const.MaxTextureLevels;
-      break;
-   case GL_TEXTURE_2D:
-   case GL_TEXTURE_2D_ARRAY_EXT:
-      maxLevels = ctx->Const.MaxTextureLevels;
-      break;
-   case GL_TEXTURE_3D:
-      maxLevels = ctx->Const.Max3DTextureLevels;
-      break;
-   case GL_TEXTURE_CUBE_MAP:
-   case GL_TEXTURE_CUBE_MAP_ARRAY:
-      maxLevels = ctx->Const.MaxCubeTextureLevels;
-      break;
-   case GL_TEXTURE_RECTANGLE_NV:
-   case GL_TEXTURE_BUFFER:
-   case GL_TEXTURE_EXTERNAL_OES:
-   case GL_TEXTURE_2D_MULTISAMPLE:
-   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
-      maxLevels = 1;  /* no mipmapping */
-      break;
-   default:
+   maxLevels = _mesa_max_texture_levels(ctx, t->Target);
+   if (maxLevels == 0) {
       _mesa_problem(ctx, "Bad t->Target in _mesa_test_texobj_completeness");
       return;
    }
@@ -746,7 +757,7 @@ _mesa_test_texobj_completeness( const struct gl_context *ctx,
       /* Adjust max level for views: the data store may have more levels than
        * the view exposes.
        */
-      t->_MaxLevel = MIN2(t->_MaxLevel, t->NumLevels - 1);
+      t->_MaxLevel = MAX2(MIN2(t->_MaxLevel, t->NumLevels - 1), 0);
    }
 
    /* Compute _MaxLambda = q - p in the spec used during mipmapping */
@@ -1051,6 +1062,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];
 }
@@ -1506,6 +1522,47 @@ delete_textures(struct gl_context *ctx, 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_OBJECT;
+
+   /* Unreference the texobj.  If refcount hits zero, the texture
+    * will be deleted.
+    */
+   _mesa_reference_texobj(&texObj, NULL);
+}
+
 
 void GLAPIENTRY
 _mesa_DeleteTextures_no_error(GLsizei n, const GLuint *textures)
@@ -1615,10 +1672,10 @@ bind_texture_object(struct gl_context *ctx, unsigned unit,
     */
    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;
       }
@@ -1646,26 +1703,59 @@ bind_texture_object(struct gl_context *ctx, unsigned unit,
    }
 }
 
-
 /**
- * Implement glBindTexture().  Do error checking, look-up or create a new
- * texture object, then bind it in the current texture unit.
+ * Light-weight bind texture for internal users
  *
- * \param target texture target.
- * \param texName texture name.
+ * 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).
  */
-static ALWAYS_INLINE void
-bind_texture(struct gl_context *ctx, GLenum target, GLuint texName,
-             bool no_error)
+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);
+}
+
+struct gl_texture_object *
+_mesa_lookup_or_create_texture(struct gl_context *ctx, GLenum target,
+                               GLuint texName, bool no_error, bool is_ext_dsa,
+                               const char *caller)
 {
    struct gl_texture_object *newTexObj = NULL;
    int targetIndex;
 
+   if (is_ext_dsa) {
+      if (_mesa_is_proxy_texture(target)) {
+         /* EXT_dsa allows proxy targets only when texName is 0 */
+         if (texName != 0) {
+            _mesa_error(ctx, GL_INVALID_OPERATION, "%s(target = %s)", caller,
+                        _mesa_enum_to_string(target));
+            return NULL;
+         }
+         return _mesa_get_current_tex_object(ctx, target);
+      }
+      if (GL_TEXTURE_CUBE_MAP_POSITIVE_X <= target &&
+          target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) {
+         target = GL_TEXTURE_CUBE_MAP;
+      }
+   }
+
    targetIndex = _mesa_tex_target_to_index(ctx, target);
    if (!no_error && targetIndex < 0) {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glBindTexture(target = %s)",
+      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target = %s)", caller,
                   _mesa_enum_to_string(target));
-      return;
+      return NULL;
    }
    assert(targetIndex < NUM_TEXTURE_TARGETS);
 
@@ -1685,26 +1775,25 @@ bind_texture(struct gl_context *ctx, GLenum target, GLuint texName,
             /* The named texture object's target doesn't match the
              * given target
              */
-            _mesa_error( ctx, GL_INVALID_OPERATION,
-                         "glBindTexture(target mismatch)" );
-            return;
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "%s(target mismatch)", caller);
+            return NULL;
          }
          if (newTexObj->Target == 0) {
             finish_texture_init(ctx, target, newTexObj, targetIndex);
          }
-      }
-      else {
+      } else {
          if (!no_error && ctx->API == API_OPENGL_CORE) {
             _mesa_error(ctx, GL_INVALID_OPERATION,
-                        "glBindTexture(non-gen name)");
-            return;
+                        "%s(non-gen name)", caller);
+            return NULL;
          }
 
          /* if this is a new texture id, allocate a texture object now */
          newTexObj = ctx->Driver.NewTextureObject(ctx, texName, target);
          if (!newTexObj) {
-            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture");
-            return;
+            _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller);
+            return NULL;
          }
 
          /* and insert it into hash table */
@@ -1715,15 +1804,36 @@ bind_texture(struct gl_context *ctx, GLenum target, GLuint texName,
    assert(newTexObj->Target == target);
    assert(newTexObj->TargetIndex == targetIndex);
 
-   bind_texture_object(ctx, ctx->Texture.CurrentUnit, newTexObj);
+   return newTexObj;
 }
 
+/**
+ * Implement glBindTexture().  Do error checking, look-up or create a new
+ * texture object, then bind it in the current texture unit.
+ *
+ * \param target texture target.
+ * \param texName texture name.
+ * \param texunit texture unit.
+ */
+static ALWAYS_INLINE void
+bind_texture(struct gl_context *ctx, GLenum target, GLuint texName,
+             GLenum texunit, bool no_error, const char *caller)
+{
+   struct gl_texture_object *newTexObj =
+      _mesa_lookup_or_create_texture(ctx, target, texName, no_error, false,
+                                     "glBindTexture");
+   if (!newTexObj)
+      return;
+
+   bind_texture_object(ctx, texunit, newTexObj);
+}
 
 void GLAPIENTRY
 _mesa_BindTexture_no_error(GLenum target, GLuint texName)
 {
    GET_CURRENT_CONTEXT(ctx);
-   bind_texture(ctx, target, texName, true);
+   bind_texture(ctx, target, texName, ctx->Texture.CurrentUnit, true,
+                "glBindTexture");
 }
 
 
@@ -1736,7 +1846,29 @@ _mesa_BindTexture(GLenum target, GLuint texName)
       _mesa_debug(ctx, "glBindTexture %s %d\n",
                   _mesa_enum_to_string(target), (GLint) texName);
 
-   bind_texture(ctx, target, texName, false);
+   bind_texture(ctx, target, texName, ctx->Texture.CurrentUnit, false,
+                "glBindTexture");
+}
+
+
+void GLAPIENTRY
+_mesa_BindMultiTextureEXT(GLenum texunit, GLenum target, GLuint texture)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   unsigned unit = texunit - GL_TEXTURE0;
+
+   if (texunit < GL_TEXTURE0 || unit >= _mesa_max_tex_unit(ctx)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glBindMultiTextureEXT(texunit=%s)",
+                  _mesa_enum_to_string(texunit));
+      return;
+   }
+
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "glBindMultiTextureEXT %s %d\n",
+                  _mesa_enum_to_string(texunit), (GLint) texture);
+
+   bind_texture(ctx, target, texture, unit, false, "glBindMultiTextureEXT");
 }