~ubuntu-branches/ubuntu/gutsy/vnc4/gutsy

« back to all changes in this revision

Viewing changes to unix/xc/lib/GL/mesa/src/drv/tdfx/tdfx_texman.c

  • Committer: Bazaar Package Importer
  • Author(s): Ola Lundqvist
  • Date: 2006-05-15 20:35:17 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060515203517-l4lre1ku942mn26k
Tags: 4.1.1+X4.3.0-10
* Correction of critical security issue. Thanks to Martin Kogler
  <e9925248@student.tuwien.ac.at> that informed me about the issue,
  and provided the patch.
  This flaw was originally found by Steve Wiseman of intelliadmin.com.
* Applied patch from Javier Kohen <jkohen@users.sourceforge.net> that
  inform the user that only 8 first characters of the password will
  actually be used when typing more than 8 characters, closes:
  #355619.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: c; c-basic-offset: 3 -*-
 
2
 *
 
3
 * Copyright 2000 VA Linux Systems Inc., Fremont, California.
 
4
 *
 
5
 * All Rights Reserved.
 
6
 *
 
7
 * Permission is hereby granted, free of charge, to any person obtaining a
 
8
 * copy of this software and associated documentation files (the "Software"),
 
9
 * to deal in the Software without restriction, including without limitation
 
10
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 
11
 * and/or sell copies of the Software, and to permit persons to whom the
 
12
 * Software is furnished to do so, subject to the following conditions:
 
13
 *
 
14
 * The above copyright notice and this permission notice (including the next
 
15
 * paragraph) shall be included in all copies or substantial portions of the
 
16
 * Software.
 
17
 *
 
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 
21
 * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 
22
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
 
23
 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 
24
 * SOFTWARE.
 
25
 */
 
26
/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_texman.c,v 1.5 2002/02/22 21:45:04 dawes Exp $ */
 
27
 
 
28
/*
 
29
 * Original rewrite:
 
30
 *      Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
 
31
 *
 
32
 * Authors:
 
33
 *      Gareth Hughes <gareth@valinux.com>
 
34
 *      Brian Paul <brianp@valinux.com>
 
35
 *
 
36
 */
 
37
 
 
38
#include "tdfx_context.h"
 
39
#include "tdfx_tex.h"
 
40
#include "tdfx_texman.h"
 
41
 
 
42
 
 
43
#define BAD_ADDRESS ((FxU32) -1)
 
44
 
 
45
 
 
46
#if 0 /* DEBUG use */
 
47
/*
 
48
 * Verify the consistancy of the texture memory manager.
 
49
 * This involves:
 
50
 *    Traversing all texture objects and computing total memory used.
 
51
 *    Traverse the free block list and computing total memory free.
 
52
 *    Compare the total free and total used amounts to the total memory size.
 
53
 *    Make various assertions about the results.
 
54
 */
 
55
static void
 
56
VerifyFreeList(tdfxContextPtr fxMesa, FxU32 tmu)
 
57
{
 
58
    struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
 
59
    struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
 
60
    tdfxMemRange *block;
 
61
    int prevStart = -1, prevEnd = -1;
 
62
    int totalFree = 0;
 
63
    int numObj = 0, numRes = 0;
 
64
    int totalUsed = 0;
 
65
 
 
66
    for (block = shared->tmFree[tmu]; block; block = block->next) {
 
67
       assert( block->endAddr > 0 );
 
68
       assert( block->startAddr <= shared->totalTexMem[tmu] );
 
69
       assert( block->endAddr <= shared->totalTexMem[tmu] );
 
70
       assert( (int) block->startAddr > prevStart );
 
71
       assert( (int) block->startAddr >= prevEnd );
 
72
       prevStart = (int) block->startAddr;
 
73
       prevEnd = (int) block->endAddr;
 
74
       totalFree += (block->endAddr - block->startAddr);
 
75
    }
 
76
    assert(totalFree == shared->freeTexMem[tmu]);
 
77
 
 
78
    {
 
79
       struct gl_texture_object *obj;
 
80
       for (obj = mesaShared->TexObjectList; obj; obj = obj->Next) {
 
81
          tdfxTexInfo *ti = TDFX_TEXTURE_DATA(obj);
 
82
          numObj++;
 
83
          if (ti) {
 
84
             if (ti->isInTM) {
 
85
                numRes++;
 
86
                assert(ti->tm[0]);
 
87
                if (ti->tm[tmu])
 
88
                   totalUsed += (ti->tm[tmu]->endAddr - ti->tm[tmu]->startAddr);
 
89
             }
 
90
             else {
 
91
                assert(!ti->tm[0]);
 
92
             }
 
93
          }
 
94
       }
 
95
    }
 
96
 
 
97
    printf("totalFree: %d  totalUsed: %d  totalMem: %d #objs=%d  #res=%d\n",
 
98
           shared->freeTexMem[tmu], totalUsed, shared->totalTexMem[tmu],
 
99
           numObj, numRes);
 
100
 
 
101
    assert(totalUsed + totalFree == shared->totalTexMem[tmu]);
 
102
}
 
103
 
 
104
 
 
105
static void
 
106
dump_texmem(tdfxContextPtr fxMesa)
 
