1 /* -*- 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 * Jose 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"
41 #include "main/context.h"
42 #include "main/macros.h"
43 #include "main/simple_list.h"
44 #include "main/texformat.h"
45 #include "main/imports.h"
48 /* Destroy hardware state associated with texture `t'.
50 void mach64DestroyTexObj( mach64ContextPtr mmesa
, mach64TexObjPtr t
)
54 /* See if it was the driver's current object.
58 for ( i
= 0 ; i
< mmesa
->glCtx
->Const
.MaxTextureUnits
; i
++ )
60 if ( t
== mmesa
->CurrentTexObj
[ i
] ) {
61 assert( t
->base
.bound
& (1 << i
) );
62 mmesa
->CurrentTexObj
[ i
] = NULL
;
68 /* Upload the texture image associated with texture `t' at level `level'
69 * at the address relative to `start'.
71 static void mach64UploadAGPSubImage( mach64ContextPtr mmesa
,
72 mach64TexObjPtr t
, int level
,
73 int x
, int y
, int width
, int height
)
75 mach64ScreenRec
*mach64Screen
= mmesa
->mach64Screen
;
76 struct gl_texture_image
*image
;
77 int texelsPerDword
= 0;
81 /* Ensure we have a valid texture to upload */
82 if ( ( level
< 0 ) || ( level
> mmesa
->glCtx
->Const
.MaxTextureLevels
) )
85 image
= t
->base
.tObj
->Image
[0][level
];
89 texelBytes
= _mesa_get_format_bytes(image
->TexFormat
->MesaFormat
);
91 switch ( texelBytes
) {
92 case 1: texelsPerDword
= 4; break;
93 case 2: texelsPerDword
= 2; break;
94 case 4: texelsPerDword
= 1; break;
98 /* FIXME: The subimage index calcs are wrong... */
101 width
= image
->Width
;
102 height
= image
->Height
;
105 dwords
= width
* height
/ texelsPerDword
;
107 #if ENABLE_PERF_BOXES
108 /* Bump the performance counter */
109 mmesa
->c_agpTextureBytes
+= (dwords
<< 2);
112 if ( MACH64_DEBUG
& DEBUG_VERBOSE_API
) {
113 fprintf( stderr
, "mach64UploadSubImage: %d,%d of %d,%d at %d,%d\n",
114 width
, height
, image
->Width
, image
->Height
, x
, y
);
115 fprintf( stderr
, " blit ofs: 0x%07x pitch: 0x%x dwords: %d\n",
116 (GLuint
)t
->bufAddr
, (GLint
)width
, dwords
);
122 CARD32
*dst
= (CARD32
*)((char *)mach64Screen
->agpTextures
.map
+ t
->base
.memBlock
->ofs
);
123 const GLubyte
*src
= (const GLubyte
*) image
->Data
+
124 (y
* image
->Width
+ x
) * texelBytes
;
125 const GLuint bytes
= width
* height
* texelBytes
;
126 memcpy(dst
, src
, bytes
);
131 /* Upload the texture image associated with texture `t' at level `level'
132 * at the address relative to `start'.
134 static void mach64UploadLocalSubImage( mach64ContextPtr mmesa
,
135 mach64TexObjPtr t
, int level
,
136 int x
, int y
, int width
, int height
)
138 struct gl_texture_image
*image
;
139 int texelsPerDword
= 0;
140 int imageWidth
, imageHeight
;
143 const int maxdwords
= (MACH64_BUFFER_MAX_DWORDS
- (MACH64_HOSTDATA_BLIT_OFFSET
/ 4));
144 CARD32 pitch
, offset
;
148 /* Ensure we have a valid texture to upload */
149 if ( ( level
< 0 ) || ( level
> mmesa
->glCtx
->Const
.MaxTextureLevels
) )
152 image
= t
->base
.tObj
->Image
[0][level
];
156 texelBytes
= _mesa_get_format_bytes(image
->TexFormat
->MesaFormat
);
158 switch ( texelBytes
) {
159 case 1: texelsPerDword
= 4; break;
160 case 2: texelsPerDword
= 2; break;
161 case 4: texelsPerDword
= 1; break;
165 /* FIXME: The subimage index calcs are wrong... */
168 width
= image
->Width
;
169 height
= image
->Height
;
172 imageWidth
= image
->Width
;
173 imageHeight
= image
->Height
;
175 format
= t
->textureFormat
;
177 /* The texel upload routines have a minimum width, so force the size
180 if ( imageWidth
< texelsPerDword
) {
183 factor
= texelsPerDword
/ imageWidth
;
184 imageWidth
= texelsPerDword
;
185 imageHeight
/= factor
;
186 if ( imageHeight
== 0 ) {
187 /* In this case, the texel converter will actually walk a
188 * texel or two off the end of the image, but normal malloc
189 * alignment should prevent it from ever causing a fault.
195 /* We can't upload to a pitch less than 64 texels so we will need to
196 * linearly upload all modified rows for textures smaller than this.
197 * This makes the x/y/width/height different for the blitter and the
200 if ( imageWidth
>= 64 ) {
201 /* The texture walker and the blitter look identical */
202 pitch
= imageWidth
>> 3;
208 start
= (y
* imageWidth
) & ~63;
209 end
= (y
+ height
) * imageWidth
;
211 if ( end
- start
< 64 ) {
212 /* Handle the case where the total number of texels
220 /* Upload some number of full 64 texel blit rows */
221 factor
= 64 / imageWidth
;
232 /* Fixed pitch of 64 */
236 dwords
= width
* height
/ texelsPerDword
;
239 #if ENABLE_PERF_BOXES
240 /* Bump the performance counter */
241 mmesa
->c_textureBytes
+= (dwords
<< 2);
244 if ( MACH64_DEBUG
& DEBUG_VERBOSE_API
) {
245 fprintf( stderr
, "mach64UploadSubImage: %d,%d of %d,%d at %d,%d\n",
246 width
, height
, image
->Width
, image
->Height
, x
, y
);
247 fprintf( stderr
, " blit ofs: 0x%07x pitch: 0x%x dwords: %d\n",
248 (GLuint
)offset
, (GLint
)width
, dwords
);
251 /* Subdivide the texture if required (account for the registers added by the drm) */
252 if ( dwords
<= maxdwords
) {
255 rows
= (maxdwords
* texelsPerDword
) / (2 * width
);
258 for ( i
= 0, remaining
= height
;
260 remaining
-= rows
, y
+= rows
, i
++ )
262 height
= MIN2(remaining
, rows
);
267 const GLubyte
*src
= (const GLubyte
*) image
->Data
+
268 (y
* image
->Width
+ x
) * texelBytes
;
270 mach64FireBlitLocked( mmesa
, (void *)src
, offset
, pitch
, format
,
271 x
, y
, width
, height
);
276 mmesa
->new_state
|= MACH64_NEW_CONTEXT
;
277 mmesa
->dirty
|= MACH64_UPLOAD_CONTEXT
| MACH64_UPLOAD_MISC
;
281 /* Upload the texture images associated with texture `t'. This might
282 * require removing our own and/or other client's texture objects to
283 * make room for these images.
285 void mach64UploadTexImages( mach64ContextPtr mmesa
, mach64TexObjPtr t
)
287 if ( MACH64_DEBUG
& DEBUG_VERBOSE_API
) {
288 fprintf( stderr
, "%s( %p, %p )\n",
289 __FUNCTION__
, mmesa
->glCtx
, t
);
293 assert(t
->base
.tObj
);
295 if ( !t
->base
.memBlock
) {
298 /* NULL heaps are skipped */
299 heap
= driAllocateTexture( mmesa
->texture_heaps
, MACH64_NR_TEX_HEAPS
,
300 (driTextureObject
*) t
);
303 fprintf( stderr
, "%s: upload texture failure, sz=%d\n", __FUNCTION__
,
311 /* Set the base offset of the texture image */
312 t
->bufAddr
= mmesa
->mach64Screen
->texOffset
[heap
] + t
->base
.memBlock
->ofs
;
314 /* Force loading the new state into the hardware */
315 mmesa
->dirty
|= (MACH64_UPLOAD_SCALE_3D_CNTL
|
316 MACH64_UPLOAD_TEXTURE
);
319 /* Let the world know we've used this memory recently */
320 driUpdateTextureLRU( (driTextureObject
*) t
);
322 /* Upload any images that are new */
323 if ( t
->base
.dirty_images
[0] ) {
324 const GLint j
= t
->base
.tObj
->BaseLevel
;
325 if (t
->heap
== MACH64_AGP_HEAP
) {
326 /* Need to make sure any vertex buffers in the queue complete */
327 mach64WaitForIdleLocked( mmesa
);
328 mach64UploadAGPSubImage( mmesa
, t
, j
, 0, 0,
329 t
->base
.tObj
->Image
[0][j
]->Width
,
330 t
->base
.tObj
->Image
[0][j
]->Height
);
332 mach64UploadLocalSubImage( mmesa
, t
, j
, 0, 0,
333 t
->base
.tObj
->Image
[0][j
]->Width
,
334 t
->base
.tObj
->Image
[0][j
]->Height
);
337 mmesa
->setup
.tex_cntl
|= MACH64_TEX_CACHE_FLUSH
;
338 t
->base
.dirty_images
[0] = 0;
341 mmesa
->dirty
|= MACH64_UPLOAD_TEXTURE
;
345 /* Allocate memory from the same texture heap `heap' for both textures
348 static int mach64AllocateMultiTex( mach64ContextPtr mmesa
,
351 int heap
, GLboolean alloc_u0
)
353 /* Both objects should be bound */
354 assert( u0
->base
.bound
&& u1
->base
.bound
);
357 /* Evict u0 from its current heap */
358 if ( u0
->base
.memBlock
) {
359 assert( u0
->heap
!= heap
);
360 driSwapOutTextureObject( (driTextureObject
*) u0
);
363 /* Try to allocate u0 in the chosen heap */
364 u0
->heap
= driAllocateTexture( &mmesa
->texture_heaps
[heap
], 1,
365 (driTextureObject
*) u0
);
367 if ( u0
->heap
== -1 ) {
372 /* Evict u1 from its current heap */
373 if ( u1
->base
.memBlock
) {
374 assert( u1
->heap
!= heap
);
375 driSwapOutTextureObject( (driTextureObject
*) u1
);
378 /* Try to allocate u1 in the same heap as u0 */
379 u1
->heap
= driAllocateTexture( &mmesa
->texture_heaps
[heap
], 1,
380 (driTextureObject
*) u1
);
382 if ( u1
->heap
== -1 ) {
386 /* Bound objects are not evicted */
387 assert( u0
->base
.memBlock
&& u1
->base
.memBlock
);
388 assert( u0
->heap
== u1
->heap
);
393 /* The mach64 needs to have both primary and secondary textures in either
394 * local or AGP memory, so we need a "buddy system" to make sure that allocation
395 * succeeds or fails for both textures.
397 void mach64UploadMultiTexImages( mach64ContextPtr mmesa
,
401 if ( MACH64_DEBUG
& DEBUG_VERBOSE_API
) {
402 fprintf( stderr
, "%s( %p, %p %p )\n",
403 __FUNCTION__
, mmesa
->glCtx
, t0
, t1
);
407 assert(t0
->base
.tObj
&& t1
->base
.tObj
);
409 if ( !t0
->base
.memBlock
|| !t1
->base
.memBlock
|| t0
->heap
!= t1
->heap
) {
410 mach64TexObjPtr u0
= NULL
;
411 mach64TexObjPtr u1
= NULL
;
412 unsigned totalSize
= t0
->base
.totalSize
+ t1
->base
.totalSize
;
416 /* Check if one of the textures is already swapped in a heap and the
417 * other texture fits in that heap.
419 if ( t0
->base
.memBlock
&& totalSize
<= t0
->base
.heap
->size
) {
422 } else if ( t1
->base
.memBlock
&& totalSize
<= t1
->base
.heap
->size
) {
430 ret
= mach64AllocateMultiTex( mmesa
, u0
, u1
, heap
, GL_FALSE
);
432 /* Both textures are swapped out or collocation is impossible */
436 /* Choose the heap appropriately */
437 heap
= MACH64_CARD_HEAP
;
439 if ( totalSize
> mmesa
->texture_heaps
[heap
]->size
) {
440 heap
= MACH64_AGP_HEAP
;
443 ret
= mach64AllocateMultiTex( mmesa
, u0
, u1
, heap
, GL_TRUE
);
446 if ( ret
== -1 && heap
== MACH64_CARD_HEAP
) {
447 /* Try AGP if local memory failed */
448 heap
= MACH64_AGP_HEAP
;
450 ret
= mach64AllocateMultiTex( mmesa
, u0
, u1
, heap
, GL_TRUE
);
455 * Swap out all textures from the AGP heap and re-run allocation, this
456 * should succeed in all cases.
458 fprintf( stderr
, "%s: upload multi-texture failure, sz0=%d sz1=%d\n",
459 __FUNCTION__
, t0
->base
.totalSize
, t1
->base
.totalSize
);
463 /* Set the base offset of the texture image */
464 t0
->bufAddr
= mmesa
->mach64Screen
->texOffset
[heap
] + t0
->base
.memBlock
->ofs
;
465 t1
->bufAddr
= mmesa
->mach64Screen
->texOffset
[heap
] + t1
->base
.memBlock
->ofs
;
467 /* Force loading the new state into the hardware */
468 mmesa
->dirty
|= (MACH64_UPLOAD_SCALE_3D_CNTL
|
469 MACH64_UPLOAD_TEXTURE
);
472 /* Let the world know we've used this memory recently */
473 driUpdateTextureLRU( (driTextureObject
*) t0
);
474 driUpdateTextureLRU( (driTextureObject
*) t1
);
476 /* Upload any images that are new */
477 if ( t0
->base
.dirty_images
[0] ) {
478 const GLint j0
= t0
->base
.tObj
->BaseLevel
;
479 if (t0
->heap
== MACH64_AGP_HEAP
) {
480 /* Need to make sure any vertex buffers in the queue complete */
481 mach64WaitForIdleLocked( mmesa
);
482 mach64UploadAGPSubImage( mmesa
, t0
, j0
, 0, 0,
483 t0
->base
.tObj
->Image
[0][j0
]->Width
,
484 t0
->base
.tObj
->Image
[0][j0
]->Height
);
486 mach64UploadLocalSubImage( mmesa
, t0
, j0
, 0, 0,
487 t0
->base
.tObj
->Image
[0][j0
]->Width
,
488 t0
->base
.tObj
->Image
[0][j0
]->Height
);
490 mmesa
->setup
.tex_cntl
|= MACH64_TEX_CACHE_FLUSH
;
491 t0
->base
.dirty_images
[0] = 0;
493 if ( t1
->base
.dirty_images
[0] ) {
494 const GLint j1
= t1
->base
.tObj
->BaseLevel
;
495 if (t1
->heap
== MACH64_AGP_HEAP
) {
496 /* Need to make sure any vertex buffers in the queue complete */
497 mach64WaitForIdleLocked( mmesa
);
498 mach64UploadAGPSubImage( mmesa
, t1
, j1
, 0, 0,
499 t1
->base
.tObj
->Image
[0][j1
]->Width
,
500 t1
->base
.tObj
->Image
[0][j1
]->Height
);
502 mach64UploadLocalSubImage( mmesa
, t1
, j1
, 0, 0,
503 t1
->base
.tObj
->Image
[0][j1
]->Width
,
504 t1
->base
.tObj
->Image
[0][j1
]->Height
);
507 mmesa
->setup
.tex_cntl
|= MACH64_TEX_CACHE_FLUSH
;
508 t1
->base
.dirty_images
[0] = 0;
511 mmesa
->dirty
|= MACH64_UPLOAD_TEXTURE
;