mesa: Allow setting GL_TEXTURE_MAX_LEVEL to 0 with GL_TEXTURE_RECTANGLE.
[mesa.git] / src / mesa / main / texobj.c
index 2168bffb1a378fa61b3c3c466e2fa776f47cb20f..8bdbb08c8ea36ded2f5988f00ca0287fcd21abc0 100644 (file)
@@ -83,7 +83,7 @@ _mesa_new_texture_object( struct gl_context *ctx, GLuint name, GLenum target )
    struct gl_texture_object *obj;
    (void) ctx;
    obj = MALLOC_STRUCT(gl_texture_object);
-   _mesa_initialize_texture_object(obj, name, target);
+   _mesa_initialize_texture_object(ctx, obj, name, target);
    return obj;
 }
 
@@ -95,7 +95,8 @@ _mesa_new_texture_object( struct gl_context *ctx, GLuint name, GLenum target )
  * \param target  the texture target
  */
 void
-_mesa_initialize_texture_object( struct gl_texture_object *obj,
+_mesa_initialize_texture_object( struct gl_context *ctx,
+                                 struct gl_texture_object *obj,
                                  GLuint name, GLenum target )
 {
    ASSERT(target == 0 ||
@@ -114,7 +115,7 @@ _mesa_initialize_texture_object( struct gl_texture_object *obj,
 
    memset(obj, 0, sizeof(*obj));
    /* init the non-zero fields */
-   _glthread_INIT_MUTEX(obj->Mutex);
+   mtx_init(&obj->Mutex, mtx_plain);
    obj->RefCount = 1;
    obj->Name = name;
    obj->Target = target;
@@ -146,7 +147,8 @@ _mesa_initialize_texture_object( struct gl_texture_object *obj,
    obj->Sampler.MaxAnisotropy = 1.0;
    obj->Sampler.CompareMode = GL_NONE;         /* ARB_shadow */
    obj->Sampler.CompareFunc = GL_LEQUAL;       /* ARB_shadow */
-   obj->DepthMode = GL_LUMINANCE;
+   obj->DepthMode = ctx->API == API_OPENGL_CORE ? GL_RED : GL_LUMINANCE;
+   obj->StencilSampling = false;
    obj->Sampler.CubeMapSeamless = GL_FALSE;
    obj->Swizzle[0] = GL_RED;
    obj->Swizzle[1] = GL_GREEN;
@@ -154,8 +156,9 @@ _mesa_initialize_texture_object( struct gl_texture_object *obj,
    obj->Swizzle[3] = GL_ALPHA;
    obj->_Swizzle = SWIZZLE_NOOP;
    obj->Sampler.sRGBDecode = GL_DECODE_EXT;
-   obj->BufferObjectFormat = GL_LUMINANCE8;
-   obj->_BufferObjectFormat = MESA_FORMAT_L8;
+   obj->BufferObjectFormat = GL_R8;
+   obj->_BufferObjectFormat = MESA_FORMAT_R_UNORM8;
+   obj->ImageFormatCompatibilityType = GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE;
 }
 
 
@@ -187,12 +190,12 @@ finish_texture_init(struct gl_context *ctx, GLenum target,
          if (ctx->Driver.TexParameter) {
             static const GLfloat fparam_wrap[1] = {(GLfloat) GL_CLAMP_TO_EDGE};
             const GLfloat fparam_filter[1] = {(GLfloat) filter};
-            ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_WRAP_S, fparam_wrap);
-            ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_WRAP_T, fparam_wrap);
-            ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_WRAP_R, fparam_wrap);
-            ctx->Driver.TexParameter(ctx, target, obj,
+            ctx->Driver.TexParameter(ctx, obj, GL_TEXTURE_WRAP_S, fparam_wrap);
+            ctx->Driver.TexParameter(ctx, obj, GL_TEXTURE_WRAP_T, fparam_wrap);
+            ctx->Driver.TexParameter(ctx, obj, GL_TEXTURE_WRAP_R, fparam_wrap);
+            ctx->Driver.TexParameter(ctx, obj,
                   GL_TEXTURE_MIN_FILTER, fparam_filter);
-            ctx->Driver.TexParameter(ctx, target, obj,
+            ctx->Driver.TexParameter(ctx, obj,
                   GL_TEXTURE_MAG_FILTER, fparam_filter);
          }
          break;
@@ -235,7 +238,9 @@ _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) */
-   _glthread_DESTROY_MUTEX(texObj->Mutex);
+   mtx_destroy(&texObj->Mutex);
+
+   free(texObj->Label);
 
    /* free this object */
    free(texObj);
@@ -276,6 +281,7 @@ _mesa_copy_texture_object( struct gl_texture_object *dest,
    dest->Sampler.CompareFunc = src->Sampler.CompareFunc;
    dest->Sampler.CubeMapSeamless = src->Sampler.CubeMapSeamless;
    dest->DepthMode = src->DepthMode;
+   dest->StencilSampling = src->StencilSampling;
    dest->Sampler.sRGBDecode = src->Sampler.sRGBDecode;
    dest->_MaxLevel = src->_MaxLevel;
    dest->_MaxLambda = src->_MaxLambda;
@@ -370,12 +376,12 @@ _mesa_reference_texobj_(struct gl_texture_object **ptr,
       ASSERT(valid_texture_object(oldTex));
       (void) valid_texture_object; /* silence warning in release builds */
 
-      _glthread_LOCK_MUTEX(oldTex->Mutex);
+      mtx_lock(&oldTex->Mutex);
       ASSERT(oldTex->RefCount > 0);
       oldTex->RefCount--;
 
       deleteFlag = (oldTex->RefCount == 0);
-      _glthread_UNLOCK_MUTEX(oldTex->Mutex);
+      mtx_unlock(&oldTex->Mutex);
 
       if (deleteFlag) {
          GET_CURRENT_CONTEXT(ctx);
@@ -392,7 +398,7 @@ _mesa_reference_texobj_(struct gl_texture_object **ptr,
    if (tex) {
       /* reference new texture */
       ASSERT(valid_texture_object(tex));
-      _glthread_LOCK_MUTEX(tex->Mutex);
+      mtx_lock(&tex->Mutex);
       if (tex->RefCount == 0) {
          /* this texture's being deleted (look just above) */
          /* Not sure this can every really happen.  Warn if it does. */
@@ -403,7 +409,7 @@ _mesa_reference_texobj_(struct gl_texture_object **ptr,
          tex->RefCount++;
          *ptr = tex;
       }
-      _glthread_UNLOCK_MUTEX(tex->Mutex);
+      mtx_unlock(&tex->Mutex);
    }
 }
 
@@ -547,12 +553,13 @@ _mesa_test_texobj_completeness( const struct gl_context *ctx,
 
    ASSERT(maxLevels > 0);
 
-   t->_MaxLevel =
-      baseLevel + baseImage->MaxNumLevels - 1; /* 'p' in the GL spec */
-   t->_MaxLevel = MIN2(t->_MaxLevel, t->MaxLevel);
-   t->_MaxLevel = MIN2(t->_MaxLevel, maxLevels - 1); /* 'q' in the GL spec */
+   t->_MaxLevel = MIN3(t->MaxLevel,
+                       /* 'p' in the GL spec */
+                       (int) (baseLevel + baseImage->MaxNumLevels - 1),
+                       /* 'q' in the GL spec */
+                       maxLevels - 1);
 
-   /* Compute _MaxLambda = q - b (see the 1.2 spec) used during mipmapping */
+   /* Compute _MaxLambda = q - p in the spec used during mipmapping */
    t->_MaxLambda = (GLfloat) (t->_MaxLevel - baseLevel);
 
    if (t->Immutable) {
@@ -711,20 +718,17 @@ _mesa_cube_complete(const struct gl_texture_object *texObj)
 
 /**
  * Mark a texture object dirty.  It forces the object to be incomplete
- * and optionally forces the context to re-validate its state.
+ * and forces the context to re-validate its state.
  *
  * \param ctx GL context.
  * \param texObj texture object.
- * \param invalidate_state also invalidate context state.
  */
 void
-_mesa_dirty_texobj(struct gl_context *ctx, struct gl_texture_object *texObj,
-                   GLboolean invalidate_state)
+_mesa_dirty_texobj(struct gl_context *ctx, struct gl_texture_object *texObj)
 {
    texObj->_BaseComplete = GL_FALSE;
    texObj->_MipmapComplete = GL_FALSE;
-   if (invalidate_state)
-      ctx->NewState |= _NEW_TEXTURE;
+   ctx->NewState |= _NEW_TEXTURE;
 }
 
 
@@ -743,7 +747,7 @@ _mesa_get_fallback_texture(struct gl_context *ctx, gl_texture_index tex)
       GLubyte texel[4];
       struct gl_texture_object *texObj;
       struct gl_texture_image *texImage;
-      gl_format texFormat;
+      mesa_format texFormat;
       GLuint dims, face, numFaces = 1;
       GLenum target;
 
@@ -888,6 +892,8 @@ count_tex_size(GLuint key, void *data, void *userData)
       (const struct gl_texture_object *) data;
    GLuint *total = (GLuint *) userData;
 
+   (void) key;
+
    *total = *total + texture_size(texObj);
 }
 
@@ -1005,7 +1011,7 @@ _mesa_GenTextures( GLsizei n, GLuint *textures )
    /*
     * This must be atomic (generation and allocation of texture IDs)
     */
-   _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
+   mtx_lock(&ctx->Shared->Mutex);
 
    first = _mesa_HashFindFreeKeyBlock(ctx->Shared->TexObjects, n);
 
@@ -1016,7 +1022,7 @@ _mesa_GenTextures( GLsizei n, GLuint *textures )
       GLenum target = 0;
       texObj = ctx->Driver.NewTextureObject(ctx, name, target);
       if (!texObj) {
-         _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
+         mtx_unlock(&ctx->Shared->Mutex);
          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTextures");
          return;
       }
@@ -1027,7 +1033,7 @@ _mesa_GenTextures( GLsizei n, GLuint *textures )
       textures[i] = name;
    }
 
-   _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
+   mtx_unlock(&ctx->Shared->Mutex);
 }
 
 
@@ -1039,23 +1045,35 @@ static void
 unbind_texobj_from_fbo(struct gl_context *ctx,
                        struct gl_texture_object *texObj)
 {
-   const GLuint n = (ctx->DrawBuffer == ctx->ReadBuffer) ? 1 : 2;
-   GLuint i;
+   bool progress = false;
 
-   for (i = 0; i < n; i++) {
-      struct gl_framebuffer *fb = (i == 0) ? ctx->DrawBuffer : ctx->ReadBuffer;
-      if (_mesa_is_user_fbo(fb)) {
-         GLuint j;
-         for (j = 0; j < BUFFER_COUNT; j++) {
-            if (fb->Attachment[j].Type == GL_TEXTURE &&
-                fb->Attachment[j].Texture == texObj) {
-              /* Vertices are already flushed by _mesa_DeleteTextures */
-              ctx->NewState |= _NEW_BUFFERS;
-               _mesa_remove_attachment(ctx, fb->Attachment + j);         
-            }
-         }
-      }
+   /* Section 4.4.2 (Attaching Images to Framebuffer Objects), subsection
+    * "Attaching Texture Images to a Framebuffer," of the OpenGL 3.1 spec
+    * says:
+    *
+    *     "If a texture object is deleted while its image is attached to one
+    *     or more attachment points in the currently bound framebuffer, then
+    *     it is as if FramebufferTexture* had been called, with a texture of
+    *     zero, for each attachment point to which this image was attached in
+    *     the currently bound framebuffer. In other words, this texture image
+    *     is first detached from all attachment points in the currently bound
+    *     framebuffer. Note that the texture image is specifically not
+    *     detached from any other framebuffer objects. Detaching the texture
+    *     image from any other framebuffer objects is the responsibility of
+    *     the application."
+    */
+   if (_mesa_is_user_fbo(ctx->DrawBuffer)) {
+      progress = _mesa_detach_renderbuffer(ctx, ctx->DrawBuffer, texObj);
+   }
+   if (_mesa_is_user_fbo(ctx->ReadBuffer)
+       && ctx->ReadBuffer != ctx->DrawBuffer) {
+      progress = _mesa_detach_renderbuffer(ctx, ctx->ReadBuffer, texObj)
+         || progress;
    }
+
+   if (progress)
+      /* Vertices are already flushed by _mesa_DeleteTextures */
+      ctx->NewState |= _NEW_BUFFERS;
 }
 
 
@@ -1083,6 +1101,25 @@ unbind_texobj_from_texunits(struct gl_context *ctx,
 }
 
 
+/**
+ * Check if the given texture object is bound to any shader image unit
+ * and unbind it if that's the case.
+ */
+static void
+unbind_texobj_from_image_units(struct gl_context *ctx,
+                               struct gl_texture_object *texObj)
+{
+   GLuint i;
+
+   for (i = 0; i < ctx->Const.MaxImageUnits; i++) {
+      struct gl_image_unit *unit = &ctx->ImageUnits[i];
+
+      if (texObj == unit->TexObj)
+         _mesa_reference_texobj(&unit->TexObj, NULL);
+   }
+}
+
+
 /**
  * Delete named textures.
  *
@@ -1130,6 +1167,12 @@ _mesa_DeleteTextures( GLsizei n, const GLuint *textures)
              */
             unbind_texobj_from_texunits(ctx, delObj);
 
+            /* 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, delObj);
+
             _mesa_unlock_texture(ctx, delObj);
 
             ctx->NewState |= _NEW_TEXTURE;
@@ -1137,9 +1180,9 @@ _mesa_DeleteTextures( GLsizei n, const GLuint *textures)
             /* The texture _name_ is now free for re-use.
              * Remove it from the hash table now.
              */
-            _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
+            mtx_lock(&ctx->Shared->Mutex);
             _mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name);
-            _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
+            mtx_unlock(&ctx->Shared->Mutex);
 
             /* Unreference the texobj.  If refcount hits zero, the texture
              * will be deleted.
@@ -1157,8 +1200,8 @@ _mesa_DeleteTextures( GLsizei n, const GLuint *textures)
  * Note that proxy targets are not valid here.
  * \return TEXTURE_x_INDEX or -1 if target is invalid
  */
-static GLint
-target_enum_to_index(struct gl_context *ctx, GLenum target)
+int
+_mesa_tex_target_to_index(const struct gl_context *ctx, GLenum target)
 {
    switch (target) {
    case GL_TEXTURE_1D:
@@ -1166,25 +1209,21 @@ target_enum_to_index(struct gl_context *ctx, GLenum target)
    case GL_TEXTURE_2D:
       return TEXTURE_2D_INDEX;
    case GL_TEXTURE_3D:
-      return TEXTURE_3D_INDEX;
-   case GL_TEXTURE_CUBE_MAP_ARB:
+      return ctx->API != API_OPENGLES ? TEXTURE_3D_INDEX : -1;
+   case GL_TEXTURE_CUBE_MAP:
       return ctx->Extensions.ARB_texture_cube_map
          ? TEXTURE_CUBE_INDEX : -1;
-   case GL_TEXTURE_RECTANGLE_NV:
+   case GL_TEXTURE_RECTANGLE:
       return _mesa_is_desktop_gl(ctx) && ctx->Extensions.NV_texture_rectangle
          ? TEXTURE_RECT_INDEX : -1;
-   case GL_TEXTURE_1D_ARRAY_EXT:
-      return _mesa_is_desktop_gl(ctx)
-         && (ctx->Extensions.EXT_texture_array
-             || ctx->Extensions.MESA_texture_array)
+   case GL_TEXTURE_1D_ARRAY:
+      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_array
          ? TEXTURE_1D_ARRAY_INDEX : -1;
-   case GL_TEXTURE_2D_ARRAY_EXT:
-      return (_mesa_is_desktop_gl(ctx)
-              && (ctx->Extensions.EXT_texture_array
-                  || ctx->Extensions.MESA_texture_array))
+   case GL_TEXTURE_2D_ARRAY:
+      return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_array)
          || _mesa_is_gles3(ctx)
          ? TEXTURE_2D_ARRAY_INDEX : -1;
-   case GL_TEXTURE_BUFFER_ARB:
+   case GL_TEXTURE_BUFFER:
       return ctx->API == API_OPENGL_CORE &&
              ctx->Extensions.ARB_texture_buffer_object ?
              TEXTURE_BUFFER_INDEX : -1;
@@ -1192,7 +1231,8 @@ target_enum_to_index(struct gl_context *ctx, GLenum target)
       return _mesa_is_gles(ctx) && ctx->Extensions.OES_EGL_image_external
          ? TEXTURE_EXTERNAL_INDEX : -1;
    case GL_TEXTURE_CUBE_MAP_ARRAY:
-      return TEXTURE_CUBE_ARRAY_INDEX;
+      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_cube_map_array
+         ? TEXTURE_CUBE_ARRAY_INDEX : -1;
    case GL_TEXTURE_2D_MULTISAMPLE:
       return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_multisample
          ? TEXTURE_2D_MULTISAMPLE_INDEX: -1;
@@ -1232,7 +1272,7 @@ _mesa_BindTexture( GLenum target, GLuint texName )
       _mesa_debug(ctx, "glBindTexture %s %d\n",
                   _mesa_lookup_enum_by_nr(target), (GLint) texName);
 
-   targetIndex = target_enum_to_index(ctx, target);
+   targetIndex = _mesa_tex_target_to_index(ctx, target);
    if (targetIndex < 0) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glBindTexture(target)");
       return;
@@ -1275,9 +1315,9 @@ _mesa_BindTexture( GLenum target, GLuint texName )
          }
 
          /* and insert it into hash table */
-         _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
+         mtx_lock(&ctx->Shared->Mutex);
          _mesa_HashInsert(ctx->Shared->TexObjects, texName, newTexObj);
-         _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
+         mtx_unlock(&ctx->Shared->Mutex);
       }
       newTexObj->Target = target;
    }
@@ -1289,10 +1329,10 @@ _mesa_BindTexture( GLenum target, GLuint texName )
     */
    {
       GLboolean early_out;
-      _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
+      mtx_lock(&ctx->Shared->Mutex);
       early_out = ((ctx->Shared->RefCount == 1)
                    && (newTexObj == texUnit->CurrentTex[targetIndex]));
-      _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
+      mtx_unlock(&ctx->Shared->Mutex);
       if (early_out) {
          return;
       }
@@ -1455,7 +1495,7 @@ _mesa_IsTexture( GLuint texture )
 void
 _mesa_lock_context_textures( struct gl_context *ctx )
 {
-   _glthread_LOCK_MUTEX(ctx->Shared->TexMutex);
+   mtx_lock(&ctx->Shared->TexMutex);
 
    if (ctx->Shared->TextureStateStamp != ctx->TextureStateTimestamp) {
       ctx->NewState |= _NEW_TEXTURE;
@@ -1468,7 +1508,7 @@ void
 _mesa_unlock_context_textures( struct gl_context *ctx )
 {
    assert(ctx->Shared->TextureStateStamp == ctx->TextureStateTimestamp);
-   _glthread_UNLOCK_MUTEX(ctx->Shared->TexMutex);
+   mtx_unlock(&ctx->Shared->TexMutex);
 }
 
 void GLAPIENTRY