source: trunk/src/opengl/mesa/texobj.c@ 3993

Last change on this file since 3993 was 3598, checked in by jeroen, 25 years ago

* empty log message *

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