#include "fbobject.h"
#include "formats.h"
#include "hash.h"
-#include "imports.h"
+
#include "macros.h"
#include "shaderimage.h"
#include "teximage.h"
#include "mtypes.h"
#include "program/prog_instruction.h"
#include "texturebindless.h"
+#include "util/u_memory.h"
}
+/**
+ * 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.
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;
_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);
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
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);
}
}
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;
}
/* 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 */
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];
}
*/
_mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name);
+ if (ctx->Driver.TextureRemovedFromShared) {
+ ctx->Driver.TextureRemovedFromShared(ctx, delObj);
+ }
+
/* Unreference the texobj. If refcount hits zero, the texture
* will be deleted.
*/
}
}
+/**
+ * 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)
*/
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;
}
}
}
-
/**
- * 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);
/* 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 */
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");
}
_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");
}