*/
+#include <stdio.h>
#include "bufferobj.h"
#include "colortab.h"
#include "context.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.
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 ||
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;
}
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).
*/
return;
}
- ASSERT(maxLevels > 0);
+ assert(maxLevels > 0);
t->_MaxLevel = MIN3(t->MaxLevel,
/* 'p' in the GL spec */
}
-/**
- * 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
return t;
}
+/**
+ * Wrapper for the driver function. Need this because _mesa_new_texture_object
+ * permits a target of 0 and does not initialize targetIndex.
+ */
+struct gl_texture_object *
+_mesa_create_nameless_texture(struct gl_context *ctx, GLenum target)
+{
+ struct gl_texture_object *texObj = NULL;
+ GLint targetIndex;
+
+ if (target == 0)
+ return texObj;
+
+ texObj = ctx->Driver.NewTextureObject(ctx, 0, target);
+ targetIndex = _mesa_tex_target_to_index(ctx, texObj->Target);
+ assert(targetIndex < NUM_TEXTURE_TARGETS);
+ texObj->TargetIndex = targetIndex;
+
+ return texObj;
+}
+
/**
* Helper function for glCreateTextures and glGenTextures. Need this because
* glCreateTextures should throw errors if target = 0. This is not exposed to
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;
}
}
+/**
+ * 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_reference_texobj(&texUnit->CurrentTex[targetIndex], newTexObj);
ctx->Texture.NumCurrentTexUsed = MAX2(ctx->Texture.NumCurrentTexUsed,
ctx->Texture.CurrentUnit + 1);
- ASSERT(texUnit->CurrentTex[targetIndex]);
+ assert(texUnit->CurrentTex[targetIndex]);
if (texName != 0)
texUnit->_BoundTextures |= (1 << targetIndex);
ctx->Driver.BindTexture(ctx, ctx->Texture.CurrentUnit, target, newTexObj);
}
+/**
+ * Do the actual binding to a numbered texture unit.
+ * The refcount on the previously bound
+ * texture object will be decremented. It'll be deleted if the
+ * count hits zero.
+ */
+void
+_mesa_bind_texture_unit(struct gl_context *ctx,
+ GLuint unit,
+ struct gl_texture_object *texObj)
+{
+ struct gl_texture_unit *texUnit;
+
+ /* Get the texture unit (this is an array look-up) */
+ texUnit = _mesa_get_tex_unit_err(ctx, unit, "glBindTextureUnit");
+ if (!texUnit)
+ return;
+
+ /* 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[texObj->TargetIndex]));
+ mtx_unlock(&ctx->Shared->Mutex);
+ if (early_out) {
+ return;
+ }
+ }
+
+ /* flush before changing binding */
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+
+ _mesa_reference_texobj(&texUnit->CurrentTex[texObj->TargetIndex],
+ texObj);
+ assert(texUnit->CurrentTex[texObj->TargetIndex]);
+ ctx->Texture.NumCurrentTexUsed = MAX2(ctx->Texture.NumCurrentTexUsed,
+ unit + 1);
+ texUnit->_BoundTextures |= (1 << texObj->TargetIndex);
+
+
+ /* Pass BindTexture call to device driver */
+ if (ctx->Driver.BindTexture) {
+ ctx->Driver.BindTexture(ctx, unit, texObj->Target, texObj);
+ }
+}
+
+/**
+ * Bind a named texture to the specified texture unit.
+ *
+ * \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 (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+ _mesa_debug(ctx, "glBindTextureUnit %s %d\n",
+ _mesa_lookup_enum_by_nr(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."
+ */
+ if (texture == 0) {
+ unbind_textures_from_unit(ctx, unit);
+ return;
+ }
+
+ /* Get the non-default texture object */
+ texObj = _mesa_lookup_texture(ctx, texture);
+
+ /* Error checking */
+ if (!texObj) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindTextureUnit(non-gen name)");
+ return;
+ }
+ if (texObj->Target == 0) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBindTextureUnit(target)");
+ return;
+ }
+ assert(valid_texture_object(texObj));
+
+ _mesa_bind_texture_unit(ctx, unit, texObj);
+}
+
void GLAPIENTRY
_mesa_BindTextures(GLuint first, GLsizei count, const GLuint *textures)