107
{
 
108
    struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
 
109
    struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
 
110
    struct gl_texture_object *oldestObj, *obj, *lowestPriorityObj;
 
111
    tdfxMemRange *r;
 
112
    FxU32 prev;
 
113
 
 
114
    printf("DUMP Objects:\n");
 
115
    for (obj = mesaShared->TexObjectList; obj; obj = obj->Next) {
 
116
        tdfxTexInfo *info = TDFX_TEXTURE_DATA(obj);
 
117
 
 
118
        if (info && info->isInTM) {
 
119
        printf("Obj %8p: %4d  info = %p\n", obj, obj->Name, info);
 
120
 
 
121
           printf("  isInTM=%d  whichTMU=%d  lastTimeUsed=%d\n",
 
122
                  info->isInTM, info->whichTMU, info->lastTimeUsed);
 
123
           printf("    tm[0] = %p", info->tm[0]);
 
124
           assert(info->tm[0]);
 
125
           if (info->tm[0]) {
 
126
              printf("  tm startAddr = %d  endAddr = %d",
 
127
                     info->tm[0]->startAddr,
 
128
                     info->tm[0]->endAddr);
 
129
           }
 
130
           printf("\n");
 
131
           printf("    tm[1] = %p", info->tm[1]);
 
132
           if (info->tm[1]) {
 
133
              printf("  tm startAddr = %d  endAddr = %d",
 
134
                     info->tm[1]->startAddr,
 
135
                     info->tm[1]->endAddr);
 
136
           }
 
137
           printf("\n");
 
138
        }
 
139
    }
 
140
 
 
141
    VerifyFreeList(fxMesa, 0);
 
142
    VerifyFreeList(fxMesa, 1);
 
143
 
 
144
    printf("Free memory unit 0:  %d bytes\n", shared->freeTexMem[0]);
 
145
    prev = 0;
 
146
    for (r = shared->tmFree[0]; r; r = r->next) {
 
147
       printf("%8p:  start %8d  end %8d  size %8d  gap %8d\n", r, r->startAddr, r->endAddr, r->endAddr - r->startAddr, r->startAddr - prev);
 
148
       prev = r->endAddr;
 
149
    }
 
150
 
 
151
    printf("Free memory unit 1:  %d bytes\n", shared->freeTexMem[1]);
 
152
    prev = 0;
 
153
    for (r = shared->tmFree[1]; r; r = r->next) {
 
154
       printf("%8p:  start %8d  end %8d  size %8d  gap %8d\n", r, r->startAddr, r->endAddr, r->endAddr - r->startAddr, r->startAddr - prev);
 
155
       prev = r->endAddr;
 
156
    }
 
157
 
 
158
}
 
159
#endif
 
160
 
 
161
 
 
162
 
 
163
#ifdef TEXSANITY
 
164
static void
 
165
fubar(void)
 
166
{
 
167
}
 
168
 
 
169
/*
 
170
 * Sanity Check
 
171
 */
 
172
static void
 
173
sanity(tdfxContextPtr fxMesa)
 
174
{
 
175
    tdfxMemRange *tmp, *prev, *pos;
 
176
 
 
177
    prev = 0;
 
178
    tmp = fxMesa->tmFree[0];
 
179
    while (tmp) {
 
180
        if (!tmp->startAddr && !tmp->endAddr) {
 
181
            fprintf(stderr, "Textures fubar\n");
 
182
            fubar();
 
183
        }
 
184
        if (tmp->startAddr >= tmp->endAddr) {
 
185
            fprintf(stderr, "Node fubar\n");
 
186
            fubar();
 
187
        }
 
188
        if (prev && (prev->startAddr >= tmp->startAddr ||
 
189
                     prev->endAddr > tmp->startAddr)) {
 
190
            fprintf(stderr, "Sorting fubar\n");
 
191
            fubar();
 
192
        }
 
193
        prev = tmp;
 
194
        tmp = tmp->next;
 
195
    }
 
196
    prev = 0;
 
197
    tmp = fxMesa->tmFree[1];
 
198
    while (tmp) {
 
199
        if (!tmp->startAddr && !tmp->endAddr) {
 
200
            fprintf(stderr, "Textures fubar\n");
 
201
            fubar();
 
202
        }
 
203
        if (tmp->startAddr >= tmp->endAddr) {
 
204
            fprintf(stderr, "Node fubar\n");
 
205
            fubar();
 
206
        }
 
207
        if (prev && (prev->startAddr >= tmp->startAddr ||
 
208
                     prev->endAddr > tmp->startAddr)) {
 
209
            fprintf(stderr, "Sorting fubar\n");
 
210
            fubar();
 
211
        }
 
212
        prev = tmp;
 
213
        tmp = tmp->next;
 
214
    }
 
215
}
 
216
#endif
 
217
 
 
218
 
 
219
 
 
220
 
 
221
 
 
222
/*
 
223
 * Allocate and initialize a new MemRange struct.
 
224
 * Try to allocate it from the pool of free MemRange nodes rather than malloc.
 
225
 */
 
226
static tdfxMemRange *
 
227
NewRangeNode(tdfxContextPtr fxMesa, FxU32 start, FxU32 end)
 
228
{
 
229
    struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
 
230
    struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
 
231
    tdfxMemRange *result;
 
232
 
 
233
    _glthread_LOCK_MUTEX(mesaShared->Mutex);
 
234
    if (shared && shared->tmPool) {
 
235
        result = shared->tmPool;
 
236
        shared->tmPool = shared->tmPool->next;
 
237
    }
 
238
    else {
 
239
        result = MALLOC(sizeof(tdfxMemRange));
 
240
 
 
241
    }
 
242
    _glthread_UNLOCK_MUTEX(mesaShared->Mutex);
 
243
 
 
244
    if (!result) {
 
245
        /*fprintf(stderr, "fxDriver: out of memory!\n");*/
 
246
        return NULL;
 
247
    }
 
248
 
 
249
    result->startAddr = start;
 
250
    result->endAddr = end;
 
251
    result->next = NULL;
 
252
 
 
253
    return result;
 
254
}
 
