Merge branch 'origin'
[mesa.git] / src / mesa / drivers / dri / r300 / r300_texmem.c
1 /* $XFree86: xc/lib/GL/mesa/src/drv/r300/r300_texmem.c,v 1.5 2002/12/17 00:32:56 dawes Exp $ */
2 /**************************************************************************
3
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.
8
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:
16
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.
20
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
28 SOFTWARE.
29
30 **************************************************************************/
31
32 /*
33 * Authors:
34 * Kevin E. Martin <martin@valinux.com>
35 * Gareth Hughes <gareth@valinux.com>
36 *
37 */
38
39 #include <errno.h>
40
41 #include "glheader.h"
42 #include "imports.h"
43 #include "context.h"
44 #include "colormac.h"
45 #include "macros.h"
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"
52 /*
53 #include "r300_swtcl.h"
54 */
55 #include "r300_tex.h"
56 #include "r300_ioctl.h"
57 #include <unistd.h> /* for usleep() */
58
59 #ifdef USER_BUFFERS
60 #include "radeon_mm.h"
61 #endif
62
63 /**
64 * Destroy any device-dependent state associated with the texture. This may
65 * include NULLing out hardware state that points to the texture.
66 */
67 void r300DestroyTexObj(r300ContextPtr rmesa, r300TexObjPtr t)
68 {
69 if (RADEON_DEBUG & DEBUG_TEXTURE) {
70 fprintf(stderr, "%s( %p, %p )\n", __FUNCTION__,
71 (void *)t, (void *)t->base.tObj);
72 }
73
74 if (rmesa != NULL) {
75 unsigned i;
76
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
82 unneeded units.
83
84 This does not appear to be worthwhile on R300 */
85 #if 0
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]);
90 #endif
91 }
92 }
93 }
94 }
95
96 /* ------------------------------------------------------------
97 * Texture image conversions
98 */
99
100 static void r300UploadGARTClientSubImage(r300ContextPtr rmesa,
101 r300TexObjPtr t,
102 struct gl_texture_image *texImage,
103 GLint hwlevel,
104 GLint x, GLint y,
105 GLint width, GLint height)
106 {
107 const struct gl_texture_format *texFormat = texImage->TexFormat;
108 GLuint srcPitch, dstPitch;
109 int blit_format;
110 int srcOffset;
111
112 /*
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.
116 */
117 switch (texFormat->TexelBytes) {
118 case 1:
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;
122 break;
123 case 2:
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;
127 break;
128 case 4:
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;
132 break;
133 case 8:
134 case 16:
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;
138 break;
139 default:
140 return;
141 }
142
143 t->image[0][hwlevel].data = texImage->Data;
144 srcOffset = r300GartOffsetFromVirtual(rmesa, texImage->Data);
145
146 assert(srcOffset != ~0);
147
148 /* Don't currently need to cope with small pitches?
149 */
150 width = texImage->Width;
151 height = texImage->Height;
152
153 if (texFormat->TexelBytes > 4) {
154 width *= texFormat->TexelBytes;
155 }
156
157 r300EmitWait(rmesa, R300_WAIT_3D);
158
159 r300EmitBlit(rmesa, blit_format,
160 srcPitch,
161 srcOffset,
162 dstPitch,
163 t->bufAddr,
164 x,
165 y,
166 t->image[0][hwlevel].x + x,
167 t->image[0][hwlevel].y + y, width, height);
168
169 r300EmitWait(rmesa, R300_WAIT_2D);
170 }
171
172 static void r300UploadRectSubImage(r300ContextPtr rmesa,
173 r300TexObjPtr t,
174 struct gl_texture_image *texImage,
175 GLint x, GLint y, GLint width, GLint height)
176 {
177 const struct gl_texture_format *texFormat = texImage->TexFormat;
178 int blit_format, dstPitch, done;
179
180 switch (texFormat->TexelBytes) {
181 case 1:
182 blit_format = R300_CP_COLOR_FORMAT_CI8;
183 break;
184 case 2:
185 blit_format = R300_CP_COLOR_FORMAT_RGB565;
186 break;
187 case 4:
188 blit_format = R300_CP_COLOR_FORMAT_ARGB8888;
189 break;
190 case 8:
191 case 16:
192 blit_format = R300_CP_COLOR_FORMAT_CI8;
193 break;
194 default:
195 return;
196 }
197
198 t->image[0][0].data = texImage->Data;
199
200 /* Currently don't need to cope with small pitches.
201 */
202 width = texImage->Width;
203 height = texImage->Height;
204 dstPitch = t->pitch;
205
206 if (texFormat->TexelBytes > 4) {
207 width *= texFormat->TexelBytes;
208 }
209
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.
213 */
214 t->offset =
215 r300GartOffsetFromVirtual(rmesa, texImage->Data);
216 t->pitch =
217 texImage->RowStride * texFormat->TexelBytes - 32;
218
219 if (RADEON_DEBUG & DEBUG_TEXTURE)
220 fprintf(stderr,
221 "Using GART texturing for rectangular client texture\n");
222
223 /* Release FB memory allocated for this image:
224 */
225 /* FIXME This may not be correct as driSwapOutTextureObject sets
226 * FIXME dirty_images. It may be fine, though.
227 */
228 if (t->base.memBlock) {
229 driSwapOutTextureObject((driTextureObject *) t);
230 }
231 } else if (texImage->IsClientData) {
232 /* Data already in GART memory, with usable pitch.
233 */
234 GLuint srcPitch;
235 srcPitch = texImage->RowStride * texFormat->TexelBytes;
236 r300EmitBlit(rmesa,
237 blit_format,
238 srcPitch,
239 r300GartOffsetFromVirtual(rmesa, texImage->Data),
240 dstPitch, t->bufAddr, 0, 0, 0, 0, width, height);
241 } else {
242 /* Data not in GART memory, or bad pitch.
243 */
244 for (done = 0; done < height;) {
245 struct r300_dma_region region;
246 int lines =
247 MIN2(height - done, RADEON_BUFFER_SIZE / dstPitch);
248 int src_pitch;
249 char *tex;
250
251 src_pitch = texImage->RowStride * texFormat->TexelBytes;
252
253 tex = (char *)texImage->Data + done * src_pitch;
254
255 memset(&region, 0, sizeof(region));
256 r300AllocDmaRegion(rmesa, &region, lines * dstPitch,
257 1024);
258
259 /* Copy texdata to dma:
260 */
261 if (0)
262 fprintf(stderr,
263 "%s: src_pitch %d dst_pitch %d\n",
264 __FUNCTION__, src_pitch, dstPitch);
265
266 if (src_pitch == dstPitch) {
267 memcpy(region.address + region.start, tex,
268 lines * src_pitch);
269 } else {
270 char *buf = region.address + region.start;
271 int i;
272 for (i = 0; i < lines; i++) {
273 memcpy(buf, tex, src_pitch);
274 buf += dstPitch;
275 tex += src_pitch;
276 }
277 }
278
279 r300EmitWait(rmesa, R300_WAIT_3D);
280
281 /* Blit to framebuffer
282 */
283 r300EmitBlit(rmesa,
284 blit_format,
285 dstPitch, GET_START(&region),
286 dstPitch | (t->tile_bits >> 16),
287 t->bufAddr,
288 0, 0,
289 0, done,
290 width, lines);
291
292 r300EmitWait(rmesa, R300_WAIT_2D);
293 #ifdef USER_BUFFERS
294 radeon_mm_use(rmesa, region.buf->id);
295 #endif
296
297 r300ReleaseDmaRegion(rmesa, &region, __FUNCTION__);
298 done += lines;
299 }
300 }
301 }
302
303 /**
304 * Upload the texture image associated with texture \a t at the specified
305 * level at the address relative to \a start.
306 */
307 static void uploadSubImage( r300ContextPtr rmesa, r300TexObjPtr t,
308 GLint hwlevel,
309 GLint x, GLint y, GLint width, GLint height,
310 GLuint face )
311 {
312 struct gl_texture_image *texImage = NULL;
313 GLuint offset;
314 GLint imageWidth, imageHeight;
315 GLint ret;
316 drm_radeon_texture_t tex;
317 drm_radeon_tex_image_t tmp;
318 const int level = hwlevel + t->base.firstLevel;
319
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 );
324 }
325
326 ASSERT(face < 6);
327
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__);
331 return;
332 }
333
334 texImage = t->base.tObj->Image[face][level];
335
336 if ( !texImage ) {
337 if ( RADEON_DEBUG & DEBUG_TEXTURE )
338 fprintf( stderr, "%s: texImage %d is NULL!\n", __FUNCTION__, level );
339 return;
340 }
341 if ( !texImage->Data ) {
342 if ( RADEON_DEBUG & DEBUG_TEXTURE )
343 fprintf( stderr, "%s: image data is NULL!\n", __FUNCTION__ );
344 return;
345 }
346
347
348 if (t->base.tObj->Target == GL_TEXTURE_RECTANGLE_NV) {
349 assert(level == 0);
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 );
354 return;
355 }
356 else if (texImage->IsClientData) {
357 if ( RADEON_DEBUG & DEBUG_TEXTURE )
358 fprintf( stderr, "%s: image data is in GART client storage\n",
359 __FUNCTION__);
360 r300UploadGARTClientSubImage( rmesa, t, texImage, hwlevel,
361 x, y, width, height );
362 return;
363 }
364 else if ( RADEON_DEBUG & DEBUG_TEXTURE )
365 fprintf( stderr, "%s: image data is in normal memory\n",
366 __FUNCTION__);
367
368
369 imageWidth = texImage->Width;
370 imageHeight = texImage->Height;
371
372 offset = t->bufAddr + t->base.totalSize / 6 * face;
373
374 if ( RADEON_DEBUG & (DEBUG_TEXTURE|DEBUG_IOCTL) ) {
375 GLint imageX = 0;
376 GLint imageY = 0;
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 );
387 }
388
389 t->image[face][hwlevel].data = texImage->Data;
390
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
395 * textures. (Brian)
396 * NOTE: can't do that with texture tiling. (sroland)
397 */
398 tex.offset = offset;
399 tex.image = &tmp;
400 /* copy (x,y,width,height,data) */
401 memcpy( &tmp, &t->image[face][hwlevel], sizeof(tmp) );
402
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;
412 }
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) {
418 case 1:
419 tex.format = RADEON_TXFORMAT_I8;
420 break;
421 case 2:
422 tex.format = RADEON_TXFORMAT_AI88;
423 break;
424 case 4:
425 tex.format = RADEON_TXFORMAT_ARGB8888;
426 break;
427 }
428 tex.pitch = MAX2((texImage->Width * texImage->TexFormat->TexelBytes) / 64, 1);
429 tex.offset += tmp.x & ~1023;
430 tmp.x = tmp.x % 1024;
431 #if 1
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;
437 }
438 else
439 #endif
440 {
441 tmp.x = tmp.x >> (texImage->TexFormat->TexelBytes >> 1);
442 }
443 #if 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;
452 }
453 #endif
454 }
455 else {
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 = RADEON_TXFORMAT_I8; /* any 1-byte texel format */
461 tex.pitch = (R300_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)
465 {
466 tex.width *= 8;
467 } else {
468 tex.width *= 16;
469 }
470 }
471
472 LOCK_HARDWARE( &rmesa->radeon );
473 do {
474 ret = drmCommandWriteRead( rmesa->radeon.dri.fd, DRM_RADEON_TEXTURE,
475 &tex, sizeof(drm_radeon_texture_t) );
476 if (ret) {
477 if (RADEON_DEBUG & DEBUG_IOCTL)
478 fprintf(stderr, "DRM_RADEON_TEXTURE: again!\n");
479 usleep(1);
480 }
481 } while ( ret == -EAGAIN );
482
483 UNLOCK_HARDWARE( &rmesa->radeon );
484
485 if ( ret ) {
486 fprintf( stderr, "DRM_RADEON_TEXTURE: return = %d\n", ret );
487 fprintf( stderr, " offset=0x%08x\n",
488 offset );
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 );
494 exit( 1 );
495 }
496 }
497
498 /**
499 * Upload the texture images associated with texture \a t. This might
500 * require the allocation of texture memory.
501 *
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.
505 */
506
507 int r300UploadTexImages(r300ContextPtr rmesa, r300TexObjPtr t, GLuint face)
508 {
509 const int numLevels = t->base.lastLevel - t->base.firstLevel + 1;
510
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,
515 t->base.lastLevel);
516 }
517
518 if (!t || t->base.totalSize == 0)
519 return 0;
520
521 if (RADEON_DEBUG & DEBUG_SYNC) {
522 fprintf(stderr, "%s: Syncing\n", __FUNCTION__);
523 radeonFinish(rmesa->radeon.glCtx);
524 }
525
526 LOCK_HARDWARE(&rmesa->radeon);
527
528 if (t->base.memBlock == NULL) {
529 int heap;
530
531 heap = driAllocateTexture(rmesa->texture_heaps, rmesa->nr_heaps,
532 (driTextureObject *) t);
533 if (heap == -1) {
534 UNLOCK_HARDWARE(&rmesa->radeon);
535 return -1;
536 }
537
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;
542
543 if (!(t->base.tObj->Image[0][0]->IsClientData)) {
544 /* hope it's safe to add that here... */
545 t->offset |= t->tile_bits;
546 }
547
548 /* Mark this texobj as dirty on all units:
549 */
550 t->dirty_state = TEX_ALL;
551 }
552
553 /* Let the world know we've used this memory recently.
554 */
555 driUpdateTextureLRU((driTextureObject *) t);
556 UNLOCK_HARDWARE(&rmesa->radeon);
557
558 /* Upload any images that are new */
559 if (t->base.dirty_images[face]) {
560 int i;
561 for (i = 0; i < numLevels; i++) {
562 if ((t->base.
563 dirty_images[face] & (1 <<
564 (i + t->base.firstLevel))) !=
565 0) {
566 uploadSubImage(rmesa, t, i, 0, 0,
567 t->image[face][i].width,
568 t->image[face][i].height, face);
569 }
570 }
571 t->base.dirty_images[face] = 0;
572 }
573
574 if (RADEON_DEBUG & DEBUG_SYNC) {
575 fprintf(stderr, "%s: Syncing\n", __FUNCTION__);
576 radeonFinish(rmesa->radeon.glCtx);
577 }
578
579 return 0;
580 }