*/
+#include <stdio.h>
#include "bufferobj.h"
-#include "colortab.h"
#include "context.h"
#include "enums.h"
#include "fbobject.h"
#include "hash.h"
#include "imports.h"
#include "macros.h"
+#include "shaderimage.h"
#include "teximage.h"
#include "texobj.h"
#include "texstate.h"
/** \name Internal functions */
/*@{*/
+/**
+ * This function checks for all valid combinations of Min and Mag filters for
+ * Float types, when extensions like OES_texture_float and
+ * OES_texture_float_linear are supported. OES_texture_float mentions support
+ * for NEAREST, NEAREST_MIPMAP_NEAREST magnification and minification filters.
+ * Mag filters like LINEAR and min filters like NEAREST_MIPMAP_LINEAR,
+ * LINEAR_MIPMAP_NEAREST and LINEAR_MIPMAP_LINEAR are only valid in case
+ * OES_texture_float_linear is supported.
+ *
+ * Returns true in case the filter is valid for given Float type else false.
+ */
+static bool
+valid_filter_for_float(const struct gl_context *ctx,
+ const struct gl_texture_object *obj)
+{
+ switch (obj->Sampler.MagFilter) {
+ case GL_LINEAR:
+ if (obj->_IsHalfFloat && !ctx->Extensions.OES_texture_half_float_linear) {
+ return false;
+ } else if (obj->_IsFloat && !ctx->Extensions.OES_texture_float_linear) {
+ return false;
+ }
+ case GL_NEAREST:
+ case GL_NEAREST_MIPMAP_NEAREST:
+ break;
+ default:
+ unreachable("Invalid mag filter");
+ }
+
+ switch (obj->Sampler.MinFilter) {
+ case GL_LINEAR:
+ case GL_NEAREST_MIPMAP_LINEAR:
+ case GL_LINEAR_MIPMAP_NEAREST:
+ case GL_LINEAR_MIPMAP_LINEAR:
+ if (obj->_IsHalfFloat && !ctx->Extensions.OES_texture_half_float_linear) {
+ return false;
+ } else if (obj->_IsFloat && !ctx->Extensions.OES_texture_float_linear) {
+ return false;
+ }
+ case GL_NEAREST:
+ case GL_NEAREST_MIPMAP_NEAREST:
+ break;
+ default:
+ unreachable("Invalid min filter");
+ }
+
+ return true;
+}
/**
* Return the gl_texture_object for a given ID.
return texUnit->CurrentTex[TEXTURE_3D_INDEX];
case GL_PROXY_TEXTURE_3D:
return ctx->Texture.ProxyTex[TEXTURE_3D_INDEX];
- case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
- case GL_TEXTURE_CUBE_MAP_ARB:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ case GL_TEXTURE_CUBE_MAP:
return ctx->Extensions.ARB_texture_cube_map
? texUnit->CurrentTex[TEXTURE_CUBE_INDEX] : NULL;
- case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
+ case GL_PROXY_TEXTURE_CUBE_MAP:
return ctx->Extensions.ARB_texture_cube_map
? ctx->Texture.ProxyTex[TEXTURE_CUBE_INDEX] : NULL;
case GL_TEXTURE_CUBE_MAP_ARRAY:
case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
return arrayTex ? ctx->Texture.ProxyTex[TEXTURE_2D_ARRAY_INDEX] : NULL;
case GL_TEXTURE_BUFFER:
- return ctx->API == API_OPENGL_CORE &&
- ctx->Extensions.ARB_texture_buffer_object ?
+ return (_mesa_has_ARB_texture_buffer_object(ctx) ||
+ _mesa_has_OES_texture_buffer(ctx)) ?
texUnit->CurrentTex[TEXTURE_BUFFER_INDEX] : NULL;
case GL_TEXTURE_EXTERNAL_OES:
return _mesa_is_gles(ctx) && ctx->Extensions.OES_EGL_image_external
* \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,
- * GL_TEXTURE_CUBE_MAP_ARB or GL_TEXTURE_RECTANGLE_NV. zero is ok for the sake
+ * GL_TEXTURE_CUBE_MAP or GL_TEXTURE_RECTANGLE_NV. zero is ok for the sake
* of GenTextures()
*
* \return pointer to new texture object.
struct gl_texture_object *obj,
GLuint name, GLenum target )
{
- ASSERT(target == 0 ||
+ assert(target == 0 ||
target == GL_TEXTURE_1D ||
target == GL_TEXTURE_2D ||
target == GL_TEXTURE_3D ||
- target == GL_TEXTURE_CUBE_MAP_ARB ||
+ target == GL_TEXTURE_CUBE_MAP ||
target == GL_TEXTURE_RECTANGLE_NV ||
target == GL_TEXTURE_1D_ARRAY_EXT ||
target == GL_TEXTURE_2D_ARRAY_EXT ||
obj->RefCount = 1;
obj->Name = name;
obj->Target = target;
+ if (target != 0) {
+ obj->TargetIndex = _mesa_tex_target_to_index(ctx, target);
+ }
+ else {
+ obj->TargetIndex = NUM_TEXTURE_TARGETS; /* invalid/error value */
+ }
obj->Priority = 1.0F;
obj->BaseLevel = 0;
obj->MaxLevel = 1000;
GLenum filter = GL_LINEAR;
assert(obj->Target == 0);
+ obj->Target = target;
+ obj->TargetIndex = _mesa_tex_target_to_index(ctx, target);
+ assert(obj->TargetIndex < NUM_TEXTURE_TARGETS);
+
switch (target) {
case GL_TEXTURE_2D_MULTISAMPLE:
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
dest->_MipmapComplete = src->_MipmapComplete;
COPY_4V(dest->Swizzle, src->Swizzle);
dest->_Swizzle = src->_Swizzle;
+ dest->_IsHalfFloat = src->_IsHalfFloat;
+ dest->_IsFloat = src->_IsFloat;
dest->RequiredTextureImageUnits = src->RequiredTextureImageUnits;
}
case GL_TEXTURE_1D:
case GL_TEXTURE_2D:
case GL_TEXTURE_3D:
- case GL_TEXTURE_CUBE_MAP_ARB:
+ case GL_TEXTURE_CUBE_MAP:
case GL_TEXTURE_RECTANGLE_NV:
case GL_TEXTURE_1D_ARRAY_EXT:
case GL_TEXTURE_2D_ARRAY_EXT:
GLboolean deleteFlag = GL_FALSE;
struct gl_texture_object *oldTex = *ptr;
- ASSERT(valid_texture_object(oldTex));
+ assert(valid_texture_object(oldTex));
(void) valid_texture_object; /* silence warning in release builds */
mtx_lock(&oldTex->Mutex);
- ASSERT(oldTex->RefCount > 0);
+ assert(oldTex->RefCount > 0);
oldTex->RefCount--;
deleteFlag = (oldTex->RefCount == 0);
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);
if (tex) {
/* reference new texture */
- ASSERT(valid_texture_object(tex));
+ assert(valid_texture_object(tex));
mtx_lock(&tex->Mutex);
if (tex->RefCount == 0) {
/* this texture's being deleted (look just above) */
t->_IsIntegerFormat = datatype == GL_INT || datatype == GL_UNSIGNED_INT;
}
+ /* Check if the texture type is Float or HalfFloatOES and ensure Min and Mag
+ * filters are supported in this case.
+ */
+ if (_mesa_is_gles(ctx) && !valid_filter_for_float(ctx, t)) {
+ incomplete(t, BASE, "Filter is not supported with Float types.");
+ return;
+ }
+
/* Compute _MaxLevel (the maximum mipmap level we'll sample from given the
* mipmap image sizes and GL_TEXTURE_MAX_LEVEL state).
*/
case GL_TEXTURE_3D:
maxLevels = ctx->Const.Max3DTextureLevels;
break;
- case GL_TEXTURE_CUBE_MAP_ARB:
+ case GL_TEXTURE_CUBE_MAP:
case GL_TEXTURE_CUBE_MAP_ARRAY:
maxLevels = ctx->Const.MaxCubeTextureLevels;
break;
return;
}
- ASSERT(maxLevels > 0);
+ assert(maxLevels > 0);
t->_MaxLevel = MIN3(t->MaxLevel,
/* 'p' in the GL spec */
return;
}
- if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
- /* Make sure that all six cube map level 0 images are the same size.
+ if (t->Target == GL_TEXTURE_CUBE_MAP) {
+ /* Make sure that all six cube map level 0 images are the same size and
+ * format.
* Note: we know that the image's width==height (we enforce that
* at glTexImage time) so we only need to test the width here.
*/
incomplete(t, BASE, "Cube face missing or mismatched size");
return;
}
+ if (t->Image[face][baseLevel]->InternalFormat !=
+ baseImage->InternalFormat) {
+ incomplete(t, BASE, "Cube face format mismatch");
+ return;
+ }
+ if (t->Image[face][baseLevel]->Border != baseImage->Border) {
+ incomplete(t, BASE, "Cube face border size mismatch");
+ return;
+ }
}
}
incomplete(t, MIPMAP, "TexImage[%d] is missing", i);
return;
}
- if (img->TexFormat != baseImage->TexFormat) {
+ if (img->InternalFormat != baseImage->InternalFormat) {
incomplete(t, MIPMAP, "Format[i] != Format[baseLevel]");
return;
}
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 ||
- img->Height2 != t->Image[0][i]->Height2) {
- incomplete(t, MIPMAP, "CubeMap Image[n][i] bad size");
- return;
- }
- }
}
}
}
-/**
- * Check if the given cube map texture is "cube complete" as defined in
- * the OpenGL specification.
- */
GLboolean
-_mesa_cube_complete(const struct gl_texture_object *texObj)
+_mesa_cube_level_complete(const struct gl_texture_object *texObj,
+ const GLint level)
{
- const GLint baseLevel = texObj->BaseLevel;
const struct gl_texture_image *img0, *img;
GLuint face;
if (texObj->Target != GL_TEXTURE_CUBE_MAP)
return GL_FALSE;
- if ((baseLevel < 0) || (baseLevel >= MAX_TEXTURE_LEVELS))
+ if ((level < 0) || (level >= MAX_TEXTURE_LEVELS))
return GL_FALSE;
/* check first face */
- img0 = texObj->Image[0][baseLevel];
+ img0 = texObj->Image[0][level];
if (!img0 ||
img0->Width < 1 ||
img0->Width != img0->Height)
/* check remaining faces vs. first face */
for (face = 1; face < 6; face++) {
- img = texObj->Image[face][baseLevel];
+ img = texObj->Image[face][level];
if (!img ||
img->Width != img0->Width ||
img->Height != img0->Height ||
return GL_TRUE;
}
+/**
+ * Check if the given cube map texture is "cube complete" as defined in
+ * the OpenGL specification.
+ */
+GLboolean
+_mesa_cube_complete(const struct gl_texture_object *texObj)
+{
+ return _mesa_cube_level_complete(texObj, texObj->BaseLevel);
+}
/**
* Mark a texture object dirty. It forces the object to be incomplete
/* need a loop here just for cube maps */
for (face = 0; face < numFaces; face++) {
- GLenum faceTarget;
-
- if (target == GL_TEXTURE_CUBE_MAP)
- faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
- else
- faceTarget = target;
+ const GLenum faceTarget = _mesa_cube_face_target(target, face);
/* initialize level[0] texture image */
texImage = _mesa_get_tex_image(ctx, texObj, faceTarget, 0);
return t;
}
-/*@}*/
-
-
-/***********************************************************************/
-/** \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().
- *
- * 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.
+ * \param target either 0 or a valid / error-checked texture target enum
*/
-void GLAPIENTRY
-_mesa_GenTextures( GLsizei n, GLuint *textures )
+static void
+create_textures(struct gl_context *ctx, GLenum target,
+ GLsizei n, GLuint *textures, const char *caller)
{
- GET_CURRENT_CONTEXT(ctx);
GLuint first;
GLint i;
if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
- _mesa_debug(ctx, "glGenTextures %d\n", n);
+ _mesa_debug(ctx, "%s %d\n", caller, n);
if (n < 0) {
- _mesa_error( ctx, GL_INVALID_VALUE, "glGenTextures" );
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", caller);
return;
}
/*
* This must be atomic (generation and allocation of texture IDs)
*/
- mtx_lock(&ctx->Shared->Mutex);
+ _mesa_HashLockMutex(ctx->Shared->TexObjects);
first = _mesa_HashFindFreeKeyBlock(ctx->Shared->TexObjects, n);
for (i = 0; i < n; i++) {
struct gl_texture_object *texObj;
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_HashUnlockMutex(ctx->Shared->TexObjects);
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "gl%sTextures", caller);
return;
}
/* insert into hash table */
- _mesa_HashInsert(ctx->Shared->TexObjects, texObj->Name, texObj);
+ _mesa_HashInsertLocked(ctx->Shared->TexObjects, texObj->Name, texObj);
textures[i] = name;
}
- mtx_unlock(&ctx->Shared->Mutex);
+ _mesa_HashUnlockMutex(ctx->Shared->TexObjects);
+}
+
+/*@}*/
+
+
+/***********************************************************************/
+/** \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, "glGenTextures");
}
+/**
+ * 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, "glCreateTextures");
+}
/**
* Check if the given texture object is bound to the current draw or
const gl_texture_index index = texObj->TargetIndex;
GLuint u;
- if (texObj->Target == 0)
+ if (texObj->Target == 0) {
+ /* texture was never bound */
return;
+ }
+
+ assert(index < NUM_TEXTURE_TARGETS);
for (u = 0; u < ctx->Texture.NumCurrentTexUsed; u++) {
struct gl_texture_unit *unit = &ctx->Texture.Unit[u];
for (i = 0; i < ctx->Const.MaxImageUnits; i++) {
struct gl_image_unit *unit = &ctx->ImageUnits[i];
- if (texObj == unit->TexObj)
+ if (texObj == unit->TexObj) {
_mesa_reference_texobj(&unit->TexObj, NULL);
+ *unit = _mesa_default_image_unit(ctx);
+ }
}
}
if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
_mesa_debug(ctx, "glDeleteTextures %d\n", n);
+ if (n < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteTextures(n < 0)");
+ return;
+ }
+
FLUSH_VERTICES(ctx, 0); /* too complex */
+ if (n < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteTextures(n)");
+ return;
+ }
+
if (!textures)
return;
/* The texture _name_ is now free for re-use.
* Remove it from the hash table now.
*/
- mtx_lock(&ctx->Shared->Mutex);
_mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name);
- mtx_unlock(&ctx->Shared->Mutex);
/* 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;
+
+ /* 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
|| _mesa_is_gles3(ctx)
? TEXTURE_2D_ARRAY_INDEX : -1;
case GL_TEXTURE_BUFFER:
- return ctx->API == API_OPENGL_CORE &&
- ctx->Extensions.ARB_texture_buffer_object ?
+ return (_mesa_has_ARB_texture_buffer_object(ctx) ||
+ _mesa_has_OES_texture_buffer(ctx)) ?
TEXTURE_BUFFER_INDEX : -1;
case GL_TEXTURE_EXTERNAL_OES:
return _mesa_is_gles(ctx) && ctx->Extensions.OES_EGL_image_external
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;
+ return ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_multisample) ||
+ _mesa_is_gles31(ctx)) ? TEXTURE_2D_MULTISAMPLE_INDEX: -1;
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
- return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_multisample
+ return ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_multisample) ||
+ _mesa_is_gles31(ctx))
? TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX: -1;
default:
return -1;
/**
- * Bind a named texture to a texturing target.
+ * Do actual texture binding. All error checking should have been done prior
+ * to calling this function. Note that the texture target (1D, 2D, etc) is
+ * always specified by the texObj->TargetIndex.
+ *
+ * \param unit index of texture unit to update
+ * \param texObj the new texture object (cannot be NULL)
+ */
+static void
+bind_texture(struct gl_context *ctx,
+ unsigned unit,
+ struct gl_texture_object *texObj)
+{
+ struct gl_texture_unit *texUnit;
+ int targetIndex;
+
+ assert(unit < ARRAY_SIZE(ctx->Texture.Unit));
+ texUnit = &ctx->Texture.Unit[unit];
+
+ assert(texObj);
+ assert(valid_texture_object(texObj));
+
+ targetIndex = texObj->TargetIndex;
+ assert(targetIndex >= 0);
+ assert(targetIndex < NUM_TEXTURE_TARGETS);
+
+ /* 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[targetIndex]));
+ mtx_unlock(&ctx->Shared->Mutex);
+ if (early_out) {
+ return;
+ }
+ }
+
+ /* flush before changing binding */
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+
+ /* If the refcount on the previously bound texture is decremented to
+ * zero, it'll be deleted here.
+ */
+ _mesa_reference_texobj(&texUnit->CurrentTex[targetIndex], texObj);
+
+ ctx->Texture.NumCurrentTexUsed = MAX2(ctx->Texture.NumCurrentTexUsed,
+ unit + 1);
+
+ if (texObj->Name != 0)
+ texUnit->_BoundTextures |= (1 << targetIndex);
+ else
+ texUnit->_BoundTextures &= ~(1 << targetIndex);
+
+ /* Pass BindTexture call to device driver */
+ if (ctx->Driver.BindTexture) {
+ ctx->Driver.BindTexture(ctx, unit, texObj->Target, texObj);
+ }
+}
+
+
+/**
+ * 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.
- *
- * \sa glBindTexture().
- *
- * Determines the old texture object bound and returns immediately if rebinding
- * the same texture. Get the current texture which is either a default texture
- * if name is null, a named texture from the hash, or a new texture if the
- * given texture name is new. Increments its reference count, binds it, and
- * calls dd_function_table::BindTexture. Decrements the old texture reference
- * count and deletes it if it reaches zero.
*/
void GLAPIENTRY
_mesa_BindTexture( GLenum target, GLuint texName )
{
GET_CURRENT_CONTEXT(ctx);
- struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx);
struct gl_texture_object *newTexObj = NULL;
GLint targetIndex;
if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
_mesa_debug(ctx, "glBindTexture %s %d\n",
- _mesa_lookup_enum_by_nr(target), (GLint) texName);
+ _mesa_enum_to_string(target), (GLint) texName);
targetIndex = _mesa_tex_target_to_index(ctx, target);
if (targetIndex < 0) {
}
/* and insert it into hash table */
- mtx_lock(&ctx->Shared->Mutex);
_mesa_HashInsert(ctx->Shared->TexObjects, texName, newTexObj);
- mtx_unlock(&ctx->Shared->Mutex);
}
- newTexObj->Target = target;
- newTexObj->TargetIndex = targetIndex;
}
- assert(valid_texture_object(newTexObj));
+ assert(newTexObj->Target == target);
+ assert(newTexObj->TargetIndex == targetIndex);
- /* Check if this texture is only used by this context and is already bound.
- * If so, just return.
- */
- {
- GLboolean early_out;
- mtx_lock(&ctx->Shared->Mutex);
- early_out = ((ctx->Shared->RefCount == 1)
- && (newTexObj == texUnit->CurrentTex[targetIndex]));
- mtx_unlock(&ctx->Shared->Mutex);
- if (early_out) {
- return;
- }
- }
+ bind_texture(ctx, ctx->Texture.CurrentUnit, newTexObj);
+}
- /* flush before changing binding */
- FLUSH_VERTICES(ctx, _NEW_TEXTURE);
- /* Do the actual binding. The refcount on the previously bound
- * texture object will be decremented. It'll be deleted if the
- * count hits zero.
+/**
+ * OpenGL 4.5 / GL_ARB_direct_state_access glBindTextureUnit().
+ *
+ * \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 (unit >= _mesa_max_tex_unit(ctx)) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glBindTextureUnit(unit=%u)", unit);
+ return;
+ }
+
+ if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+ _mesa_debug(ctx, "glBindTextureUnit %s %d\n",
+ _mesa_enum_to_string(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."
*/
- _mesa_reference_texobj(&texUnit->CurrentTex[targetIndex], newTexObj);
- ctx->Texture.NumCurrentTexUsed = MAX2(ctx->Texture.NumCurrentTexUsed,
- ctx->Texture.CurrentUnit + 1);
- ASSERT(texUnit->CurrentTex[targetIndex]);
+ if (texture == 0) {
+ unbind_textures_from_unit(ctx, unit);
+ return;
+ }
- if (texName != 0)
- texUnit->_BoundTextures |= (1 << targetIndex);
- else
- texUnit->_BoundTextures &= ~(1 << targetIndex);
+ /* Get the non-default texture object */
+ texObj = _mesa_lookup_texture(ctx, texture);
- /* Pass BindTexture call to device driver */
- if (ctx->Driver.BindTexture)
- ctx->Driver.BindTexture(ctx, ctx->Texture.CurrentUnit, target, newTexObj);
+ /* Error checking */
+ if (!texObj) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindTextureUnit(non-gen name)");
+ return;
+ }
+ if (texObj->Target == 0) {
+ /* Texture object was gen'd but never bound so the target is not set */
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glBindTextureUnit(target)");
+ return;
+ }
+ assert(valid_texture_object(texObj));
+
+ bind_texture(ctx, unit, texObj);
}
+/**
+ * OpenGL 4.4 / GL_ARB_multi_bind glBindTextures().
+ */
void GLAPIENTRY
_mesa_BindTextures(GLuint first, GLsizei count, const GLuint *textures)
{
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.
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);
- }
+ bind_texture(ctx, first + i, texObj);
} else {
/* The ARB_multi_bind spec says:
*