1 /* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */
3 * Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
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:
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
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.
29 * Gareth Hughes <gareth@valinux.com>
30 * Leif Delgass <ldelgass@retinalburn.net>
31 * José Fonseca <j_r_fonseca@yahoo.co.uk>
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"
43 #include "simple_list.h"
44 #include "texformat.h"
48 /* Destroy hardware state associated with texture `t'.
50 void mach64DestroyTexObj( mach64ContextPtr mmesa
, mach64TexObjPtr t
)
53 /* Bump the performace counter */
55 mmesa
->c_textureSwaps
++;
60 if ( t
->tObj
&& t
->memBlock
&& mmesa
) {
61 /* not a placeholder, so release from global LRU if necessary */
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
;
69 mmesa
->lastTexAge
[heap
] = ++mmesa
->sarea
->tex_age
[heap
];
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
) {
76 list
[i
].age
= mmesa
->lastTexAge
[heap
];
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
;
87 mmFreeMem( t
->memBlock
);
92 t
->tObj
->DriverData
= NULL
;
95 if ( t
->bound
&& mmesa
)
96 mmesa
->CurrentTexObj
[t
->bound
-1] = NULL
;
98 remove_from_list( t
);
102 /* Keep track of swapped out texture objects.
104 void mach64SwapOutTexObj( mach64ContextPtr mmesa
,
107 #if ENABLE_PERF_BOXES
108 /* Bump the performace counter */
110 mmesa
->c_textureSwaps
++;
114 if ( t
->tObj
&& t
->memBlock
&& mmesa
) {
115 /* not a placeholder, so release from global LRU if necessary */
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
;
123 mmesa
->lastTexAge
[heap
] = ++mmesa
->sarea
->tex_age
[heap
];
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
) {
130 list
[i
].age
= mmesa
->lastTexAge
[heap
];
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
;
141 mmFreeMem( t
->memBlock
);
146 move_to_tail( &mmesa
->SwappedOut
, t
);
149 /* Print out debugging information about texture LRU.
151 void mach64PrintLocalLRU( mach64ContextPtr mmesa
, int heap
)
154 int sz
= 1 << (mmesa
->mach64Screen
->logTexGranularity
[heap
]);
156 fprintf( stderr
, "\nLocal LRU, heap %d:\n", heap
);
158 foreach( t
, &mmesa
->TexObjList
[heap
] ) {
160 fprintf( stderr
, "Placeholder %d at 0x%x sz 0x%x\n",
161 t
->memBlock
->ofs
/ sz
,
165 fprintf( stderr
, "Texture (bound %d) at 0x%x sz 0x%x\n",
172 fprintf( stderr
, "\n" );
175 void mach64PrintGlobalLRU( mach64ContextPtr mmesa
, int heap
)
177 drmTextureRegion
*list
= mmesa
->sarea
->tex_list
[heap
];
180 fprintf( stderr
, "\nGlobal LRU, heap %d list %p:\n", heap
, list
);
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
);
186 if ( j
== MACH64_NR_TEX_REGIONS
) break;
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
);
197 fprintf( stderr
, "\n" );
200 /* Reset the global texture LRU.
202 /* NOTE: This function is only called while holding the hardware lock */
203 static void mach64ResetGlobalLRU( mach64ContextPtr mmesa
, int heap
)
205 drmTextureRegion
*list
= mmesa
->sarea
->tex_list
[heap
];
206 int sz
= 1 << mmesa
->mach64Screen
->logTexGranularity
[heap
];
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.
214 for ( i
= 0 ; (i
+1) * sz
<= mmesa
->mach64Screen
->texSize
[heap
] ; i
++ ) {
222 list
[0].prev
= MACH64_NR_TEX_REGIONS
;
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;
230 /* Update the local and global texture LRUs.
232 /* NOTE: This function is only called while holding the hardware lock */
233 void mach64UpdateTexLRU( mach64ContextPtr mmesa
,
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
;
243 mmesa
->lastTexAge
[heap
] = ++mmesa
->sarea
->tex_age
[heap
];
245 if ( !t
->memBlock
) {
246 fprintf( stderr
, "no memblock\n\n" );
250 /* Update our local LRU */
251 move_to_head( &mmesa
->TexObjList
[heap
], t
);
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
];
259 /* if this is the last region, it's not in the list */
260 if ( !(i
*(1<<log2sz
) > mmesa
->mach64Screen
->texSize
[heap
] ) ) {
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
;
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
;
276 if ( MACH64_DEBUG
& DEBUG_VERBOSE_LRU
) {
277 mach64PrintGlobalLRU( mmesa
, t
->heap
);
278 mach64PrintLocalLRU( mmesa
, t
->heap
);
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).
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
)
292 mach64TexObjPtr t
, tmp
;
294 foreach_s ( t
, tmp
, &mmesa
->TexObjList
[heap
] ) {
295 if ( t
->memBlock
->ofs
>= offset
+ size
||
296 t
->memBlock
->ofs
+ t
->memBlock
->size
<= offset
)
299 /* It overlaps - kick it out. Need to hold onto the currently
300 * bound objects, however.
303 mach64SwapOutTexObj( mmesa
, t
);
305 mach64DestroyTexObj( mmesa
, t
);
309 if ( in_use
> 0 && in_use
!= mmesa
->hHWContext
) {
310 t
= (mach64TexObjPtr
) CALLOC( sizeof(*t
) );
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
] );
320 insert_at_head( &mmesa
->TexObjList
[heap
], t
);
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
329 void mach64AgeTextures( mach64ContextPtr mmesa
, int heap
)
331 drm_mach64_sarea_t
*sarea
= mmesa
->sarea
;
333 if ( sarea
->tex_age
[heap
] != mmesa
->lastTexAge
[heap
] ) {
334 int sz
= 1 << mmesa
->mach64Screen
->logTexGranularity
[heap
];
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.
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
++ )
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.
349 if ( idx
* sz
> mmesa
->mach64Screen
->texSize
[heap
] ) {
350 nr
= MACH64_NR_TEX_REGIONS
;
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
);
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.
364 if ( nr
== MACH64_NR_TEX_REGIONS
) {
365 mach64TexturesGone( mmesa
, heap
, 0,
366 mmesa
->mach64Screen
->texSize
[heap
], 0 );
367 mach64ResetGlobalLRU( mmesa
, heap
);
371 mach64PrintGlobalLRU( mmesa
, heap
);
372 mach64PrintLocalLRU( mmesa
, heap
);
375 mmesa
->dirty
|= (MACH64_UPLOAD_CONTEXT
|
376 MACH64_UPLOAD_TEX0IMAGE
|
377 MACH64_UPLOAD_TEX1IMAGE
);
378 mmesa
->lastTexAge
[heap
] = sarea
->tex_age
[heap
];
382 /* Upload the texture image associated with texture `t' at level `level'
383 * at the address relative to `start'.
385 static void mach64UploadAGPSubImage( mach64ContextPtr mmesa
,
386 mach64TexObjPtr t
, int level
,
387 int x
, int y
, int width
, int height
)
389 mach64ScreenRec
*mach64Screen
= mmesa
->mach64Screen
;
390 struct gl_texture_image
*image
;
391 int texelsPerDword
= 0;
394 /* Ensure we have a valid texture to upload */
395 if ( ( level
< 0 ) || ( level
> mmesa
->glCtx
->Const
.MaxTextureLevels
) )
398 image
= t
->tObj
->Image
[0][level
];
402 switch ( image
->TexFormat
->TexelBytes
) {
403 case 1: texelsPerDword
= 4; break;
404 case 2: texelsPerDword
= 2; break;
405 case 4: texelsPerDword
= 1; break;
409 /* FIXME: The subimage index calcs are wrong... */
412 width
= image
->Width
;
413 height
= image
->Height
;
416 dwords
= width
* height
/ texelsPerDword
;
418 #if ENABLE_PERF_BOXES
419 /* Bump the performance counter */
420 mmesa
->c_agpTextureBytes
+= (dwords
<< 2);
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
] );
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
);
443 /* Upload the texture image associated with texture `t' at level `level'
444 * at the address relative to `start'.
446 static void mach64UploadLocalSubImage( mach64ContextPtr mmesa
,
447 mach64TexObjPtr t
, int level
,
448 int x
, int y
, int width
, int height
)
450 struct gl_texture_image
*image
;
451 int texelsPerDword
= 0;
452 int imageWidth
, imageHeight
;
455 const int maxdwords
= (MACH64_BUFFER_MAX_DWORDS
- (MACH64_HOSTDATA_BLIT_OFFSET
/ 4));
456 CARD32 pitch
, offset
;
459 /* Ensure we have a valid texture to upload */
460 if ( ( level
< 0 ) || ( level
> mmesa
->glCtx
->Const
.MaxTextureLevels
) )
463 image
= t
->tObj
->Image
[0][level
];
467 switch ( image
->TexFormat
->TexelBytes
) {
468 case 1: texelsPerDword
= 4; break;
469 case 2: texelsPerDword
= 2; break;
470 case 4: texelsPerDword
= 1; break;
474 /* FIXME: The subimage index calcs are wrong... */
477 width
= image
->Width
;
478 height
= image
->Height
;
481 imageWidth
= image
->Width
;
482 imageHeight
= image
->Height
;
484 format
= t
->textureFormat
;
486 /* The texel upload routines have a minimum width, so force the size
489 if ( imageWidth
< texelsPerDword
) {
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.
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
509 if ( imageWidth
>= 64 ) {
510 /* The texture walker and the blitter look identical */
511 pitch
= imageWidth
>> 3;
517 start
= (y
* imageWidth
) & ~63;
518 end
= (y
+ height
) * imageWidth
;
520 if ( end
- start
< 64 ) {
521 /* Handle the case where the total number of texels
529 /* Upload some number of full 64 texel blit rows */
530 factor
= 64 / imageWidth
;
541 /* Fixed pitch of 64 */
545 dwords
= width
* height
/ texelsPerDword
;
548 #if ENABLE_PERF_BOXES
549 /* Bump the performance counter */
550 mmesa
->c_textureBytes
+= (dwords
<< 2);
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
] );
561 /* Subdivide the texture if required (account for the registers added by the drm) */
562 if ( dwords
<= maxdwords
) {
565 rows
= (maxdwords
* texelsPerDword
) / (2 * width
);
568 for ( i
= 0, remaining
= height
;
570 remaining
-= rows
, y
+= rows
, i
++ )
575 height
= MIN2(remaining
, rows
);
577 /* Grab the dma buffer for the texture blit */
578 buffer
= mach64GetBufferLocked( mmesa
);
580 dst
= (CARD32
*)((char *)buffer
->address
+ MACH64_HOSTDATA_BLIT_OFFSET
);
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
);
591 mach64FireBlitLocked( mmesa
, buffer
, offset
, pitch
, format
,
592 x
, y
, width
, height
);
596 mmesa
->new_state
|= MACH64_NEW_CONTEXT
;
597 mmesa
->dirty
|= MACH64_UPLOAD_CONTEXT
| MACH64_UPLOAD_MISC
;
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.
605 void mach64UploadTexImages( mach64ContextPtr mmesa
, mach64TexObjPtr t
)
609 if ( MACH64_DEBUG
& DEBUG_VERBOSE_API
) {
610 fprintf( stderr
, "%s( %p, %p )\n",
611 __FUNCTION__
, mmesa
->glCtx
, t
);
617 /* Choose the heap appropriately */
618 heap
= MACH64_CARD_HEAP
;
620 if ( !mmesa
->mach64Screen
->IsPCI
&&
621 t
->size
> mmesa
->mach64Screen
->texSize
[heap
] ) {
622 heap
= MACH64_AGP_HEAP
;
625 /* Do we need to eject LRU texture objects? */
626 if ( !t
->memBlock
) {
629 /* Allocate a memory block on a 64-byte boundary */
630 t
->memBlock
= mmAllocMem( mmesa
->texHeap
[heap
], t
->size
, 6, 0 );
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
],
638 heap
= t
->heap
= MACH64_AGP_HEAP
;
641 /* Kick out textures until the requested texture fits */
642 while ( !t
->memBlock
) {
643 if ( mmesa
->TexObjList
[heap
].prev
->bound
) {
645 "mach64UploadTexImages: ran into bound texture\n" );
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__
,
654 } else if ( heap
== MACH64_CARD_HEAP
) {
655 heap
= t
->heap
= MACH64_AGP_HEAP
;
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 " : "",
663 for ( i
= mmesa
->firstTexHeap
; i
< mmesa
->lastTexHeap
; i
++ ) {
664 mach64PrintLocalLRU( mmesa
, i
);
665 mmDumpMemInfo( mmesa
->texHeap
[i
] );
672 mach64SwapOutTexObj( mmesa
, mmesa
->TexObjList
[heap
].prev
);
674 t
->memBlock
= mmAllocMem( mmesa
->texHeap
[heap
], t
->size
, 6, 0 );
677 /* Set the base offset of the texture image */
678 t
->offset
= mmesa
->mach64Screen
->texOffset
[heap
] + t
->memBlock
->ofs
;
680 /* Force loading the new state into the hardware */
681 mmesa
->dirty
|= (MACH64_UPLOAD_SCALE_3D_CNTL
|
682 MACH64_UPLOAD_TEXTURE
);
685 /* Let the world know we've used this memory recently */
686 mach64UpdateTexLRU( mmesa
, t
);
688 /* Upload any images that are new */
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
);
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
);
702 mmesa
->setup
.tex_cntl
|= MACH64_TEX_CACHE_FLUSH
;
705 mmesa
->dirty
|= MACH64_UPLOAD_TEXTURE
;
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.
715 void mach64UploadMultiTexImages( mach64ContextPtr mmesa
,
721 if ( MACH64_DEBUG
& DEBUG_VERBOSE_API
) {
722 fprintf( stderr
, "%s( %p, %p %p )\n",
723 __FUNCTION__
, mmesa
->glCtx
, t0
, t1
);
727 assert(t0
->tObj
&& t1
->tObj
);
729 /* Choose the heap appropriately */
730 heap
= MACH64_CARD_HEAP
;
732 if ( !mmesa
->mach64Screen
->IsPCI
&&
733 ((t0
->size
+ t1
->size
) > mmesa
->mach64Screen
->texSize
[heap
]) ) {
734 heap
= MACH64_AGP_HEAP
;
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
);
743 if ( t1
->memBlock
) {
744 mach64SwapOutTexObj( mmesa
, t1
);
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
);
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
);
767 if ( t0
->memBlock
&& t1
->memBlock
)
768 heap
= t0
->heap
= t1
->heap
= MACH64_AGP_HEAP
;
771 /* Kick out textures until the requested texture fits */
772 while ( !t0
->memBlock
|| !t1
->memBlock
) {
773 if ( mmesa
->TexObjList
[heap
].prev
->bound
) {
775 "%s: ran into bound texture\n", __FUNCTION__
);
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
);
784 } else if ( heap
== MACH64_CARD_HEAP
) {
785 /* If only one allocation succeeded, start over again in AGP */
787 mmFreeMem( t0
->memBlock
);
791 mmFreeMem( t1
->memBlock
);
794 heap
= t0
->heap
= t1
->heap
= MACH64_AGP_HEAP
;
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
] );
811 mach64SwapOutTexObj( mmesa
, mmesa
->TexObjList
[heap
].prev
);
814 t0
->memBlock
= mmAllocMem( mmesa
->texHeap
[heap
], t0
->size
, 6, 0 );
816 t1
->memBlock
= mmAllocMem( mmesa
->texHeap
[heap
], t1
->size
, 6, 0 );
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
;
823 /* Force loading the new state into the hardware */
824 mmesa
->dirty
|= (MACH64_UPLOAD_SCALE_3D_CNTL
|
825 MACH64_UPLOAD_TEXTURE
);
828 /* Let the world know we've used this memory recently */
829 mach64UpdateTexLRU( mmesa
, t0
);
830 mach64UpdateTexLRU( mmesa
, t1
);
832 /* Upload any images that are new */
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
);
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
);
845 mmesa
->setup
.tex_cntl
|= MACH64_TEX_CACHE_FLUSH
;
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
);
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
);
860 mmesa
->setup
.tex_cntl
|= MACH64_TEX_CACHE_FLUSH
;
863 mmesa
->dirty
|= MACH64_UPLOAD_TEXTURE
;