255
 
 
256
 
 
257
/*
 
258
 * Initialize texture memory.
 
259
 * We take care of one or both TMU's here.
 
260
 */
 
261
void
 
262
tdfxTMInit(tdfxContextPtr fxMesa)
 
263
{
 
264
    if (!fxMesa->glCtx->Shared->DriverData) {
 
265
        const char *extensions;
 
266
        struct tdfxSharedState *shared = CALLOC_STRUCT(tdfxSharedState);
 
267
        if (!shared)
 
268
           return;
 
269
 
 
270
        LOCK_HARDWARE(fxMesa);
 
271
        extensions = fxMesa->Glide.grGetString(GR_EXTENSION);
 
272
        UNLOCK_HARDWARE(fxMesa);
 
273
        if (strstr(extensions, "TEXUMA")) {
 
274
            FxU32 start, end;
 
275
            shared->umaTexMemory = GL_TRUE;
 
276
            LOCK_HARDWARE(fxMesa);
 
277
            fxMesa->Glide.grEnable(GR_TEXTURE_UMA_EXT);
 
278
            start = fxMesa->Glide.grTexMinAddress(0);
 
279
            end = fxMesa->Glide.grTexMaxAddress(0);
 
280
            UNLOCK_HARDWARE(fxMesa);
 
281
            shared->totalTexMem[0] = end - start;
 
282
            shared->totalTexMem[1] = 0;
 
283
            shared->freeTexMem[0] = end - start;
 
284
            shared->freeTexMem[1] = 0;
 
285
            shared->tmFree[0] = NewRangeNode(fxMesa, start, end);
 
286
            shared->tmFree[1] = NULL;
 
287
            /*printf("UMA tex memory: %d\n", (int) (end - start));*/
 
288
        }
 
289
        else {
 
290
            const int numTMUs = fxMesa->haveTwoTMUs ? 2 : 1;
 
291
            int tmu;
 
292
            shared->umaTexMemory = GL_FALSE;
 
293
            LOCK_HARDWARE(fxMesa);
 
294
            for (tmu = 0; tmu < numTMUs; tmu++) {
 
295
                FxU32 start = fxMesa->Glide.grTexMinAddress(tmu);
 
296
                FxU32 end = fxMesa->Glide.grTexMaxAddress(tmu);
 
297
                shared->totalTexMem[tmu] = end - start;
 
298
                shared->freeTexMem[tmu] = end - start;
 
299
                shared->tmFree[tmu] = NewRangeNode(fxMesa, start, end);
 
300
                /*printf("Split tex memory: %d\n", (int) (end - start));*/
 
301
            }
 
302
            UNLOCK_HARDWARE(fxMesa);
 
303
        }
 
304
 
 
305
        shared->tmPool = NULL;
 
306
        fxMesa->glCtx->Shared->DriverData = shared;
 
307
        /*printf("Texture memory init UMA: %d\n", shared->umaTexMemory);*/
 
308
    }
 
309
}
 
310
 
 
311
 
 
312
/*
 
313
 * Clean-up texture memory before destroying context.
 
314
 */
 
315
void
 
316
tdfxTMClose(tdfxContextPtr fxMesa)
 
317
{
 
318
    if (fxMesa->glCtx->Shared->RefCount == 1 && fxMesa->driDrawable) {
 
319
        /* refcount will soon go to zero, free our 3dfx stuff */
 
320
        struct tdfxSharedState *shared = (struct tdfxSharedState *) fxMesa->glCtx->Shared->DriverData;
 
321
 
 
322
        const int numTMUs = fxMesa->haveTwoTMUs ? 2 : 1;
 
323
        int tmu;
 
324
        tdfxMemRange *tmp, *next;
 
325
 
 
326
        /* Deallocate the pool of free tdfxMemRange nodes */
 
327
        tmp = shared->tmPool;
 
328
        while (tmp) {
 
329
            next = tmp->next;
 
330
            FREE(tmp);
 
331
            tmp = next;
 
332
        }
 
333
 
 
334
        /* Delete the texture memory block tdfxMemRange nodes */
 
335
        for (tmu = 0; tmu < numTMUs; tmu++) {
 
336
            tmp = shared->tmFree[tmu];
 
337
            while (tmp) {
 
338
                next = tmp->next;
 
339
                FREE(tmp);
 
340
                tmp = next;
 
341
            }
 
342
        }
 
343
 
 
344
        FREE(shared);
 
345
        fxMesa->glCtx->Shared->DriverData = NULL;
 
346
    }
 
347
}
 
348
 
 
349
 
 
350
 
 
351
/*
 
352
 * Delete a tdfxMemRange struct.
 
353
 * We keep a linked list of free/available tdfxMemRange structs to
 
354
 * avoid extra malloc/free calls.
 
355
 */
 
356
#if 0
 
357
static void
 
358
DeleteRangeNode_NoLock(struct TdfxSharedState *shared, tdfxMemRange *range)
 
