summaryrefslogtreecommitdiff
path: root/src/mesa/main/texobj.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/main/texobj.c')
-rw-r--r--src/mesa/main/texobj.c571
1 files changed, 571 insertions, 0 deletions
diff --git a/src/mesa/main/texobj.c b/src/mesa/main/texobj.c
new file mode 100644
index 0000000000..78691d24f2
--- /dev/null
+++ b/src/mesa/main/texobj.c
@@ -0,0 +1,571 @@
+/* $Id: texobj.c,v 1.1 1999/08/19 00:55:41 jtg Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.1
+ *
+ * Copyright (C) 1999 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+
+
+
+#ifdef PC_HEADER
+#include "all.h"
+#else
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "context.h"
+#include "enums.h"
+#include "hash.h"
+#include "macros.h"
+#include "teximage.h"
+#include "texstate.h"
+#include "texobj.h"
+#include "types.h"
+#ifdef XFree86Server
+#include "GL/xf86glx.h"
+#endif
+#endif
+
+
+
+/*
+ * Allocate a new texture object and add it to the linked list of texture
+ * objects. If name>0 then also insert the new texture object into the hash
+ * table.
+ * Input: shared - the shared GL state structure to contain the texture object
+ * name - integer name for the texture object
+ * dimensions - either 1, 2 or 3
+ * Return: pointer to new texture object
+ */
+struct gl_texture_object *
+gl_alloc_texture_object( struct gl_shared_state *shared, GLuint name,
+ GLuint dimensions)
+{
+ struct gl_texture_object *obj;
+
+ assert(dimensions <= 3);
+
+ obj = (struct gl_texture_object *)
+ calloc(1,sizeof(struct gl_texture_object));
+ if (obj) {
+ /* init the non-zero fields */
+ obj->Name = name;
+ obj->Dimensions = dimensions;
+ obj->WrapS = GL_REPEAT;
+ obj->WrapT = GL_REPEAT;
+ obj->MinFilter = GL_NEAREST_MIPMAP_LINEAR;
+ obj->MagFilter = GL_LINEAR;
+ obj->MinLod = -1000.0;
+ obj->MaxLod = 1000.0;
+ obj->BaseLevel = 0;
+ obj->MaxLevel = 1000;
+ obj->MinMagThresh = 0.0F;
+ obj->Palette[0] = 255;
+ obj->Palette[1] = 255;
+ obj->Palette[2] = 255;
+ obj->Palette[3] = 255;
+ obj->PaletteSize = 1;
+ obj->PaletteIntFormat = GL_RGBA;
+ obj->PaletteFormat = GL_RGBA;
+
+ /* insert into linked list */
+ if (shared) {
+ obj->Next = shared->TexObjectList;
+ shared->TexObjectList = obj;
+ }
+
+ if (name > 0) {
+ /* insert into hash table */
+ HashInsert(shared->TexObjects, name, obj);
+ }
+ }
+ return obj;
+}
+
+
+/*
+ * Deallocate a texture object struct and remove it from the given
+ * shared GL state.
+ * Input: shared - the shared GL state to which the object belongs
+ * t - the texture object to delete
+ */
+void gl_free_texture_object( struct gl_shared_state *shared,
+ struct gl_texture_object *t )
+{
+ struct gl_texture_object *tprev, *tcurr;
+
+ assert(t);
+
+ /* Remove t from dirty list so we don't touch free'd memory later.
+ * Test for shared since Proxy texture aren't in global linked list.
+ */
+ if (shared)
+ gl_remove_texobj_from_dirty_list( shared, t );
+
+ /* unlink t from the linked list */
+ if (shared) {
+ tprev = NULL;
+ tcurr = shared->TexObjectList;
+ while (tcurr) {
+ if (tcurr==t) {
+ if (tprev) {
+ tprev->Next = t->Next;
+ }
+ else {
+ shared->TexObjectList = t->Next;
+ }
+ break;
+ }
+ tprev = tcurr;
+ tcurr = tcurr->Next;
+ }
+ }
+
+ if (t->Name) {
+ /* remove from hash table */
+ HashRemove(shared->TexObjects, t->Name);
+ }
+
+ /* free texture image */
+ {
+ GLuint i;
+ for (i=0;i<MAX_TEXTURE_LEVELS;i++) {
+ if (t->Image[i]) {
+ gl_free_texture_image( t->Image[i] );
+ }
+ }
+ }
+ /* free this object */
+ free( t );
+}
+
+
+
+/*
+ * Examine a texture object to determine if it is complete or not.
+ * The t->Complete flag will be set to GL_TRUE or GL_FALSE accordingly.
+ */
+void gl_test_texture_object_completeness( const GLcontext *ctx, struct gl_texture_object *t )
+{
+ t->Complete = GL_TRUE; /* be optimistic */
+
+ /* Always need level zero image */
+ if (!t->Image[0] || !t->Image[0]->Data) {
+ t->Complete = GL_FALSE;
+ return;
+ }
+
+ /* Compute number of mipmap levels */
+ if (t->Dimensions==1) {
+ t->P = t->Image[0]->WidthLog2;
+ }
+ else if (t->Dimensions==2) {
+ t->P = MAX2(t->Image[0]->WidthLog2, t->Image[0]->HeightLog2);
+ }
+ else if (t->Dimensions==3) {
+ GLint max = MAX2(t->Image[0]->WidthLog2, t->Image[0]->HeightLog2);
+ max = MAX2(max, (GLint)(t->Image[0]->DepthLog2));
+ t->P = max;
+ }
+
+ /* Compute M (see the 1.2 spec) used during mipmapping */
+ t->M = (GLfloat) (MIN2(t->MaxLevel, t->P) - t->BaseLevel);
+
+
+ if (t->MinFilter!=GL_NEAREST && t->MinFilter!=GL_LINEAR) {
+ /*
+ * Mipmapping: determine if we have a complete set of mipmaps
+ */
+ GLint i;
+ GLint minLevel = t->BaseLevel;
+ GLint maxLevel = MIN2(t->P, ctx->Const.MaxTextureLevels-1);
+ maxLevel = MIN2(maxLevel, t->MaxLevel);
+
+ if (minLevel > maxLevel) {
+ t->Complete = GL_FALSE;
+ return;
+ }
+
+ /* Test dimension-independent attributes */
+ for (i = minLevel; i <= maxLevel; i++) {
+ if (t->Image[i]) {
+ if (!t->Image[i]->Data) {
+ t->Complete = GL_FALSE;
+ return;
+ }
+ if (t->Image[i]->Format != t->Image[0]->Format) {
+ t->Complete = GL_FALSE;
+ return;
+ }
+ if (t->Image[i]->Border != t->Image[0]->Border) {
+ t->Complete = GL_FALSE;
+ return;
+ }
+ }
+ }
+
+ /* Test things which depend on number of texture image dimensions */
+ if (t->Dimensions==1) {
+ /* Test 1-D mipmaps */
+ GLuint width = t->Image[0]->Width2;
+ for (i=1; i<ctx->Const.MaxTextureLevels; i++) {
+ if (width>1) {
+ width /= 2;
+ }
+ if (i >= minLevel && i <= maxLevel) {
+ if (!t->Image[i]) {
+ t->Complete = GL_FALSE;
+ return;
+ }
+ if (!t->Image[i]->Data) {
+ t->Complete = GL_FALSE;
+ return;
+ }
+ if (t->Image[i]->Width2 != width ) {
+ t->Complete = GL_FALSE;
+ return;
+ }
+ }
+ if (width==1) {
+ return; /* found smallest needed mipmap, all done! */
+ }
+ }
+ }
+ else if (t->Dimensions==2) {
+ /* Test 2-D mipmaps */
+ GLuint width = t->Image[0]->Width2;
+ GLuint height = t->Image[0]->Height2;
+ for (i=1; i<ctx->Const.MaxTextureLevels; i++) {
+ if (width>1) {
+ width /= 2;
+ }
+ if (height>1) {
+ height /= 2;
+ }
+ if (i >= minLevel && i <= maxLevel) {
+ if (!t->Image[i]) {
+ t->Complete = GL_FALSE;
+ return;
+ }
+ if (t->Image[i]->Width2 != width) {
+ t->Complete = GL_FALSE;
+ return;
+ }
+ if (t->Image[i]->Height2 != height) {
+ t->Complete = GL_FALSE;
+ return;
+ }
+ if (width==1 && height==1) {
+ return; /* found smallest needed mipmap, all done! */
+ }
+ }
+ }
+ }
+ else if (t->Dimensions==3) {
+ /* Test 3-D mipmaps */
+ GLuint width = t->Image[0]->Width2;
+ GLuint height = t->Image[0]->Height2;
+ GLuint depth = t->Image[0]->Depth2;
+ for (i=1; i<ctx->Const.MaxTextureLevels; i++) {
+ if (width>1) {
+ width /= 2;
+ }
+ if (height>1) {
+ height /= 2;
+ }
+ if (depth>1) {
+ depth /= 2;
+ }
+ if (i >= minLevel && i <= maxLevel) {
+ if (!t->Image[i]) {
+ t->Complete = GL_FALSE;
+ return;
+ }
+ if (t->Image[i]->Width2 != width) {
+ t->Complete = GL_FALSE;
+ return;
+ }
+ if (t->Image[i]->Height2 != height) {
+ t->Complete = GL_FALSE;
+ return;
+ }
+ if (t->Image[i]->Depth2 != depth) {
+ t->Complete = GL_FALSE;
+ return;
+ }
+ }
+ if (width==1 && height==1 && depth==1) {
+ return; /* found smallest needed mipmap, all done! */
+ }
+ }
+ }
+ else {
+ /* Dimensions = ??? */
+ gl_problem(NULL, "Bug in gl_test_texture_object_completeness\n");
+ }
+ }
+}
+
+
+
+/*
+ * Execute glGenTextures
+ */
+void gl_GenTextures( GLcontext *ctx, GLsizei n, GLuint *texName )
+{
+ GLuint first;
+ GLint i;
+
+ ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGenTextures");
+ if (n<0) {
+ gl_error( ctx, GL_INVALID_VALUE, "glGenTextures" );
+ return;
+ }
+
+ first = HashFindFreeKeyBlock(ctx->Shared->TexObjects, n);
+
+ /* Return the texture names */
+ for (i=0;i<n;i++) {
+ texName[i] = first + i;
+ }
+
+ /* Allocate new, empty texture objects */
+ for (i=0;i<n;i++) {
+ GLuint name = first + i;
+ GLuint dims = 0;
+ (void) gl_alloc_texture_object(ctx->Shared, name, dims);
+ }
+}
+
+
+
+/*
+ * Execute glDeleteTextures
+ */
+void gl_DeleteTextures( GLcontext *ctx, GLsizei n, const GLuint *texName)
+{
+ GLint i;
+
+ ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDeleteTextures");
+
+ for (i=0;i<n;i++) {
+ struct gl_texture_object *t;
+ if (texName[i]>0) {
+ t = (struct gl_texture_object *)
+ HashLookup(ctx->Shared->TexObjects, texName[i]);
+ if (t) {
+ GLuint u;
+ for (u=0; u<MAX_TEXTURE_UNITS; u++) {
+ struct gl_texture_unit *unit = &ctx->Texture.Unit[u];
+ GLuint d;
+ for (d = 1 ; d <= 3 ; d++) {
+ if (unit->CurrentD[d]==t) {
+ unit->CurrentD[d] = ctx->Shared->DefaultD[d][u];
+ ctx->Shared->DefaultD[d][u]->RefCount++;
+ t->RefCount--;
+ assert( t->RefCount >= 0 );
+ }
+ }
+ }
+
+ /* tell device driver to delete texture */
+ if (ctx->Driver.DeleteTexture) {
+ (*ctx->Driver.DeleteTexture)( ctx, t );
+ }
+
+ if (t->RefCount==0) {
+ gl_free_texture_object(ctx->Shared, t);
+ }
+ }
+ }
+ }
+}
+
+
+
+/*
+ * Execute glBindTexture
+ */
+void gl_BindTexture( GLcontext *ctx, GLenum target, GLuint texName )
+{
+ GLuint unit = ctx->Texture.CurrentUnit;
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+ struct gl_texture_object *oldTexObj;
+ struct gl_texture_object *newTexObj;
+ GLint dim;
+
+ if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+ fprintf(stderr, "glBindTexture %s %d\n",
+ gl_lookup_enum_by_nr(target), (GLint) texName);
+
+ ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glBindTexture");
+
+ dim = target - GL_TEXTURE_1D;
+
+ if (dim < 0 || dim > 2) {
+ gl_error( ctx, GL_INVALID_ENUM, "glBindTexture" );
+ return;
+ }
+
+ dim++;
+ oldTexObj = texUnit->CurrentD[dim];
+
+ if (oldTexObj->Name == texName)
+ return;
+
+ if (texName == 0)
+ newTexObj = ctx->Shared->DefaultD[unit][dim];
+ else {
+ struct HashTable *hash = ctx->Shared->TexObjects;
+ newTexObj = (struct gl_texture_object *) HashLookup(hash, texName);
+
+ if (!newTexObj)
+ newTexObj = gl_alloc_texture_object(ctx->Shared, texName, dim);
+
+ if (newTexObj->Dimensions != dim) {
+ if (newTexObj->Dimensions) {
+ gl_error( ctx, GL_INVALID_OPERATION, "glBindTexture" );
+ return;
+ }
+ newTexObj->Dimensions = dim;
+ }
+ }
+
+ oldTexObj->RefCount--;
+ newTexObj->RefCount++;
+ texUnit->CurrentD[dim] = newTexObj;
+
+ /* If we've changed the CurrentD[123] texture object then update the
+ * ctx->Texture.Current pointer to point to the new texture object.
+ */
+ texUnit->Current = texUnit->CurrentD[texUnit->CurrentDimension];
+
+ /* Check if we may have to use a new triangle rasterizer */
+ if ((ctx->IndirectTriangles & DD_SW_RASTERIZE) &&
+ ( oldTexObj->WrapS != newTexObj->WrapS
+ || oldTexObj->WrapT != newTexObj->WrapT
+ || oldTexObj->WrapR != newTexObj->WrapR
+ || oldTexObj->MinFilter != newTexObj->MinFilter
+ || oldTexObj->MagFilter != newTexObj->MagFilter
+ || (oldTexObj->Image[0] && newTexObj->Image[0] &&
+ (oldTexObj->Image[0]->Format!=newTexObj->Image[0]->Format))))
+ {
+ ctx->NewState |= (NEW_RASTER_OPS | NEW_TEXTURING);
+ }
+
+ if (oldTexObj->Complete != newTexObj->Complete)
+ ctx->NewState |= NEW_TEXTURING;
+
+ /* Pass BindTexture call to device driver */
+ if (ctx->Driver.BindTexture) {
+ (*ctx->Driver.BindTexture)( ctx, target, newTexObj );
+ }
+}
+
+
+
+/*
+ * Execute glPrioritizeTextures
+ */
+void gl_PrioritizeTextures( GLcontext *ctx,
+ GLsizei n, const GLuint *texName,
+ const GLclampf *priorities )
+{
+ GLint i;
+
+ ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glPrioritizeTextures");
+ if (n<0) {
+ gl_error( ctx, GL_INVALID_VALUE, "glPrioritizeTextures" );
+ return;
+ }
+
+ for (i=0;i<n;i++) {
+ struct gl_texture_object *t;
+ if (texName[i]>0) {
+ t = (struct gl_texture_object *)
+ HashLookup(ctx->Shared->TexObjects, texName[i]);
+ if (t) {
+ t->Priority = CLAMP( priorities[i], 0.0F, 1.0F );
+ }
+ }
+ }
+}
+
+
+
+/*
+ * Execute glAreTexturesResident
+ */
+GLboolean gl_AreTexturesResident( GLcontext *ctx, GLsizei n,
+ const GLuint *texName,
+ GLboolean *residences )
+{
+ GLboolean resident = GL_TRUE;
+ GLint i;
+
+ ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx,
+ "glAreTexturesResident",
+ GL_FALSE);
+ if (n<0) {
+ gl_error( ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)" );
+ return GL_FALSE;
+ }
+
+ for (i=0;i<n;i++) {
+ struct gl_texture_object *t;
+ if (texName[i]==0) {
+ gl_error( ctx, GL_INVALID_VALUE, "glAreTexturesResident(textures)" );
+ return GL_FALSE;
+ }
+ t = (struct gl_texture_object *)
+ HashLookup(ctx->Shared->TexObjects, texName[i]);
+ if (t) {
+ /* we consider all valid texture objects to be resident */
+ residences[i] = GL_TRUE;
+ }
+ else {
+ gl_error( ctx, GL_INVALID_VALUE, "glAreTexturesResident(textures)" );
+ return GL_FALSE;
+ }
+ }
+ return resident;
+}
+
+
+
+/*
+ * Execute glIsTexture
+ */
+GLboolean gl_IsTexture( GLcontext *ctx, GLuint texture )
+{
+ ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx, "glIsTextures",
+ GL_FALSE);
+ if (texture>0 && HashLookup(ctx->Shared->TexObjects, texture)) {
+ return GL_TRUE;
+ }
+ else {
+ return GL_FALSE;
+ }
+}
+