Remove unnecessary #include "mach64_common.h" which breaks the build for me.
[mesa.git] / src / mesa / drivers / dri / mach64 / mach64_texmem.c
1 /* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */
2 /*
3 * Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
4 * Cedar Park, Texas.
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 * on the rights to use, copy, modify, merge, publish, distribute, sub
11 * license, and/or sell copies of the Software, and to permit persons to whom
12 * the 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 NON-INFRINGEMENT. IN NO EVENT SHALL
21 * ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 * USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27 /*
28 * Authors:
29 * Gareth Hughes <gareth@valinux.com>
30 * Leif Delgass <ldelgass@retinalburn.net>
31 * José Fonseca <j_r_fonseca@yahoo.co.uk>
32 */
33
34 #include "mach64_context.h"
35 #include "mach64_state.h"
36 #include "mach64_ioctl.h"
37 #include "mach64_vb.h"
38 #include "mach64_tris.h"
39 #include "mach64_tex.h"
40
41 #include "context.h"
42 #include "macros.h"
43 #include "simple_list.h"
44 #include "texformat.h"
45 #include "imports.h"
46
47
48 /* Destroy hardware state associated with texture `t'.
49 */
50 void mach64DestroyTexObj( mach64ContextPtr mmesa, mach64TexObjPtr t )
51 {
52 #if ENABLE_PERF_BOXES
53 /* Bump the performace counter */
54 if (mmesa)
55 mmesa->c_textureSwaps++;
56 #endif
57 if ( !t ) return;
58
59 #if 0
60 if ( t->tObj && t->memBlock && mmesa ) {
61 /* not a placeholder, so release from global LRU if necessary */
62 int heap = t->heap;
63 drmTextureRegion *list = mmesa->sarea->tex_list[heap];
64 int log2sz = mmesa->mach64Screen->logTexGranularity[heap];
65 int start = t->memBlock->ofs >> log2sz;
66 int end = (t->memBlock->ofs + t->memBlock->size - 1) >> log2sz;
67 int i;
68
69 mmesa->lastTexAge[heap] = ++mmesa->sarea->tex_age[heap];
70
71 /* Update the global LRU */
72 for ( i = start ; i <= end ; i++ ) {
73 /* do we own this block? */
74 if (list[i].in_use == mmesa->hHWContext) {
75 list[i].in_use = 0;
76 list[i].age = mmesa->lastTexAge[heap];
77
78 /* remove_from_list(i) */
79 list[(GLuint)list[i].next].prev = list[i].prev;
80 list[(GLuint)list[i].prev].next = list[i].next;
81 }
82 }
83 }
84 #endif
85
86 if ( t->memBlock ) {
87 mmFreeMem( t->memBlock );
88 t->memBlock = NULL;
89 }
90
91 if ( t->tObj ) {
92 t->tObj->DriverData = NULL;
93 }
94
95 if ( t->bound && mmesa )
96 mmesa->CurrentTexObj[t->bound-1] = NULL;
97
98 remove_from_list( t );
99 FREE( t );
100 }
101
102 /* Keep track of swapped out texture objects.
103 */
104 void mach64SwapOutTexObj( mach64ContextPtr mmesa,
105 mach64TexObjPtr t )
106 {
107 #if ENABLE_PERF_BOXES
108 /* Bump the performace counter */
109 if (mmesa)
110 mmesa->c_textureSwaps++;
111 #endif
112
113 #if 0
114 if ( t->tObj && t->memBlock && mmesa ) {
115 /* not a placeholder, so release from global LRU if necessary */
116 int heap = t->heap;
117 drmTextureRegion *list = mmesa->sarea->tex_list[heap];
118 int log2sz = mmesa->mach64Screen->logTexGranularity[heap];
119 int start = t->memBlock->ofs >> log2sz;
120 int end = (t->memBlock->ofs + t->memBlock->size - 1) >> log2sz;
121 int i;
122
123 mmesa->lastTexAge[heap] = ++mmesa->sarea->tex_age[heap];
124
125 /* Update the global LRU */
126 for ( i = start ; i <= end ; i++ ) {
127 /* do we own this block? */
128 if (list[i].in_use == mmesa->hHWContext) {
129 list[i].in_use = 0;
130 list[i].age = mmesa->lastTexAge[heap];
131
132 /* remove_from_list(i) */
133 list[(GLuint)list[i].next].prev = list[i].prev;
134 list[(GLuint)list[i].prev].next = list[i].next;
135 }
136 }
137 }
138 #endif
139
140 if ( t->memBlock ) {
141 mmFreeMem( t->memBlock );
142 t->memBlock = NULL;
143 }
144
145 t->dirty = ~0;
146 move_to_tail( &mmesa->SwappedOut, t );
147 }
148
149 /* Print out debugging information about texture LRU.
150 */
151 void mach64PrintLocalLRU( mach64ContextPtr mmesa, int heap )
152 {
153 mach64TexObjPtr t;
154 int sz = 1 << (mmesa->mach64Screen->logTexGranularity[heap]);
155
156 fprintf( stderr, "\nLocal LRU, heap %d:\n", heap );
157
158 foreach( t, &mmesa->TexObjList[heap] ) {
159 if ( !t->tObj ) {
160 fprintf( stderr, "Placeholder %d at 0x%x sz 0x%x\n",
161 t->memBlock->ofs / sz,
162 t->memBlock->ofs,
163 t->memBlock->size );
164 } else {
165 fprintf( stderr, "Texture (bound %d) at 0x%x sz 0x%x\n",
166 t->bound,
167 t->memBlock->ofs,
168 t->memBlock->size );
169 }
170 }
171
172 fprintf( stderr, "\n" );
173 }
174
175 void mach64PrintGlobalLRU( mach64ContextPtr mmesa, int heap )
176 {
177 drmTextureRegion *list = mmesa->sarea->tex_list[heap];
178 int i, j;
179
180 fprintf( stderr, "\nGlobal LRU, heap %d list %p:\n", heap, list );
181
182 for ( i = 0, j = MACH64_NR_TEX_REGIONS ; i < MACH64_NR_TEX_REGIONS ; i++ ) {
183 fprintf( stderr, "list[%d] age %d in_use %d next %d prev %d\n",
184 j, list[j].age, list[j].in_use, list[j].next, list[j].prev );
185 j = list[j].next;
186 if ( j == MACH64_NR_TEX_REGIONS ) break;
187 }
188
189 if ( j != MACH64_NR_TEX_REGIONS ) {
190 fprintf( stderr, "Loop detected in global LRU\n" );
191 for ( i = 0 ; i < MACH64_NR_TEX_REGIONS ; i++ ) {
192 fprintf( stderr, "list[%d] age %d in_use %d next %d prev %d\n",
193 i, list[i].age, list[i].in_use, list[i].next, list[i].prev );
194 }
195 }
196
197 fprintf( stderr, "\n" );
198 }
199
200 /* Reset the global texture LRU.
201 */
202 /* NOTE: This function is only called while holding the hardware lock */
203 static void mach64ResetGlobalLRU( mach64ContextPtr mmesa, int heap )
204 {
205 drmTextureRegion *list = mmesa->sarea->tex_list[heap];
206 int sz = 1 << mmesa->mach64Screen->logTexGranularity[heap];
207 int i;
208
209 /* (Re)initialize the global circular LRU list. The last element in
210 * the array (MACH64_NR_TEX_REGIONS) is the sentinal. Keeping it at
211 * the end of the array allows it to be addressed rationally when
212 * looking up objects at a particular location in texture memory.
213 */
214 for ( i = 0 ; (i+1) * sz <= mmesa->mach64Screen->texSize[heap] ; i++ ) {
215 list[i].prev = i-1;
216 list[i].next = i+1;
217 list[i].age = 0;
218 list[i].in_use = 0;
219 }
220
221 i--;
222 list[0].prev = MACH64_NR_TEX_REGIONS;
223 list[i].prev = i-1;
224 list[i].next = MACH64_NR_TEX_REGIONS;
225 list[MACH64_NR_TEX_REGIONS].prev = i;
226 list[MACH64_NR_TEX_REGIONS].next = 0;
227 mmesa->sarea->tex_age[heap] = 0;
228 }
229
230 /* Update the local and global texture LRUs.
231 */
232 /* NOTE: This function is only called while holding the hardware lock */
233 void mach64UpdateTexLRU( mach64ContextPtr mmesa,
234 mach64TexObjPtr t )
235 {
236 int heap = t->heap;
237 drmTextureRegion *list = mmesa->sarea->tex_list[heap];
238 int log2sz = mmesa->mach64Screen->logTexGranularity[heap];
239 int start = t->memBlock->ofs >> log2sz;
240 int end = (t->memBlock->ofs + t->memBlock->size - 1) >> log2sz;
241 int i;
242
243 mmesa->lastTexAge[heap] = ++mmesa->sarea->tex_age[heap];
244
245 if ( !t->memBlock ) {
246 fprintf( stderr, "no memblock\n\n" );
247 return;
248 }
249
250 /* Update our local LRU */
251 move_to_head( &mmesa->TexObjList[heap], t );
252
253 /* Update the global LRU */
254 for ( i = start ; i <= end ; i++ ) {
255 list[i].in_use = mmesa->hHWContext;
256 list[i].age = mmesa->lastTexAge[heap];
257
258 #if 0
259 /* if this is the last region, it's not in the list */
260 if ( !(i*(1<<log2sz) > mmesa->mach64Screen->texSize[heap] ) ) {
261 #endif
262 /* remove_from_list(i) */
263 list[(GLuint)list[i].next].prev = list[i].prev;
264 list[(GLuint)list[i].prev].next = list[i].next;
265 #if 0
266 }
267 #endif
268
269 /* insert_at_head(list, i) */
270 list[i].prev = MACH64_NR_TEX_REGIONS;
271 list[i].next = list[MACH64_NR_TEX_REGIONS].next;
272 list[(GLuint)list[MACH64_NR_TEX_REGIONS].next].prev = i;
273 list[MACH64_NR_TEX_REGIONS].next = i;
274 }
275
276 if ( MACH64_DEBUG & DEBUG_VERBOSE_LRU ) {
277 mach64PrintGlobalLRU( mmesa, t->heap );
278 mach64PrintLocalLRU( mmesa, t->heap );
279 }
280 }
281
282 /* Update our notion of what textures have been changed since we last
283 * held the lock. This pertains to both our local textures and the
284 * textures belonging to other clients. Keep track of other client's
285 * textures by pushing a placeholder texture onto the LRU list -- these
286 * are denoted by (tObj == NULL).
287 */
288 /* NOTE: This function is only called while holding the hardware lock */
289 static void mach64TexturesGone( mach64ContextPtr mmesa, int heap,
290 int offset, int size, int in_use )
291 {
292 mach64TexObjPtr t, tmp;
293
294 foreach_s ( t, tmp, &mmesa->TexObjList[heap] ) {
295 if ( t->memBlock->ofs >= offset + size ||
296 t->memBlock->ofs + t->memBlock->size <= offset )
297 continue;
298
299 /* It overlaps - kick it out. Need to hold onto the currently
300 * bound objects, however.
301 */
302 if ( t->bound ) {
303 mach64SwapOutTexObj( mmesa, t );
304 } else {
305 mach64DestroyTexObj( mmesa, t );
306 }
307 }
308
309 if ( in_use > 0 && in_use != mmesa->hHWContext ) {
310 t = (mach64TexObjPtr) CALLOC( sizeof(*t) );
311 if (!t) return;
312
313 t->memBlock = mmAllocMem( mmesa->texHeap[heap], size, 0, offset );
314 if ( !t->memBlock ) {
315 fprintf( stderr, "Couldn't alloc placeholder sz %x ofs %x\n",
316 (int)size, (int)offset );
317 mmDumpMemInfo( mmesa->texHeap[heap] );
318 return;
319 }
320 insert_at_head( &mmesa->TexObjList[heap], t );
321 }
322 }
323
324 /* Update our client's shared texture state. If another client has
325 * modified a region in which we have textures, then we need to figure
326 * out which of our textures has been removed, and update our global
327 * LRU.
328 */
329 void mach64AgeTextures( mach64ContextPtr mmesa, int heap )
330 {
331 drm_mach64_sarea_t *sarea = mmesa->sarea;
332
333 if ( sarea->tex_age[heap] != mmesa->lastTexAge[heap] ) {
334 int sz = 1 << mmesa->mach64Screen->logTexGranularity[heap];
335 int nr = 0;
336 int idx;
337
338 /* Have to go right round from the back to ensure stuff ends up
339 * LRU in our local list... Fix with a cursor pointer.
340 */
341 for ( idx = sarea->tex_list[heap][MACH64_NR_TEX_REGIONS].prev ;
342 idx != MACH64_NR_TEX_REGIONS && nr < MACH64_NR_TEX_REGIONS ;
343 idx = sarea->tex_list[heap][idx].prev, nr++ )
344 {
345 /* If switching texturing schemes, then the SAREA might not
346 * have been properly cleared, so we need to reset the
347 * global texture LRU.
348 */
349 if ( idx * sz > mmesa->mach64Screen->texSize[heap] ) {
350 nr = MACH64_NR_TEX_REGIONS;
351 break;
352 }
353
354 if ( sarea->tex_list[heap][idx].age > mmesa->lastTexAge[heap] ) {
355 mach64TexturesGone( mmesa, heap, idx * sz, sz,
356 sarea->tex_list[heap][idx].in_use );
357 }
358 }
359
360 /* If switching texturing schemes, then the SAREA might not
361 * have been properly cleared, so we need to reset the
362 * global texture LRU.
363 */
364 if ( nr == MACH64_NR_TEX_REGIONS ) {
365 mach64TexturesGone( mmesa, heap, 0,
366 mmesa->mach64Screen->texSize[heap], 0 );
367 mach64ResetGlobalLRU( mmesa, heap );
368 }
369
370 if ( 0 ) {
371 mach64PrintGlobalLRU( mmesa, heap );
372 mach64PrintLocalLRU( mmesa, heap );
373 }
374
375 mmesa->dirty |= (MACH64_UPLOAD_CONTEXT |
376 MACH64_UPLOAD_TEX0IMAGE |
377 MACH64_UPLOAD_TEX1IMAGE);
378 mmesa->lastTexAge[heap] = sarea->tex_age[heap];
379 }
380 }
381
382 /* Upload the texture image associated with texture `t' at level `level'
383 * at the address relative to `start'.
384 */
385 static void mach64UploadAGPSubImage( mach64ContextPtr mmesa,
386 mach64TexObjPtr t, int level,
387 int x, int y, int width, int height )
388 {
389 mach64ScreenRec *mach64Screen = mmesa->mach64Screen;
390 struct gl_texture_image *image;
391 int texelsPerDword = 0;
392 int dwords;
393
394 /* Ensure we have a valid texture to upload */
395 if ( ( level < 0 ) || ( level > mmesa->glCtx->Const.MaxTextureLevels ) )
396 return;
397
398 image = t->tObj->Image[0][level];
399 if ( !image )
400 return;
401
402 switch ( image->TexFormat->TexelBytes ) {
403 case 1: texelsPerDword = 4; break;
404 case 2: texelsPerDword = 2; break;
405 case 4: texelsPerDword = 1; break;
406 }
407
408 #if 1
409 /* FIXME: The subimage index calcs are wrong... */
410 x = 0;
411 y = 0;
412 width = image->Width;
413 height = image->Height;
414 #endif
415
416 dwords = width * height / texelsPerDword;
417
418 #if ENABLE_PERF_BOXES
419 /* Bump the performance counter */
420 mmesa->c_agpTextureBytes += (dwords << 2);
421 #endif
422
423 if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) {
424 fprintf( stderr, "mach64UploadSubImage: %d,%d of %d,%d at %d,%d\n",
425 width, height, image->Width, image->Height, x, y );
426 fprintf( stderr, " blit ofs: 0x%07x pitch: 0x%x dwords: %d\n",
427 (GLuint)t->offset, (GLint)width, dwords );
428 mmDumpMemInfo( mmesa->texHeap[t->heap] );
429 }
430
431 assert(image->Data);
432
433 {
434 CARD32 *dst = (CARD32 *)((char *)mach64Screen->agpTextures.map + t->memBlock->ofs);
435 const GLubyte *src = (const GLubyte *) image->Data +
436 (y * image->Width + x) * image->TexFormat->TexelBytes;
437 const GLuint bytes = width * height * image->TexFormat->TexelBytes;
438 memcpy(dst, src, bytes);
439 }
440
441 }
442
443 /* Upload the texture image associated with texture `t' at level `level'
444 * at the address relative to `start'.
445 */
446 static void mach64UploadLocalSubImage( mach64ContextPtr mmesa,
447 mach64TexObjPtr t, int level,
448 int x, int y, int width, int height )
449 {
450 struct gl_texture_image *image;
451 int texelsPerDword = 0;
452 int imageWidth, imageHeight;
453 int remaining, rows;
454 int format, dwords;
455 const int maxdwords = (MACH64_BUFFER_MAX_DWORDS - (MACH64_HOSTDATA_BLIT_OFFSET / 4));
456 CARD32 pitch, offset;
457 int i;
458
459 /* Ensure we have a valid texture to upload */
460 if ( ( level < 0 ) || ( level > mmesa->glCtx->Const.MaxTextureLevels ) )
461 return;
462
463 image = t->tObj->Image[0][level];
464 if ( !image )
465 return;
466
467 switch ( image->TexFormat->TexelBytes ) {
468 case 1: texelsPerDword = 4; break;
469 case 2: texelsPerDword = 2; break;
470 case 4: texelsPerDword = 1; break;
471 }
472
473 #if 1
474 /* FIXME: The subimage index calcs are wrong... */
475 x = 0;
476 y = 0;
477 width = image->Width;
478 height = image->Height;
479 #endif
480
481 imageWidth = image->Width;
482 imageHeight = image->Height;
483
484 format = t->textureFormat;
485
486 /* The texel upload routines have a minimum width, so force the size
487 * if needed.
488 */
489 if ( imageWidth < texelsPerDword ) {
490 int factor;
491
492 factor = texelsPerDword / imageWidth;
493 imageWidth = texelsPerDword;
494 imageHeight /= factor;
495 if ( imageHeight == 0 ) {
496 /* In this case, the texel converter will actually walk a
497 * texel or two off the end of the image, but normal malloc
498 * alignment should prevent it from ever causing a fault.
499 */
500 imageHeight = 1;
501 }
502 }
503
504 /* We can't upload to a pitch less than 64 texels so we will need to
505 * linearly upload all modified rows for textures smaller than this.
506 * This makes the x/y/width/height different for the blitter and the
507 * texture walker.
508 */
509 if ( imageWidth >= 64 ) {
510 /* The texture walker and the blitter look identical */
511 pitch = imageWidth >> 3;
512 } else {
513 int factor;
514 int y2;
515 int start, end;
516
517 start = (y * imageWidth) & ~63;
518 end = (y + height) * imageWidth;
519
520 if ( end - start < 64 ) {
521 /* Handle the case where the total number of texels
522 * uploaded is < 64.
523 */
524 x = 0;
525 y = start / 64;
526 width = end - start;
527 height = 1;
528 } else {
529 /* Upload some number of full 64 texel blit rows */
530 factor = 64 / imageWidth;
531
532 y2 = y + height - 1;
533 y /= factor;
534 y2 /= factor;
535
536 x = 0;
537 width = 64;
538 height = y2 - y + 1;
539 }
540
541 /* Fixed pitch of 64 */
542 pitch = 8;
543 }
544
545 dwords = width * height / texelsPerDword;
546 offset = t->offset;
547
548 #if ENABLE_PERF_BOXES
549 /* Bump the performance counter */
550 mmesa->c_textureBytes += (dwords << 2);
551 #endif
552
553 if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) {
554 fprintf( stderr, "mach64UploadSubImage: %d,%d of %d,%d at %d,%d\n",
555 width, height, image->Width, image->Height, x, y );
556 fprintf( stderr, " blit ofs: 0x%07x pitch: 0x%x dwords: %d\n",
557 (GLuint)offset, (GLint)width, dwords );
558 mmDumpMemInfo( mmesa->texHeap[t->heap] );
559 }
560
561 /* Subdivide the texture if required (account for the registers added by the drm) */
562 if ( dwords <= maxdwords ) {
563 rows = height;
564 } else {
565 rows = (maxdwords * texelsPerDword) / (2 * width);
566 }
567
568 for ( i = 0, remaining = height ;
569 remaining > 0 ;
570 remaining -= rows, y += rows, i++ )
571 {
572 drmBufPtr buffer;
573 CARD32 *dst;
574
575 height = MIN2(remaining, rows);
576
577 /* Grab the dma buffer for the texture blit */
578 buffer = mach64GetBufferLocked( mmesa );
579
580 dst = (CARD32 *)((char *)buffer->address + MACH64_HOSTDATA_BLIT_OFFSET);
581
582 assert(image->Data);
583
584 {
585 const GLubyte *src = (const GLubyte *) image->Data +
586 (y * image->Width + x) * image->TexFormat->TexelBytes;
587 const GLuint bytes = width * height * image->TexFormat->TexelBytes;
588 memcpy(dst, src, bytes);
589 }
590
591 mach64FireBlitLocked( mmesa, buffer, offset, pitch, format,
592 x, y, width, height );
593
594 }
595
596 mmesa->new_state |= MACH64_NEW_CONTEXT;
597 mmesa->dirty |= MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC;
598 }
599
600
601 /* Upload the texture images associated with texture `t'. This might
602 * require removing our own and/or other client's texture objects to
603 * make room for these images.
604 */
605 void mach64UploadTexImages( mach64ContextPtr mmesa, mach64TexObjPtr t )
606 {
607 GLint heap;
608
609 if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) {
610 fprintf( stderr, "%s( %p, %p )\n",
611 __FUNCTION__, mmesa->glCtx, t );
612 }
613
614 assert(t);
615 assert(t->tObj);
616
617 /* Choose the heap appropriately */
618 heap = MACH64_CARD_HEAP;
619
620 if ( !mmesa->mach64Screen->IsPCI &&
621 t->size > mmesa->mach64Screen->texSize[heap] ) {
622 heap = MACH64_AGP_HEAP;
623 }
624
625 /* Do we need to eject LRU texture objects? */
626 if ( !t->memBlock ) {
627 t->heap = heap;
628
629 /* Allocate a memory block on a 64-byte boundary */
630 t->memBlock = mmAllocMem( mmesa->texHeap[heap], t->size, 6, 0 );
631
632 /* Try AGP before kicking anything out of local mem */
633 if ( !mmesa->mach64Screen->IsPCI && !t->memBlock && heap == MACH64_CARD_HEAP ) {
634 t->memBlock = mmAllocMem( mmesa->texHeap[MACH64_AGP_HEAP],
635 t->size, 6, 0 );
636
637 if ( t->memBlock )
638 heap = t->heap = MACH64_AGP_HEAP;
639 }
640
641 /* Kick out textures until the requested texture fits */
642 while ( !t->memBlock ) {
643 if ( mmesa->TexObjList[heap].prev->bound ) {
644 fprintf( stderr,
645 "mach64UploadTexImages: ran into bound texture\n" );
646 return;
647 }
648 if ( mmesa->TexObjList[heap].prev == &mmesa->TexObjList[heap] ) {
649 if ( mmesa->mach64Screen->IsPCI ) {
650 fprintf( stderr, "%s: upload texture failure on "
651 "local texture heaps, sz=%d\n", __FUNCTION__,
652 t->size );
653 return;
654 } else if ( heap == MACH64_CARD_HEAP ) {
655 heap = t->heap = MACH64_AGP_HEAP;
656 continue;
657 } else {
658 int i;
659 fprintf( stderr, "%s: upload texture failure on "
660 "%sAGP texture heaps, sz=%d\n", __FUNCTION__,
661 mmesa->firstTexHeap == MACH64_CARD_HEAP ? "both local and " : "",
662 t->size );
663 for ( i = mmesa->firstTexHeap ; i < mmesa->lastTexHeap ; i++ ) {
664 mach64PrintLocalLRU( mmesa, i );
665 mmDumpMemInfo( mmesa->texHeap[i] );
666 }
667 exit(-1);
668 return;
669 }
670 }
671
672 mach64SwapOutTexObj( mmesa, mmesa->TexObjList[heap].prev );
673
674 t->memBlock = mmAllocMem( mmesa->texHeap[heap], t->size, 6, 0 );
675 }
676
677 /* Set the base offset of the texture image */
678 t->offset = mmesa->mach64Screen->texOffset[heap] + t->memBlock->ofs;
679
680 /* Force loading the new state into the hardware */
681 mmesa->dirty |= (MACH64_UPLOAD_SCALE_3D_CNTL |
682 MACH64_UPLOAD_TEXTURE);
683 }
684
685 /* Let the world know we've used this memory recently */
686 mach64UpdateTexLRU( mmesa, t );
687
688 /* Upload any images that are new */
689 if ( t->dirty ) {
690 if (t->heap == MACH64_AGP_HEAP) {
691 /* Need to make sure any vertex buffers in the queue complete */
692 mach64WaitForIdleLocked( mmesa );
693 mach64UploadAGPSubImage( mmesa, t, t->tObj->BaseLevel, 0, 0,
694 t->tObj->Image[0][t->tObj->BaseLevel]->Width,
695 t->tObj->Image[0][t->tObj->BaseLevel]->Height );
696 } else {
697 mach64UploadLocalSubImage( mmesa, t, t->tObj->BaseLevel, 0, 0,
698 t->tObj->Image[0][t->tObj->BaseLevel]->Width,
699 t->tObj->Image[0][t->tObj->BaseLevel]->Height );
700 }
701
702 mmesa->setup.tex_cntl |= MACH64_TEX_CACHE_FLUSH;
703 }
704
705 mmesa->dirty |= MACH64_UPLOAD_TEXTURE;
706
707 t->dirty = 0;
708 }
709
710 /* The mach64 needs to have both primary and secondary textures in either
711 * local or AGP memory, so we need a "buddy system" to make sure that allocation
712 * succeeds or fails for both textures.
713 * FIXME: This needs to be optimized better.
714 */
715 void mach64UploadMultiTexImages( mach64ContextPtr mmesa,
716 mach64TexObjPtr t0,
717 mach64TexObjPtr t1 )
718 {
719 GLint heap;
720
721 if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) {
722 fprintf( stderr, "%s( %p, %p %p )\n",
723 __FUNCTION__, mmesa->glCtx, t0, t1 );
724 }
725
726 assert(t0 && t1);
727 assert(t0->tObj && t1->tObj);
728
729 /* Choose the heap appropriately */
730 heap = MACH64_CARD_HEAP;
731
732 if ( !mmesa->mach64Screen->IsPCI &&
733 ((t0->size + t1->size) > mmesa->mach64Screen->texSize[heap]) ) {
734 heap = MACH64_AGP_HEAP;
735 }
736
737 /* Do we need to eject LRU texture objects? */
738 if ( !t0->memBlock || !t1->memBlock || t0->heap != t1->heap ) {
739 /* FIXME: starting from scratch for now to keep it simple */
740 if ( t0->memBlock ) {
741 mach64SwapOutTexObj( mmesa, t0 );
742 }
743 if ( t1->memBlock ) {
744 mach64SwapOutTexObj( mmesa, t1 );
745 }
746 t0->heap = t1->heap = heap;
747 /* Allocate a memory block on a 64-byte boundary */
748 t0->memBlock = mmAllocMem( mmesa->texHeap[heap], t0->size, 6, 0 );
749 if ( t0->memBlock ) {
750 t1->memBlock = mmAllocMem( mmesa->texHeap[heap], t1->size, 6, 0 );
751 if ( !t1->memBlock ) {
752 mmFreeMem( t0->memBlock );
753 t0->memBlock = NULL;
754 }
755 }
756 /* Try AGP before kicking anything out of local mem */
757 if ( (!t0->memBlock || !t1->memBlock) && heap == MACH64_CARD_HEAP ) {
758 t0->memBlock = mmAllocMem( mmesa->texHeap[MACH64_AGP_HEAP], t0->size, 6, 0 );
759 if ( t0->memBlock ) {
760 t1->memBlock = mmAllocMem( mmesa->texHeap[MACH64_AGP_HEAP], t1->size, 6, 0 );
761 if ( !t1->memBlock ) {
762 mmFreeMem( t0->memBlock );
763 t0->memBlock = NULL;
764 }
765 }
766
767 if ( t0->memBlock && t1->memBlock )
768 heap = t0->heap = t1->heap = MACH64_AGP_HEAP;
769 }
770
771 /* Kick out textures until the requested texture fits */
772 while ( !t0->memBlock || !t1->memBlock ) {
773 if ( mmesa->TexObjList[heap].prev->bound ) {
774 fprintf( stderr,
775 "%s: ran into bound texture\n", __FUNCTION__ );
776 return;
777 }
778 if ( mmesa->TexObjList[heap].prev == &mmesa->TexObjList[heap] ) {
779 if ( mmesa->mach64Screen->IsPCI ) {
780 fprintf( stderr, "%s: upload texture failure on local "
781 "texture heaps, tex0 sz=%d tex1 sz=%d\n", __FUNCTION__,
782 t0->size, t1->size );
783 return;
784 } else if ( heap == MACH64_CARD_HEAP ) {
785 /* If only one allocation succeeded, start over again in AGP */
786 if (t0->memBlock) {
787 mmFreeMem( t0->memBlock );
788 t0->memBlock = NULL;
789 }
790 if (t1->memBlock) {
791 mmFreeMem( t1->memBlock );
792 t1->memBlock = NULL;
793 }
794 heap = t0->heap = t1->heap = MACH64_AGP_HEAP;
795 continue;
796 } else {
797 int i;
798 fprintf( stderr, "%s: upload texture failure on %s"
799 "AGP texture heaps, tex0 sz=%d tex1 sz=%d\n", __FUNCTION__,
800 mmesa->firstTexHeap == MACH64_CARD_HEAP ? "both local and " : "",
801 t0->size, t1->size );
802 for ( i = mmesa->firstTexHeap ; i < mmesa->lastTexHeap ; i++ ) {
803 mach64PrintLocalLRU( mmesa, i );
804 mmDumpMemInfo( mmesa->texHeap[i] );
805 }
806 exit(-1);
807 return;
808 }
809 }
810
811 mach64SwapOutTexObj( mmesa, mmesa->TexObjList[heap].prev );
812
813 if (!t0->memBlock)
814 t0->memBlock = mmAllocMem( mmesa->texHeap[heap], t0->size, 6, 0 );
815 if (!t1->memBlock)
816 t1->memBlock = mmAllocMem( mmesa->texHeap[heap], t1->size, 6, 0 );
817 }
818
819 /* Set the base offset of the texture image */
820 t0->offset = mmesa->mach64Screen->texOffset[heap] + t0->memBlock->ofs;
821 t1->offset = mmesa->mach64Screen->texOffset[heap] + t1->memBlock->ofs;
822
823 /* Force loading the new state into the hardware */
824 mmesa->dirty |= (MACH64_UPLOAD_SCALE_3D_CNTL |
825 MACH64_UPLOAD_TEXTURE);
826 }
827
828 /* Let the world know we've used this memory recently */
829 mach64UpdateTexLRU( mmesa, t0 );
830 mach64UpdateTexLRU( mmesa, t1 );
831
832 /* Upload any images that are new */
833 if ( t0->dirty ) {
834 if (t0->heap == MACH64_AGP_HEAP) {
835 /* Need to make sure any vertex buffers in the queue complete */
836 mach64WaitForIdleLocked( mmesa );
837 mach64UploadAGPSubImage( mmesa, t0, t0->tObj->BaseLevel, 0, 0,
838 t0->tObj->Image[0][t0->tObj->BaseLevel]->Width,
839 t0->tObj->Image[0][t0->tObj->BaseLevel]->Height );
840 } else {
841 mach64UploadLocalSubImage( mmesa, t0, t0->tObj->BaseLevel, 0, 0,
842 t0->tObj->Image[0][t0->tObj->BaseLevel]->Width,
843 t0->tObj->Image[0][t0->tObj->BaseLevel]->Height );
844 }
845 mmesa->setup.tex_cntl |= MACH64_TEX_CACHE_FLUSH;
846 }
847 if ( t1->dirty ) {
848 if (t1->heap == MACH64_AGP_HEAP) {
849 /* Need to make sure any vertex buffers in the queue complete */
850 mach64WaitForIdleLocked( mmesa );
851 mach64UploadAGPSubImage( mmesa, t1, t1->tObj->BaseLevel, 0, 0,
852 t1->tObj->Image[0][t1->tObj->BaseLevel]->Width,
853 t1->tObj->Image[0][t1->tObj->BaseLevel]->Height );
854 } else {
855 mach64UploadLocalSubImage( mmesa, t1, t1->tObj->BaseLevel, 0, 0,
856 t1->tObj->Image[0][t1->tObj->BaseLevel]->Width,
857 t1->tObj->Image[0][t1->tObj->BaseLevel]->Height );
858 }
859
860 mmesa->setup.tex_cntl |= MACH64_TEX_CACHE_FLUSH;
861 }
862
863 mmesa->dirty |= MACH64_UPLOAD_TEXTURE;
864
865 t0->dirty = 0;
866 t1->dirty = 0;
867 }