359
{
 
360
    /* insert at head of list */
 
361
    range->next = shared->tmPool;
 
362
    shared->tmPool = range;
 
363
}
 
364
#endif
 
365
 
 
366
#define DELETE_RANGE_NODE(shared, range) \
 
367
    (range)->next = (shared)->tmPool;    \
 
368
    (shared)->tmPool = (range)
 
369
 
 
370
 
 
371
 
 
372
/*
 
373
 * When we've run out of texture memory we have to throw out an
 
374
 * existing texture to make room for the new one.  This function
 
375
 * determins the texture to throw out.
 
376
 */
 
377
static struct gl_texture_object *
 
378
FindOldestObject(tdfxContextPtr fxMesa, FxU32 tmu)
 
379
{
 
380
    const GLuint bindnumber = fxMesa->texBindNumber;
 
381
    struct gl_texture_object *oldestObj, *obj, *lowestPriorityObj;
 
382
    GLfloat lowestPriority;
 
383
    GLuint oldestAge;
 
384
 
 
385
    oldestObj = NULL;
 
386
    oldestAge = 0;
 
387
 
 
388
    lowestPriority = 1.0F;
 
389
    lowestPriorityObj = NULL;
 
390
 
 
391
    for (obj = fxMesa->glCtx->Shared->TexObjectList; obj; obj = obj->Next) {
 
392
        tdfxTexInfo *info = TDFX_TEXTURE_DATA(obj);
 
393
 
 
394
        if (info && info->isInTM &&
 
395
            ((info->whichTMU == tmu) || (info->whichTMU == TDFX_TMU_BOTH) ||
 
396
             (info->whichTMU == TDFX_TMU_SPLIT))) {
 
397
            GLuint age, lasttime;
 
398
 
 
399
            assert(info->tm[0]);
 
400
            lasttime = info->lastTimeUsed;
 
401
 
 
402
            if (lasttime > bindnumber)
 
403
                age = bindnumber + (UINT_MAX - lasttime + 1); /* TO DO: check wrap around */
 
404
            else
 
405
                age = bindnumber - lasttime;
 
406
 
 
407
            if (age >= oldestAge) {
 
408
                oldestAge = age;
 
409
                oldestObj = obj;
 
410
            }
 
411
 
 
412
            /* examine priority */
 
413
            if (obj->Priority < lowestPriority) {
 
414
                lowestPriority = obj->Priority;
 
415
                lowestPriorityObj = obj;
 
416
            }
 
417
        }
 
418
    }
 
419
 
 
420
    if (lowestPriority < 1.0) {
 
421
        ASSERT(lowestPriorityObj);
 
422
        /*
 
423
        printf("discard %d pri=%f\n", lowestPriorityObj->Name, lowestPriority);
 
424
        */
 
425
        return lowestPriorityObj;
 
426
    }
 
427
    else {
 
428
        /*
 
429
        printf("discard %d age=%d\n", oldestObj->Name, oldestAge);
 
430
        */
 
431
        return oldestObj;
 
432
    }
 
433
}
 
434
 
 
435
 
 
436
#if 0
 
437
static void
 
438
FlushTexMemory(tdfxContextPtr fxMesa)
 
439
{
 
440
    struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
 
441
    struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
 
442
    struct gl_texture_object *obj;
 
443
 
 
444
    for (obj = mesaShared->TexObjectList; obj; obj = obj->Next) {
 
445
       if (obj->RefCount < 2) {
 
446
          /* don't flush currently bound textures */
 
447
          tdfxTMMoveOutTM_NoLock(fxMesa, obj);
 
448
       }
 
449
    }
 
450
}
 
451
#endif
 
452
 
 
453
 
 
454
/*
 
455
 * Find the address (offset?) at which we can store a new texture.
 
456
 * <tmu> is the texture unit.
 
457
 * <size> is the texture size in bytes.
 
458
 */
 
459
static FxU32
 
460
FindStartAddr(tdfxContextPtr fxMesa, FxU32 tmu, FxU32 size)
 
