Get NeHe lesson08 to work. Note: it appears the filtering does not work properly...
[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 "radeon_ioctl.h"
51 /*
52 #include "r300_swtcl.h"
53 */
54 #include "r300_tex.h"
55
56 #include <unistd.h> /* for usleep() */
57
58 /**
59 * Destroy any device-dependent state associated with the texture. This may
60 * include NULLing out hardware state that points to the texture.
61 */
62 void r300DestroyTexObj(r300ContextPtr rmesa, r300TexObjPtr t)
63 {
64 if (RADEON_DEBUG & DEBUG_TEXTURE) {
65 fprintf(stderr, "%s( %p, %p )\n", __FUNCTION__,
66 (void *)t, (void *)t->base.tObj);
67 }
68
69 if (rmesa != NULL) {
70 unsigned i;
71
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
77 unneeded units.
78
79 This does not appear to be worthwhile on R300 */
80 #if 0
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]);
85 #endif
86 }
87 }
88 }
89 }
90
91 /* ------------------------------------------------------------
92 * Texture image conversions
93 */
94
95 static void r300UploadGARTClientSubImage(r300ContextPtr rmesa,
96 r300TexObjPtr t,
97 struct gl_texture_image *texImage,
98 GLint hwlevel,
99 GLint x, GLint y,
100 GLint width, GLint height)
101 {
102 const struct gl_texture_format *texFormat = texImage->TexFormat;
103 GLuint srcPitch, dstPitch;
104 int blit_format;
105 int srcOffset;
106
107 /*
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.
111 */
112 switch (texFormat->TexelBytes) {
113 case 1:
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;
117 break;
118 case 2:
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;
122 break;
123 case 4:
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;
127 break;
128 default:
129 return;
130 }
131
132 t->image[0][hwlevel].data = texImage->Data;
133 srcOffset = r300GartOffsetFromVirtual(rmesa, texImage->Data);
134
135 assert(srcOffset != ~0);
136
137 /* Don't currently need to cope with small pitches?
138 */
139 width = texImage->Width;
140 height = texImage->Height;
141
142 r300EmitWait(rmesa, RADEON_WAIT_3D);
143
144 r300EmitBlit(rmesa, blit_format,
145 srcPitch,
146 srcOffset,
147 dstPitch,
148 t->bufAddr,
149 x,
150 y,
151 t->image[0][hwlevel].x + x,
152 t->image[0][hwlevel].y + y, width, height);
153
154 r300EmitWait(rmesa, RADEON_WAIT_2D);
155 }
156
157 static void r300UploadRectSubImage(r300ContextPtr rmesa,
158 r300TexObjPtr t,
159 struct gl_texture_image *texImage,
160 GLint x, GLint y, GLint width, GLint height)
161 {
162 const struct gl_texture_format *texFormat = texImage->TexFormat;
163 int blit_format, dstPitch, done;
164
165 switch (texFormat->TexelBytes) {
166 case 1:
167 blit_format = R200_CP_COLOR_FORMAT_CI8;
168 break;
169 case 2:
170 blit_format = R200_CP_COLOR_FORMAT_RGB565;
171 break;
172 case 4:
173 blit_format = R200_CP_COLOR_FORMAT_ARGB8888;
174 break;
175 default:
176 return;
177 }
178
179 t->image[0][0].data = texImage->Data;
180
181 /* Currently don't need to cope with small pitches.
182 */
183 width = texImage->Width;
184 height = texImage->Height;
185 dstPitch = t->pitch + 32;
186
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.
190 */
191 t->offset =
192 r300GartOffsetFromVirtual(rmesa, texImage->Data);
193 t->pitch =
194 texImage->RowStride * texFormat->TexelBytes - 32;
195
196 if (RADEON_DEBUG & DEBUG_TEXTURE)
197 fprintf(stderr,
198 "Using GART texturing for rectangular client texture\n");
199
200 /* Release FB memory allocated for this image:
201 */
202 /* FIXME This may not be correct as driSwapOutTextureObject sets
203 * FIXME dirty_images. It may be fine, though.
204 */
205 if (t->base.memBlock) {
206 driSwapOutTextureObject((driTextureObject *) t);
207 }
208 } else if (texImage->IsClientData) {
209 /* Data already in GART memory, with usable pitch.
210 */
211 GLuint srcPitch;
212 srcPitch = texImage->RowStride * texFormat->TexelBytes;
213 r300EmitBlit(rmesa,
214 blit_format,
215 srcPitch,
216 r300GartOffsetFromVirtual(rmesa, texImage->Data),
217 dstPitch, t->bufAddr, 0, 0, 0, 0, width, height);
218 } else {
219 /* Data not in GART memory, or bad pitch.
220 */
221 for (done = 0; done < height;) {
222 struct r300_dma_region region;
223 int lines =
224 MIN2(height - done, RADEON_BUFFER_SIZE / dstPitch);
225 int src_pitch;
226 char *tex;
227
228 src_pitch = texImage->RowStride * texFormat->TexelBytes;
229
230 tex = (char *)texImage->Data + done * src_pitch;
231
232 memset(&region, 0, sizeof(region));
233 r300AllocDmaRegion(rmesa, &region, lines * dstPitch,
234 1024);
235
236 /* Copy texdata to dma:
237 */
238 if (0)
239 fprintf(stderr,
240 "%s: src_pitch %d dst_pitch %d\n",
241 __FUNCTION__, src_pitch, dstPitch);
242
243 if (src_pitch == dstPitch) {
244 memcpy(region.address + region.start, tex,
245 lines * src_pitch);
246 } else {
247 char *buf = region.address + region.start;
248 int i;
249 for (i = 0; i < lines; i++) {
250 memcpy(buf, tex, src_pitch);
251 buf += dstPitch;
252 tex += src_pitch;
253 }
254 }
255
256 r300EmitWait(rmesa, RADEON_WAIT_3D);
257
258 /* Blit to framebuffer
259 */
260 r300EmitBlit(rmesa,
261 blit_format,
262 dstPitch, GET_START(&region),
263 dstPitch, t->bufAddr,
264 0, 0, 0, done, width, lines);
265
266 r300EmitWait(rmesa, RADEON_WAIT_2D);
267
268 r300ReleaseDmaRegion(rmesa, &region, __FUNCTION__);
269 done += lines;
270 }
271 }
272 }
273
274 /**
275 * Upload the texture image associated with texture \a t at the specified
276 * level at the address relative to \a start.
277 */
278 static void uploadSubImage(r300ContextPtr rmesa, r300TexObjPtr t,
279 GLint hwlevel,
280 GLint x, GLint y, GLint width, GLint height,
281 GLuint face)
282 {
283 struct gl_texture_image *texImage = NULL;
284 GLuint offset;
285 GLint imageWidth, imageHeight;
286 GLint ret;
287 drm_radeon_texture_t tex;
288 drm_radeon_tex_image_t tmp;
289 const int level = hwlevel + t->base.firstLevel;
290
291 if (RADEON_DEBUG & DEBUG_TEXTURE) {
292 fprintf(stderr,
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);
296 }
297
298 ASSERT(face < 6);
299
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__);
303 return;
304 }
305
306 texImage = t->base.tObj->Image[face][level];
307
308 if (!texImage) {
309 if (RADEON_DEBUG & DEBUG_TEXTURE)
310 fprintf(stderr, "%s: texImage %d is NULL!\n",
311 __FUNCTION__, level);
312 return;
313 }
314 if (!texImage->Data) {
315 if (RADEON_DEBUG & DEBUG_TEXTURE)
316 fprintf(stderr, "%s: image data is NULL!\n",
317 __FUNCTION__);
318 return;
319 }
320
321 if (t->base.tObj->Target == GL_TEXTURE_RECTANGLE_NV) {
322 assert(level == 0);
323 assert(hwlevel == 0);
324 if (RADEON_DEBUG & DEBUG_TEXTURE)
325 fprintf(stderr, "%s: image data is rectangular\n",
326 __FUNCTION__);
327 r300UploadRectSubImage(rmesa, t, texImage, x, y, width, height);
328 return;
329 } else if (texImage->IsClientData) {
330 if (RADEON_DEBUG & DEBUG_TEXTURE)
331 fprintf(stderr,
332 "%s: image data is in GART client storage\n",
333 __FUNCTION__);
334 r300UploadGARTClientSubImage(rmesa, t, texImage, hwlevel, x, y,
335 width, height);
336 return;
337 } else if (RADEON_DEBUG & DEBUG_TEXTURE)
338 fprintf(stderr, "%s: image data is in normal memory\n",
339 __FUNCTION__);
340
341 imageWidth = texImage->Width;
342 imageHeight = texImage->Height;
343
344 offset = t->bufAddr;
345
346 if (RADEON_DEBUG & (DEBUG_TEXTURE | DEBUG_IOCTL)) {
347 GLint imageX = 0;
348 GLint imageY = 0;
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);
359 }
360
361 t->image[face][hwlevel].data = texImage->Data;
362
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
367 * textures. (Brian)
368 */
369 tex.offset = offset;
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;
375 } else {
376 tex.width = imageWidth; /* compressed */
377 tex.height = imageHeight;
378 if (tex.height < 4)
379 tex.height = 4;
380 }
381 tex.image = &tmp;
382
383 /* copy (x,y,width,height,data) */
384 memcpy(&tmp, &t->image[face][hwlevel], sizeof(tmp));
385
386 LOCK_HARDWARE(&rmesa->radeon);
387 do {
388 ret = drmCommandWriteRead(rmesa->radeon.dri.fd, DRM_RADEON_TEXTURE,
389 &tex, sizeof(drm_radeon_texture_t));
390 if (ret) {
391 if (RADEON_DEBUG & DEBUG_IOCTL)
392 fprintf(stderr,
393 "DRM_RADEON_TEXTURE: again!\n");
394 usleep(1);
395 }
396 } while (ret && errno == EAGAIN);
397
398 UNLOCK_HARDWARE(&rmesa->radeon);
399
400 if (ret) {
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);
409 exit(1);
410 }
411 }
412
413 /**
414 * Upload the texture images associated with texture \a t. This might
415 * require the allocation of texture memory.
416 *
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.
420 */
421
422 int r300UploadTexImages(r300ContextPtr rmesa, r300TexObjPtr t, GLuint face)
423 {
424 const int numLevels = t->base.lastLevel - t->base.firstLevel + 1;
425
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,
430 t->base.lastLevel);
431 }
432
433 if (!t || t->base.totalSize == 0)
434 return 0;
435
436 if (RADEON_DEBUG & DEBUG_SYNC) {
437 fprintf(stderr, "%s: Syncing\n", __FUNCTION__);
438 radeonFinish(rmesa->radeon.glCtx);
439 }
440
441 LOCK_HARDWARE(&rmesa->radeon);
442
443 if (t->base.memBlock == NULL) {
444 int heap;
445
446 heap = driAllocateTexture(rmesa->texture_heaps, rmesa->nr_heaps,
447 (driTextureObject *) t);
448 if (heap == -1) {
449 UNLOCK_HARDWARE(&rmesa->radeon);
450 return -1;
451 }
452
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;
457
458 /* Mark this texobj as dirty on all units:
459 */
460 t->dirty_state = TEX_ALL;
461 }
462
463 /* Let the world know we've used this memory recently.
464 */
465 driUpdateTextureLRU((driTextureObject *) t);
466 UNLOCK_HARDWARE(&rmesa->radeon);
467
468 /* Upload any images that are new */
469 if (t->base.dirty_images[face]) {
470 int i;
471 for (i = 0; i < numLevels; i++) {
472 if ((t->base.
473 dirty_images[face] & (1 <<
474 (i + t->base.firstLevel))) !=
475 0) {
476 uploadSubImage(rmesa, t, i, 0, 0,
477 t->image[face][i].width,
478 t->image[face][i].height, face);
479 }
480 }
481 t->base.dirty_images[face] = 0;
482 }
483
484 if (RADEON_DEBUG & DEBUG_SYNC) {
485 fprintf(stderr, "%s: Syncing\n", __FUNCTION__);
486 radeonFinish(rmesa->radeon.glCtx);
487 }
488
489 return 0;
490 }