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 * Destroy any device-dependent state associated with the texture. This may
61 * include NULLing out hardware state that points to the texture.
63 void r300DestroyTexObj(r300ContextPtr rmesa
, r300TexObjPtr t
)
65 if (RADEON_DEBUG
& DEBUG_TEXTURE
) {
66 fprintf(stderr
, "%s( %p, %p )\n", __FUNCTION__
,
67 (void *)t
, (void *)t
->base
.tObj
);
73 for (i
= 0; i
< rmesa
->radeon
.glCtx
->Const
.MaxTextureUnits
; i
++) {
74 if (t
== rmesa
->state
.texture
.unit
[i
].texobj
) {
75 rmesa
->state
.texture
.unit
[i
].texobj
= NULL
;
76 /* This code below is meant to shorten state
77 pushed to the hardware by not programming
80 This does not appear to be worthwhile on R300 */
82 remove_from_list(&rmesa
->hw
.tex
[i
]);
83 make_empty_list(&rmesa
->hw
.tex
[i
]);
84 remove_from_list(&rmesa
->hw
.cube
[i
]);
85 make_empty_list(&rmesa
->hw
.cube
[i
]);
92 /* ------------------------------------------------------------
93 * Texture image conversions
96 static void r300UploadGARTClientSubImage(r300ContextPtr rmesa
,
98 struct gl_texture_image
*texImage
,
101 GLint width
, GLint height
)
103 const struct gl_texture_format
*texFormat
= texImage
->TexFormat
;
104 GLuint srcPitch
, dstPitch
;
109 * XXX it appears that we always upload the full image, not a subimage.
110 * I.e. x==0, y==0, width=texWidth, height=texWidth. If this is ever
111 * changed, the src pitch will have to change.
113 switch (texFormat
->TexelBytes
) {
115 blit_format
= R200_CP_COLOR_FORMAT_CI8
;
116 srcPitch
= t
->image
[0][0].width
* texFormat
->TexelBytes
;
117 dstPitch
= t
->image
[0][0].width
* texFormat
->TexelBytes
;
120 blit_format
= R200_CP_COLOR_FORMAT_RGB565
;
121 srcPitch
= t
->image
[0][0].width
* texFormat
->TexelBytes
;
122 dstPitch
= t
->image
[0][0].width
* texFormat
->TexelBytes
;
125 blit_format
= R200_CP_COLOR_FORMAT_ARGB8888
;
126 srcPitch
= t
->image
[0][0].width
* texFormat
->TexelBytes
;
127 dstPitch
= t
->image
[0][0].width
* texFormat
->TexelBytes
;
133 t
->image
[0][hwlevel
].data
= texImage
->Data
;
134 srcOffset
= r300GartOffsetFromVirtual(rmesa
, texImage
->Data
);
136 assert(srcOffset
!= ~0);
138 /* Don't currently need to cope with small pitches?
140 width
= texImage
->Width
;
141 height
= texImage
->Height
;
143 r300EmitWait(rmesa
, R300_WAIT_3D
);
145 r300EmitBlit(rmesa
, blit_format
,
152 t
->image
[0][hwlevel
].x
+ x
,
153 t
->image
[0][hwlevel
].y
+ y
, width
, height
);
155 r300EmitWait(rmesa
, R300_WAIT_2D
);
158 static void r300UploadRectSubImage(r300ContextPtr rmesa
,
160 struct gl_texture_image
*texImage
,
161 GLint x
, GLint y
, GLint width
, GLint height
)
163 const struct gl_texture_format
*texFormat
= texImage
->TexFormat
;
164 int blit_format
, dstPitch
, done
;
166 switch (texFormat
->TexelBytes
) {
168 blit_format
= R200_CP_COLOR_FORMAT_CI8
;
171 blit_format
= R200_CP_COLOR_FORMAT_RGB565
;
174 blit_format
= R200_CP_COLOR_FORMAT_ARGB8888
;
180 t
->image
[0][0].data
= texImage
->Data
;
182 /* Currently don't need to cope with small pitches.
184 width
= texImage
->Width
;
185 height
= texImage
->Height
;
188 if (rmesa
->prefer_gart_client_texturing
&& texImage
->IsClientData
) {
189 /* In this case, could also use GART texturing. This is
190 * currently disabled, but has been tested & works.
193 r300GartOffsetFromVirtual(rmesa
, texImage
->Data
);
195 texImage
->RowStride
* texFormat
->TexelBytes
- 32;
197 if (RADEON_DEBUG
& DEBUG_TEXTURE
)
199 "Using GART texturing for rectangular client texture\n");
201 /* Release FB memory allocated for this image:
203 /* FIXME This may not be correct as driSwapOutTextureObject sets
204 * FIXME dirty_images. It may be fine, though.
206 if (t
->base
.memBlock
) {
207 driSwapOutTextureObject((driTextureObject
*) t
);
209 } else if (texImage
->IsClientData
) {
210 /* Data already in GART memory, with usable pitch.
213 srcPitch
= texImage
->RowStride
* texFormat
->TexelBytes
;
217 r300GartOffsetFromVirtual(rmesa
, texImage
->Data
),
218 dstPitch
, t
->bufAddr
, 0, 0, 0, 0, width
, height
);
220 /* Data not in GART memory, or bad pitch.
222 for (done
= 0; done
< height
;) {
223 struct r300_dma_region region
;
225 MIN2(height
- done
, RADEON_BUFFER_SIZE
/ dstPitch
);
229 src_pitch
= texImage
->RowStride
* texFormat
->TexelBytes
;
231 tex
= (char *)texImage
->Data
+ done
* src_pitch
;
233 memset(®ion
, 0, sizeof(region
));
234 r300AllocDmaRegion(rmesa
, ®ion
, lines
* dstPitch
,
237 /* Copy texdata to dma:
241 "%s: src_pitch %d dst_pitch %d\n",
242 __FUNCTION__
, src_pitch
, dstPitch
);
244 if (src_pitch
== dstPitch
) {
245 memcpy(region
.address
+ region
.start
, tex
,
248 char *buf
= region
.address
+ region
.start
;
250 for (i
= 0; i
< lines
; i
++) {
251 memcpy(buf
, tex
, src_pitch
);
257 r300EmitWait(rmesa
, R300_WAIT_3D
);
259 /* Blit to framebuffer
263 dstPitch
, GET_START(®ion
),
264 dstPitch
, t
->bufAddr
,
265 0, 0, 0, done
, width
, lines
);
267 r300EmitWait(rmesa
, R300_WAIT_2D
);
269 r300ReleaseDmaRegion(rmesa
, ®ion
, __FUNCTION__
);
276 * Upload the texture image associated with texture \a t at the specified
277 * level at the address relative to \a start.
279 static void uploadSubImage( r300ContextPtr rmesa
, r300TexObjPtr t
,
281 GLint x
, GLint y
, GLint width
, GLint height
,
284 struct gl_texture_image
*texImage
= NULL
;
286 GLint imageWidth
, imageHeight
;
288 drm_radeon_texture_t tex
;
289 drm_radeon_tex_image_t tmp
;
290 const int level
= hwlevel
+ t
->base
.firstLevel
;
292 if ( RADEON_DEBUG
& DEBUG_TEXTURE
) {
293 fprintf( stderr
, "%s( %p, %p ) level/width/height/face = %d/%d/%d/%u\n",
294 __FUNCTION__
, (void *)t
, (void *)t
->base
.tObj
,
295 level
, width
, height
, face
);
300 /* Ensure we have a valid texture to upload */
301 if ( ( hwlevel
< 0 ) || ( hwlevel
>= RADEON_MAX_TEXTURE_LEVELS
) ) {
302 _mesa_problem(NULL
, "bad texture level in %s", __FUNCTION__
);
306 texImage
= t
->base
.tObj
->Image
[face
][level
];
309 if ( RADEON_DEBUG
& DEBUG_TEXTURE
)
310 fprintf( stderr
, "%s: texImage %d is NULL!\n", __FUNCTION__
, level
);
313 if ( !texImage
->Data
) {
314 if ( RADEON_DEBUG
& DEBUG_TEXTURE
)
315 fprintf( stderr
, "%s: image data is NULL!\n", __FUNCTION__
);
320 if (t
->base
.tObj
->Target
== GL_TEXTURE_RECTANGLE_NV
) {
322 assert(hwlevel
== 0);
323 if ( RADEON_DEBUG
& DEBUG_TEXTURE
)
324 fprintf( stderr
, "%s: image data is rectangular\n", __FUNCTION__
);
325 r300UploadRectSubImage( rmesa
, t
, texImage
, x
, y
, width
, height
);
328 else if (texImage
->IsClientData
) {
329 if ( RADEON_DEBUG
& DEBUG_TEXTURE
)
330 fprintf( stderr
, "%s: image data is in GART client storage\n",
332 r300UploadGARTClientSubImage( rmesa
, t
, texImage
, hwlevel
,
333 x
, y
, width
, height
);
336 else if ( RADEON_DEBUG
& DEBUG_TEXTURE
)
337 fprintf( stderr
, "%s: image data is in normal memory\n",
341 imageWidth
= texImage
->Width
;
342 imageHeight
= texImage
->Height
;
344 offset
= t
->bufAddr
+ t
->base
.totalSize
/ 6 * face
;
346 if ( RADEON_DEBUG
& (DEBUG_TEXTURE
|DEBUG_IOCTL
) ) {
349 GLint blitX
= t
->image
[face
][hwlevel
].x
;
350 GLint blitY
= t
->image
[face
][hwlevel
].y
;
351 GLint blitWidth
= t
->image
[face
][hwlevel
].width
;
352 GLint blitHeight
= t
->image
[face
][hwlevel
].height
;
353 fprintf( stderr
, " upload image: %d,%d at %d,%d\n",
354 imageWidth
, imageHeight
, imageX
, imageY
);
355 fprintf( stderr
, " upload blit: %d,%d at %d,%d\n",
356 blitWidth
, blitHeight
, blitX
, blitY
);
357 fprintf( stderr
, " blit ofs: 0x%07x level: %d/%d\n",
358 (GLuint
)offset
, hwlevel
, level
);
361 t
->image
[face
][hwlevel
].data
= texImage
->Data
;
363 /* Init the DRM_RADEON_TEXTURE command / drm_radeon_texture_t struct.
364 * NOTE: we're always use a 1KB-wide blit and I8 texture format.
365 * We used to use 1, 2 and 4-byte texels and used to use the texture
366 * width to dictate the blit width - but that won't work for compressed
368 * NOTE: can't do that with texture tiling. (sroland)
372 /* copy (x,y,width,height,data) */
373 memcpy( &tmp
, &t
->image
[face
][hwlevel
], sizeof(tmp
) );
375 if (texImage
->TexFormat
->TexelBytes
) {
376 /* use multi-byte upload scheme */
377 tex
.height
= imageHeight
;
378 tex
.width
= imageWidth
;
379 switch(texImage
->TexFormat
->TexelBytes
) {
381 tex
.format
= RADEON_TXFORMAT_I8
;
384 tex
.format
= RADEON_TXFORMAT_AI88
;
387 tex
.format
= RADEON_TXFORMAT_ARGB8888
;
390 tex
.pitch
= MAX2((texImage
->Width
* texImage
->TexFormat
->TexelBytes
) / 64, 1);
391 tex
.offset
+= tmp
.x
& ~1023;
392 tmp
.x
= tmp
.x
% 1024;
394 if (t
->tile_bits
& R200_TXO_MICRO_TILE
) {
395 /* need something like "tiled coordinates" ? */
396 tmp
.y
= tmp
.x
/ (tex
.pitch
* 128) * 2;
397 tmp
.x
= tmp
.x
% (tex
.pitch
* 128) / 2 / texImage
->TexFormat
->TexelBytes
;
398 tex
.pitch
|= RADEON_DST_TILE_MICRO
>> 22;
403 tmp
.x
= tmp
.x
>> (texImage
->TexFormat
->TexelBytes
>> 1);
406 if ((t
->tile_bits
& R200_TXO_MACRO_TILE
) &&
407 (texImage
->Width
* texImage
->TexFormat
->TexelBytes
>= 256) &&
408 ((!(t
->tile_bits
& R200_TXO_MICRO_TILE
) && (texImage
->Height
>= 8)) ||
409 (texImage
->Height
>= 16))) {
410 /* weird: R200 disables macro tiling if mip width is smaller than 256 bytes,
411 OR if height is smaller than 8 automatically, but if micro tiling is active
412 the limit is height 16 instead ? */
413 tex
.pitch
|= RADEON_DST_TILE_MACRO
>> 22;
418 /* In case of for instance 8x8 texture (2x2 dxt blocks), padding after the first two blocks is
419 needed (only with dxt1 since 2 dxt3/dxt5 blocks already use 32 Byte). */
420 /* set tex.height to 1/4 since 1 "macropixel" (dxt-block) has 4 real pixels. Needed
421 so the kernel module reads the right amount of data. */
422 tex
.format
= R200_TXFORMAT_I8
; /* any 1-byte texel format */
423 tex
.pitch
= (BLIT_WIDTH_BYTES
/ 64);
424 tex
.height
= (imageHeight
+ 3) / 4;
425 tex
.width
= (imageWidth
+ 3) / 4;
426 if ((t
->format
& R300_TX_FORMAT_DXT1
) == R300_TX_FORMAT_DXT1
)
434 LOCK_HARDWARE( &rmesa
->radeon
);
436 ret
= drmCommandWriteRead( rmesa
->radeon
.dri
.fd
, DRM_RADEON_TEXTURE
,
437 &tex
, sizeof(drm_radeon_texture_t
) );
439 if (RADEON_DEBUG
& DEBUG_IOCTL
)
440 fprintf(stderr
, "DRM_RADEON_TEXTURE: again!\n");
443 } while ( ret
== -EAGAIN
);
445 UNLOCK_HARDWARE( &rmesa
->radeon
);
448 fprintf( stderr
, "DRM_RADEON_TEXTURE: return = %d\n", ret
);
449 fprintf( stderr
, " offset=0x%08x\n",
451 fprintf( stderr
, " image width=%d height=%d\n",
452 imageWidth
, imageHeight
);
453 fprintf( stderr
, " blit width=%d height=%d data=%p\n",
454 t
->image
[face
][hwlevel
].width
, t
->image
[face
][hwlevel
].height
,
455 t
->image
[face
][hwlevel
].data
);
461 * Upload the texture images associated with texture \a t. This might
462 * require the allocation of texture memory.
464 * \param rmesa Context pointer
465 * \param t Texture to be uploaded
466 * \param face Cube map face to be uploaded. Zero for non-cube maps.
469 int r300UploadTexImages(r300ContextPtr rmesa
, r300TexObjPtr t
, GLuint face
)
471 const int numLevels
= t
->base
.lastLevel
- t
->base
.firstLevel
+ 1;
473 if (RADEON_DEBUG
& (DEBUG_TEXTURE
| DEBUG_IOCTL
)) {
474 fprintf(stderr
, "%s( %p, %p ) sz=%d lvls=%d-%d\n", __FUNCTION__
,
475 (void *)rmesa
->radeon
.glCtx
, (void *)t
->base
.tObj
,
476 t
->base
.totalSize
, t
->base
.firstLevel
,
480 if (!t
|| t
->base
.totalSize
== 0)
483 if (RADEON_DEBUG
& DEBUG_SYNC
) {
484 fprintf(stderr
, "%s: Syncing\n", __FUNCTION__
);
485 radeonFinish(rmesa
->radeon
.glCtx
);
488 LOCK_HARDWARE(&rmesa
->radeon
);
490 if (t
->base
.memBlock
== NULL
) {
493 heap
= driAllocateTexture(rmesa
->texture_heaps
, rmesa
->nr_heaps
,
494 (driTextureObject
*) t
);
496 UNLOCK_HARDWARE(&rmesa
->radeon
);
500 /* Set the base offset of the texture image */
501 t
->bufAddr
= rmesa
->radeon
.radeonScreen
->texOffset
[heap
]
502 + t
->base
.memBlock
->ofs
;
503 t
->offset
= t
->bufAddr
;
505 /* Mark this texobj as dirty on all units:
507 t
->dirty_state
= TEX_ALL
;
510 /* Let the world know we've used this memory recently.
512 driUpdateTextureLRU((driTextureObject
*) t
);
513 UNLOCK_HARDWARE(&rmesa
->radeon
);
515 /* Upload any images that are new */
516 if (t
->base
.dirty_images
[face
]) {
518 for (i
= 0; i
< numLevels
; i
++) {
520 dirty_images
[face
] & (1 <<
521 (i
+ t
->base
.firstLevel
))) !=
523 uploadSubImage(rmesa
, t
, i
, 0, 0,
524 t
->image
[face
][i
].width
,
525 t
->image
[face
][i
].height
, face
);
528 t
->base
.dirty_images
[face
] = 0;
531 if (RADEON_DEBUG
& DEBUG_SYNC
) {
532 fprintf(stderr
, "%s: Syncing\n", __FUNCTION__
);
533 radeonFinish(rmesa
->radeon
.glCtx
);