461
{
 
462
    struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
 
463
    struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
 
464
    tdfxMemRange *prev, *block;
 
465
    FxU32 result;
 
466
#if 0
 
467
    int discardedCount = 0;
 
468
#define MAX_DISCARDS 10
 
469
#endif
 
470
 
 
471
    if (shared->umaTexMemory) {
 
472
        assert(tmu == TDFX_TMU0);
 
473
    }
 
474
 
 
475
    _glthread_LOCK_MUTEX(mesaShared->Mutex);
 
476
    while (1) {
 
477
        prev = NULL;
 
478
        block = shared->tmFree[tmu];
 
479
        while (block) {
 
480
            if (block->endAddr - block->startAddr >= size) {
 
481
                /* The texture will fit here */
 
482
                result = block->startAddr;
 
483
                block->startAddr += size;
 
484
                if (block->startAddr == block->endAddr) {
 
485
                    /* Remove this node since it's empty */
 
486
                    if (prev) {
 
487
                        prev->next = block->next;
 
488
                    }
 
489
                    else {
 
490
                        shared->tmFree[tmu] = block->next;
 
491
                    }
 
492
                    DELETE_RANGE_NODE(shared, block);
 
493
                }
 
494
                shared->freeTexMem[tmu] -= size;
 
495
                _glthread_UNLOCK_MUTEX(mesaShared->Mutex);
 
496
                return result;
 
497
            }
 
498
            prev = block;
 
499
            block = block->next;
 
500
        }
 
501
        /* We failed to find a block large enough to accomodate <size> bytes.
 
502
         * Find the oldest texObject and free it.
 
503
         */
 
504
#if 0
 
505
        discardedCount++;
 
506
        if (discardedCount > MAX_DISCARDS + 1) {
 
507
            _mesa_problem(NULL, "tdfx driver: extreme texmem fragmentation");
 
508
            _glthread_UNLOCK_MUTEX(mesaShared->Mutex);
 
509
            return BAD_ADDRESS;
 
510
        }
 
511
        else if (discardedCount > MAX_DISCARDS) {
 
512
            /* texture memory is probably really fragmented, flush it */
 
513
            FlushTexMemory(fxMesa);
 
514
        }
 
515
        else
 
516
#endif
 
517
        {
 
518
            struct gl_texture_object *obj = FindOldestObject(fxMesa, tmu);
 
519
            if (obj) {
 
520
                tdfxTMMoveOutTM_NoLock(fxMesa, obj);
 
521
                fxMesa->stats.texSwaps++;
 
522
            }
 
523
            else {
 
524
                _mesa_problem(NULL, "tdfx driver: extreme texmem fragmentation");
 
525
                _glthread_UNLOCK_MUTEX(mesaShared->Mutex);
 
526
                return BAD_ADDRESS;
 
527
            }
 
528
        }
 
529
    }
 
530
 
 
531
    /* never get here, but play it safe */
 
532
    _glthread_UNLOCK_MUTEX(mesaShared->Mutex);
 
533
    return BAD_ADDRESS;
 
534
}
 
535
 
 
536
 
 
537
/*
 
538
 * Remove the given tdfxMemRange node from hardware texture memory.
 
539
 */
 
540
static void
 
541
RemoveRange_NoLock(tdfxContextPtr fxMesa, FxU32 tmu, tdfxMemRange *range)
 
542
{
 
543
    struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
 
544
    struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
 
545
    tdfxMemRange *block, *prev;
 
546
 
 
547
    if (shared->umaTexMemory) {
 
548
       assert(tmu == TDFX_TMU0);
 
549
    }
 
550
 
 
551
    if (!range)
 
552
        return;
 
553
 
 
554
    if (range->startAddr == range->endAddr) {
 
555
        DELETE_RANGE_NODE(shared, range);
 
556
        return;
 
557
    }
 
558
    shared->freeTexMem[tmu] += range->endAddr - range->startAddr;
 
559
 
 
560
    /* find position in linked list to insert this tdfxMemRange node */
 
561
    prev = NULL;
 
562
    block = shared->tmFree[tmu];
 
563
    while (block) {
 
564
        assert(range->startAddr != block->startAddr);
 
565
        if (range->startAddr > block->startAddr) {
 
566
            prev = block;
 
567
            block = block->next;
 
568
        }
 
569
        else {
 
570
            break;
 
571
        }
 
572
    }
 
573
 
 
574
    /* Insert the free block, combine with adjacent blocks when possible */
 
575
    range->next = block;
 
576
    if (block) {
 
577
        if (range->endAddr == block->startAddr) {
 
578
            /* Combine */
 
579
            block->startAddr = range->startAddr;
 
580
            DELETE_RANGE_NODE(shared, range);
 
581
            range = block;
 
582
        }
 
583
    }
 
584
    if (prev) {
 
585
        if (prev->endAddr == range->startAddr) {
 
586
            /* Combine */
 
587
            prev->endAddr = range->endAddr;
 
588
            prev->next = range->next;
 
589
            DELETE_RANGE_NODE(shared, range);
 
590
        }
 
591
        else {
 
592
            prev->next = range;
 
593
        }
 
594
    }
 
595
    else {
 
596
        shared->tmFree[tmu] = range;
 
597
    }
 
598
}
 
599
 
 
600
 
 
601
#if 0 /* NOT USED */
 
602
static void
 
603
RemoveRange(tdfxContextPtr fxMesa, FxU32 tmu, tdfxMemRange *range)
 
604
{
 
605
    struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
 
606
    _glthread_LOCK_MUTEX(mesaShared->Mutex);
 
607
    RemoveRange_NoLock(fxMesa, tmu, range);
 
608
    _glthread_UNLOCK_MUTEX(mesaShared->Mutex);
 
609
}
 
610
#endif
 
611
 
 
612
 
 
613
/*
 
614
 * Allocate space for a texture image.
 
615
 * <tmu> is the texture unit
 
616
 * <texmemsize> is the number of bytes to allocate
 
617
 */
 
618
static tdfxMemRange *
 
619
AllocTexMem(tdfxContextPtr fxMesa, FxU32 tmu, FxU32 texmemsize)
 
620
{
 
621
    FxU32 startAddr;
 
622
    startAddr = FindStartAddr(fxMesa, tmu, texmemsize);
 
623
    if (startAddr == BAD_ADDRESS) {
 
624
        char err[100];
 
625
        sprintf(err, "AllocTexMem returned NULL!  tmu=%d texmemsize=%d\n",
 
626
               (int) tmu, (int) texmemsize);
 
627
        _mesa_problem(fxMesa->glCtx, err);
 
628
        return NULL;
 
629
    }
 
630
    else {
 
631
        tdfxMemRange *range;
 
632
        range = NewRangeNode(fxMesa, startAddr, startAddr + texmemsize);
 
633
        return range;
 
634
    }
 
635
}
 
