changed a warning string
[mesa.git] / src / mesa / main / texobj.c
1 /* $Id: texobj.c,v 1.8 1999/11/11 01:22:28 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.3
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 #ifdef PC_HEADER
29 #include "all.h"
30 #else
31 #include "glheader.h"
32 #include "context.h"
33 #include "enums.h"
34 #include "hash.h"
35 #include "mem.h"
36 #include "teximage.h"
37 #include "texstate.h"
38 #include "texobj.h"
39 #include "types.h"
40 #endif
41
42
43
44 /*
45 * Allocate a new texture object and add it to the linked list of texture
46 * objects. If name>0 then also insert the new texture object into the hash
47 * table.
48 * Input: shared - the shared GL state structure to contain the texture object
49 * name - integer name for the texture object
50 * dimensions - either 1, 2 or 3
51 * Return: pointer to new texture object
52 */
53 struct gl_texture_object *
54 gl_alloc_texture_object( struct gl_shared_state *shared, GLuint name,
55 GLuint dimensions)
56 {
57 struct gl_texture_object *obj;
58
59 assert(dimensions <= 3);
60
61 obj = (struct gl_texture_object *)
62 calloc(1,sizeof(struct gl_texture_object));
63 if (obj) {
64 /* init the non-zero fields */
65 obj->RefCount = 1;
66 obj->Name = name;
67 obj->Dimensions = dimensions;
68 obj->WrapS = GL_REPEAT;
69 obj->WrapT = GL_REPEAT;
70 obj->MinFilter = GL_NEAREST_MIPMAP_LINEAR;
71 obj->MagFilter = GL_LINEAR;
72 obj->MinLod = -1000.0;
73 obj->MaxLod = 1000.0;
74 obj->BaseLevel = 0;
75 obj->MaxLevel = 1000;
76 obj->MinMagThresh = 0.0F;
77 obj->Palette.Table[0] = 255;
78 obj->Palette.Table[1] = 255;
79 obj->Palette.Table[2] = 255;
80 obj->Palette.Table[3] = 255;
81 obj->Palette.Size = 1;
82 obj->Palette.IntFormat = GL_RGBA;
83 obj->Palette.Format = GL_RGBA;
84
85 /* insert into linked list */
86 if (shared) {
87 obj->Next = shared->TexObjectList;
88 shared->TexObjectList = obj;
89 }
90
91 if (name > 0) {
92 /* insert into hash table */
93 HashInsert(shared->TexObjects, name, obj);
94 }
95 }
96 return obj;
97 }
98
99
100 /*
101 * Deallocate a texture object struct and remove it from the given
102 * shared GL state.
103 * Input: shared - the shared GL state to which the object belongs
104 * t - the texture object to delete
105 */
106 void gl_free_texture_object( struct gl_shared_state *shared,
107 struct gl_texture_object *t )
108 {
109 struct gl_texture_object *tprev, *tcurr;
110
111 assert(t);
112
113 /* Remove t from dirty list so we don't touch free'd memory later.
114 * Test for shared since Proxy texture aren't in global linked list.
115 */
116 if (shared)
117 gl_remove_texobj_from_dirty_list( shared, t );
118
119 /* unlink t from the linked list */
120 if (shared) {
121 tprev = NULL;
122 tcurr = shared->TexObjectList;
123 while (tcurr) {
124 if (tcurr==t) {
125 if (tprev) {
126 tprev->Next = t->Next;
127 }
128 else {
129 shared->TexObjectList = t->Next;
130 }
131 break;
132 }
133 tprev = tcurr;
134 tcurr = tcurr->Next;
135 }
136 }
137
138 if (t->Name) {
139 /* remove from hash table */
140 HashRemove(shared->TexObjects, t->Name);
141 }
142
143 /* free texture image */
144 {
145 GLuint i;
146 for (i=0;i<MAX_TEXTURE_LEVELS;i++) {
147 if (t->Image[i]) {
148 gl_free_texture_image( t->Image[i] );
149 }
150 }
151 }
152 /* free this object */
153 FREE( t );
154 }
155
156
157
158 /*
159 * Examine a texture object to determine if it is complete or not.
160 * The t->Complete flag will be set to GL_TRUE or GL_FALSE accordingly.
161 */
162 void gl_test_texture_object_completeness( const GLcontext *ctx, struct gl_texture_object *t )
163 {
164 t->Complete = GL_TRUE; /* be optimistic */
165
166 /* Always need level zero image */
167 if (!t->Image[0] || !t->Image[0]->Data) {
168 t->Complete = GL_FALSE;
169 return;
170 }
171
172 /* Compute number of mipmap levels */
173 if (t->Dimensions==1) {
174 t->P = t->Image[0]->WidthLog2;
175 }
176 else if (t->Dimensions==2) {
177 t->P = MAX2(t->Image[0]->WidthLog2, t->Image[0]->HeightLog2);
178 }
179 else if (t->Dimensions==3) {
180 GLint max = MAX2(t->Image[0]->WidthLog2, t->Image[0]->HeightLog2);
181 max = MAX2(max, (GLint)(t->Image[0]->DepthLog2));
182 t->P = max;
183 }
184
185 /* Compute M (see the 1.2 spec) used during mipmapping */
186 t->M = (GLfloat) (MIN2(t->MaxLevel, t->P) - t->BaseLevel);
187
188
189 if (t->MinFilter!=GL_NEAREST && t->MinFilter!=GL_LINEAR) {
190 /*
191 * Mipmapping: determine if we have a complete set of mipmaps
192 */
193 GLint i;
194 GLint minLevel = t->BaseLevel;
195 GLint maxLevel = MIN2(t->P, ctx->Const.MaxTextureLevels-1);
196 maxLevel = MIN2(maxLevel, t->MaxLevel);
197
198 if (minLevel > maxLevel) {
199 t->Complete = GL_FALSE;
200 return;
201 }
202
203 /* Test dimension-independent attributes */
204 for (i = minLevel; i <= maxLevel; i++) {
205 if (t->Image[i]) {
206 if (!t->Image[i]->Data) {
207 t->Complete = GL_FALSE;
208 return;
209 }
210 if (t->Image[i]->Format != t->Image[0]->Format) {
211 t->Complete = GL_FALSE;
212 return;
213 }
214 if (t->Image[i]->Border != t->Image[0]->Border) {
215 t->Complete = GL_FALSE;
216 return;
217 }
218 }
219 }
220
221 /* Test things which depend on number of texture image dimensions */
222 if (t->Dimensions==1) {
223 /* Test 1-D mipmaps */
224 GLuint width = t->Image[0]->Width2;
225 for (i=1; i<ctx->Const.MaxTextureLevels; i++) {
226 if (width>1) {
227 width /= 2;
228 }
229 if (i >= minLevel && i <= maxLevel) {
230 if (!t->Image[i]) {
231 t->Complete = GL_FALSE;
232 return;
233 }
234 if (!t->Image[i]->Data) {
235 t->Complete = GL_FALSE;
236 return;
237 }
238 if (t->Image[i]->Width2 != width ) {
239 t->Complete = GL_FALSE;
240 return;
241 }
242 }
243 if (width==1) {
244 return; /* found smallest needed mipmap, all done! */
245 }
246 }
247 }
248 else if (t->Dimensions==2) {
249 /* Test 2-D mipmaps */
250 GLuint width = t->Image[0]->Width2;
251 GLuint height = t->Image[0]->Height2;
252 for (i=1; i<ctx->Const.MaxTextureLevels; i++) {
253 if (width>1) {
254 width /= 2;
255 }
256 if (height>1) {
257 height /= 2;
258 }
259 if (i >= minLevel && i <= maxLevel) {
260 if (!t->Image[i]) {
261 t->Complete = GL_FALSE;
262 return;
263 }
264 if (t->Image[i]->Width2 != width) {
265 t->Complete = GL_FALSE;
266 return;
267 }
268 if (t->Image[i]->Height2 != height) {
269 t->Complete = GL_FALSE;
270 return;
271 }
272 if (width==1 && height==1) {
273 return; /* found smallest needed mipmap, all done! */
274 }
275 }
276 }
277 }
278 else if (t->Dimensions==3) {
279 /* Test 3-D mipmaps */
280 GLuint width = t->Image[0]->Width2;
281 GLuint height = t->Image[0]->Height2;
282 GLuint depth = t->Image[0]->Depth2;
283 for (i=1; i<ctx->Const.MaxTextureLevels; i++) {
284 if (width>1) {
285 width /= 2;
286 }
287 if (height>1) {
288 height /= 2;
289 }
290 if (depth>1) {
291 depth /= 2;
292 }
293 if (i >= minLevel && i <= maxLevel) {
294 if (!t->Image[i]) {
295 t->Complete = GL_FALSE;
296 return;
297 }
298 if (t->Image[i]->Width2 != width) {
299 t->Complete = GL_FALSE;
300 return;
301 }
302 if (t->Image[i]->Height2 != height) {
303 t->Complete = GL_FALSE;
304 return;
305 }
306 if (t->Image[i]->Depth2 != depth) {
307 t->Complete = GL_FALSE;
308 return;
309 }
310 }
311 if (width==1 && height==1 && depth==1) {
312 return; /* found smallest needed mipmap, all done! */
313 }
314 }
315 }
316 else {
317 /* Dimensions = ??? */
318 gl_problem(NULL, "Bug in gl_test_texture_object_completeness\n");
319 }
320 }
321 }
322
323
324
325 /*
326 * Execute glGenTextures
327 */
328 void
329 _mesa_GenTextures( GLsizei n, GLuint *texName )
330 {
331 GET_CURRENT_CONTEXT(ctx);
332 GLuint first;
333 GLint i;
334
335 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGenTextures");
336 if (n<0) {
337 gl_error( ctx, GL_INVALID_VALUE, "glGenTextures" );
338 return;
339 }
340
341 first = HashFindFreeKeyBlock(ctx->Shared->TexObjects, n);
342
343 /* Return the texture names */
344 for (i=0;i<n;i++) {
345 texName[i] = first + i;
346 }
347
348 /* Allocate new, empty texture objects */
349 for (i=0;i<n;i++) {
350 GLuint name = first + i;
351 GLuint dims = 0;
352 (void) gl_alloc_texture_object(ctx->Shared, name, dims);
353 }
354 }
355
356
357
358 /*
359 * Execute glDeleteTextures
360 */
361 void
362 _mesa_DeleteTextures( GLsizei n, const GLuint *texName)
363 {
364 GET_CURRENT_CONTEXT(ctx);
365 GLint i;
366
367 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDeleteTextures");
368
369 for (i=0;i<n;i++) {
370 struct gl_texture_object *t;
371 if (texName[i]>0) {
372 t = (struct gl_texture_object *)
373 HashLookup(ctx->Shared->TexObjects, texName[i]);
374 if (t) {
375 GLuint u;
376 for (u=0; u<MAX_TEXTURE_UNITS; u++) {
377 struct gl_texture_unit *unit = &ctx->Texture.Unit[u];
378 GLuint d;
379 for (d = 1 ; d <= 3 ; d++) {
380 if (unit->CurrentD[d]==t) {
381 unit->CurrentD[d] = ctx->Shared->DefaultD[d];
382 ctx->Shared->DefaultD[d]->RefCount++;
383 t->RefCount--;
384 assert( t->RefCount >= 0 );
385 }
386 }
387 }
388
389 /* tell device driver to delete texture */
390 if (ctx->Driver.DeleteTexture) {
391 (*ctx->Driver.DeleteTexture)( ctx, t );
392 }
393
394 if (t->RefCount==0) {
395 gl_free_texture_object(ctx->Shared, t);
396 }
397 }
398 }
399 }
400 }
401
402
403
404 /*
405 * Execute glBindTexture
406 */
407 void
408 _mesa_BindTexture( GLenum target, GLuint texName )
409 {
410 GET_CURRENT_CONTEXT(ctx);
411 GLuint unit = ctx->Texture.CurrentUnit;
412 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
413 struct gl_texture_object *oldTexObj;
414 struct gl_texture_object *newTexObj;
415 GLuint dim;
416
417 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
418 fprintf(stderr, "glBindTexture %s %d\n",
419 gl_lookup_enum_by_nr(target), (GLint) texName);
420
421 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glBindTexture");
422
423 dim = (GLuint) (target - GL_TEXTURE_1D);
424
425 if (dim < 0 || dim > 2) {
426 gl_error( ctx, GL_INVALID_ENUM, "glBindTexture" );
427 return;
428 }
429
430 dim++;
431 oldTexObj = texUnit->CurrentD[dim];
432
433 if (oldTexObj->Name == texName)
434 return;
435
436 if (texName == 0)
437 newTexObj = ctx->Shared->DefaultD[dim];
438 else {
439 struct HashTable *hash = ctx->Shared->TexObjects;
440 newTexObj = (struct gl_texture_object *) HashLookup(hash, texName);
441
442 if (!newTexObj)
443 newTexObj = gl_alloc_texture_object(ctx->Shared, texName, dim);
444
445 if (newTexObj->Dimensions != dim) {
446 if (newTexObj->Dimensions) {
447 gl_error( ctx, GL_INVALID_OPERATION, "glBindTexture" );
448 return;
449 }
450 newTexObj->Dimensions = dim;
451 }
452 }
453
454 newTexObj->RefCount++;
455
456 texUnit->CurrentD[dim] = newTexObj;
457
458 /* If we've changed the CurrentD[123] texture object then update the
459 * ctx->Texture.Current pointer to point to the new texture object.
460 */
461 texUnit->Current = texUnit->CurrentD[texUnit->CurrentDimension];
462
463 /* Check if we may have to use a new triangle rasterizer */
464 if ((ctx->IndirectTriangles & DD_SW_RASTERIZE) &&
465 ( oldTexObj->WrapS != newTexObj->WrapS
466 || oldTexObj->WrapT != newTexObj->WrapT
467 || oldTexObj->WrapR != newTexObj->WrapR
468 || oldTexObj->MinFilter != newTexObj->MinFilter
469 || oldTexObj->MagFilter != newTexObj->MagFilter
470 || (oldTexObj->Image[0] && newTexObj->Image[0] &&
471 (oldTexObj->Image[0]->Format!=newTexObj->Image[0]->Format))))
472 {
473 ctx->NewState |= (NEW_RASTER_OPS | NEW_TEXTURING);
474 }
475
476 if (oldTexObj->Complete != newTexObj->Complete)
477 ctx->NewState |= NEW_TEXTURING;
478
479 /* Pass BindTexture call to device driver */
480 if (ctx->Driver.BindTexture) {
481 (*ctx->Driver.BindTexture)( ctx, target, newTexObj );
482 }
483
484 if (oldTexObj->Name > 0) {
485 /* never delete default (id=0) texture objects */
486 oldTexObj->RefCount--;
487 if (oldTexObj->RefCount <= 0) {
488 if (ctx->Driver.DeleteTexture) {
489 (*ctx->Driver.DeleteTexture)( ctx, oldTexObj );
490 }
491 gl_free_texture_object(ctx->Shared, oldTexObj);
492 }
493 }
494 }
495
496
497
498 /*
499 * Execute glPrioritizeTextures
500 */
501 void
502 _mesa_PrioritizeTextures( GLsizei n, const GLuint *texName,
503 const GLclampf *priorities )
504 {
505 GET_CURRENT_CONTEXT(ctx);
506 GLint i;
507
508 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glPrioritizeTextures");
509 if (n<0) {
510 gl_error( ctx, GL_INVALID_VALUE, "glPrioritizeTextures" );
511 return;
512 }
513
514 for (i=0;i<n;i++) {
515 struct gl_texture_object *t;
516 if (texName[i]>0) {
517 t = (struct gl_texture_object *)
518 HashLookup(ctx->Shared->TexObjects, texName[i]);
519 if (t) {
520 t->Priority = CLAMP( priorities[i], 0.0F, 1.0F );
521
522 if (ctx->Driver.PrioritizeTexture)
523 ctx->Driver.PrioritizeTexture( ctx, t, t->Priority );
524 }
525 }
526 }
527 }
528
529
530
531 /*
532 * Execute glAreTexturesResident
533 */
534 GLboolean
535 _mesa_AreTexturesResident( GLsizei n, const GLuint *texName,
536 GLboolean *residences )
537 {
538 GET_CURRENT_CONTEXT(ctx);
539 GLboolean resident = GL_TRUE;
540 GLint i;
541
542 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx,
543 "glAreTexturesResident",
544 GL_FALSE);
545 if (n<0) {
546 gl_error( ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)" );
547 return GL_FALSE;
548 }
549
550 for (i=0;i<n;i++) {
551 struct gl_texture_object *t;
552 if (texName[i]==0) {
553 gl_error( ctx, GL_INVALID_VALUE, "glAreTexturesResident(textures)" );
554 return GL_FALSE;
555 }
556 t = (struct gl_texture_object *)
557 HashLookup(ctx->Shared->TexObjects, texName[i]);
558 if (t) {
559 if (ctx->Driver.IsTextureResident)
560 residences[i] = ctx->Driver.IsTextureResident( ctx, t );
561 else
562 residences[i] = GL_TRUE;
563 }
564 else {
565 gl_error( ctx, GL_INVALID_VALUE, "glAreTexturesResident(textures)" );
566 return GL_FALSE;
567 }
568 }
569 return resident;
570 }
571
572
573
574 /*
575 * Execute glIsTexture
576 */
577 GLboolean
578 _mesa_IsTexture( GLuint texture )
579 {
580 GET_CURRENT_CONTEXT(ctx);
581 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx, "glIsTextures",
582 GL_FALSE);
583 if (texture>0 && HashLookup(ctx->Shared->TexObjects, texture)) {
584 return GL_TRUE;
585 }
586 else {
587 return GL_FALSE;
588 }
589 }
590