Revert "r300: Perform the locking closer to the DRM texture upload call."
[mesa.git] / src / mesa / drivers / dri / r300 / r300_texmem.c
1 /**************************************************************************
2
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.
7
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:
15
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.
19
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
27 SOFTWARE.
28
29 **************************************************************************/
30
31 /**
32 * \file
33 *
34 * \author Gareth Hughes <gareth@valinux.com>
35 *
36 * \author Kevin E. Martin <martin@valinux.com>
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 "r300_mem.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 = r300GartOffsetFromVirtual(rmesa, texImage->Data);
215 t->pitch = texImage->RowStride * texFormat->TexelBytes - 32;
216
217 if (RADEON_DEBUG & DEBUG_TEXTURE)
218 fprintf(stderr,
219 "Using GART texturing for rectangular client texture\n");
220
221 /* Release FB memory allocated for this image:
222 */
223 /* FIXME This may not be correct as driSwapOutTextureObject sets
224 * FIXME dirty_images. It may be fine, though.
225 */
226 if (t->base.memBlock) {
227 driSwapOutTextureObject((driTextureObject *) t);
228 }
229 } else if (texImage->IsClientData) {
230 /* Data already in GART memory, with usable pitch.
231 */
232 GLuint srcPitch;
233 srcPitch = texImage->RowStride * texFormat->TexelBytes;
234 r300EmitBlit(rmesa,
235 blit_format,
236 srcPitch,
237 r300GartOffsetFromVirtual(rmesa, texImage->Data),
238 dstPitch, t->bufAddr, 0, 0, 0, 0, width, height);
239 } else {
240 /* Data not in GART memory, or bad pitch.
241 */
242 for (done = 0; done < height;) {
243 struct r300_dma_region region;
244 int lines =
245 MIN2(height - done, RADEON_BUFFER_SIZE / dstPitch);
246 int src_pitch;
247 char *tex;
248
249 src_pitch = texImage->RowStride * texFormat->TexelBytes;
250
251 tex = (char *)texImage->Data + done * src_pitch;
252
253 memset(&region, 0, sizeof(region));
254 r300AllocDmaRegion(rmesa, &region, lines * dstPitch,
255 1024);
256
257 /* Copy texdata to dma:
258 */
259 if (RADEON_DEBUG & DEBUG_TEXTURE)
260 fprintf(stderr,
261 "%s: src_pitch %d dst_pitch %d\n",
262 __FUNCTION__, src_pitch, dstPitch);
263
264 if (src_pitch == dstPitch) {
265 memcpy(region.address + region.start, tex,
266 lines * src_pitch);
267 } else {
268 char *buf = region.address + region.start;
269 int i;
270 for (i = 0; i < lines; i++) {
271 memcpy(buf, tex, src_pitch);
272 buf += dstPitch;
273 tex += src_pitch;
274 }
275 }
276
277 r300EmitWait(rmesa, R300_WAIT_3D);
278
279 /* Blit to framebuffer
280 */
281 r300EmitBlit(rmesa,
282 blit_format,
283 dstPitch, GET_START(&region),
284 dstPitch | (t->tile_bits >> 16),
285 t->bufAddr, 0, 0, 0, done, width, lines);
286
287 r300EmitWait(rmesa, R300_WAIT_2D);
288 #ifdef USER_BUFFERS
289 r300_mem_use(rmesa, region.buf->id);
290 #endif
291
292 r300ReleaseDmaRegion(rmesa, &region, __FUNCTION__);
293 done += lines;
294 }
295 }
296 }
297
298 /**
299 * Upload the texture image associated with texture \a t at the specified
300 * level at the address relative to \a start.
301 */
302 static void r300UploadSubImage(r300ContextPtr rmesa, r300TexObjPtr t,
303 GLint hwlevel,
304 GLint x, GLint y, GLint width, GLint height,
305 GLuint face)
306 {
307 struct gl_texture_image *texImage = NULL;
308 GLuint offset;
309 GLint imageWidth, imageHeight;
310 GLint ret;
311 drm_radeon_texture_t tex;
312 drm_radeon_tex_image_t tmp;
313 const int level = hwlevel + t->base.firstLevel;
314
315 if (RADEON_DEBUG & DEBUG_TEXTURE) {
316 fprintf(stderr,
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);
320 }
321
322 ASSERT(face < 6);
323
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__);
327 return;
328 }
329
330 texImage = t->base.tObj->Image[face][level];
331
332 if (!texImage) {
333 if (RADEON_DEBUG & DEBUG_TEXTURE)
334 fprintf(stderr, "%s: texImage %d is NULL!\n",
335 __FUNCTION__, level);
336 return;
337 }
338 if (!texImage->Data) {
339 if (RADEON_DEBUG & DEBUG_TEXTURE)
340 fprintf(stderr, "%s: image data is NULL!\n",
341 __FUNCTION__);
342 return;
343 }
344
345 if (t->base.tObj->Target == GL_TEXTURE_RECTANGLE_NV) {
346 assert(level == 0);
347 assert(hwlevel == 0);
348 if (RADEON_DEBUG & DEBUG_TEXTURE)
349 fprintf(stderr, "%s: image data is rectangular\n",
350 __FUNCTION__);
351 r300UploadRectSubImage(rmesa, t, texImage, x, y, width, height);
352 return;
353 } else if (texImage->IsClientData) {
354 if (RADEON_DEBUG & DEBUG_TEXTURE)
355 fprintf(stderr,
356 "%s: image data is in GART client storage\n",
357 __FUNCTION__);
358 r300UploadGARTClientSubImage(rmesa, t, texImage, hwlevel, x, y,
359 width, height);
360 return;
361 } else if (RADEON_DEBUG & DEBUG_TEXTURE)
362 fprintf(stderr, "%s: image data is in normal memory\n",
363 __FUNCTION__);
364
365 imageWidth = texImage->Width;
366 imageHeight = texImage->Height;
367
368 offset = t->bufAddr + t->base.totalSize / 6 * face;
369
370 if (RADEON_DEBUG & (DEBUG_TEXTURE | DEBUG_IOCTL)) {
371 GLint imageX = 0;
372 GLint imageY = 0;
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);
383 }
384
385 t->image[face][hwlevel].data = texImage->Data;
386
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
391 * textures. (Brian)
392 * NOTE: can't do that with texture tiling. (sroland)
393 */
394 tex.offset = offset;
395 tex.image = &tmp;
396 /* copy (x,y,width,height,data) */
397 memcpy(&tmp, &t->image[face][hwlevel], sizeof(tmp));
398
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 */
403 tex.pitch =
404 MAX2((texImage->Width * texImage->TexFormat->TexelBytes) /
405 64, 1);
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) {
416 case 1:
417 tex.format = RADEON_TXFORMAT_I8;
418 break;
419 case 2:
420 tex.format = RADEON_TXFORMAT_AI88;
421 break;
422 case 4:
423 tex.format = RADEON_TXFORMAT_ARGB8888;
424 break;
425 }
426 tex.pitch =
427 MAX2((texImage->Width * texImage->TexFormat->TexelBytes) /
428 64, 1);
429 tex.offset += tmp.x & ~1023;
430 tmp.x = tmp.x % 1024;
431
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 =
436 tmp.x % (tex.pitch * 128) / 2 /
437 texImage->TexFormat->TexelBytes;
438 tex.pitch |= RADEON_DST_TILE_MICRO >> 22;
439 } else {
440 tmp.x = tmp.x >> (texImage->TexFormat->TexelBytes >> 1);
441 }
442 #if 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;
452 }
453 #endif
454 } else {
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) {
466 tex.width *= 8;
467 } else {
468 tex.width *= 16;
469 }
470 }
471
472 LOCK_HARDWARE(&rmesa->radeon);
473 do {
474 ret =
475 drmCommandWriteRead(rmesa->radeon.dri.fd,
476 DRM_RADEON_TEXTURE, &tex,
477 sizeof(drm_radeon_texture_t));
478 if (ret) {
479 if (RADEON_DEBUG & DEBUG_IOCTL)
480 fprintf(stderr,
481 "DRM_RADEON_TEXTURE: again!\n");
482 usleep(1);
483 }
484 } while (ret == -EAGAIN);
485
486 UNLOCK_HARDWARE(&rmesa->radeon);
487
488 if (ret) {
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);
497 _mesa_exit(-1);
498 }
499 }
500
501 /**
502 * Upload the texture images associated with texture \a t. This might
503 * require the allocation of texture memory.
504 *
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.
508 */
509
510 int r300UploadTexImages(r300ContextPtr rmesa, r300TexObjPtr t, GLuint face)
511 {
512 const int numLevels = t->base.lastLevel - t->base.firstLevel + 1;
513
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,
518 t->base.lastLevel);
519 }
520
521 if (!t || t->base.totalSize == 0)
522 return 0;
523
524 if (RADEON_DEBUG & DEBUG_SYNC) {
525 fprintf(stderr, "%s: Syncing\n", __FUNCTION__);
526 radeonFinish(rmesa->radeon.glCtx);
527 }
528
529 LOCK_HARDWARE(&rmesa->radeon);
530
531 if (t->base.memBlock == NULL) {
532 int heap;
533
534 heap = driAllocateTexture(rmesa->texture_heaps, rmesa->nr_heaps,
535 (driTextureObject *) t);
536 if (heap == -1) {
537 UNLOCK_HARDWARE(&rmesa->radeon);
538 return -1;
539 }
540
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;
545
546 if (!(t->base.tObj->Image[0][0]->IsClientData)) {
547 /* hope it's safe to add that here... */
548 t->offset |= t->tile_bits;
549 }
550
551 /* Mark this texobj as dirty on all units:
552 */
553 t->dirty_state = TEX_ALL;
554 }
555
556 /* Let the world know we've used this memory recently.
557 */
558 driUpdateTextureLRU((driTextureObject *) t);
559 UNLOCK_HARDWARE(&rmesa->radeon);
560
561 /* Upload any images that are new */
562 if (t->base.dirty_images[face]) {
563 int i;
564 for (i = 0; i < numLevels; i++) {
565 if ((t->base.
566 dirty_images[face] & (1 <<
567 (i + t->base.firstLevel))) !=
568 0) {
569 r300UploadSubImage(rmesa, t, i, 0, 0,
570 t->image[face][i].width,
571 t->image[face][i].height,
572 face);
573 }
574 }
575 t->base.dirty_images[face] = 0;
576 }
577
578 if (RADEON_DEBUG & DEBUG_SYNC) {
579 fprintf(stderr, "%s: Syncing\n", __FUNCTION__);
580 radeonFinish(rmesa->radeon.glCtx);
581 }
582
583 return 0;
584 }