636
 
 
637
 
 
638
/*
 
639
 * Download (copy) the given texture data (all mipmap levels) into the
 
640
 * Voodoo's texture memory.
 
641
 * The texture memory must have already been allocated.
 
642
 */
 
643
void
 
644
tdfxTMDownloadTexture(tdfxContextPtr fxMesa, struct gl_texture_object *tObj)
 
645
{
 
646
    tdfxTexInfo *ti;
 
647
    GLint l;
 
648
    FxU32 targetTMU;
 
649
 
 
650
    assert(tObj);
 
651
    ti = TDFX_TEXTURE_DATA(tObj);
 
652
    assert(ti);
 
653
    targetTMU = ti->whichTMU;
 
654
 
 
655
    switch (targetTMU) {
 
656
    case TDFX_TMU0:
 
657
    case TDFX_TMU1:
 
658
        if (ti->tm[targetTMU]) {
 
659
            for (l = ti->minLevel; l <= ti->maxLevel
 
660
                    && tObj->Image[l]->Data; l++) {
 
661
                GrLOD_t glideLod = ti->info.largeLodLog2 - l + tObj->BaseLevel;
 
662
                fxMesa->Glide.grTexDownloadMipMapLevel(targetTMU,
 
663
                                                  ti->tm[targetTMU]->startAddr,
 
664
                                                  glideLod,
 
665
                                                  ti->info.largeLodLog2,
 
666
                                                  ti->info.aspectRatioLog2,
 
667
                                                  ti->info.format,
 
668
                                                  GR_MIPMAPLEVELMASK_BOTH,
 
669
                                                  tObj->Image[l]->Data);
 
670
            }
 
671
        }
 
672
        break;
 
673
    case TDFX_TMU_SPLIT:
 
674
        if (ti->tm[TDFX_TMU0] && ti->tm[TDFX_TMU1]) {
 
675
            for (l = ti->minLevel; l <= ti->maxLevel
 
676
                    && tObj->Image[l]->Data; l++) {
 
677
                GrLOD_t glideLod = ti->info.largeLodLog2 - l + tObj->BaseLevel;
 
678
                fxMesa->Glide.grTexDownloadMipMapLevel(GR_TMU0,
 
679
                                                  ti->tm[TDFX_TMU0]->startAddr,
 
680
                                                  glideLod,
 
681
                                                  ti->info.largeLodLog2,
 
682
                                                  ti->info.aspectRatioLog2,
 
683
                                                  ti->info.format,
 
684
                                                  GR_MIPMAPLEVELMASK_ODD,
 
685
                                                  tObj->Image[l]->Data);
 
686
 
 
687
                fxMesa->Glide.grTexDownloadMipMapLevel(GR_TMU1,
 
688
                                                  ti->tm[TDFX_TMU1]->startAddr,
 
689
                                                  glideLod,
 
690
                                                  ti->info.largeLodLog2,
 
691
                                                  ti->info.aspectRatioLog2,
 
692
                                                  ti->info.format,
 
693
                                                  GR_MIPMAPLEVELMASK_EVEN,
 
694
                                                  tObj->Image[l]->Data);
 
695
            }
 
696
        }
 
697
        break;
 
698
    case TDFX_TMU_BOTH:
 
699
        if (ti->tm[TDFX_TMU0] && ti->tm[TDFX_TMU1]) {
 
700
            for (l = ti->minLevel; l <= ti->maxLevel
 
701
                    && tObj->Image[l]->Data; l++) {
 
702
                GrLOD_t glideLod = ti->info.largeLodLog2 - l + tObj->BaseLevel;
 
703
                fxMesa->Glide.grTexDownloadMipMapLevel(GR_TMU0,
 
704
                                                  ti->tm[TDFX_TMU0]->startAddr,
 
705
                                                  glideLod,
 
706
                                                  ti->info.largeLodLog2,
 
707
                                                  ti->info.aspectRatioLog2,
 
708
                                                  ti->info.format,
 
709
                                                  GR_MIPMAPLEVELMASK_BOTH,
 
710
                                                  tObj->Image[l]->Data);
 
711
 
 
712
                fxMesa->Glide.grTexDownloadMipMapLevel(GR_TMU1,
 
713
                                                  ti->tm[TDFX_TMU1]->startAddr,
 
714
                                                  glideLod,
 
715
                                                  ti->info.largeLodLog2,
 
716
                                                  ti->info.aspectRatioLog2,
 
717
                                                  ti->info.format,
 
718
                                                  GR_MIPMAPLEVELMASK_BOTH,
 
719
                                                  tObj->Image[l]->Data);
 
720
            }
 
721
        }
 
722
        break;
 
723
    default:
 
724
        _mesa_problem(NULL, "error in tdfxTMDownloadTexture: bad tmu");
 
725
        return;
 
726
    }
 
727
}
 
728
 
 
729
 
 
730
void
 
731
tdfxTMReloadMipMapLevel(GLcontext *ctx, struct gl_texture_object *tObj,
 
732
                        GLint level)
 
