1 /**************************************************************************
3 Copyright (C) Tungsten Graphics 2002. All Rights Reserved.
4 The Weather Channel, Inc. funded Tungsten Graphics to develop the
5 initial release of the Radeon 8500 driver under the XFree86
6 license. This notice must be preserved.
8 Permission is hereby granted, free of charge, to any person obtaining
9 a copy of this software and associated documentation files (the
10 "Software"), to deal in the Software without restriction, including
11 without limitation on the rights to use, copy, modify, merge, publish,
12 distribute, sub license, and/or sell copies of the Software, and to
13 permit persons to whom the Software is furnished to do so, subject to
14 the following conditions:
16 The above copyright notice and this permission notice (including the
17 next paragraph) shall be included in all copies or substantial
18 portions of the Software.
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR THEIR
24 SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
25 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
26 IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 **************************************************************************/
34 * \author Gareth Hughes <gareth@valinux.com>
36 * \author Kevin E. Martin <martin@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() */
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
= R300_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
= R300_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
= R300_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
= R300_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
= R300_CP_COLOR_FORMAT_CI8
;
185 blit_format
= R300_CP_COLOR_FORMAT_RGB565
;
188 blit_format
= R300_CP_COLOR_FORMAT_ARGB8888
;
192 blit_format
= R300_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.
214 t
->offset
= r300GartOffsetFromVirtual(rmesa
, texImage
->Data
);
215 t
->pitch
= texImage
->RowStride
* texFormat
->TexelBytes
- 32;
217 if (RADEON_DEBUG
& DEBUG_TEXTURE
)
219 "Using GART texturing for rectangular client texture\n");
221 /* Release FB memory allocated for this image:
223 /* FIXME This may not be correct as driSwapOutTextureObject sets
224 * FIXME dirty_images. It may be fine, though.
226 if (t
->base
.memBlock
) {
227 driSwapOutTextureObject((driTextureObject
*) t
);
229 } else if (texImage
->IsClientData
) {
230 /* Data already in GART memory, with usable pitch.
233 srcPitch
= texImage
->RowStride
* texFormat
->TexelBytes
;
237 r300GartOffsetFromVirtual(rmesa
, texImage
->Data
),
238 dstPitch
, t
->bufAddr
, 0, 0, 0, 0, width
, height
);
240 /* Data not in GART memory, or bad pitch.
242 for (done
= 0; done
< height
;) {
243 struct r300_dma_region region
;
245 MIN2(height
- done
, RADEON_BUFFER_SIZE
/ dstPitch
);
249 src_pitch
= texImage
->RowStride
* texFormat
->TexelBytes
;
251 tex
= (char *)texImage
->Data
+ done
* src_pitch
;
253 memset(®ion
, 0, sizeof(region
));
254 r300AllocDmaRegion(rmesa
, ®ion
, lines
* dstPitch
,
257 /* Copy texdata to dma:
259 if (RADEON_DEBUG
& DEBUG_TEXTURE
)
261 "%s: src_pitch %d dst_pitch %d\n",
262 __FUNCTION__
, src_pitch
, dstPitch
);
264 if (src_pitch
== dstPitch
) {
265 memcpy(region
.address
+ region
.start
, tex
,
268 char *buf
= region
.address
+ region
.start
;
270 for (i
= 0; i
< lines
; i
++) {
271 memcpy(buf
, tex
, src_pitch
);
277 r300EmitWait(rmesa
, R300_WAIT_3D
);
279 /* Blit to framebuffer
283 dstPitch
, GET_START(®ion
),
284 dstPitch
| (t
->tile_bits
>> 16),
285 t
->bufAddr
, 0, 0, 0, done
, width
, lines
);
287 r300EmitWait(rmesa
, R300_WAIT_2D
);
289 r300_mem_use(rmesa
, region
.buf
->id
);
292 r300ReleaseDmaRegion(rmesa
, ®ion
, __FUNCTION__
);
299 * Upload the texture image associated with texture \a t at the specified
300 * level at the address relative to \a start.
302 static void r300UploadSubImage(r300ContextPtr rmesa
, r300TexObjPtr t
,
304 GLint x
, GLint y
, GLint width
, GLint height
,
307 struct gl_texture_image
*texImage
= NULL
;
309 GLint imageWidth
, imageHeight
;
311 drm_radeon_texture_t tex
;
312 drm_radeon_tex_image_t tmp
;
313 const int level
= hwlevel
+ t
->base
.firstLevel
;
315 if (RADEON_DEBUG
& DEBUG_TEXTURE
) {
317 "%s( %p, %p ) level/width/height/face = %d/%d/%d/%u\n",
318 __FUNCTION__
, (void *)t
, (void *)t
->base
.tObj
, level
,
319 width
, height
, face
);
324 /* Ensure we have a valid texture to upload */
325 if ((hwlevel
< 0) || (hwlevel
>= RADEON_MAX_TEXTURE_LEVELS
)) {
326 _mesa_problem(NULL
, "bad texture level in %s", __FUNCTION__
);
330 texImage
= t
->base
.tObj
->Image
[face
][level
];
333 if (RADEON_DEBUG
& DEBUG_TEXTURE
)
334 fprintf(stderr
, "%s: texImage %d is NULL!\n",
335 __FUNCTION__
, level
);
338 if (!texImage
->Data
) {
339 if (RADEON_DEBUG
& DEBUG_TEXTURE
)
340 fprintf(stderr
, "%s: image data is NULL!\n",
345 if (t
->base
.tObj
->Target
== GL_TEXTURE_RECTANGLE_NV
) {
347 assert(hwlevel
== 0);
348 if (RADEON_DEBUG
& DEBUG_TEXTURE
)
349 fprintf(stderr
, "%s: image data is rectangular\n",
351 r300UploadRectSubImage(rmesa
, t
, texImage
, x
, y
, width
, height
);
353 } else if (texImage
->IsClientData
) {
354 if (RADEON_DEBUG
& DEBUG_TEXTURE
)
356 "%s: image data is in GART client storage\n",
358 r300UploadGARTClientSubImage(rmesa
, t
, texImage
, hwlevel
, x
, y
,
361 } else if (RADEON_DEBUG
& DEBUG_TEXTURE
)
362 fprintf(stderr
, "%s: image data is in normal memory\n",
365 imageWidth
= texImage
->Width
;
366 imageHeight
= texImage
->Height
;
368 offset
= t
->bufAddr
+ t
->base
.totalSize
/ 6 * face
;
370 if (RADEON_DEBUG
& (DEBUG_TEXTURE
| DEBUG_IOCTL
)) {
373 GLint blitX
= t
->image
[face
][hwlevel
].x
;
374 GLint blitY
= t
->image
[face
][hwlevel
].y
;
375 GLint blitWidth
= t
->image
[face
][hwlevel
].width
;
376 GLint blitHeight
= t
->image
[face
][hwlevel
].height
;
377 fprintf(stderr
, " upload image: %d,%d at %d,%d\n",
378 imageWidth
, imageHeight
, imageX
, imageY
);
379 fprintf(stderr
, " upload blit: %d,%d at %d,%d\n",
380 blitWidth
, blitHeight
, blitX
, blitY
);
381 fprintf(stderr
, " blit ofs: 0x%07x level: %d/%d\n",
382 (GLuint
) offset
, hwlevel
, level
);
385 t
->image
[face
][hwlevel
].data
= texImage
->Data
;
387 /* Init the DRM_RADEON_TEXTURE command / drm_radeon_texture_t struct.
388 * NOTE: we're always use a 1KB-wide blit and I8 texture format.
389 * We used to use 1, 2 and 4-byte texels and used to use the texture
390 * width to dictate the blit width - but that won't work for compressed
392 * NOTE: can't do that with texture tiling. (sroland)
396 /* copy (x,y,width,height,data) */
397 memcpy(&tmp
, &t
->image
[face
][hwlevel
], sizeof(tmp
));
399 if (texImage
->TexFormat
->TexelBytes
> 4) {
400 const int log2TexelBytes
=
401 (3 + (texImage
->TexFormat
->TexelBytes
>> 4));
402 tex
.format
= RADEON_TXFORMAT_I8
; /* any 1-byte texel format */
404 MAX2((texImage
->Width
* texImage
->TexFormat
->TexelBytes
) /
406 tex
.height
= imageHeight
;
407 tex
.width
= imageWidth
<< log2TexelBytes
;
408 tex
.offset
+= (tmp
.x
<< log2TexelBytes
) & ~1023;
409 tmp
.x
= tmp
.x
% (1024 >> log2TexelBytes
);
410 tmp
.width
= tmp
.width
<< log2TexelBytes
;
411 } else if (texImage
->TexFormat
->TexelBytes
) {
412 /* use multi-byte upload scheme */
413 tex
.height
= imageHeight
;
414 tex
.width
= imageWidth
;
415 switch (texImage
->TexFormat
->TexelBytes
) {
417 tex
.format
= RADEON_TXFORMAT_I8
;
420 tex
.format
= RADEON_TXFORMAT_AI88
;
423 tex
.format
= RADEON_TXFORMAT_ARGB8888
;
427 MAX2((texImage
->Width
* texImage
->TexFormat
->TexelBytes
) /
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;
436 tmp
.x
% (tex
.pitch
* 128) / 2 /
437 texImage
->TexFormat
->TexelBytes
;
438 tex
.pitch
|= RADEON_DST_TILE_MICRO
>> 22;
440 tmp
.x
= tmp
.x
>> (texImage
->TexFormat
->TexelBytes
>> 1);
443 if ((t
->tile_bits
& R300_TXO_MACRO_TILE
) &&
444 (texImage
->Width
* texImage
->TexFormat
->TexelBytes
>= 256)
445 && ((!(t
->tile_bits
& R300_TXO_MICRO_TILE
)
446 && (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;
455 /* In case of for instance 8x8 texture (2x2 dxt blocks),
456 padding after the first two blocks is needed (only
457 with dxt1 since 2 dxt3/dxt5 blocks already use 32 Byte). */
458 /* set tex.height to 1/4 since 1 "macropixel" (dxt-block)
459 has 4 real pixels. Needed so the kernel module reads
460 the right amount of data. */
461 tex
.format
= RADEON_TXFORMAT_I8
; /* any 1-byte texel format */
462 tex
.pitch
= (R300_BLIT_WIDTH_BYTES
/ 64);
463 tex
.height
= (imageHeight
+ 3) / 4;
464 tex
.width
= (imageWidth
+ 3) / 4;
465 if ((t
->format
& R300_TX_FORMAT_DXT1
) == R300_TX_FORMAT_DXT1
) {
472 LOCK_HARDWARE(&rmesa
->radeon
);
475 drmCommandWriteRead(rmesa
->radeon
.dri
.fd
,
476 DRM_RADEON_TEXTURE
, &tex
,
477 sizeof(drm_radeon_texture_t
));
479 if (RADEON_DEBUG
& DEBUG_IOCTL
)
481 "DRM_RADEON_TEXTURE: again!\n");
484 } while (ret
== -EAGAIN
);
486 UNLOCK_HARDWARE(&rmesa
->radeon
);
489 fprintf(stderr
, "DRM_RADEON_TEXTURE: return = %d\n", ret
);
490 fprintf(stderr
, " offset=0x%08x\n", offset
);
491 fprintf(stderr
, " image width=%d height=%d\n",
492 imageWidth
, imageHeight
);
493 fprintf(stderr
, " blit width=%d height=%d data=%p\n",
494 t
->image
[face
][hwlevel
].width
,
495 t
->image
[face
][hwlevel
].height
,
496 t
->image
[face
][hwlevel
].data
);
502 * Upload the texture images associated with texture \a t. This might
503 * require the allocation of texture memory.
505 * \param rmesa Context pointer
506 * \param t Texture to be uploaded
507 * \param face Cube map face to be uploaded. Zero for non-cube maps.
510 int r300UploadTexImages(r300ContextPtr rmesa
, r300TexObjPtr t
, GLuint face
)
512 const int numLevels
= t
->base
.lastLevel
- t
->base
.firstLevel
+ 1;
514 if (RADEON_DEBUG
& (DEBUG_TEXTURE
| DEBUG_IOCTL
)) {
515 fprintf(stderr
, "%s( %p, %p ) sz=%d lvls=%d-%d\n", __FUNCTION__
,
516 (void *)rmesa
->radeon
.glCtx
, (void *)t
->base
.tObj
,
517 t
->base
.totalSize
, t
->base
.firstLevel
,
521 if (!t
|| t
->base
.totalSize
== 0)
524 if (RADEON_DEBUG
& DEBUG_SYNC
) {
525 fprintf(stderr
, "%s: Syncing\n", __FUNCTION__
);
526 radeonFinish(rmesa
->radeon
.glCtx
);
529 LOCK_HARDWARE(&rmesa
->radeon
);
531 if (t
->base
.memBlock
== NULL
) {
534 heap
= driAllocateTexture(rmesa
->texture_heaps
, rmesa
->nr_heaps
,
535 (driTextureObject
*) t
);
537 UNLOCK_HARDWARE(&rmesa
->radeon
);
541 /* Set the base offset of the texture image */
542 t
->bufAddr
= rmesa
->radeon
.radeonScreen
->texOffset
[heap
]
543 + t
->base
.memBlock
->ofs
;
544 t
->offset
= t
->bufAddr
;
546 if (!(t
->base
.tObj
->Image
[0][0]->IsClientData
)) {
547 /* hope it's safe to add that here... */
548 t
->offset
|= t
->tile_bits
;
551 /* Mark this texobj as dirty on all units:
553 t
->dirty_state
= TEX_ALL
;
556 /* Let the world know we've used this memory recently.
558 driUpdateTextureLRU((driTextureObject
*) t
);
559 UNLOCK_HARDWARE(&rmesa
->radeon
);
561 /* Upload any images that are new */
562 if (t
->base
.dirty_images
[face
]) {
564 for (i
= 0; i
< numLevels
; i
++) {
566 dirty_images
[face
] & (1 <<
567 (i
+ t
->base
.firstLevel
))) !=
569 r300UploadSubImage(rmesa
, t
, i
, 0, 0,
570 t
->image
[face
][i
].width
,
571 t
->image
[face
][i
].height
,
575 t
->base
.dirty_images
[face
] = 0;
578 if (RADEON_DEBUG
& DEBUG_SYNC
) {
579 fprintf(stderr
, "%s: Syncing\n", __FUNCTION__
);
580 radeonFinish(rmesa
->radeon
.glCtx
);