1 /* $XFree86: xc/lib/GL/mesa/src/drv/r300/r300_texmem.c,v 1.5 2002/12/17 00:32:56 dawes Exp $ */
2 /**************************************************************************
4 Copyright (C) Tungsten Graphics 2002. All Rights Reserved.
5 The Weather Channel, Inc. funded Tungsten Graphics to develop the
6 initial release of the Radeon 8500 driver under the XFree86
7 license. This notice must be preserved.
9 Permission is hereby granted, free of charge, to any person obtaining
10 a copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation on the rights to use, copy, modify, merge, publish,
13 distribute, sub license, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
17 The above copyright notice and this permission notice (including the
18 next paragraph) shall be included in all copies or substantial
19 portions of the Software.
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR THEIR
25 SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
26 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
27 IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 **************************************************************************/
34 * Kevin E. Martin <martin@valinux.com>
35 * Gareth Hughes <gareth@valinux.com>
46 #include "simple_list.h"
47 #include "radeon_reg.h" /* gets definition for usleep */
48 #include "r300_context.h"
49 #include "r300_state.h"
50 #include "r300_cmdbuf.h"
51 #include "radeon_ioctl.h"
53 #include "r300_swtcl.h"
56 #include "r300_ioctl.h"
57 #include <unistd.h> /* for usleep() */
60 #include "radeon_mm.h"
64 * Destroy any device-dependent state associated with the texture. This may
65 * include NULLing out hardware state that points to the texture.
67 void r300DestroyTexObj(r300ContextPtr rmesa
, r300TexObjPtr t
)
69 if (RADEON_DEBUG
& DEBUG_TEXTURE
) {
70 fprintf(stderr
, "%s( %p, %p )\n", __FUNCTION__
,
71 (void *)t
, (void *)t
->base
.tObj
);
77 for (i
= 0; i
< rmesa
->radeon
.glCtx
->Const
.MaxTextureUnits
; i
++) {
78 if (t
== rmesa
->state
.texture
.unit
[i
].texobj
) {
79 rmesa
->state
.texture
.unit
[i
].texobj
= NULL
;
80 /* This code below is meant to shorten state
81 pushed to the hardware by not programming
84 This does not appear to be worthwhile on R300 */
86 remove_from_list(&rmesa
->hw
.tex
[i
]);
87 make_empty_list(&rmesa
->hw
.tex
[i
]);
88 remove_from_list(&rmesa
->hw
.cube
[i
]);
89 make_empty_list(&rmesa
->hw
.cube
[i
]);
96 /* ------------------------------------------------------------
97 * Texture image conversions
100 static void r300UploadGARTClientSubImage(r300ContextPtr rmesa
,
102 struct gl_texture_image
*texImage
,
105 GLint width
, GLint height
)
107 const struct gl_texture_format
*texFormat
= texImage
->TexFormat
;
108 GLuint srcPitch
, dstPitch
;
113 * XXX it appears that we always upload the full image, not a subimage.
114 * I.e. x==0, y==0, width=texWidth, height=texWidth. If this is ever
115 * changed, the src pitch will have to change.
117 switch (texFormat
->TexelBytes
) {
119 blit_format
= R200_CP_COLOR_FORMAT_CI8
;
120 srcPitch
= t
->image
[0][0].width
* texFormat
->TexelBytes
;
121 dstPitch
= t
->image
[0][0].width
* texFormat
->TexelBytes
;
124 blit_format
= R200_CP_COLOR_FORMAT_RGB565
;
125 srcPitch
= t
->image
[0][0].width
* texFormat
->TexelBytes
;
126 dstPitch
= t
->image
[0][0].width
* texFormat
->TexelBytes
;
129 blit_format
= R200_CP_COLOR_FORMAT_ARGB8888
;
130 srcPitch
= t
->image
[0][0].width
* texFormat
->TexelBytes
;
131 dstPitch
= t
->image
[0][0].width
* texFormat
->TexelBytes
;
135 blit_format
= R200_CP_COLOR_FORMAT_CI8
;
136 srcPitch
= t
->image
[0][0].width
* texFormat
->TexelBytes
;
137 dstPitch
= t
->image
[0][0].width
* texFormat
->TexelBytes
;
143 t
->image
[0][hwlevel
].data
= texImage
->Data
;
144 srcOffset
= r300GartOffsetFromVirtual(rmesa
, texImage
->Data
);
146 assert(srcOffset
!= ~0);
148 /* Don't currently need to cope with small pitches?
150 width
= texImage
->Width
;
151 height
= texImage
->Height
;
153 if (texFormat
->TexelBytes
> 4) {
154 width
*= texFormat
->TexelBytes
;
157 r300EmitWait(rmesa
, R300_WAIT_3D
);
159 r300EmitBlit(rmesa
, blit_format
,
166 t
->image
[0][hwlevel
].x
+ x
,
167 t
->image
[0][hwlevel
].y
+ y
, width
, height
);
169 r300EmitWait(rmesa
, R300_WAIT_2D
);
172 static void r300UploadRectSubImage(r300ContextPtr rmesa
,
174 struct gl_texture_image
*texImage
,
175 GLint x
, GLint y
, GLint width
, GLint height
)
177 const struct gl_texture_format
*texFormat
= texImage
->TexFormat
;
178 int blit_format
, dstPitch
, done
;
180 switch (texFormat
->TexelBytes
) {
182 blit_format
= R200_CP_COLOR_FORMAT_CI8
;
185 blit_format
= R200_CP_COLOR_FORMAT_RGB565
;
188 blit_format
= R200_CP_COLOR_FORMAT_ARGB8888
;
192 blit_format
= R200_CP_COLOR_FORMAT_CI8
;
198 t
->image
[0][0].data
= texImage
->Data
;
200 /* Currently don't need to cope with small pitches.
202 width
= texImage
->Width
;
203 height
= texImage
->Height
;
206 if (texFormat
->TexelBytes
> 4) {
207 width
*= texFormat
->TexelBytes
;
210 if (rmesa
->prefer_gart_client_texturing
&& texImage
->IsClientData
) {
211 /* In this case, could also use GART texturing. This is
212 * currently disabled, but has been tested & works.
215 r300GartOffsetFromVirtual(rmesa
, texImage
->Data
);
217 texImage
->RowStride
* texFormat
->TexelBytes
- 32;
219 if (RADEON_DEBUG
& DEBUG_TEXTURE
)
221 "Using GART texturing for rectangular client texture\n");
223 /* Release FB memory allocated for this image:
225 /* FIXME This may not be correct as driSwapOutTextureObject sets
226 * FIXME dirty_images. It may be fine, though.
228 if (t
->base
.memBlock
) {
229 driSwapOutTextureObject((driTextureObject
*) t
);
231 } else if (texImage
->IsClientData
) {
232 /* Data already in GART memory, with usable pitch.
235 srcPitch
= texImage
->RowStride
* texFormat
->TexelBytes
;
239 r300GartOffsetFromVirtual(rmesa
, texImage
->Data
),
240 dstPitch
, t
->bufAddr
, 0, 0, 0, 0, width
, height
);
242 /* Data not in GART memory, or bad pitch.
244 for (done
= 0; done
< height
;) {
245 struct r300_dma_region region
;
247 MIN2(height
- done
, RADEON_BUFFER_SIZE
/ dstPitch
);
251 src_pitch
= texImage
->RowStride
* texFormat
->TexelBytes
;
253 tex
= (char *)texImage
->Data
+ done
* src_pitch
;
255 memset(®ion
, 0, sizeof(region
));
256 r300AllocDmaRegion(rmesa
, ®ion
, lines
* dstPitch
,
259 /* Copy texdata to dma:
263 "%s: src_pitch %d dst_pitch %d\n",
264 __FUNCTION__
, src_pitch
, dstPitch
);
266 if (src_pitch
== dstPitch
) {
267 memcpy(region
.address
+ region
.start
, tex
,
270 char *buf
= region
.address
+ region
.start
;
272 for (i
= 0; i
< lines
; i
++) {
273 memcpy(buf
, tex
, src_pitch
);
279 r300EmitWait(rmesa
, R300_WAIT_3D
);
281 /* Blit to framebuffer
285 dstPitch
, GET_START(®ion
),
286 dstPitch
| (t
->tile_bits
>> 16),
292 r300EmitWait(rmesa
, R300_WAIT_2D
);
294 radeon_mm_use(rmesa
, region
.buf
->id
);
297 r300ReleaseDmaRegion(rmesa
, ®ion
, __FUNCTION__
);
304 * Upload the texture image associated with texture \a t at the specified
305 * level at the address relative to \a start.
307 static void uploadSubImage( r300ContextPtr rmesa
, r300TexObjPtr t
,
309 GLint x
, GLint y
, GLint width
, GLint height
,
312 struct gl_texture_image
*texImage
= NULL
;
314 GLint imageWidth
, imageHeight
;
316 drm_radeon_texture_t tex
;
317 drm_radeon_tex_image_t tmp
;
318 const int level
= hwlevel
+ t
->base
.firstLevel
;
320 if ( RADEON_DEBUG
& DEBUG_TEXTURE
) {
321 fprintf( stderr
, "%s( %p, %p ) level/width/height/face = %d/%d/%d/%u\n",
322 __FUNCTION__
, (void *)t
, (void *)t
->base
.tObj
,
323 level
, width
, height
, face
);
328 /* Ensure we have a valid texture to upload */
329 if ( ( hwlevel
< 0 ) || ( hwlevel
>= RADEON_MAX_TEXTURE_LEVELS
) ) {
330 _mesa_problem(NULL
, "bad texture level in %s", __FUNCTION__
);
334 texImage
= t
->base
.tObj
->Image
[face
][level
];
337 if ( RADEON_DEBUG
& DEBUG_TEXTURE
)
338 fprintf( stderr
, "%s: texImage %d is NULL!\n", __FUNCTION__
, level
);
341 if ( !texImage
->Data
) {
342 if ( RADEON_DEBUG
& DEBUG_TEXTURE
)
343 fprintf( stderr
, "%s: image data is NULL!\n", __FUNCTION__
);
348 if (t
->base
.tObj
->Target
== GL_TEXTURE_RECTANGLE_NV
) {
350 assert(hwlevel
== 0);
351 if ( RADEON_DEBUG
& DEBUG_TEXTURE
)
352 fprintf( stderr
, "%s: image data is rectangular\n", __FUNCTION__
);
353 r300UploadRectSubImage( rmesa
, t
, texImage
, x
, y
, width
, height
);
356 else if (texImage
->IsClientData
) {
357 if ( RADEON_DEBUG
& DEBUG_TEXTURE
)
358 fprintf( stderr
, "%s: image data is in GART client storage\n",
360 r300UploadGARTClientSubImage( rmesa
, t
, texImage
, hwlevel
,
361 x
, y
, width
, height
);
364 else if ( RADEON_DEBUG
& DEBUG_TEXTURE
)
365 fprintf( stderr
, "%s: image data is in normal memory\n",
369 imageWidth
= texImage
->Width
;
370 imageHeight
= texImage
->Height
;
372 offset
= t
->bufAddr
+ t
->base
.totalSize
/ 6 * face
;
374 if ( RADEON_DEBUG
& (DEBUG_TEXTURE
|DEBUG_IOCTL
) ) {
377 GLint blitX
= t
->image
[face
][hwlevel
].x
;
378 GLint blitY
= t
->image
[face
][hwlevel
].y
;
379 GLint blitWidth
= t
->image
[face
][hwlevel
].width
;
380 GLint blitHeight
= t
->image
[face
][hwlevel
].height
;
381 fprintf( stderr
, " upload image: %d,%d at %d,%d\n",
382 imageWidth
, imageHeight
, imageX
, imageY
);
383 fprintf( stderr
, " upload blit: %d,%d at %d,%d\n",
384 blitWidth
, blitHeight
, blitX
, blitY
);
385 fprintf( stderr
, " blit ofs: 0x%07x level: %d/%d\n",
386 (GLuint
)offset
, hwlevel
, level
);
389 t
->image
[face
][hwlevel
].data
= texImage
->Data
;
391 /* Init the DRM_RADEON_TEXTURE command / drm_radeon_texture_t struct.
392 * NOTE: we're always use a 1KB-wide blit and I8 texture format.
393 * We used to use 1, 2 and 4-byte texels and used to use the texture
394 * width to dictate the blit width - but that won't work for compressed
396 * NOTE: can't do that with texture tiling. (sroland)
400 /* copy (x,y,width,height,data) */
401 memcpy( &tmp
, &t
->image
[face
][hwlevel
], sizeof(tmp
) );
403 if (texImage
->TexFormat
->TexelBytes
> 4) {
404 const int log2TexelBytes
= (3 + (texImage
->TexFormat
->TexelBytes
>> 4));
405 tex
.format
= RADEON_TXFORMAT_I8
; /* any 1-byte texel format */
406 tex
.pitch
= MAX2((texImage
->Width
* texImage
->TexFormat
->TexelBytes
) / 64, 1);
407 tex
.height
= imageHeight
;
408 tex
.width
= imageWidth
<< log2TexelBytes
;
409 tex
.offset
+= (tmp
.x
<< log2TexelBytes
) & ~1023;
410 tmp
.x
= tmp
.x
% (1024 >> log2TexelBytes
);
411 tmp
.width
= tmp
.width
<< log2TexelBytes
;
413 else if (texImage
->TexFormat
->TexelBytes
) {
414 /* use multi-byte upload scheme */
415 tex
.height
= imageHeight
;
416 tex
.width
= imageWidth
;
417 switch(texImage
->TexFormat
->TexelBytes
) {
419 tex
.format
= RADEON_TXFORMAT_I8
;
422 tex
.format
= RADEON_TXFORMAT_AI88
;
425 tex
.format
= RADEON_TXFORMAT_ARGB8888
;
428 tex
.pitch
= MAX2((texImage
->Width
* texImage
->TexFormat
->TexelBytes
) / 64, 1);
429 tex
.offset
+= tmp
.x
& ~1023;
430 tmp
.x
= tmp
.x
% 1024;
432 if (t
->tile_bits
& R300_TXO_MICRO_TILE
) {
433 /* need something like "tiled coordinates" ? */
434 tmp
.y
= tmp
.x
/ (tex
.pitch
* 128) * 2;
435 tmp
.x
= tmp
.x
% (tex
.pitch
* 128) / 2 / texImage
->TexFormat
->TexelBytes
;
436 tex
.pitch
|= RADEON_DST_TILE_MICRO
>> 22;
441 tmp
.x
= tmp
.x
>> (texImage
->TexFormat
->TexelBytes
>> 1);
444 if ((t
->tile_bits
& R300_TXO_MACRO_TILE
) &&
445 (texImage
->Width
* texImage
->TexFormat
->TexelBytes
>= 256) &&
446 ((!(t
->tile_bits
& R300_TXO_MICRO_TILE
) && (texImage
->Height
>= 8)) ||
447 (texImage
->Height
>= 16))) {
448 /* weird: R200 disables macro tiling if mip width is smaller than 256 bytes,
449 OR if height is smaller than 8 automatically, but if micro tiling is active
450 the limit is height 16 instead ? */
451 tex
.pitch
|= RADEON_DST_TILE_MACRO
>> 22;
456 /* In case of for instance 8x8 texture (2x2 dxt blocks), padding after the first two blocks is
457 needed (only with dxt1 since 2 dxt3/dxt5 blocks already use 32 Byte). */
458 /* set tex.height to 1/4 since 1 "macropixel" (dxt-block) has 4 real pixels. Needed
459 so the kernel module reads the right amount of data. */
460 tex
.format
= R200_TXFORMAT_I8
; /* any 1-byte texel format */
461 tex
.pitch
= (BLIT_WIDTH_BYTES
/ 64);
462 tex
.height
= (imageHeight
+ 3) / 4;
463 tex
.width
= (imageWidth
+ 3) / 4;
464 if ((t
->format
& R300_TX_FORMAT_DXT1
) == R300_TX_FORMAT_DXT1
)
472 LOCK_HARDWARE( &rmesa
->radeon
);
474 ret
= drmCommandWriteRead( rmesa
->radeon
.dri
.fd
, DRM_RADEON_TEXTURE
,
475 &tex
, sizeof(drm_radeon_texture_t
) );
477 if (RADEON_DEBUG
& DEBUG_IOCTL
)
478 fprintf(stderr
, "DRM_RADEON_TEXTURE: again!\n");
481 } while ( ret
== -EAGAIN
);
483 UNLOCK_HARDWARE( &rmesa
->radeon
);
486 fprintf( stderr
, "DRM_RADEON_TEXTURE: return = %d\n", ret
);
487 fprintf( stderr
, " offset=0x%08x\n",
489 fprintf( stderr
, " image width=%d height=%d\n",
490 imageWidth
, imageHeight
);
491 fprintf( stderr
, " blit width=%d height=%d data=%p\n",
492 t
->image
[face
][hwlevel
].width
, t
->image
[face
][hwlevel
].height
,
493 t
->image
[face
][hwlevel
].data
);
499 * Upload the texture images associated with texture \a t. This might
500 * require the allocation of texture memory.
502 * \param rmesa Context pointer
503 * \param t Texture to be uploaded
504 * \param face Cube map face to be uploaded. Zero for non-cube maps.
507 int r300UploadTexImages(r300ContextPtr rmesa
, r300TexObjPtr t
, GLuint face
)
509 const int numLevels
= t
->base
.lastLevel
- t
->base
.firstLevel
+ 1;
511 if (RADEON_DEBUG
& (DEBUG_TEXTURE
| DEBUG_IOCTL
)) {
512 fprintf(stderr
, "%s( %p, %p ) sz=%d lvls=%d-%d\n", __FUNCTION__
,
513 (void *)rmesa
->radeon
.glCtx
, (void *)t
->base
.tObj
,
514 t
->base
.totalSize
, t
->base
.firstLevel
,
518 if (!t
|| t
->base
.totalSize
== 0)
521 if (RADEON_DEBUG
& DEBUG_SYNC
) {
522 fprintf(stderr
, "%s: Syncing\n", __FUNCTION__
);
523 radeonFinish(rmesa
->radeon
.glCtx
);
526 LOCK_HARDWARE(&rmesa
->radeon
);
528 if (t
->base
.memBlock
== NULL
) {
531 heap
= driAllocateTexture(rmesa
->texture_heaps
, rmesa
->nr_heaps
,
532 (driTextureObject
*) t
);
534 UNLOCK_HARDWARE(&rmesa
->radeon
);
538 /* Set the base offset of the texture image */
539 t
->bufAddr
= rmesa
->radeon
.radeonScreen
->texOffset
[heap
]
540 + t
->base
.memBlock
->ofs
;
541 t
->offset
= t
->bufAddr
;
543 if (!(t
->base
.tObj
->Image
[0][0]->IsClientData
)) {
544 /* hope it's safe to add that here... */
545 t
->offset
|= t
->tile_bits
;
548 /* Mark this texobj as dirty on all units:
550 t
->dirty_state
= TEX_ALL
;
553 /* Let the world know we've used this memory recently.
555 driUpdateTextureLRU((driTextureObject
*) t
);
556 UNLOCK_HARDWARE(&rmesa
->radeon
);
558 /* Upload any images that are new */
559 if (t
->base
.dirty_images
[face
]) {
561 for (i
= 0; i
< numLevels
; i
++) {
563 dirty_images
[face
] & (1 <<
564 (i
+ t
->base
.firstLevel
))) !=
566 uploadSubImage(rmesa
, t
, i
, 0, 0,
567 t
->image
[face
][i
].width
,
568 t
->image
[face
][i
].height
, face
);
571 t
->base
.dirty_images
[face
] = 0;
574 if (RADEON_DEBUG
& DEBUG_SYNC
) {
575 fprintf(stderr
, "%s: Syncing\n", __FUNCTION__
);
576 radeonFinish(rmesa
->radeon
.glCtx
);