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 "main/context.h"
35 #include "main/macros.h"
36 #include "main/simple_list.h"
37 #include "main/imports.h"
39 #include "mach64_context.h"
40 #include "mach64_ioctl.h"
41 #include "mach64_tex.h"
44 /* Destroy hardware state associated with texture `t'.
46 void mach64DestroyTexObj( mach64ContextPtr mmesa
, mach64TexObjPtr t
)
50 /* See if it was the driver's current object.
54 for ( i
= 0 ; i
< mmesa
->glCtx
->Const
.MaxTextureUnits
; i
++ )
56 if ( t
== mmesa
->CurrentTexObj
[ i
] ) {
57 assert( t
->base
.bound
& (1 << i
) );
58 mmesa
->CurrentTexObj
[ i
] = NULL
;
64 /* Upload the texture image associated with texture `t' at level `level'
65 * at the address relative to `start'.
67 static void mach64UploadAGPSubImage( mach64ContextPtr mmesa
,
68 mach64TexObjPtr t
, int level
,
69 int x
, int y
, int width
, int height
)
71 mach64ScreenRec
*mach64Screen
= mmesa
->mach64Screen
;
72 struct gl_texture_image
*image
;
73 int texelsPerDword
= 0;
77 /* Ensure we have a valid texture to upload */
78 if ( ( level
< 0 ) || ( level
> mmesa
->glCtx
->Const
.MaxTextureLevels
) )
81 image
= t
->base
.tObj
->Image
[0][level
];
85 texelBytes
= _mesa_get_format_bytes(image
->TexFormat
);
87 switch ( texelBytes
) {
88 case 1: texelsPerDword
= 4; break;
89 case 2: texelsPerDword
= 2; break;
90 case 4: texelsPerDword
= 1; break;
94 /* FIXME: The subimage index calcs are wrong... */
98 height
= image
->Height
;
101 dwords
= width
* height
/ texelsPerDword
;
103 #if ENABLE_PERF_BOXES
104 /* Bump the performance counter */
105 mmesa
->c_agpTextureBytes
+= (dwords
<< 2);
108 if ( MACH64_DEBUG
& DEBUG_VERBOSE_API
) {
109 fprintf( stderr
, "mach64UploadSubImage: %d,%d of %d,%d at %d,%d\n",
110 width
, height
, image
->Width
, image
->Height
, x
, y
);
111 fprintf( stderr
, " blit ofs: 0x%07x pitch: 0x%x dwords: %d\n",
112 (GLuint
)t
->bufAddr
, (GLint
)width
, dwords
);
118 CARD32
*dst
= (CARD32
*)((char *)mach64Screen
->agpTextures
.map
+ t
->base
.memBlock
->ofs
);
119 const GLubyte
*src
= (const GLubyte
*) image
->Data
+
120 (y
* image
->Width
+ x
) * texelBytes
;
121 const GLuint bytes
= width
* height
* texelBytes
;
122 memcpy(dst
, src
, bytes
);
127 /* Upload the texture image associated with texture `t' at level `level'
128 * at the address relative to `start'.
130 static void mach64UploadLocalSubImage( mach64ContextPtr mmesa
,
131 mach64TexObjPtr t
, int level
,
132 int x
, int y
, int width
, int height
)
134 struct gl_texture_image
*image
;
135 int texelsPerDword
= 0;
136 int imageWidth
, imageHeight
;
139 const int maxdwords
= (MACH64_BUFFER_MAX_DWORDS
- (MACH64_HOSTDATA_BLIT_OFFSET
/ 4));
140 CARD32 pitch
, offset
;
144 /* Ensure we have a valid texture to upload */
145 if ( ( level
< 0 ) || ( level
> mmesa
->glCtx
->Const
.MaxTextureLevels
) )
148 image
= t
->base
.tObj
->Image
[0][level
];
152 texelBytes
= _mesa_get_format_bytes(image
->TexFormat
);
154 switch ( texelBytes
) {
155 case 1: texelsPerDword
= 4; break;
156 case 2: texelsPerDword
= 2; break;
157 case 4: texelsPerDword
= 1; break;
161 /* FIXME: The subimage index calcs are wrong... */
164 width
= image
->Width
;
165 height
= image
->Height
;
168 imageWidth
= image
->Width
;
169 imageHeight
= image
->Height
;
171 format
= t
->textureFormat
;
173 /* The texel upload routines have a minimum width, so force the size
176 if ( imageWidth
< texelsPerDword
) {
179 factor
= texelsPerDword
/ imageWidth
;
180 imageWidth
= texelsPerDword
;
181 imageHeight
/= factor
;
182 if ( imageHeight
== 0 ) {
183 /* In this case, the texel converter will actually walk a
184 * texel or two off the end of the image, but normal malloc
185 * alignment should prevent it from ever causing a fault.
191 /* We can't upload to a pitch less than 64 texels so we will need to
192 * linearly upload all modified rows for textures smaller than this.
193 * This makes the x/y/width/height different for the blitter and the
196 if ( imageWidth
>= 64 ) {
197 /* The texture walker and the blitter look identical */
198 pitch
= imageWidth
>> 3;
204 start
= (y
* imageWidth
) & ~63;
205 end
= (y
+ height
) * imageWidth
;
207 if ( end
- start
< 64 ) {
208 /* Handle the case where the total number of texels
216 /* Upload some number of full 64 texel blit rows */
217 factor
= 64 / imageWidth
;
228 /* Fixed pitch of 64 */
232 dwords
= width
* height
/ texelsPerDword
;
235 #if ENABLE_PERF_BOXES
236 /* Bump the performance counter */
237 mmesa
->c_textureBytes
+= (dwords
<< 2);
240 if ( MACH64_DEBUG
& DEBUG_VERBOSE_API
) {
241 fprintf( stderr
, "mach64UploadSubImage: %d,%d of %d,%d at %d,%d\n",
242 width
, height
, image
->Width
, image
->Height
, x
, y
);
243 fprintf( stderr
, " blit ofs: 0x%07x pitch: 0x%x dwords: %d\n",
244 (GLuint
)offset
, (GLint
)width
, dwords
);
247 /* Subdivide the texture if required (account for the registers added by the drm) */
248 if ( dwords
<= maxdwords
) {
251 rows
= (maxdwords
* texelsPerDword
) / (2 * width
);
254 for ( i
= 0, remaining
= height
;
256 remaining
-= rows
, y
+= rows
, i
++ )
258 height
= MIN2(remaining
, rows
);
263 const GLubyte
*src
= (const GLubyte
*) image
->Data
+
264 (y
* image
->Width
+ x
) * texelBytes
;
266 mach64FireBlitLocked( mmesa
, (void *)src
, offset
, pitch
, format
,
267 x
, y
, width
, height
);
272 mmesa
->new_state
|= MACH64_NEW_CONTEXT
;
273 mmesa
->dirty
|= MACH64_UPLOAD_CONTEXT
| MACH64_UPLOAD_MISC
;
277 /* Upload the texture images associated with texture `t'. This might
278 * require removing our own and/or other client's texture objects to
279 * make room for these images.
281 void mach64UploadTexImages( mach64ContextPtr mmesa
, mach64TexObjPtr t
)
283 if ( MACH64_DEBUG
& DEBUG_VERBOSE_API
) {
284 fprintf( stderr
, "%s( %p, %p )\n",
285 __FUNCTION__
, mmesa
->glCtx
, t
);
289 assert(t
->base
.tObj
);
291 if ( !t
->base
.memBlock
) {
294 /* NULL heaps are skipped */
295 heap
= driAllocateTexture( mmesa
->texture_heaps
, MACH64_NR_TEX_HEAPS
,
296 (driTextureObject
*) t
);
299 fprintf( stderr
, "%s: upload texture failure, sz=%d\n", __FUNCTION__
,
307 /* Set the base offset of the texture image */
308 t
->bufAddr
= mmesa
->mach64Screen
->texOffset
[heap
] + t
->base
.memBlock
->ofs
;
310 /* Force loading the new state into the hardware */
311 mmesa
->dirty
|= (MACH64_UPLOAD_SCALE_3D_CNTL
|
312 MACH64_UPLOAD_TEXTURE
);
315 /* Let the world know we've used this memory recently */
316 driUpdateTextureLRU( (driTextureObject
*) t
);
318 /* Upload any images that are new */
319 if ( t
->base
.dirty_images
[0] ) {
320 const GLint j
= t
->base
.tObj
->BaseLevel
;
321 if (t
->heap
== MACH64_AGP_HEAP
) {
322 /* Need to make sure any vertex buffers in the queue complete */
323 mach64WaitForIdleLocked( mmesa
);
324 mach64UploadAGPSubImage( mmesa
, t
, j
, 0, 0,
325 t
->base
.tObj
->Image
[0][j
]->Width
,
326 t
->base
.tObj
->Image
[0][j
]->Height
);
328 mach64UploadLocalSubImage( mmesa
, t
, j
, 0, 0,
329 t
->base
.tObj
->Image
[0][j
]->Width
,
330 t
->base
.tObj
->Image
[0][j
]->Height
);
333 mmesa
->setup
.tex_cntl
|= MACH64_TEX_CACHE_FLUSH
;
334 t
->base
.dirty_images
[0] = 0;
337 mmesa
->dirty
|= MACH64_UPLOAD_TEXTURE
;
341 /* Allocate memory from the same texture heap `heap' for both textures
344 static int mach64AllocateMultiTex( mach64ContextPtr mmesa
,
347 int heap
, GLboolean alloc_u0
)
349 /* Both objects should be bound */
350 assert( u0
->base
.bound
&& u1
->base
.bound
);
353 /* Evict u0 from its current heap */
354 if ( u0
->base
.memBlock
) {
355 assert( u0
->heap
!= heap
);
356 driSwapOutTextureObject( (driTextureObject
*) u0
);
359 /* Try to allocate u0 in the chosen heap */
360 u0
->heap
= driAllocateTexture( &mmesa
->texture_heaps
[heap
], 1,
361 (driTextureObject
*) u0
);
363 if ( u0
->heap
== -1 ) {
368 /* Evict u1 from its current heap */
369 if ( u1
->base
.memBlock
) {
370 assert( u1
->heap
!= heap
);
371 driSwapOutTextureObject( (driTextureObject
*) u1
);
374 /* Try to allocate u1 in the same heap as u0 */
375 u1
->heap
= driAllocateTexture( &mmesa
->texture_heaps
[heap
], 1,
376 (driTextureObject
*) u1
);
378 if ( u1
->heap
== -1 ) {
382 /* Bound objects are not evicted */
383 assert( u0
->base
.memBlock
&& u1
->base
.memBlock
);
384 assert( u0
->heap
== u1
->heap
);
389 /* The mach64 needs to have both primary and secondary textures in either
390 * local or AGP memory, so we need a "buddy system" to make sure that allocation
391 * succeeds or fails for both textures.
393 void mach64UploadMultiTexImages( mach64ContextPtr mmesa
,
397 if ( MACH64_DEBUG
& DEBUG_VERBOSE_API
) {
398 fprintf( stderr
, "%s( %p, %p %p )\n",
399 __FUNCTION__
, mmesa
->glCtx
, t0
, t1
);
403 assert(t0
->base
.tObj
&& t1
->base
.tObj
);
405 if ( !t0
->base
.memBlock
|| !t1
->base
.memBlock
|| t0
->heap
!= t1
->heap
) {
406 mach64TexObjPtr u0
= NULL
;
407 mach64TexObjPtr u1
= NULL
;
408 unsigned totalSize
= t0
->base
.totalSize
+ t1
->base
.totalSize
;
412 /* Check if one of the textures is already swapped in a heap and the
413 * other texture fits in that heap.
415 if ( t0
->base
.memBlock
&& totalSize
<= t0
->base
.heap
->size
) {
418 } else if ( t1
->base
.memBlock
&& totalSize
<= t1
->base
.heap
->size
) {
426 ret
= mach64AllocateMultiTex( mmesa
, u0
, u1
, heap
, GL_FALSE
);
428 /* Both textures are swapped out or collocation is impossible */
432 /* Choose the heap appropriately */
433 heap
= MACH64_CARD_HEAP
;
435 if ( totalSize
> mmesa
->texture_heaps
[heap
]->size
) {
436 heap
= MACH64_AGP_HEAP
;
439 ret
= mach64AllocateMultiTex( mmesa
, u0
, u1
, heap
, GL_TRUE
);
442 if ( ret
== -1 && heap
== MACH64_CARD_HEAP
) {
443 /* Try AGP if local memory failed */
444 heap
= MACH64_AGP_HEAP
;
446 ret
= mach64AllocateMultiTex( mmesa
, u0
, u1
, heap
, GL_TRUE
);
451 * Swap out all textures from the AGP heap and re-run allocation, this
452 * should succeed in all cases.
454 fprintf( stderr
, "%s: upload multi-texture failure, sz0=%d sz1=%d\n",
455 __FUNCTION__
, t0
->base
.totalSize
, t1
->base
.totalSize
);
459 /* Set the base offset of the texture image */
460 t0
->bufAddr
= mmesa
->mach64Screen
->texOffset
[heap
] + t0
->base
.memBlock
->ofs
;
461 t1
->bufAddr
= mmesa
->mach64Screen
->texOffset
[heap
] + t1
->base
.memBlock
->ofs
;
463 /* Force loading the new state into the hardware */
464 mmesa
->dirty
|= (MACH64_UPLOAD_SCALE_3D_CNTL
|
465 MACH64_UPLOAD_TEXTURE
);
468 /* Let the world know we've used this memory recently */
469 driUpdateTextureLRU( (driTextureObject
*) t0
);
470 driUpdateTextureLRU( (driTextureObject
*) t1
);
472 /* Upload any images that are new */
473 if ( t0
->base
.dirty_images
[0] ) {
474 const GLint j0
= t0
->base
.tObj
->BaseLevel
;
475 if (t0
->heap
== MACH64_AGP_HEAP
) {
476 /* Need to make sure any vertex buffers in the queue complete */
477 mach64WaitForIdleLocked( mmesa
);
478 mach64UploadAGPSubImage( mmesa
, t0
, j0
, 0, 0,
479 t0
->base
.tObj
->Image
[0][j0
]->Width
,
480 t0
->base
.tObj
->Image
[0][j0
]->Height
);
482 mach64UploadLocalSubImage( mmesa
, t0
, j0
, 0, 0,
483 t0
->base
.tObj
->Image
[0][j0
]->Width
,
484 t0
->base
.tObj
->Image
[0][j0
]->Height
);
486 mmesa
->setup
.tex_cntl
|= MACH64_TEX_CACHE_FLUSH
;
487 t0
->base
.dirty_images
[0] = 0;
489 if ( t1
->base
.dirty_images
[0] ) {
490 const GLint j1
= t1
->base
.tObj
->BaseLevel
;
491 if (t1
->heap
== MACH64_AGP_HEAP
) {
492 /* Need to make sure any vertex buffers in the queue complete */
493 mach64WaitForIdleLocked( mmesa
);
494 mach64UploadAGPSubImage( mmesa
, t1
, j1
, 0, 0,
495 t1
->base
.tObj
->Image
[0][j1
]->Width
,
496 t1
->base
.tObj
->Image
[0][j1
]->Height
);
498 mach64UploadLocalSubImage( mmesa
, t1
, j1
, 0, 0,
499 t1
->base
.tObj
->Image
[0][j1
]->Width
,
500 t1
->base
.tObj
->Image
[0][j1
]->Height
);
503 mmesa
->setup
.tex_cntl
|= MACH64_TEX_CACHE_FLUSH
;
504 t1
->base
.dirty_images
[0] = 0;
507 mmesa
->dirty
|= MACH64_UPLOAD_TEXTURE
;