Cleaning up
[mesa.git] / src / mesa / main / texobj.c
1 /* $Id: texobj.c,v 1.1 1999/08/19 00:55:41 jtg Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.1
6 *
7 * Copyright (C) 1999 Brian Paul All Rights Reserved.
8 *
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:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
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.
25 */
26
27
28
29
30
31 #ifdef PC_HEADER
32 #include "all.h"
33 #else
34 #include <assert.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include "context.h"
38 #include "enums.h"
39 #include "hash.h"
40 #include "macros.h"
41 #include "teximage.h"
42 #include "texstate.h"
43 #include "texobj.h"
44 #include "types.h"
45 #ifdef XFree86Server
46 #include "GL/xf86glx.h"
47 #endif
48 #endif
49
50
51
52 /*
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
55 * table.
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
60 */
61 struct gl_texture_object *
62 gl_alloc_texture_object( struct gl_shared_state *shared, GLuint name,
63 GLuint dimensions)
64 {
65 struct gl_texture_object *obj;
66
67 assert(dimensions <= 3);
68
69 obj = (struct gl_texture_object *)
70 calloc(1,sizeof(struct gl_texture_object));
71 if (obj) {
72 /* init the non-zero fields */
73 obj->Name = name;
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;
80 obj->MaxLod = 1000.0;
81 obj->BaseLevel = 0;
82 obj->MaxLevel = 1000;
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;
88 obj->PaletteSize = 1;
89 obj->PaletteIntFormat = GL_RGBA;
90 obj->PaletteFormat = GL_RGBA;
91
92 /* insert into linked list */
93 if (shared) {
94 obj->Next = shared->TexObjectList;
95 shared->TexObjectList = obj;
96 }
97
98 if (name > 0) {
99 /* insert into hash table */
100 HashInsert(shared->TexObjects, name, obj);
101 }
102 }
103 return obj;
104 }
105
106
107 /*
108 * Deallocate a texture object struct and remove it from the given
109 * shared GL state.
110 * Input: shared - the shared GL state to which the object belongs
111 * t - the texture object to delete
112 */
113 void gl_free_texture_object( struct gl_shared_state *shared,
114 struct gl_texture_object *t )
115 {
116 struct gl_texture_object *tprev, *tcurr;
117
118 assert(t);
119
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.
122 */
123 if (shared)
124 gl_remove_texobj_from_dirty_list( shared, t );
125
126 /* unlink t from the linked list */
127 if (shared) {
128 tprev = NULL;
129 tcurr = shared->TexObjectList;
130 while (tcurr) {
131 if (tcurr==t) {
132 if (tprev) {
133 tprev->Next = t->Next;
134 }
135 else {
136 shared->TexObjectList = t->Next;
137 }
138 break;
139 }
140 tprev = tcurr;
141 tcurr = tcurr->Next;
142 }
143 }
144
145 if (t->Name) {
146 /* remove from hash table */
147 HashRemove(shared->TexObjects, t->Name);
148 }
149
150 /* free texture image */
151 {
152 GLuint i;
153 for (i=0;i<MAX_TEXTURE_LEVELS;i++) {
154 if (t->Image[i]) {
155 gl_free_texture_image( t->Image[i] );
156 }
157 }
158 }
159 /* free this object */
160 free( t );
161 }
162
163
164
165 /*
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.
168 */
169 void gl_test_texture_object_completeness( const GLcontext *ctx, struct gl_texture_object *t )
170 {
171 t->Complete = GL_TRUE; /* be optimistic */
172
173 /* Always need level zero image */
174 if (!t->Image[0] || !t->Image[0]->Data) {
175 t->Complete = GL_FALSE;
176 return;
177 }
178
179 /* Compute number of mipmap levels */
180 if (t->Dimensions==1) {
181 t->P = t->Image[0]->WidthLog2;
182 }
183 else if (t->Dimensions==2) {
184 t->P = MAX2(t->Image[0]->WidthLog2, t->Image[0]->HeightLog2);
185 }
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));
189 t->P = max;
190 }
191
192 /* Compute M (see the 1.2 spec) used during mipmapping */
193 t->M = (GLfloat) (MIN2(t->MaxLevel, t->P) - t->BaseLevel);
194
195
196 if (t->MinFilter!=GL_NEAREST && t->MinFilter!=GL_LINEAR) {
197 /*
198 * Mipmapping: determine if we have a complete set of mipmaps
199 */
200 GLint i;
201 GLint minLevel = t->BaseLevel;
202 GLint maxLevel = MIN2(t->P, ctx->Const.MaxTextureLevels-1);
203 maxLevel = MIN2(maxLevel, t->MaxLevel);
204
205 if (minLevel > maxLevel) {
206 t->Complete = GL_FALSE;
207 return;
208 }
209
210 /* Test dimension-independent attributes */
211 for (i = minLevel; i <= maxLevel; i++) {
212 if (t->Image[i]) {
213 if (!t->Image[i]->Data) {
214 t->Complete = GL_FALSE;
215 return;
216 }
217 if (t->Image[i]->Format != t->Image[0]->Format) {
218 t->Complete = GL_FALSE;
219 return;
220 }
221 if (t->Image[i]->Border != t->Image[0]->Border) {
222 t->Complete = GL_FALSE;
223 return;
224 }
225 }
226 }
227
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++) {
233 if (width>1) {
234 width /= 2;
235 }
236 if (i >= minLevel && i <= maxLevel) {
237 if (!t->Image[i]) {
238 t->Complete = GL_FALSE;
239 return;
240 }
241 if (!t->Image[i]->Data) {
242 t->Complete = GL_FALSE;
243 return;
244 }
245 if (t->Image[i]->Width2 != width ) {
246 t->Complete = GL_FALSE;
247 return;
248 }
249 }
250 if (width==1) {
251 return; /* found smallest needed mipmap, all done! */
252 }
253 }
254 }
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++) {
260 if (width>1) {
261 width /= 2;
262 }
263 if (height>1) {
264 height /= 2;
265 }
266 if (i >= minLevel && i <= maxLevel) {
267 if (!t->Image[i]) {
268 t->Complete = GL_FALSE;
269 return;
270 }
271 if (t->Image[i]->Width2 != width) {
272 t->Complete = GL_FALSE;
273 return;
274 }
275 if (t->Image[i]->Height2 != height) {
276 t->Complete = GL_FALSE;
277 return;
278 }
279 if (width==1 && height==1) {
280 return; /* found smallest needed mipmap, all done! */
281 }
282 }
283 }
284 }
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++) {
291 if (width>1) {
292 width /= 2;
293 }
294 if (height>1) {
295 height /= 2;
296 }
297 if (depth>1) {
298 depth /= 2;
299 }
300 if (i >= minLevel && i <= maxLevel) {
301 if (!t->Image[i]) {
302 t->Complete = GL_FALSE;
303 return;
304 }
305 if (t->Image[i]->Width2 != width) {
306 t->Complete = GL_FALSE;
307 return;
308 }
309 if (t->Image[i]->Height2 != height) {
310 t->Complete = GL_FALSE;
311 return;
312 }
313 if (t->Image[i]->Depth2 != depth) {
314 t->Complete = GL_FALSE;
315 return;
316 }
317 }
318 if (width==1 && height==1 && depth==1) {
319 return; /* found smallest needed mipmap, all done! */
320 }
321 }
322 }
323 else {
324 /* Dimensions = ??? */
325 gl_problem(NULL, "Bug in gl_test_texture_object_completeness\n");
326 }
327 }
328 }
329
330
331
332 /*
333 * Execute glGenTextures
334 */
335 void gl_GenTextures( GLcontext *ctx, GLsizei n, GLuint *texName )
336 {
337 GLuint first;
338 GLint i;
339
340 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGenTextures");
341 if (n<0) {
342 gl_error( ctx, GL_INVALID_VALUE, "glGenTextures" );
343 return;
344 }
345
346 first = HashFindFreeKeyBlock(ctx->Shared->TexObjects, n);
347
348 /* Return the texture names */
349 for (i=0;i<n;i++) {
350 texName[i] = first + i;
351 }
352
353 /* Allocate new, empty texture objects */
354 for (i=0;i<n;i++) {
355 GLuint name = first + i;
356 GLuint dims = 0;
357 (void) gl_alloc_texture_object(ctx->Shared, name, dims);
358 }
359 }
360
361
362
363 /*
364 * Execute glDeleteTextures
365 */
366 void gl_DeleteTextures( GLcontext *ctx, GLsizei n, const GLuint *texName)
367 {
368 GLint i;
369
370 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDeleteTextures");
371
372 for (i=0;i<n;i++) {
373 struct gl_texture_object *t;
374 if (texName[i]>0) {
375 t = (struct gl_texture_object *)
376 HashLookup(ctx->Shared->TexObjects, texName[i]);
377 if (t) {
378 GLuint u;
379 for (u=0; u<MAX_TEXTURE_UNITS; u++) {
380 struct gl_texture_unit *unit = &ctx->Texture.Unit[u];
381 GLuint d;
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++;
386 t->RefCount--;
387 assert( t->RefCount >= 0 );
388 }
389 }
390 }
391
392 /* tell device driver to delete texture */
393 if (ctx->Driver.DeleteTexture) {
394 (*ctx->Driver.DeleteTexture)( ctx, t );
395 }
396
397 if (t->RefCount==0) {
398 gl_free_texture_object(ctx->Shared, t);
399 }
400 }
401 }
402 }
403 }
404
405
406
407 /*
408 * Execute glBindTexture
409 */
410 void gl_BindTexture( GLcontext *ctx, GLenum target, GLuint texName )
411 {
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;
416 GLint dim;
417
418 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
419 fprintf(stderr, "glBindTexture %s %d\n",
420 gl_lookup_enum_by_nr(target), (GLint) texName);
421
422 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glBindTexture");
423
424 dim = target - GL_TEXTURE_1D;
425
426 if (dim < 0 || dim > 2) {
427 gl_error( ctx, GL_INVALID_ENUM, "glBindTexture" );
428 return;
429 }
430
431 dim++;
432 oldTexObj = texUnit->CurrentD[dim];
433
434 if (oldTexObj->Name == texName)
435 return;
436
437 if (texName == 0)
438 newTexObj = ctx->Shared->DefaultD[unit][dim];
439 else {
440 struct HashTable *hash = ctx->Shared->TexObjects;
441 newTexObj = (struct gl_texture_object *) HashLookup(hash, texName);
442
443 if (!newTexObj)
444 newTexObj = gl_alloc_texture_object(ctx->Shared, texName, dim);
445
446 if (newTexObj->Dimensions != dim) {
447 if (newTexObj->Dimensions) {
448 gl_error( ctx, GL_INVALID_OPERATION, "glBindTexture" );
449 return;
450 }
451 newTexObj->Dimensions = dim;
452 }
453 }
454
455 oldTexObj->RefCount--;
456 newTexObj->RefCount++;
457 texUnit->CurrentD[dim] = newTexObj;
458
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.
461 */
462 texUnit->Current = texUnit->CurrentD[texUnit->CurrentDimension];
463
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))))
473 {
474 ctx->NewState |= (NEW_RASTER_OPS | NEW_TEXTURING);
475 }
476
477 if (oldTexObj->Complete != newTexObj->Complete)
478 ctx->NewState |= NEW_TEXTURING;
479
480 /* Pass BindTexture call to device driver */
481 if (ctx->Driver.BindTexture) {
482 (*ctx->Driver.BindTexture)( ctx, target, newTexObj );
483 }
484 }
485
486
487
488 /*
489 * Execute glPrioritizeTextures
490 */
491 void gl_PrioritizeTextures( GLcontext *ctx,
492 GLsizei n, const GLuint *texName,
493 const GLclampf *priorities )
494 {
495 GLint i;
496
497 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glPrioritizeTextures");
498 if (n<0) {
499 gl_error( ctx, GL_INVALID_VALUE, "glPrioritizeTextures" );
500 return;
501 }
502
503 for (i=0;i<n;i++) {
504 struct gl_texture_object *t;
505 if (texName[i]>0) {
506 t = (struct gl_texture_object *)
507 HashLookup(ctx->Shared->TexObjects, texName[i]);
508 if (t) {
509 t->Priority = CLAMP( priorities[i], 0.0F, 1.0F );
510 }
511 }
512 }
513 }
514
515
516
517 /*
518 * Execute glAreTexturesResident
519 */
520 GLboolean gl_AreTexturesResident( GLcontext *ctx, GLsizei n,
521 const GLuint *texName,
522 GLboolean *residences )
523 {
524 GLboolean resident = GL_TRUE;
525 GLint i;
526
527 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx,
528 "glAreTexturesResident",
529 GL_FALSE);
530 if (n<0) {
531 gl_error( ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)" );
532 return GL_FALSE;
533 }
534
535 for (i=0;i<n;i++) {
536 struct gl_texture_object *t;
537 if (texName[i]==0) {
538 gl_error( ctx, GL_INVALID_VALUE, "glAreTexturesResident(textures)" );
539 return GL_FALSE;
540 }
541 t = (struct gl_texture_object *)
542 HashLookup(ctx->Shared->TexObjects, texName[i]);
543 if (t) {
544 /* we consider all valid texture objects to be resident */
545 residences[i] = GL_TRUE;
546 }
547 else {
548 gl_error( ctx, GL_INVALID_VALUE, "glAreTexturesResident(textures)" );
549 return GL_FALSE;
550 }
551 }
552 return resident;
553 }
554
555
556
557 /*
558 * Execute glIsTexture
559 */
560 GLboolean gl_IsTexture( GLcontext *ctx, GLuint texture )
561 {
562 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx, "glIsTextures",
563 GL_FALSE);
564 if (texture>0 && HashLookup(ctx->Shared->TexObjects, texture)) {
565 return GL_TRUE;
566 }
567 else {
568 return GL_FALSE;
569 }
570 }
571