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 "radeon_ioctl.h"
52 #include "r300_swtcl.h"
56 #include <unistd.h> /* for usleep() */
59 * Destroy any device-dependent state associated with the texture. This may
60 * include NULLing out hardware state that points to the texture.
62 void r300DestroyTexObj(r300ContextPtr rmesa
, r300TexObjPtr t
)
64 if (RADEON_DEBUG
& DEBUG_TEXTURE
) {
65 fprintf(stderr
, "%s( %p, %p )\n", __FUNCTION__
,
66 (void *)t
, (void *)t
->base
.tObj
);
72 for (i
= 0; i
< rmesa
->radeon
.glCtx
->Const
.MaxTextureUnits
; i
++) {
73 if (t
== rmesa
->state
.texture
.unit
[i
].texobj
) {
74 rmesa
->state
.texture
.unit
[i
].texobj
= NULL
;
75 /* This code below is meant to shorten state
76 pushed to the hardware by not programming
79 This does not appear to be worthwhile on R300 */
81 remove_from_list(&rmesa
->hw
.tex
[i
]);
82 make_empty_list(&rmesa
->hw
.tex
[i
]);
83 remove_from_list(&rmesa
->hw
.cube
[i
]);
84 make_empty_list(&rmesa
->hw
.cube
[i
]);
91 /* ------------------------------------------------------------
92 * Texture image conversions
95 static void r300UploadGARTClientSubImage(r300ContextPtr rmesa
,
97 struct gl_texture_image
*texImage
,
100 GLint width
, GLint height
)
102 const struct gl_texture_format
*texFormat
= texImage
->TexFormat
;
103 GLuint srcPitch
, dstPitch
;
108 * XXX it appears that we always upload the full image, not a subimage.
109 * I.e. x==0, y==0, width=texWidth, height=texWidth. If this is ever
110 * changed, the src pitch will have to change.
112 switch (texFormat
->TexelBytes
) {
114 blit_format
= R200_CP_COLOR_FORMAT_CI8
;
115 srcPitch
= t
->image
[0][0].width
* texFormat
->TexelBytes
;
116 dstPitch
= t
->image
[0][0].width
* texFormat
->TexelBytes
;
119 blit_format
= R200_CP_COLOR_FORMAT_RGB565
;
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_ARGB8888
;
125 srcPitch
= t
->image
[0][0].width
* texFormat
->TexelBytes
;
126 dstPitch
= t
->image
[0][0].width
* texFormat
->TexelBytes
;
132 t
->image
[0][hwlevel
].data
= texImage
->Data
;
133 srcOffset
= r300GartOffsetFromVirtual(rmesa
, texImage
->Data
);
135 assert(srcOffset
!= ~0);
137 /* Don't currently need to cope with small pitches?
139 width
= texImage
->Width
;
140 height
= texImage
->Height
;
142 r300EmitWait(rmesa
, RADEON_WAIT_3D
);
144 r300EmitBlit(rmesa
, blit_format
,
151 t
->image
[0][hwlevel
].x
+ x
,
152 t
->image
[0][hwlevel
].y
+ y
, width
, height
);
154 r300EmitWait(rmesa
, RADEON_WAIT_2D
);
157 static void r300UploadRectSubImage(r300ContextPtr rmesa
,
159 struct gl_texture_image
*texImage
,
160 GLint x
, GLint y
, GLint width
, GLint height
)
162 const struct gl_texture_format
*texFormat
= texImage
->TexFormat
;
163 int blit_format
, dstPitch
, done
;
165 switch (texFormat
->TexelBytes
) {
167 blit_format
= R200_CP_COLOR_FORMAT_CI8
;
170 blit_format
= R200_CP_COLOR_FORMAT_RGB565
;
173 blit_format
= R200_CP_COLOR_FORMAT_ARGB8888
;
179 t
->image
[0][0].data
= texImage
->Data
;
181 /* Currently don't need to cope with small pitches.
183 width
= texImage
->Width
;
184 height
= texImage
->Height
;
185 dstPitch
= t
->pitch
+ 32;
187 if (rmesa
->prefer_gart_client_texturing
&& texImage
->IsClientData
) {
188 /* In this case, could also use GART texturing. This is
189 * currently disabled, but has been tested & works.
192 r300GartOffsetFromVirtual(rmesa
, texImage
->Data
);
194 texImage
->RowStride
* texFormat
->TexelBytes
- 32;
196 if (RADEON_DEBUG
& DEBUG_TEXTURE
)
198 "Using GART texturing for rectangular client texture\n");
200 /* Release FB memory allocated for this image:
202 /* FIXME This may not be correct as driSwapOutTextureObject sets
203 * FIXME dirty_images. It may be fine, though.
205 if (t
->base
.memBlock
) {
206 driSwapOutTextureObject((driTextureObject
*) t
);
208 } else if (texImage
->IsClientData
) {
209 /* Data already in GART memory, with usable pitch.
212 srcPitch
= texImage
->RowStride
* texFormat
->TexelBytes
;
216 r300GartOffsetFromVirtual(rmesa
, texImage
->Data
),
217 dstPitch
, t
->bufAddr
, 0, 0, 0, 0, width
, height
);
219 /* Data not in GART memory, or bad pitch.
221 for (done
= 0; done
< height
;) {
222 struct r300_dma_region region
;
224 MIN2(height
- done
, RADEON_BUFFER_SIZE
/ dstPitch
);
228 src_pitch
= texImage
->RowStride
* texFormat
->TexelBytes
;
230 tex
= (char *)texImage
->Data
+ done
* src_pitch
;
232 memset(®ion
, 0, sizeof(region
));
233 r300AllocDmaRegion(rmesa
, ®ion
, lines
* dstPitch
,
236 /* Copy texdata to dma:
240 "%s: src_pitch %d dst_pitch %d\n",
241 __FUNCTION__
, src_pitch
, dstPitch
);
243 if (src_pitch
== dstPitch
) {
244 memcpy(region
.address
+ region
.start
, tex
,
247 char *buf
= region
.address
+ region
.start
;
249 for (i
= 0; i
< lines
; i
++) {
250 memcpy(buf
, tex
, src_pitch
);
256 r300EmitWait(rmesa
, RADEON_WAIT_3D
);
258 /* Blit to framebuffer
262 dstPitch
, GET_START(®ion
),
263 dstPitch
, t
->bufAddr
,
264 0, 0, 0, done
, width
, lines
);
266 r300EmitWait(rmesa
, RADEON_WAIT_2D
);
268 r300ReleaseDmaRegion(rmesa
, ®ion
, __FUNCTION__
);
275 * Upload the texture image associated with texture \a t at the specified
276 * level at the address relative to \a start.
278 static void uploadSubImage(r300ContextPtr rmesa
, r300TexObjPtr t
,
280 GLint x
, GLint y
, GLint width
, GLint height
,
283 struct gl_texture_image
*texImage
= NULL
;
285 GLint imageWidth
, imageHeight
;
287 drm_radeon_texture_t tex
;
288 drm_radeon_tex_image_t tmp
;
289 const int level
= hwlevel
+ t
->base
.firstLevel
;
291 if (RADEON_DEBUG
& DEBUG_TEXTURE
) {
293 "%s( %p, %p ) level/width/height/face = %d/%d/%d/%u\n",
294 __FUNCTION__
, (void *)t
, (void *)t
->base
.tObj
, level
,
295 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",
311 __FUNCTION__
, level
);
314 if (!texImage
->Data
) {
315 if (RADEON_DEBUG
& DEBUG_TEXTURE
)
316 fprintf(stderr
, "%s: image data is NULL!\n",
321 if (t
->base
.tObj
->Target
== GL_TEXTURE_RECTANGLE_NV
) {
323 assert(hwlevel
== 0);
324 if (RADEON_DEBUG
& DEBUG_TEXTURE
)
325 fprintf(stderr
, "%s: image data is rectangular\n",
327 r300UploadRectSubImage(rmesa
, t
, texImage
, x
, y
, width
, height
);
329 } else if (texImage
->IsClientData
) {
330 if (RADEON_DEBUG
& DEBUG_TEXTURE
)
332 "%s: image data is in GART client storage\n",
334 r300UploadGARTClientSubImage(rmesa
, t
, texImage
, hwlevel
, x
, y
,
337 } else if (RADEON_DEBUG
& DEBUG_TEXTURE
)
338 fprintf(stderr
, "%s: image data is in normal memory\n",
341 imageWidth
= texImage
->Width
;
342 imageHeight
= texImage
->Height
;
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
370 tex
.pitch
= BLIT_WIDTH_BYTES
/ 64;
371 tex
.format
= R200_TXFORMAT_I8
; /* any 1-byte texel format */
372 if (texImage
->TexFormat
->TexelBytes
) {
373 tex
.width
= imageWidth
* texImage
->TexFormat
->TexelBytes
; /* in bytes */
374 tex
.height
= imageHeight
;
376 tex
.width
= imageWidth
; /* compressed */
377 tex
.height
= imageHeight
;
383 /* copy (x,y,width,height,data) */
384 memcpy(&tmp
, &t
->image
[face
][hwlevel
], sizeof(tmp
));
386 LOCK_HARDWARE(&rmesa
->radeon
);
388 ret
= drmCommandWriteRead(rmesa
->radeon
.dri
.fd
, DRM_RADEON_TEXTURE
,
389 &tex
, sizeof(drm_radeon_texture_t
));
391 if (RADEON_DEBUG
& DEBUG_IOCTL
)
393 "DRM_RADEON_TEXTURE: again!\n");
396 } while (ret
&& errno
== EAGAIN
);
398 UNLOCK_HARDWARE(&rmesa
->radeon
);
401 fprintf(stderr
, "DRM_RADEON_TEXTURE: return = %d\n", ret
);
402 fprintf(stderr
, " offset=0x%08x\n", offset
);
403 fprintf(stderr
, " image width=%d height=%d\n",
404 imageWidth
, imageHeight
);
405 fprintf(stderr
, " blit width=%d height=%d data=%p\n",
406 t
->image
[face
][hwlevel
].width
,
407 t
->image
[face
][hwlevel
].height
,
408 t
->image
[face
][hwlevel
].data
);
414 * Upload the texture images associated with texture \a t. This might
415 * require the allocation of texture memory.
417 * \param rmesa Context pointer
418 * \param t Texture to be uploaded
419 * \param face Cube map face to be uploaded. Zero for non-cube maps.
422 int r300UploadTexImages(r300ContextPtr rmesa
, r300TexObjPtr t
, GLuint face
)
424 const int numLevels
= t
->base
.lastLevel
- t
->base
.firstLevel
+ 1;
426 if (RADEON_DEBUG
& (DEBUG_TEXTURE
| DEBUG_IOCTL
)) {
427 fprintf(stderr
, "%s( %p, %p ) sz=%d lvls=%d-%d\n", __FUNCTION__
,
428 (void *)rmesa
->radeon
.glCtx
, (void *)t
->base
.tObj
,
429 t
->base
.totalSize
, t
->base
.firstLevel
,
433 if (!t
|| t
->base
.totalSize
== 0)
436 if (RADEON_DEBUG
& DEBUG_SYNC
) {
437 fprintf(stderr
, "%s: Syncing\n", __FUNCTION__
);
438 radeonFinish(rmesa
->radeon
.glCtx
);
441 LOCK_HARDWARE(&rmesa
->radeon
);
443 if (t
->base
.memBlock
== NULL
) {
446 heap
= driAllocateTexture(rmesa
->texture_heaps
, rmesa
->nr_heaps
,
447 (driTextureObject
*) t
);
449 UNLOCK_HARDWARE(&rmesa
->radeon
);
453 /* Set the base offset of the texture image */
454 t
->bufAddr
= rmesa
->radeon
.radeonScreen
->texOffset
[heap
]
455 + t
->base
.memBlock
->ofs
;
456 t
->offset
= t
->bufAddr
;
458 /* Mark this texobj as dirty on all units:
460 t
->dirty_state
= TEX_ALL
;
463 /* Let the world know we've used this memory recently.
465 driUpdateTextureLRU((driTextureObject
*) t
);
466 UNLOCK_HARDWARE(&rmesa
->radeon
);
468 /* Upload any images that are new */
469 if (t
->base
.dirty_images
[face
]) {
471 for (i
= 0; i
< numLevels
; i
++) {
473 dirty_images
[face
] & (1 <<
474 (i
+ t
->base
.firstLevel
))) !=
476 uploadSubImage(rmesa
, t
, i
, 0, 0,
477 t
->image
[face
][i
].width
,
478 t
->image
[face
][i
].height
, face
);
481 t
->base
.dirty_images
[face
] = 0;
484 if (RADEON_DEBUG
& DEBUG_SYNC
) {
485 fprintf(stderr
, "%s: Syncing\n", __FUNCTION__
);
486 radeonFinish(rmesa
->radeon
.glCtx
);