xref: /reactos/dll/opengl/mesa/texobj.c (revision 5f2bebf7)
1 /* $Id: texobj.c,v 1.21 1998/01/16 01:09:44 brianp Exp $ */
2 
3 /*
4  * Mesa 3-D graphics library
5  * Version:  2.6
6  * Copyright (C) 1995-1997  Brian Paul
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the Free
20  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22 
23 
24 /*
25  * $Log: texobj.c,v $
26  * Revision 1.21  1998/01/16 01:09:44  brianp
27  * glGenTextures() didn't reserve the returned texture IDs
28  *
29  * Revision 1.20  1997/12/07 17:34:05  brianp
30  * added DavidB's v0.21 fxmesa driver patch
31  *
32  * Revision 1.19  1997/11/07 03:38:07  brianp
33  * added stdio.h include for SunOS 4.x
34  *
35  * Revision 1.18  1997/10/13 23:57:59  brianp
36  * added target parameter to Driver.BindTexture()
37  *
38  * Revision 1.17  1997/09/29 23:28:14  brianp
39  * updated for new device driver texture functions
40  *
41  * Revision 1.16  1997/09/27 00:14:39  brianp
42  * added GL_EXT_paletted_texture extension
43  *
44  * Revision 1.15  1997/09/23 00:58:15  brianp
45  * now using hash table for texture objects
46  *
47  * Revision 1.14  1997/08/23 18:41:40  brianp
48  * fixed bug in glBindTexture() when binding an incomplete texture image
49  *
50  * Revision 1.13  1997/08/23 17:14:44  brianp
51  * fixed bug:  glBindTexture(target, 0) caused segfault
52  *
53  * Revision 1.12  1997/07/24 01:25:34  brianp
54  * changed precompiled header symbol from PCH to PC_HEADER
55  *
56  * Revision 1.11  1997/05/28 03:26:49  brianp
57  * added precompiled header (PCH) support
58  *
59  * Revision 1.10  1997/05/17 03:41:49  brianp
60  * added code to update ctx->Texture.Current in gl_BindTexture()
61  *
62  * Revision 1.9  1997/05/03 00:52:52  brianp
63  * removed a few unused variables
64  *
65  * Revision 1.8  1997/05/01 02:08:12  brianp
66  * new implementation of gl_BindTexture()
67  *
68  * Revision 1.7  1997/04/28 23:38:45  brianp
69  * added gl_test_texture_object_completeness()
70  *
71  * Revision 1.6  1997/04/14 02:03:05  brianp
72  * added MinMagThresh to texture object
73  *
74  * Revision 1.5  1997/02/09 18:52:15  brianp
75  * added GL_EXT_texture3D support
76  *
77  * Revision 1.4  1997/01/16 03:35:34  brianp
78  * added calls to device driver DeleteTexture() and BindTexture() functions
79  *
80  * Revision 1.3  1997/01/09 19:49:47  brianp
81  * added a check to switch rasterizers if needed in glBindTexture()
82  *
83  * Revision 1.2  1996/09/27 17:09:42  brianp
84  * removed a redundant return statement
85  *
86  * Revision 1.1  1996/09/13 01:38:16  brianp
87  * Initial revision
88  *
89  */
90 
91 
92 #ifdef PC_HEADER
93 #include "all.h"
94 #else
95 #include <assert.h>
96 #include <stdio.h>
97 #include <stdlib.h>
98 #include "context.h"
99 #include "hash.h"
100 #include "macros.h"
101 #include "teximage.h"
102 #include "texobj.h"
103 #include "types.h"
104 #endif
105 
106 
107 
108 /*
109  * Allocate a new texture object and add it to the linked list of texture
110  * objects.  If name>0 then also insert the new texture object into the hash
111  * table.
112  * Input:  shared - the shared GL state structure to contain the texture object
113  *         name - integer name for the texture object
114  *         dimensions - either 1, 2 or 3
115  * Return:  pointer to new texture object
116  */
117 struct gl_texture_object *
gl_alloc_texture_object(struct gl_shared_state * shared,GLuint name,GLuint dimensions)118 gl_alloc_texture_object( struct gl_shared_state *shared, GLuint name,
119                          GLuint dimensions)
120 {
121    struct gl_texture_object *obj;
122 
123    assert(dimensions >= 0 && dimensions <= 2);
124 
125    obj = (struct gl_texture_object *)
126                      calloc(1,sizeof(struct gl_texture_object));
127    if (obj) {
128       /* init the non-zero fields */
129       obj->Name = name;
130       obj->Dimensions = dimensions;
131       obj->WrapS = GL_REPEAT;
132       obj->WrapT = GL_REPEAT;
133       obj->MinFilter = GL_NEAREST_MIPMAP_LINEAR;
134       obj->MagFilter = GL_LINEAR;
135       obj->MinMagThresh = 0.0F;
136       obj->Palette[0] = 255;
137       obj->Palette[1] = 255;
138       obj->Palette[2] = 255;
139       obj->Palette[3] = 255;
140       obj->PaletteSize = 1;
141       obj->PaletteIntFormat = GL_RGBA;
142       obj->PaletteFormat = GL_RGBA;
143 
144       /* insert into linked list */
145       if (shared) {
146          obj->Next = shared->TexObjectList;
147          shared->TexObjectList = obj;
148       }
149 
150       if (name > 0) {
151          /* insert into hash table */
152          HashInsert(shared->TexObjects, name, obj);
153       }
154    }
155    return obj;
156 }
157 
158 
159 /*
160  * Deallocate a texture object struct and remove it from the given
161  * shared GL state.
162  * Input:  shared - the shared GL state to which the object belongs
163  *         t - the texture object to delete
164  */
gl_free_texture_object(struct gl_shared_state * shared,struct gl_texture_object * t)165 void gl_free_texture_object( struct gl_shared_state *shared,
166                              struct gl_texture_object *t )
167 {
168    struct gl_texture_object *tprev, *tcurr;
169 
170    assert(t);
171 
172    /* unlink t from the linked list */
173    if (shared) {
174       tprev = NULL;
175       tcurr = shared->TexObjectList;
176       while (tcurr) {
177          if (tcurr==t) {
178             if (tprev) {
179                tprev->Next = t->Next;
180             }
181             else {
182                shared->TexObjectList = t->Next;
183             }
184             break;
185          }
186          tprev = tcurr;
187          tcurr = tcurr->Next;
188       }
189    }
190 
191    if (t->Name) {
192       /* remove from hash table */
193       HashRemove(shared->TexObjects, t->Name);
194    }
195 
196    /* free texture image */
197    {
198       GLuint i;
199       for (i=0;i<MAX_TEXTURE_LEVELS;i++) {
200          if (t->Image[i]) {
201             gl_free_texture_image( t->Image[i] );
202          }
203       }
204    }
205    /* free this object */
206    free( t );
207 }
208 
209 
210 
211 /*
212  * Examine a texture object to determine if it is complete or not.
213  * The t->Complete flag will be set to GL_TRUE or GL_FALSE accordingly.
214  */
gl_test_texture_object_completeness(struct gl_texture_object * t)215 void gl_test_texture_object_completeness( struct gl_texture_object *t )
216 {
217    t->Complete = GL_TRUE;  /* be optimistic */
218 
219    /* Always need level zero image */
220    if (!t->Image[0] || !t->Image[0]->Data) {
221       t->Complete = GL_FALSE;
222       return;
223    }
224 
225    if (t->MinFilter!=GL_NEAREST && t->MinFilter!=GL_LINEAR) {
226       /*
227        * Mipmapping: determine if we have a complete set of mipmaps
228        */
229       int i;
230 
231       /* Test dimension-independent attributes */
232       for (i=1; i<MAX_TEXTURE_LEVELS; i++) {
233          if (t->Image[i]) {
234             if (!t->Image[i]->Data) {
235                t->Complete = GL_FALSE;
236                return;
237             }
238             if (t->Image[i]->Format != t->Image[0]->Format) {
239                t->Complete = GL_FALSE;
240                return;
241             }
242             if (t->Image[i]->Border != t->Image[0]->Border) {
243                t->Complete = GL_FALSE;
244                return;
245             }
246          }
247       }
248 
249       /* Test things which depend on number of texture image dimensions */
250       if (t->Dimensions==1) {
251          /* Test 1-D mipmaps */
252          GLuint width = t->Image[0]->Width2;
253          for (i=1; i<MAX_TEXTURE_LEVELS; i++) {
254             if (width>1) {
255                width /= 2;
256             }
257             if (!t->Image[i]) {
258                t->Complete = GL_FALSE;
259                return;
260             }
261             if (!t->Image[i]->Data) {
262                t->Complete = GL_FALSE;
263                return;
264             }
265             if (t->Image[i]->Format != t->Image[0]->Format) {
266                t->Complete = GL_FALSE;
267                return;
268             }
269             if (t->Image[i]->Border != t->Image[0]->Border) {
270                t->Complete = GL_FALSE;
271                return;
272             }
273             if (t->Image[i]->Width2 != width ) {
274                t->Complete = GL_FALSE;
275                return;
276             }
277             if (width==1) {
278                return;  /* found smallest needed mipmap, all done! */
279             }
280          }
281       }
282       else if (t->Dimensions==2) {
283          /* Test 2-D mipmaps */
284          GLuint width = t->Image[0]->Width2;
285          GLuint height = t->Image[0]->Height2;
286          for (i=1; i<MAX_TEXTURE_LEVELS; i++) {
287             if (width>1) {
288                width /= 2;
289             }
290             if (height>1) {
291                height /= 2;
292             }
293             if (!t->Image[i]) {
294                t->Complete = GL_FALSE;
295                return;
296             }
297             if (t->Image[i]->Width2 != width) {
298                t->Complete = GL_FALSE;
299                return;
300             }
301             if (t->Image[i]->Height2 != height) {
302                t->Complete = GL_FALSE;
303                return;
304             }
305             if (width==1 && height==1) {
306                return;  /* found smallest needed mipmap, all done! */
307             }
308          }
309       }
310       else {
311          /* Dimensions = ??? */
312          gl_problem(NULL, "Bug in gl_test_texture_object_completeness\n");
313       }
314    }
315 }
316 
317 
318 
319 /*
320  * Execute glGenTextures
321  */
gl_GenTextures(GLcontext * ctx,GLsizei n,GLuint * texName)322 void gl_GenTextures( GLcontext *ctx, GLsizei n, GLuint *texName )
323 {
324    GLuint first, i;
325 
326    if (INSIDE_BEGIN_END(ctx)) {
327       gl_error( ctx, GL_INVALID_OPERATION, "glGenTextures" );
328       return;
329    }
330    if (n<0) {
331       gl_error( ctx, GL_INVALID_VALUE, "glGenTextures" );
332       return;
333    }
334 
335    first = HashFindFreeKeyBlock(ctx->Shared->TexObjects, n);
336 
337    /* Return the texture names */
338    for (i=0;i<n;i++) {
339       texName[i] = first + i;
340    }
341 
342    /* Allocate new, empty texture objects */
343    for (i=0;i<n;i++) {
344       GLuint name = first + i;
345       GLuint dims = 0;
346       struct gl_texture_object *newTexObj = gl_alloc_texture_object(ctx->Shared, name, dims);
347       (void)newTexObj;
348    }
349 }
350 
351 
352 
353 /*
354  * Execute glDeleteTextures
355  */
gl_DeleteTextures(GLcontext * ctx,GLsizei n,const GLuint * texName)356 void gl_DeleteTextures( GLcontext *ctx, GLsizei n, const GLuint *texName)
357 {
358    GLuint i;
359 
360    if (INSIDE_BEGIN_END(ctx)) {
361       gl_error( ctx, GL_INVALID_OPERATION, "glAreTexturesResident" );
362       return;
363    }
364 
365    for (i=0;i<n;i++) {
366       struct gl_texture_object *t;
367       if (texName[i]>0) {
368          t = (struct gl_texture_object *)
369             HashLookup(ctx->Shared->TexObjects, texName[i]);
370          if (t) {
371             if (ctx->Texture.Current1D==t) {
372                /* revert to default 1-D texture */
373                ctx->Texture.Current1D = ctx->Shared->Default1D;
374                t->RefCount--;
375                assert( t->RefCount >= 0 );
376             }
377             else if (ctx->Texture.Current2D==t) {
378                /* revert to default 2-D texture */
379                ctx->Texture.Current2D = ctx->Shared->Default2D;
380                t->RefCount--;
381                assert( t->RefCount >= 0 );
382             }
383 
384             /* tell device driver to delete texture */
385             if (ctx->Driver.DeleteTexture) {
386                (*ctx->Driver.DeleteTexture)( ctx, t );
387             }
388 
389             if (t->RefCount==0) {
390                gl_free_texture_object(ctx->Shared, t);
391             }
392          }
393       }
394    }
395 }
396 
397 
398 
399 /*
400  * Execute glBindTexture
401  */
gl_BindTexture(GLcontext * ctx,GLenum target,GLuint texName)402 void gl_BindTexture( GLcontext *ctx, GLenum target, GLuint texName )
403 {
404    struct gl_texture_object *oldTexObj;
405    struct gl_texture_object *newTexObj;
406    struct gl_texture_object **targetPointer;
407    GLuint targetDimensions;
408 
409    if (INSIDE_BEGIN_END(ctx)) {
410       gl_error( ctx, GL_INVALID_OPERATION, "glAreTexturesResident" );
411       return;
412    }
413    switch (target) {
414       case GL_TEXTURE_1D:
415          oldTexObj = ctx->Texture.Current1D;
416          targetPointer = &ctx->Texture.Current1D;
417          targetDimensions = 1;
418          break;
419       case GL_TEXTURE_2D:
420          oldTexObj = ctx->Texture.Current2D;
421          targetPointer = &ctx->Texture.Current2D;
422          targetDimensions = 2;
423          break;
424       default:
425          gl_error( ctx, GL_INVALID_ENUM, "glBindTexture" );
426          return;
427    }
428 
429    if (texName==0) {
430       /* use default n-D texture */
431       switch (target) {
432          case GL_TEXTURE_1D:
433             newTexObj = ctx->Shared->Default1D;
434             break;
435          case GL_TEXTURE_2D:
436             newTexObj = ctx->Shared->Default2D;
437             break;
438          default:
439             gl_problem(ctx, "Bad target in gl_BindTexture");
440             return;
441       }
442    }
443    else {
444       newTexObj = (struct gl_texture_object *)
445                              HashLookup(ctx->Shared->TexObjects, texName);
446       if (newTexObj) {
447          if (newTexObj->Dimensions == 0) {
448             /* first time bound */
449             newTexObj->Dimensions = targetDimensions;
450          }
451          else if (newTexObj->Dimensions != targetDimensions) {
452             /* wrong dimensionality */
453             gl_error( ctx, GL_INVALID_OPERATION, "glBindTextureEXT" );
454             return;
455          }
456       }
457       else {
458          /* create new texture object */
459          newTexObj = gl_alloc_texture_object(ctx->Shared, texName,
460                                              targetDimensions);
461       }
462    }
463 
464    /* Update the Texture.Current[123]D pointer */
465    *targetPointer = newTexObj;
466 
467    /* Tidy up reference counting */
468    if (*targetPointer != oldTexObj && oldTexObj->Name>0) {
469       /* decrement reference count of the prev texture object */
470       oldTexObj->RefCount--;
471       assert( oldTexObj->RefCount >= 0 );
472    }
473 
474    if (newTexObj->Name>0) {
475       newTexObj->RefCount++;
476    }
477 
478    /* Check if we may have to use a new triangle rasterizer */
479    if (   oldTexObj->WrapS != newTexObj->WrapS
480        || oldTexObj->WrapT != newTexObj->WrapT
481        || oldTexObj->WrapR != newTexObj->WrapR
482        || oldTexObj->MinFilter != newTexObj->MinFilter
483        || oldTexObj->MagFilter != newTexObj->MagFilter
484        || (oldTexObj->Image[0] && newTexObj->Image[0] &&
485 	  (oldTexObj->Image[0]->Format!=newTexObj->Image[0]->Format))
486        || !newTexObj->Complete) {
487       ctx->NewState |= NEW_RASTER_OPS;
488    }
489 
490    /* If we've changed the Current[123]D texture object then update the
491     * ctx->Texture.Current pointer to point to the new texture object.
492     */
493    if (oldTexObj==ctx->Texture.Current) {
494       ctx->Texture.Current = newTexObj;
495    }
496 
497    /* The current n-D texture object can never be NULL! */
498    assert(*targetPointer);
499 
500    /* Pass BindTexture call to device driver */
501    if (ctx->Driver.BindTexture) {
502       (*ctx->Driver.BindTexture)( ctx, target, newTexObj );
503    }
504 }
505 
506 
507 
508 /*
509  * Execute glPrioritizeTextures
510  */
gl_PrioritizeTextures(GLcontext * ctx,GLsizei n,const GLuint * texName,const GLclampf * priorities)511 void gl_PrioritizeTextures( GLcontext *ctx,
512                             GLsizei n, const GLuint *texName,
513                             const GLclampf *priorities )
514 {
515    GLuint i;
516 
517    if (INSIDE_BEGIN_END(ctx)) {
518       gl_error( ctx, GL_INVALID_OPERATION, "glAreTexturesResident" );
519       return;
520    }
521    if (n<0) {
522       gl_error( ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)" );
523       return;
524    }
525 
526    for (i=0;i<n;i++) {
527       struct gl_texture_object *t;
528       if (texName[i]>0) {
529          t = (struct gl_texture_object *)
530             HashLookup(ctx->Shared->TexObjects, texName[i]);
531          if (t) {
532             t->Priority = CLAMP( priorities[i], 0.0F, 1.0F );
533          }
534       }
535    }
536 }
537 
538 
539 
540 /*
541  * Execute glAreTexturesResident
542  */
gl_AreTexturesResident(GLcontext * ctx,GLsizei n,const GLuint * texName,GLboolean * residences)543 GLboolean gl_AreTexturesResident( GLcontext *ctx, GLsizei n,
544                                   const GLuint *texName,
545                                   GLboolean *residences )
546 {
547    GLboolean resident = GL_TRUE;
548    GLuint i;
549 
550    if (INSIDE_BEGIN_END(ctx)) {
551       gl_error( ctx, GL_INVALID_OPERATION, "glAreTexturesResident" );
552       return GL_FALSE;
553    }
554    if (n<0) {
555       gl_error( ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)" );
556       return GL_FALSE;
557    }
558 
559    for (i=0;i<n;i++) {
560       struct gl_texture_object *t;
561       if (texName[i]==0) {
562          gl_error( ctx, GL_INVALID_VALUE, "glAreTexturesResident(textures)" );
563          return GL_FALSE;
564       }
565       t = (struct gl_texture_object *)
566          HashLookup(ctx->Shared->TexObjects, texName[i]);
567       if (t) {
568          /* we consider all valid texture objects to be resident */
569          residences[i] = GL_TRUE;
570       }
571       else {
572          gl_error( ctx, GL_INVALID_VALUE, "glAreTexturesResident(textures)" );
573          return GL_FALSE;
574       }
575    }
576    return resident;
577 }
578 
579 
580 
581 /*
582  * Execute glIsTexture
583  */
gl_IsTexture(GLcontext * ctx,GLuint texture)584 GLboolean gl_IsTexture( GLcontext *ctx, GLuint texture )
585 {
586    if (INSIDE_BEGIN_END(ctx)) {
587       gl_error( ctx, GL_INVALID_OPERATION, "glIsTextures" );
588       return GL_FALSE;
589    }
590    if (texture>0 && HashLookup(ctx->Shared->TexObjects, texture)) {
591       return GL_TRUE;
592    }
593    else {
594       return GL_FALSE;
595    }
596 }
597 
598