733
{
 
734
    tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
 
735
    tdfxTexInfo *ti = TDFX_TEXTURE_DATA(tObj);
 
736
    GrLOD_t glideLod;
 
737
    FxU32 tmu;
 
738
 
 
739
    tmu = ti->whichTMU;
 
740
    glideLod =  ti->info.largeLodLog2 - level + tObj->BaseLevel;
 
741
    ASSERT(ti->isInTM);
 
742
 
 
743
    LOCK_HARDWARE(fxMesa);
 
744
 
 
745
    switch (tmu) {
 
746
    case TDFX_TMU0:
 
747
    case TDFX_TMU1:
 
748
        fxMesa->Glide.grTexDownloadMipMapLevel(tmu,
 
749
                                    ti->tm[tmu]->startAddr,
 
750
                                    glideLod,
 
751
                                    ti->info.largeLodLog2,
 
752
                                    ti->info.aspectRatioLog2,
 
753
                                    ti->info.format,
 
754
                                    GR_MIPMAPLEVELMASK_BOTH,
 
755
                                    tObj->Image[level]->Data);
 
756
        break;
 
757
    case TDFX_TMU_SPLIT:
 
758
        fxMesa->Glide.grTexDownloadMipMapLevel(GR_TMU0,
 
759
                                    ti->tm[GR_TMU0]->startAddr,
 
760
                                    glideLod,
 
761
                                    ti->info.largeLodLog2,
 
762
                                    ti->info.aspectRatioLog2,
 
763
                                    ti->info.format,
 
764
                                    GR_MIPMAPLEVELMASK_ODD,
 
765
                                    tObj->Image[level]->Data);
 
766
 
 
767
        fxMesa->Glide.grTexDownloadMipMapLevel(GR_TMU1,
 
768
                                    ti->tm[GR_TMU1]->startAddr,
 
769
                                    glideLod,
 
770
                                    ti->info.largeLodLog2,
 
771
                                    ti->info.aspectRatioLog2,
 
772
                                    ti->info.format,
 
773
                                    GR_MIPMAPLEVELMASK_EVEN,
 
774
                                    tObj->Image[level]->Data);
 
775
        break;
 
776
    case TDFX_TMU_BOTH:
 
777
        fxMesa->Glide.grTexDownloadMipMapLevel(GR_TMU0,
 
778
                                    ti->tm[GR_TMU0]->startAddr,
 
779
                                    glideLod,
 
780
                                    ti->info.largeLodLog2,
 
781
                                    ti->info.aspectRatioLog2,
 
782
                                    ti->info.format,
 
783
                                    GR_MIPMAPLEVELMASK_BOTH,
 
784
                                    tObj->Image[level]->Data);
 
785
 
 
786
        fxMesa->Glide.grTexDownloadMipMapLevel(GR_TMU1,
 
787
                                    ti->tm[GR_TMU1]->startAddr,
 
788
                                    glideLod,
 
789
                                    ti->info.largeLodLog2,
 
790
                                    ti->info.aspectRatioLog2,
 
791
                                    ti->info.format,
 
792
                                    GR_MIPMAPLEVELMASK_BOTH,
 
793
                                    tObj->Image[level]->Data);
 
794
        break;
 
795
 
 
796
    default:
 
797
        _mesa_problem(ctx, "error in tdfxTMReloadMipMapLevel(): wrong tmu");
 
798
        break;
 
799
    }
 
800
    UNLOCK_HARDWARE(fxMesa);
 
801
}
 
802
 
 
803
 
 
804
/*
 
805
 * Allocate space for the given texture in texture memory then
 
806
 * download (copy) it into that space.
 
807
 */
 
808
void
 
809
tdfxTMMoveInTM_NoLock( tdfxContextPtr fxMesa, struct gl_texture_object *tObj,
 
810
                       FxU32 targetTMU )
 
811
{
 
812
    tdfxTexInfo *ti = TDFX_TEXTURE_DATA(tObj);
 
813
    FxU32 texmemsize;
 
814
 
 
815
    fxMesa->stats.reqTexUpload++;
 
816
 
 
817
    if (ti->isInTM) {
 
818
        if (ti->whichTMU == targetTMU)
 
819
            return;
 
820
        if (targetTMU == TDFX_TMU_SPLIT || ti->whichTMU == TDFX_TMU_SPLIT) {
 
821
            tdfxTMMoveOutTM_NoLock(fxMesa, tObj);
 
822
        }
 
823
        else {
 
824
            if (ti->whichTMU == TDFX_TMU_BOTH)
 
825
                return;
 
826
            targetTMU = TDFX_TMU_BOTH;
 
827
        }
 
828
    }
 
829
 
 
830
    ti->whichTMU = targetTMU;
 
831
 
 
832
    switch (targetTMU) {
 
833
    case TDFX_TMU0:
 
834
    case TDFX_TMU1:
 
835
        texmemsize = fxMesa->Glide.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH,
 
836
                                                       &(ti->info));
 
837
        ti->tm[targetTMU] = AllocTexMem(fxMesa, targetTMU, texmemsize);
 
838
        break;
 
839
    case TDFX_TMU_SPLIT:
 
840
        texmemsize = fxMesa->Glide.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_ODD,
 
841
                                                       &(ti->info));
 
842
        ti->tm[TDFX_TMU0] = AllocTexMem(fxMesa, TDFX_TMU0, texmemsize);
 
843
        if (ti->tm[TDFX_TMU0])
 
844
           fxMesa->stats.memTexUpload += texmemsize;
 
845
 
 
846
        texmemsize = fxMesa->Glide.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_EVEN,
 
847
                                                       &(ti->info));
 
848
        ti->tm[TDFX_TMU1] = AllocTexMem(fxMesa, TDFX_TMU1, texmemsize);
 
849
        break;
 
850
    case TDFX_TMU_BOTH:
 
851
        texmemsize = fxMesa->Glide.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH,
 
