main: remove extern C around #includes in ff_fragment_shader.cpp
[mesa.git] / src / mesa / main / texobj.c
index 43cf1c5c5a1085729fe04b56d8b24bee2fa777bc..f0ff605fc506a89cef6f10a362c4114d902b8378 100644 (file)
@@ -61,6 +61,27 @@ _mesa_lookup_texture(struct gl_context *ctx, GLuint id)
 }
 
 
+void
+_mesa_begin_texture_lookups(struct gl_context *ctx)
+{
+   _mesa_HashLockMutex(ctx->Shared->TexObjects);
+}
+
+
+void
+_mesa_end_texture_lookups(struct gl_context *ctx)
+{
+   _mesa_HashUnlockMutex(ctx->Shared->TexObjects);
+}
+
+
+struct gl_texture_object *
+_mesa_lookup_texture_locked(struct gl_context *ctx, GLuint id)
+{
+   return (struct gl_texture_object *)
+      _mesa_HashLookupLocked(ctx->Shared->TexObjects, id);
+}
+
 
 /**
  * Allocate and initialize a new texture object.  But don't put it into the
@@ -68,7 +89,7 @@ _mesa_lookup_texture(struct gl_context *ctx, GLuint id)
  *
  * Called via ctx->Driver.NewTextureObject, unless overridden by a device
  * driver.
- * 
+ *
  * \param shared the shared GL state structure to contain the texture object
  * \param name integer name for the texture object
  * \param target either GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D,
@@ -247,7 +268,6 @@ _mesa_delete_texture_object(struct gl_context *ctx,
 }
 
 
-
 /**
  * Copy texture object state from one texture object to another.
  * Use for glPush/PopAttrib.
@@ -632,7 +652,8 @@ _mesa_test_texobj_completeness( const struct gl_context *ctx,
          if (height > 1 && t->Target != GL_TEXTURE_1D_ARRAY) {
             height /= 2;
          }
-         if (depth > 1 && t->Target != GL_TEXTURE_2D_ARRAY && t->Target != GL_TEXTURE_CUBE_MAP_ARRAY) {
+         if (depth > 1 && t->Target != GL_TEXTURE_2D_ARRAY
+             && t->Target != GL_TEXTURE_CUBE_MAP_ARRAY) {
             depth /= 2;
          }
 
@@ -654,22 +675,25 @@ _mesa_test_texobj_completeness( const struct gl_context *ctx,
                   return;
                }
                if (img->Width2 != width) {
-                  incomplete(t, MIPMAP, "TexImage[%d] bad width %u", i, img->Width2);
+                  incomplete(t, MIPMAP, "TexImage[%d] bad width %u", i,
+                             img->Width2);
                   return;
                }
                if (img->Height2 != height) {
-                  incomplete(t, MIPMAP, "TexImage[%d] bad height %u", i, img->Height2);
+                  incomplete(t, MIPMAP, "TexImage[%d] bad height %u", i,
+                             img->Height2);
                   return;
                }
                if (img->Depth2 != depth) {
-                  incomplete(t, MIPMAP, "TexImage[%d] bad depth %u", i, img->Depth2);
+                  incomplete(t, MIPMAP, "TexImage[%d] bad depth %u", i,
+                             img->Depth2);
                   return;
                }
 
                /* Extra checks for cube textures */
                if (face > 0) {
                   /* check that cube faces are the same size */
-                  if (img->Width2 != t->Image[0][i]->Width2 || 
+                  if (img->Width2 != t->Image[0][i]->Width2 ||
                       img->Height2 != t->Image[0][i]->Height2) {
                     incomplete(t, MIPMAP, "CubeMap Image[n][i] bad size");
                     return;
@@ -677,7 +701,7 @@ _mesa_test_texobj_completeness( const struct gl_context *ctx,
                }
             }
          }
-         
+
          if (width == 1 && height == 1 && depth == 1) {
             return;  /* found smallest needed mipmap, all done! */
          }
@@ -751,18 +775,21 @@ _mesa_get_fallback_texture(struct gl_context *ctx, gl_texture_index tex)
 {
    if (!ctx->Shared->FallbackTex[tex]) {
       /* create fallback texture now */
-      const GLsizei width = 1, height = 1, depth = 1;
-      GLubyte texel[4];
+      const GLsizei width = 1, height = 1;
+      GLsizei depth = 1;
+      GLubyte texel[24];
       struct gl_texture_object *texObj;
       struct gl_texture_image *texImage;
       mesa_format texFormat;
       GLuint dims, face, numFaces = 1;
       GLenum target;
 
-      texel[0] =
-      texel[1] =
-      texel[2] = 0x0;
-      texel[3] = 0xff;
+      for (face = 0; face < 6; face++) {
+         texel[4*face + 0] =
+         texel[4*face + 1] =
+         texel[4*face + 2] = 0x0;
+         texel[4*face + 3] = 0xff;
+      }
 
       switch (tex) {
       case TEXTURE_2D_ARRAY_INDEX:
@@ -801,6 +828,7 @@ _mesa_get_fallback_texture(struct gl_context *ctx, gl_texture_index tex)
       case TEXTURE_CUBE_ARRAY_INDEX:
          dims = 3;
          target = GL_TEXTURE_CUBE_MAP_ARRAY;
+         depth = 6;
          break;
       case TEXTURE_EXTERNAL_INDEX:
          dims = 2;
@@ -925,6 +953,7 @@ _mesa_total_texture_memory(struct gl_context *ctx)
    return total;
 }
 
+
 static struct gl_texture_object *
 invalidate_tex_image_error_check(struct gl_context *ctx, GLuint texture,
                                  GLint level, const char *name)
@@ -997,7 +1026,7 @@ invalidate_tex_image_error_check(struct gl_context *ctx, GLuint texture,
  * 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 )
 {
@@ -1131,6 +1160,30 @@ unbind_texobj_from_image_units(struct gl_context *ctx,
 }
 
 
+/**
+ * Unbinds all textures bound to the given texture image unit.
+ */
+static void
+unbind_textures_from_unit(struct gl_context *ctx, GLuint unit)
+{
+   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+
+   while (texUnit->_BoundTextures) {
+      const GLuint index = ffs(texUnit->_BoundTextures) - 1;
+      struct gl_texture_object *texObj = ctx->Shared->DefaultTex[index];
+
+      _mesa_reference_texobj(&texUnit->CurrentTex[index], texObj);
+
+      /* Pass BindTexture call to device driver */
+      if (ctx->Driver.BindTexture)
+         ctx->Driver.BindTexture(ctx, unit, 0, texObj);
+
+      texUnit->_BoundTextures &= ~(1 << index);
+      ctx->NewState |= _NEW_TEXTURE;
+   }
+}
+
+
 /**
  * Delete named textures.
  *
@@ -1258,10 +1311,10 @@ _mesa_tex_target_to_index(const struct gl_context *ctx, GLenum target)
 
 /**
  * Bind a named texture to a texturing target.
- * 
+ *
  * \param target texture target.
  * \param texName texture name.
- * 
+ *
  * \sa glBindTexture().
  *
  * Determines the old texture object bound and returns immediately if rebinding
@@ -1303,7 +1356,9 @@ _mesa_BindTexture( GLenum target, GLuint texName )
       if (newTexObj) {
          /* error checking */
          if (newTexObj->Target != 0 && newTexObj->Target != target) {
-            /* the named texture object's target doesn't match the given target */
+            /* The named texture object's target doesn't match the
+             * given target
+             */
             _mesa_error( ctx, GL_INVALID_OPERATION,
                          "glBindTexture(target mismatch)" );
             return;
@@ -1314,7 +1369,8 @@ _mesa_BindTexture( GLenum target, GLuint texName )
       }
       else {
          if (ctx->API == API_OPENGL_CORE) {
-            _mesa_error(ctx, GL_INVALID_OPERATION, "glBindTexture(non-gen name)");
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "glBindTexture(non-gen name)");
             return;
          }
 
@@ -1369,19 +1425,123 @@ _mesa_BindTexture( GLenum target, GLuint texName )
 
    /* Pass BindTexture call to device driver */
    if (ctx->Driver.BindTexture)
-      ctx->Driver.BindTexture(ctx, target, newTexObj);
+      ctx->Driver.BindTexture(ctx, ctx->Texture.CurrentUnit, target, newTexObj);
+}
+
+
+void GLAPIENTRY
+_mesa_BindTextures(GLuint first, GLsizei count, const GLuint *textures)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   GLint i;
+
+   /* 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;
+   }
+
+   /* Flush before changing bindings */
+   FLUSH_VERTICES(ctx, 0);
+
+   ctx->Texture.NumCurrentTexUsed = MAX2(ctx->Texture.NumCurrentTexUsed,
+                                         first + count);
+
+   if (textures) {
+      /* Note that the error semantics for multi-bind commands differ from
+       * those of other GL commands.
+       *
+       * The issues section in the ARB_multi_bind spec says:
+       *
+       *    "(11) Typically, OpenGL specifies that if an error is generated by
+       *          a command, that command has no effect.  This is somewhat
+       *          unfortunate for multi-bind commands, because it would require
+       *          a first pass to scan the entire list of bound objects for
+       *          errors and then a second pass to actually perform the
+       *          bindings.  Should we have different error semantics?
+       *
+       *       RESOLVED:  Yes.  In this specification, when the parameters for
+       *       one of the <count> binding points are invalid, that binding
+       *       point is not updated and an error will be generated.  However,
+       *       other binding points in the same command will be updated if
+       *       their parameters are valid and no other error occurs."
+       */
+
+      _mesa_begin_texture_lookups(ctx);
+
+      for (i = 0; i < count; i++) {
+         if (textures[i] != 0) {
+            struct gl_texture_unit *texUnit = &ctx->Texture.Unit[first + i];
+            struct gl_texture_object *current = texUnit->_Current;
+            struct gl_texture_object *texObj;
+
+            if (current && current->Name == textures[i])
+               texObj = current;
+            else
+               texObj = _mesa_lookup_texture_locked(ctx, textures[i]);
+
+            if (texObj && texObj->Target != 0) {
+               const gl_texture_index targetIndex = texObj->TargetIndex;
+
+               if (texUnit->CurrentTex[targetIndex] != texObj) {
+                  /* Do the actual binding.  The refcount on the previously
+                   * bound texture object will be decremented.  It will be
+                   * deleted if the count hits zero.
+                   */
+                  _mesa_reference_texobj(&texUnit->CurrentTex[targetIndex],
+                                         texObj);
+
+                  texUnit->_BoundTextures |= (1 << targetIndex);
+                  ctx->NewState |= _NEW_TEXTURE;
+
+                  /* Pass the BindTexture call to the device driver */
+                  if (ctx->Driver.BindTexture)
+                     ctx->Driver.BindTexture(ctx, first + i,
+                                             texObj->Target, texObj);
+               }
+            } else {
+               /* The ARB_multi_bind spec says:
+                *
+                *     "An INVALID_OPERATION error is generated if any value
+                *      in <textures> is not zero or the name of an existing
+                *      texture object (per binding)."
+                */
+               _mesa_error(ctx, GL_INVALID_OPERATION,
+                           "glBindTextures(textures[%d]=%u is not zero "
+                           "or the name of an existing texture object)",
+                           i, textures[i]);
+            }
+         } else {
+            unbind_textures_from_unit(ctx, first + i);
+         }
+      }
+
+      _mesa_end_texture_lookups(ctx);
+   } else {
+      /* Unbind all textures in the range <first> through <first>+<count>-1 */
+      for (i = 0; i < count; i++)
+         unbind_textures_from_unit(ctx, first + i);
+   }
 }
 
 
 /**
  * Set texture priorities.
- * 
+ *
  * \param n number of textures.
  * \param texName texture names.
  * \param priorities corresponding texture priorities.
- * 
+ *
  * \sa glPrioritizeTextures().
- * 
+ *
  * Looks up each texture in the hash, clamps the corresponding priority between
  * 0.0 and 1.0, and calls dd_function_table::PrioritizeTexture.
  */
@@ -1421,13 +1581,14 @@ _mesa_PrioritizeTextures( GLsizei n, const GLuint *texName,
 
 /**
  * See if textures are loaded in texture memory.
- * 
+ *
  * \param n number of textures to query.
  * \param texName array with the texture names.
  * \param residences array which will hold the residence status.
  *
- * \return GL_TRUE if all textures are resident and \p residences is left unchanged, 
- * 
+ * \return GL_TRUE if all textures are resident and
+ *                 residences is left unchanged,
+ *
  * Note: we assume all textures are always resident
  */
 GLboolean GLAPIENTRY
@@ -1463,7 +1624,7 @@ _mesa_AreTexturesResident(GLsizei n, const GLuint *texName,
          return GL_FALSE;
       }
    }
-   
+
    return allResident;
 }
 
@@ -1475,7 +1636,7 @@ _mesa_AreTexturesResident(GLsizei n, const GLuint *texName,
  *
  * \return GL_TRUE if texture name corresponds to a texture, or GL_FALSE
  * otherwise.
- * 
+ *
  * \sa glIsTexture().
  *
  * Calls _mesa_HashLookup().
@@ -1530,6 +1691,7 @@ _mesa_unlock_context_textures( struct gl_context *ctx )
    mtx_unlock(&ctx->Shared->TexMutex);
 }
 
+
 void GLAPIENTRY
 _mesa_InvalidateTexSubImage(GLuint texture, GLint level, GLint xoffset,
                             GLint yoffset, GLint zoffset, GLsizei width,
@@ -1676,6 +1838,7 @@ _mesa_InvalidateTexSubImage(GLuint texture, GLint level, GLint xoffset,
    return;
 }
 
+
 void GLAPIENTRY
 _mesa_InvalidateTexImage(GLuint texture, GLint level)
 {