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;
80 /* Ensure we have a valid texture to upload */
81 if ( ( level
< 0 ) || ( level
> mmesa
->glCtx
->Const
.MaxTextureLevels
) )
84 image
= t
->base
.tObj
->Image
[0][level
];
88 switch ( image
->TexFormat
->TexelBytes
) {
89 case 1: texelsPerDword
= 4; break;
90 case 2: texelsPerDword
= 2; break;
91 case 4: texelsPerDword
= 1; break;
95 /* FIXME: The subimage index calcs are wrong... */
99 height
= image
->Height
;
102 dwords
= width
* height
/ texelsPerDword
;
104 #if ENABLE_PERF_BOXES
105 /* Bump the performance counter */
106 mmesa
->c_agpTextureBytes
+= (dwords
<< 2);
109 if ( MACH64_DEBUG
& DEBUG_VERBOSE_API
) {
110 fprintf( stderr
, "mach64UploadSubImage: %d,%d of %d,%d at %d,%d\n",
111 width
, height
, image
->Width
, image
->Height
, x
, y
);
112 fprintf( stderr
, " blit ofs: 0x%07x pitch: 0x%x dwords: %d\n",
113 (GLuint
)t
->bufAddr
, (GLint
)width
, dwords
);
119 CARD32
*dst
= (CARD32
*)((char *)mach64Screen
->agpTextures
.map
+ t
->base
.memBlock
->ofs
);
120 const GLubyte
*src
= (const GLubyte
*) image
->Data
+
121 (y
* image
->Width
+ x
) * image
->TexFormat
->TexelBytes
;
122 const GLuint bytes
= width
* height
* image
->TexFormat
->TexelBytes
;
123 memcpy(dst
, src
, bytes
);
128 /* Upload the texture image associated with texture `t' at level `level'
129 * at the address relative to `start'.
131 static void mach64UploadLocalSubImage( mach64ContextPtr mmesa
,
132 mach64TexObjPtr t
, int level
,
133 int x
, int y
, int width
, int height
)
135 struct gl_texture_image
*image
;
136 int texelsPerDword
= 0;
137 int imageWidth
, imageHeight
;
140 const int maxdwords
= (MACH64_BUFFER_MAX_DWORDS
- (MACH64_HOSTDATA_BLIT_OFFSET
/ 4));
141 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 switch ( image
->TexFormat
->TexelBytes
) {
153 case 1: texelsPerDword
= 4; break;
154 case 2: texelsPerDword
= 2; break;
155 case 4: texelsPerDword
= 1; break;
159 /* FIXME: The subimage index calcs are wrong... */
162 width
= image
->Width
;
163 height
= image
->Height
;
166 imageWidth
= image
->Width
;
167 imageHeight
= image
->Height
;
169 format
= t
->textureFormat
;
171 /* The texel upload routines have a minimum width, so force the size
174 if ( imageWidth
< texelsPerDword
) {
177 factor
= texelsPerDword
/ imageWidth
;
178 imageWidth
= texelsPerDword
;
179 imageHeight
/= factor
;
180 if ( imageHeight
== 0 ) {
181 /* In this case, the texel converter will actually walk a
182 * texel or two off the end of the image, but normal malloc
183 * alignment should prevent it from ever causing a fault.
189 /* We can't upload to a pitch less than 64 texels so we will need to
190 * linearly upload all modified rows for textures smaller than this.
191 * This makes the x/y/width/height different for the blitter and the
194 if ( imageWidth
>= 64 ) {
195 /* The texture walker and the blitter look identical */
196 pitch
= imageWidth
>> 3;
202 start
= (y
* imageWidth
) & ~63;
203 end
= (y
+ height
) * imageWidth
;
205 if ( end
- start
< 64 ) {
206 /* Handle the case where the total number of texels
214 /* Upload some number of full 64 texel blit rows */
215 factor
= 64 / imageWidth
;
226 /* Fixed pitch of 64 */
230 dwords
= width
* height
/ texelsPerDword
;
233 #if ENABLE_PERF_BOXES
234 /* Bump the performance counter */
235 mmesa
->c_textureBytes
+= (dwords
<< 2);
238 if ( MACH64_DEBUG
& DEBUG_VERBOSE_API
) {
239 fprintf( stderr
, "mach64UploadSubImage: %d,%d of %d,%d at %d,%d\n",
240 width
, height
, image
->Width
, image
->Height
, x
, y
);
241 fprintf( stderr
, " blit ofs: 0x%07x pitch: 0x%x dwords: %d\n",
242 (GLuint
)offset
, (GLint
)width
, dwords
);
245 /* Subdivide the texture if required (account for the registers added by the drm) */
246 if ( dwords
<= maxdwords
) {
249 rows
= (maxdwords
* texelsPerDword
) / (2 * width
);
252 for ( i
= 0, remaining
= height
;
254 remaining
-= rows
, y
+= rows
, i
++ )
256 height
= MIN2(remaining
, rows
);
261 const GLubyte
*src
= (const GLubyte
*) image
->Data
+
262 (y
* image
->Width
+ x
) * image
->TexFormat
->TexelBytes
;
264 mach64FireBlitLocked( mmesa
, (void *)src
, offset
, pitch
, format
,
265 x
, y
, width
, height
);
270 mmesa
->new_state
|= MACH64_NEW_CONTEXT
;
271 mmesa
->dirty
|= MACH64_UPLOAD_CONTEXT
| MACH64_UPLOAD_MISC
;
275 /* Upload the texture images associated with texture `t'. This might
276 * require removing our own and/or other client's texture objects to
277 * make room for these images.
279 void mach64UploadTexImages( mach64ContextPtr mmesa
, mach64TexObjPtr t
)
281 if ( MACH64_DEBUG
& DEBUG_VERBOSE_API
) {
282 fprintf( stderr
, "%s( %p, %p )\n",
283 __FUNCTION__
, mmesa
->glCtx
, t
);
287 assert(t
->base
.tObj
);
289 if ( !t
->base
.memBlock
) {
292 /* NULL heaps are skipped */
293 heap
= driAllocateTexture( mmesa
->texture_heaps
, MACH64_NR_TEX_HEAPS
,
294 (driTextureObject
*) t
);
297 fprintf( stderr
, "%s: upload texture failure, sz=%d\n", __FUNCTION__
,
305 /* Set the base offset of the texture image */
306 t
->bufAddr
= mmesa
->mach64Screen
->texOffset
[heap
] + t
->base
.memBlock
->ofs
;
308 /* Force loading the new state into the hardware */
309 mmesa
->dirty
|= (MACH64_UPLOAD_SCALE_3D_CNTL
|
310 MACH64_UPLOAD_TEXTURE
);
313 /* Let the world know we've used this memory recently */
314 driUpdateTextureLRU( (driTextureObject
*) t
);
316 /* Upload any images that are new */
317 if ( t
->base
.dirty_images
[0] ) {
318 const GLint j
= t
->base
.tObj
->BaseLevel
;
319 if (t
->heap
== MACH64_AGP_HEAP
) {
320 /* Need to make sure any vertex buffers in the queue complete */
321 mach64WaitForIdleLocked( mmesa
);
322 mach64UploadAGPSubImage( mmesa
, t
, j
, 0, 0,
323 t
->base
.tObj
->Image
[0][j
]->Width
,
324 t
->base
.tObj
->Image
[0][j
]->Height
);
326 mach64UploadLocalSubImage( mmesa
, t
, j
, 0, 0,
327 t
->base
.tObj
->Image
[0][j
]->Width
,
328 t
->base
.tObj
->Image
[0][j
]->Height
);
331 mmesa
->setup
.tex_cntl
|= MACH64_TEX_CACHE_FLUSH
;
332 t
->base
.dirty_images
[0] = 0;
335 mmesa
->dirty
|= MACH64_UPLOAD_TEXTURE
;
339 /* Allocate memory from the same texture heap `heap' for both textures
342 static int mach64AllocateMultiTex( mach64ContextPtr mmesa
,
345 int heap
, GLboolean alloc_u0
)
347 /* Both objects should be bound */
348 assert( u0
->base
.bound
&& u1
->base
.bound
);
351 /* Evict u0 from its current heap */
352 if ( u0
->base
.memBlock
) {
353 assert( u0
->heap
!= heap
);
354 driSwapOutTextureObject( (driTextureObject
*) u0
);
357 /* Try to allocate u0 in the chosen heap */
358 u0
->heap
= driAllocateTexture( &mmesa
->texture_heaps
[heap
], 1,
359 (driTextureObject
*) u0
);
361 if ( u0
->heap
== -1 ) {
366 /* Evict u1 from its current heap */
367 if ( u1
->base
.memBlock
) {
368 assert( u1
->heap
!= heap
);
369 driSwapOutTextureObject( (driTextureObject
*) u1
);
372 /* Try to allocate u1 in the same heap as u0 */
373 u1
->heap
= driAllocateTexture( &mmesa
->texture_heaps
[heap
], 1,
374 (driTextureObject
*) u1
);
376 if ( u1
->heap
== -1 ) {
380 /* Bound objects are not evicted */
381 assert( u0
->base
.memBlock
&& u1
->base
.memBlock
);
382 assert( u0
->heap
== u1
->heap
);
387 /* The mach64 needs to have both primary and secondary textures in either
388 * local or AGP memory, so we need a "buddy system" to make sure that allocation
389 * succeeds or fails for both textures.
391 void mach64UploadMultiTexImages( mach64ContextPtr mmesa
,
395 if ( MACH64_DEBUG
& DEBUG_VERBOSE_API
) {
396 fprintf( stderr
, "%s( %p, %p %p )\n",
397 __FUNCTION__
, mmesa
->glCtx
, t0
, t1
);
401 assert(t0
->base
.tObj
&& t1
->base
.tObj
);
403 if ( !t0
->base
.memBlock
|| !t1
->base
.memBlock
|| t0
->heap
!= t1
->heap
) {
404 mach64TexObjPtr u0
= NULL
;
405 mach64TexObjPtr u1
= NULL
;
406 unsigned totalSize
= t0
->base
.totalSize
+ t1
->base
.totalSize
;
410 /* Check if one of the textures is already swapped in a heap and the
411 * other texture fits in that heap.
413 if ( t0
->base
.memBlock
&& totalSize
<= t0
->base
.heap
->size
) {
416 } else if ( t1
->base
.memBlock
&& totalSize
<= t1
->base
.heap
->size
) {
424 ret
= mach64AllocateMultiTex( mmesa
, u0
, u1
, heap
, GL_FALSE
);
426 /* Both textures are swapped out or collocation is impossible */
430 /* Choose the heap appropriately */
431 heap
= MACH64_CARD_HEAP
;
433 if ( totalSize
> mmesa
->texture_heaps
[heap
]->size
) {
434 heap
= MACH64_AGP_HEAP
;
437 ret
= mach64AllocateMultiTex( mmesa
, u0
, u1
, heap
, GL_TRUE
);
440 if ( ret
== -1 && heap
== MACH64_CARD_HEAP
) {
441 /* Try AGP if local memory failed */
442 heap
= MACH64_AGP_HEAP
;
444 ret
= mach64AllocateMultiTex( mmesa
, u0
, u1
, heap
, GL_TRUE
);
449 * Swap out all textures from the AGP heap and re-run allocation, this
450 * should succeed in all cases.
452 fprintf( stderr
, "%s: upload multi-texture failure, sz0=%d sz1=%d\n",
453 __FUNCTION__
, t0
->base
.totalSize
, t1
->base
.totalSize
);
457 /* Set the base offset of the texture image */
458 t0
->bufAddr
= mmesa
->mach64Screen
->texOffset
[heap
] + t0
->base
.memBlock
->ofs
;
459 t1
->bufAddr
= mmesa
->mach64Screen
->texOffset
[heap
] + t1
->base
.memBlock
->ofs
;
461 /* Force loading the new state into the hardware */
462 mmesa
->dirty
|= (MACH64_UPLOAD_SCALE_3D_CNTL
|
463 MACH64_UPLOAD_TEXTURE
);
466 /* Let the world know we've used this memory recently */
467 driUpdateTextureLRU( (driTextureObject
*) t0
);
468 driUpdateTextureLRU( (driTextureObject
*) t1
);
470 /* Upload any images that are new */
471 if ( t0
->base
.dirty_images
[0] ) {
472 const GLint j0
= t0
->base
.tObj
->BaseLevel
;
473 if (t0
->heap
== MACH64_AGP_HEAP
) {
474 /* Need to make sure any vertex buffers in the queue complete */
475 mach64WaitForIdleLocked( mmesa
);
476 mach64UploadAGPSubImage( mmesa
, t0
, j0
, 0, 0,
477 t0
->base
.tObj
->Image
[0][j0
]->Width
,
478 t0
->base
.tObj
->Image
[0][j0
]->Height
);
480 mach64UploadLocalSubImage( mmesa
, t0
, j0
, 0, 0,
481 t0
->base
.tObj
->Image
[0][j0
]->Width
,
482 t0
->base
.tObj
->Image
[0][j0
]->Height
);
484 mmesa
->setup
.tex_cntl
|= MACH64_TEX_CACHE_FLUSH
;
485 t0
->base
.dirty_images
[0] = 0;
487 if ( t1
->base
.dirty_images
[0] ) {
488 const GLint j1
= t1
->base
.tObj
->BaseLevel
;
489 if (t1
->heap
== MACH64_AGP_HEAP
) {
490 /* Need to make sure any vertex buffers in the queue complete */
491 mach64WaitForIdleLocked( mmesa
);
492 mach64UploadAGPSubImage( mmesa
, t1
, j1
, 0, 0,
493 t1
->base
.tObj
->Image
[0][j1
]->Width
,
494 t1
->base
.tObj
->Image
[0][j1
]->Height
);
496 mach64UploadLocalSubImage( mmesa
, t1
, j1
, 0, 0,
497 t1
->base
.tObj
->Image
[0][j1
]->Width
,
498 t1
->base
.tObj
->Image
[0][j1
]->Height
);
501 mmesa
->setup
.tex_cntl
|= MACH64_TEX_CACHE_FLUSH
;
502 t1
->base
.dirty_images
[0] = 0;
505 mmesa
->dirty
|= MACH64_UPLOAD_TEXTURE
;