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