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