852
                                                       &(ti->info));
 
853
        ti->tm[TDFX_TMU0] = AllocTexMem(fxMesa, TDFX_TMU0, texmemsize);
 
854
        if (ti->tm[TDFX_TMU0])
 
855
           fxMesa->stats.memTexUpload += texmemsize;
 
856
 
 
857
        texmemsize = fxMesa->Glide.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH,
 
858
                                                       &(ti->info));
 
859
        ti->tm[TDFX_TMU1] = AllocTexMem(fxMesa, TDFX_TMU1, texmemsize);
 
860
        break;
 
861
    default:
 
862
        _mesa_problem(NULL, "error in tdfxTMMoveInTM() -> bad tmu (%d)");
 
863
        return;
 
864
    }
 
865
 
 
866
    ti->reloadImages = GL_TRUE;
 
867
    ti->isInTM = GL_TRUE;
 
868
 
 
869
    fxMesa->stats.texUpload++;
 
870
}
 
871
 
 
872
 
 
873
/*
 
874
 * Move the given texture out of hardware texture memory.
 
875
 * This deallocates the texture's memory space.
 
876
 */
 
877
void
 
878
tdfxTMMoveOutTM_NoLock( tdfxContextPtr fxMesa, struct gl_texture_object *tObj )
 
879
{
 
880
    struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
 
881
    struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
 
882
    tdfxTexInfo *ti = TDFX_TEXTURE_DATA(tObj);
 
883
 
 
884
    if (MESA_VERBOSE & VERBOSE_DRIVER) {
 
885
        fprintf(stderr, "fxmesa: fxTMMoveOutTM(%p (%d))\n", tObj, tObj->Name);
 
886
    }
 
887
 
 
888
    /*
 
889
    VerifyFreeList(fxMesa, 0);
 
890
    VerifyFreeList(fxMesa, 1);
 
891
    */
 
892
 
 
893
    if (!ti || !ti->isInTM)
 
894
        return;
 
895
 
 
896
    switch (ti->whichTMU) {
 
897
    case TDFX_TMU0:
 
898
    case TDFX_TMU1:
 
899
        RemoveRange_NoLock(fxMesa, ti->whichTMU, ti->tm[ti->whichTMU]);
 
900
        break;
 
901
    case TDFX_TMU_SPLIT:
 
902
    case TDFX_TMU_BOTH:
 
903
        assert(!shared->umaTexMemory);
 
904
        RemoveRange_NoLock(fxMesa, TDFX_TMU0, ti->tm[TDFX_TMU0]);
 
905
        RemoveRange_NoLock(fxMesa, TDFX_TMU1, ti->tm[TDFX_TMU1]);
 
906
        break;
 
907
    default:
 
908
        _mesa_problem(NULL, "tdfx driver: bad tmu in tdfxTMMOveOutTM()");
 
909
        return;
 
910
    }
 
911
 
 
912
    ti->isInTM = GL_FALSE;
 
913
    ti->tm[0] = NULL;
 
914
    ti->tm[1] = NULL;
 
915
    ti->whichTMU = TDFX_TMU_NONE;
 
916
 
 
917
    /*
 
918
    VerifyFreeList(fxMesa, 0);
 
919
    VerifyFreeList(fxMesa, 1);
 
920
    */
 
921
}
 
922
 
 
923
 
 
924
/*
 
925
 * Called via glDeleteTexture to delete a texture object.
 
926
 */
 
927
void
 
928
tdfxTMFreeTexture(tdfxContextPtr fxMesa, struct gl_texture_object *tObj)
 
929
{
 
930
    tdfxTexInfo *ti = TDFX_TEXTURE_DATA(tObj);
 
931
    if (ti) {
 
932
        tdfxTMMoveOutTM(fxMesa, tObj);
 
933
        FREE(ti);
 
934
        tObj->DriverData = NULL;
 
935
    }
 
936
    /*
 
937
    VerifyFreeList(fxMesa, 0);
 
938
    VerifyFreeList(fxMesa, 1);
 
939
    */
 
940
}
 
941
 
 
942
 
 
943
 
 
944
/*
 
945
 * After a context switch this function will be called to restore
 
946
 * texture memory for the new context.
 
947
 */
 
948
void tdfxTMRestoreTextures_NoLock( tdfxContextPtr fxMesa )
 
949
{
 
950
   GLcontext *ctx = fxMesa->glCtx;
 
951
   struct gl_texture_object *tObj;
 
952
   int i;
 
953
 
 
954
   for ( tObj = ctx->Shared->TexObjectList ; tObj ; tObj = tObj->Next ) {
 
955
      tdfxTexInfo *ti = TDFX_TEXTURE_DATA( tObj );
 
956
      if ( ti && ti->isInTM ) {
 
957
         for ( i = 0 ; i < MAX_TEXTURE_UNITS ; i++ ) {
 
958
            if ( ctx->Texture.Unit[i]._Current == tObj ) {
 
959
               tdfxTMDownloadTexture( fxMesa, tObj );
 
960
               break;
 
961
            }
 
962
         }
 
963
         if ( i == MAX_TEXTURE_UNITS ) {
 
964
            tdfxTMMoveOutTM_NoLock( fxMesa, tObj );
 
965
         }
 
966
      }
 
967
   }
 
968
   /*
 
969
   VerifyFreeList(fxMesa, 0);
 
970
   VerifyFreeList(fxMesa, 1);
 
971
   */
 
972
}