1 /* $Id: texobj.c,v 1.1 1999/08/19 00:55:41 jtg Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999 Brian Paul All Rights Reserved.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
46 #include "GL/xf86glx.h"
53 * Allocate a new texture object and add it to the linked list of texture
54 * objects. If name>0 then also insert the new texture object into the hash
56 * Input: shared - the shared GL state structure to contain the texture object
57 * name - integer name for the texture object
58 * dimensions - either 1, 2 or 3
59 * Return: pointer to new texture object
61 struct gl_texture_object
*
62 gl_alloc_texture_object( struct gl_shared_state
*shared
, GLuint name
,
65 struct gl_texture_object
*obj
;
67 assert(dimensions
<= 3);
69 obj
= (struct gl_texture_object
*)
70 calloc(1,sizeof(struct gl_texture_object
));
72 /* init the non-zero fields */
74 obj
->Dimensions
= dimensions
;
75 obj
->WrapS
= GL_REPEAT
;
76 obj
->WrapT
= GL_REPEAT
;
77 obj
->MinFilter
= GL_NEAREST_MIPMAP_LINEAR
;
78 obj
->MagFilter
= GL_LINEAR
;
79 obj
->MinLod
= -1000.0;
83 obj
->MinMagThresh
= 0.0F
;
84 obj
->Palette
[0] = 255;
85 obj
->Palette
[1] = 255;
86 obj
->Palette
[2] = 255;
87 obj
->Palette
[3] = 255;
89 obj
->PaletteIntFormat
= GL_RGBA
;
90 obj
->PaletteFormat
= GL_RGBA
;
92 /* insert into linked list */
94 obj
->Next
= shared
->TexObjectList
;
95 shared
->TexObjectList
= obj
;
99 /* insert into hash table */
100 HashInsert(shared
->TexObjects
, name
, obj
);
108 * Deallocate a texture object struct and remove it from the given
110 * Input: shared - the shared GL state to which the object belongs
111 * t - the texture object to delete
113 void gl_free_texture_object( struct gl_shared_state
*shared
,
114 struct gl_texture_object
*t
)
116 struct gl_texture_object
*tprev
, *tcurr
;
120 /* Remove t from dirty list so we don't touch free'd memory later.
121 * Test for shared since Proxy texture aren't in global linked list.
124 gl_remove_texobj_from_dirty_list( shared
, t
);
126 /* unlink t from the linked list */
129 tcurr
= shared
->TexObjectList
;
133 tprev
->Next
= t
->Next
;
136 shared
->TexObjectList
= t
->Next
;
146 /* remove from hash table */
147 HashRemove(shared
->TexObjects
, t
->Name
);
150 /* free texture image */
153 for (i
=0;i
<MAX_TEXTURE_LEVELS
;i
++) {
155 gl_free_texture_image( t
->Image
[i
] );
159 /* free this object */
166 * Examine a texture object to determine if it is complete or not.
167 * The t->Complete flag will be set to GL_TRUE or GL_FALSE accordingly.
169 void gl_test_texture_object_completeness( const GLcontext
*ctx
, struct gl_texture_object
*t
)
171 t
->Complete
= GL_TRUE
; /* be optimistic */
173 /* Always need level zero image */
174 if (!t
->Image
[0] || !t
->Image
[0]->Data
) {
175 t
->Complete
= GL_FALSE
;
179 /* Compute number of mipmap levels */
180 if (t
->Dimensions
==1) {
181 t
->P
= t
->Image
[0]->WidthLog2
;
183 else if (t
->Dimensions
==2) {
184 t
->P
= MAX2(t
->Image
[0]->WidthLog2
, t
->Image
[0]->HeightLog2
);
186 else if (t
->Dimensions
==3) {
187 GLint max
= MAX2(t
->Image
[0]->WidthLog2
, t
->Image
[0]->HeightLog2
);
188 max
= MAX2(max
, (GLint
)(t
->Image
[0]->DepthLog2
));
192 /* Compute M (see the 1.2 spec) used during mipmapping */
193 t
->M
= (GLfloat
) (MIN2(t
->MaxLevel
, t
->P
) - t
->BaseLevel
);
196 if (t
->MinFilter
!=GL_NEAREST
&& t
->MinFilter
!=GL_LINEAR
) {
198 * Mipmapping: determine if we have a complete set of mipmaps
201 GLint minLevel
= t
->BaseLevel
;
202 GLint maxLevel
= MIN2(t
->P
, ctx
->Const
.MaxTextureLevels
-1);
203 maxLevel
= MIN2(maxLevel
, t
->MaxLevel
);
205 if (minLevel
> maxLevel
) {
206 t
->Complete
= GL_FALSE
;
210 /* Test dimension-independent attributes */
211 for (i
= minLevel
; i
<= maxLevel
; i
++) {
213 if (!t
->Image
[i
]->Data
) {
214 t
->Complete
= GL_FALSE
;
217 if (t
->Image
[i
]->Format
!= t
->Image
[0]->Format
) {
218 t
->Complete
= GL_FALSE
;
221 if (t
->Image
[i
]->Border
!= t
->Image
[0]->Border
) {
222 t
->Complete
= GL_FALSE
;
228 /* Test things which depend on number of texture image dimensions */
229 if (t
->Dimensions
==1) {
230 /* Test 1-D mipmaps */
231 GLuint width
= t
->Image
[0]->Width2
;
232 for (i
=1; i
<ctx
->Const
.MaxTextureLevels
; i
++) {
236 if (i
>= minLevel
&& i
<= maxLevel
) {
238 t
->Complete
= GL_FALSE
;
241 if (!t
->Image
[i
]->Data
) {
242 t
->Complete
= GL_FALSE
;
245 if (t
->Image
[i
]->Width2
!= width
) {
246 t
->Complete
= GL_FALSE
;
251 return; /* found smallest needed mipmap, all done! */
255 else if (t
->Dimensions
==2) {
256 /* Test 2-D mipmaps */
257 GLuint width
= t
->Image
[0]->Width2
;
258 GLuint height
= t
->Image
[0]->Height2
;
259 for (i
=1; i
<ctx
->Const
.MaxTextureLevels
; i
++) {
266 if (i
>= minLevel
&& i
<= maxLevel
) {
268 t
->Complete
= GL_FALSE
;
271 if (t
->Image
[i
]->Width2
!= width
) {
272 t
->Complete
= GL_FALSE
;
275 if (t
->Image
[i
]->Height2
!= height
) {
276 t
->Complete
= GL_FALSE
;
279 if (width
==1 && height
==1) {
280 return; /* found smallest needed mipmap, all done! */
285 else if (t
->Dimensions
==3) {
286 /* Test 3-D mipmaps */
287 GLuint width
= t
->Image
[0]->Width2
;
288 GLuint height
= t
->Image
[0]->Height2
;
289 GLuint depth
= t
->Image
[0]->Depth2
;
290 for (i
=1; i
<ctx
->Const
.MaxTextureLevels
; i
++) {
300 if (i
>= minLevel
&& i
<= maxLevel
) {
302 t
->Complete
= GL_FALSE
;
305 if (t
->Image
[i
]->Width2
!= width
) {
306 t
->Complete
= GL_FALSE
;
309 if (t
->Image
[i
]->Height2
!= height
) {
310 t
->Complete
= GL_FALSE
;
313 if (t
->Image
[i
]->Depth2
!= depth
) {
314 t
->Complete
= GL_FALSE
;
318 if (width
==1 && height
==1 && depth
==1) {
319 return; /* found smallest needed mipmap, all done! */
324 /* Dimensions = ??? */
325 gl_problem(NULL
, "Bug in gl_test_texture_object_completeness\n");
333 * Execute glGenTextures
335 void gl_GenTextures( GLcontext
*ctx
, GLsizei n
, GLuint
*texName
)
340 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glGenTextures");
342 gl_error( ctx
, GL_INVALID_VALUE
, "glGenTextures" );
346 first
= HashFindFreeKeyBlock(ctx
->Shared
->TexObjects
, n
);
348 /* Return the texture names */
350 texName
[i
] = first
+ i
;
353 /* Allocate new, empty texture objects */
355 GLuint name
= first
+ i
;
357 (void) gl_alloc_texture_object(ctx
->Shared
, name
, dims
);
364 * Execute glDeleteTextures
366 void gl_DeleteTextures( GLcontext
*ctx
, GLsizei n
, const GLuint
*texName
)
370 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glDeleteTextures");
373 struct gl_texture_object
*t
;
375 t
= (struct gl_texture_object
*)
376 HashLookup(ctx
->Shared
->TexObjects
, texName
[i
]);
379 for (u
=0; u
<MAX_TEXTURE_UNITS
; u
++) {
380 struct gl_texture_unit
*unit
= &ctx
->Texture
.Unit
[u
];
382 for (d
= 1 ; d
<= 3 ; d
++) {
383 if (unit
->CurrentD
[d
]==t
) {
384 unit
->CurrentD
[d
] = ctx
->Shared
->DefaultD
[d
][u
];
385 ctx
->Shared
->DefaultD
[d
][u
]->RefCount
++;
387 assert( t
->RefCount
>= 0 );
392 /* tell device driver to delete texture */
393 if (ctx
->Driver
.DeleteTexture
) {
394 (*ctx
->Driver
.DeleteTexture
)( ctx
, t
);
397 if (t
->RefCount
==0) {
398 gl_free_texture_object(ctx
->Shared
, t
);
408 * Execute glBindTexture
410 void gl_BindTexture( GLcontext
*ctx
, GLenum target
, GLuint texName
)
412 GLuint unit
= ctx
->Texture
.CurrentUnit
;
413 struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[unit
];
414 struct gl_texture_object
*oldTexObj
;
415 struct gl_texture_object
*newTexObj
;
418 if (MESA_VERBOSE
& (VERBOSE_API
|VERBOSE_TEXTURE
))
419 fprintf(stderr
, "glBindTexture %s %d\n",
420 gl_lookup_enum_by_nr(target
), (GLint
) texName
);
422 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glBindTexture");
424 dim
= target
- GL_TEXTURE_1D
;
426 if (dim
< 0 || dim
> 2) {
427 gl_error( ctx
, GL_INVALID_ENUM
, "glBindTexture" );
432 oldTexObj
= texUnit
->CurrentD
[dim
];
434 if (oldTexObj
->Name
== texName
)
438 newTexObj
= ctx
->Shared
->DefaultD
[unit
][dim
];
440 struct HashTable
*hash
= ctx
->Shared
->TexObjects
;
441 newTexObj
= (struct gl_texture_object
*) HashLookup(hash
, texName
);
444 newTexObj
= gl_alloc_texture_object(ctx
->Shared
, texName
, dim
);
446 if (newTexObj
->Dimensions
!= dim
) {
447 if (newTexObj
->Dimensions
) {
448 gl_error( ctx
, GL_INVALID_OPERATION
, "glBindTexture" );
451 newTexObj
->Dimensions
= dim
;
455 oldTexObj
->RefCount
--;
456 newTexObj
->RefCount
++;
457 texUnit
->CurrentD
[dim
] = newTexObj
;
459 /* If we've changed the CurrentD[123] texture object then update the
460 * ctx->Texture.Current pointer to point to the new texture object.
462 texUnit
->Current
= texUnit
->CurrentD
[texUnit
->CurrentDimension
];
464 /* Check if we may have to use a new triangle rasterizer */
465 if ((ctx
->IndirectTriangles
& DD_SW_RASTERIZE
) &&
466 ( oldTexObj
->WrapS
!= newTexObj
->WrapS
467 || oldTexObj
->WrapT
!= newTexObj
->WrapT
468 || oldTexObj
->WrapR
!= newTexObj
->WrapR
469 || oldTexObj
->MinFilter
!= newTexObj
->MinFilter
470 || oldTexObj
->MagFilter
!= newTexObj
->MagFilter
471 || (oldTexObj
->Image
[0] && newTexObj
->Image
[0] &&
472 (oldTexObj
->Image
[0]->Format
!=newTexObj
->Image
[0]->Format
))))
474 ctx
->NewState
|= (NEW_RASTER_OPS
| NEW_TEXTURING
);
477 if (oldTexObj
->Complete
!= newTexObj
->Complete
)
478 ctx
->NewState
|= NEW_TEXTURING
;
480 /* Pass BindTexture call to device driver */
481 if (ctx
->Driver
.BindTexture
) {
482 (*ctx
->Driver
.BindTexture
)( ctx
, target
, newTexObj
);
489 * Execute glPrioritizeTextures
491 void gl_PrioritizeTextures( GLcontext
*ctx
,
492 GLsizei n
, const GLuint
*texName
,
493 const GLclampf
*priorities
)
497 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glPrioritizeTextures");
499 gl_error( ctx
, GL_INVALID_VALUE
, "glPrioritizeTextures" );
504 struct gl_texture_object
*t
;
506 t
= (struct gl_texture_object
*)
507 HashLookup(ctx
->Shared
->TexObjects
, texName
[i
]);
509 t
->Priority
= CLAMP( priorities
[i
], 0.0F
, 1.0F
);
518 * Execute glAreTexturesResident
520 GLboolean
gl_AreTexturesResident( GLcontext
*ctx
, GLsizei n
,
521 const GLuint
*texName
,
522 GLboolean
*residences
)
524 GLboolean resident
= GL_TRUE
;
527 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx
,
528 "glAreTexturesResident",
531 gl_error( ctx
, GL_INVALID_VALUE
, "glAreTexturesResident(n)" );
536 struct gl_texture_object
*t
;
538 gl_error( ctx
, GL_INVALID_VALUE
, "glAreTexturesResident(textures)" );
541 t
= (struct gl_texture_object
*)
542 HashLookup(ctx
->Shared
->TexObjects
, texName
[i
]);
544 /* we consider all valid texture objects to be resident */
545 residences
[i
] = GL_TRUE
;
548 gl_error( ctx
, GL_INVALID_VALUE
, "glAreTexturesResident(textures)" );
558 * Execute glIsTexture
560 GLboolean
gl_IsTexture( GLcontext
*ctx
, GLuint texture
)
562 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx
, "glIsTextures",
564 if (texture
>0 && HashLookup(ctx
->Shared
->TexObjects
, texture
)) {