Merge commit 'origin/mesa_7_7_branch'
[mesa.git] / src / mesa / drivers / dri / radeon / radeon_mipmap_tree.c
1 /*
2 * Copyright (C) 2009 Maciej Cencora.
3 * Copyright (C) 2008 Nicolai Haehnle.
4 *
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial
17 * portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
23 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 */
28
29 #include "radeon_mipmap_tree.h"
30
31 #include <errno.h>
32 #include <unistd.h>
33
34 #include "main/simple_list.h"
35 #include "main/texcompress.h"
36 #include "main/teximage.h"
37 #include "main/texobj.h"
38 #include "radeon_texture.h"
39
40 static unsigned get_aligned_compressed_row_stride(
41 gl_format format,
42 unsigned width,
43 unsigned minStride)
44 {
45 const unsigned blockSize = _mesa_get_format_bytes(format);
46 unsigned blockWidth, blockHeight, numXBlocks;
47
48 _mesa_get_format_block_size(format, &blockWidth, &blockHeight);
49 numXBlocks = (width + blockWidth - 1) / blockWidth;
50
51 while (numXBlocks * blockSize < minStride)
52 {
53 ++numXBlocks;
54 }
55
56 return numXBlocks * blockSize;
57 }
58
59 static unsigned get_compressed_image_size(
60 gl_format format,
61 unsigned rowStride,
62 unsigned height)
63 {
64 unsigned blockWidth, blockHeight;
65
66 _mesa_get_format_block_size(format, &blockWidth, &blockHeight);
67
68 return rowStride * ((height + blockHeight - 1) / blockHeight);
69 }
70
71 /**
72 * Compute sizes and fill in offset and blit information for the given
73 * image (determined by \p face and \p level).
74 *
75 * \param curOffset points to the offset at which the image is to be stored
76 * and is updated by this function according to the size of the image.
77 */
78 static void compute_tex_image_offset(radeonContextPtr rmesa, radeon_mipmap_tree *mt,
79 GLuint face, GLuint level, GLuint* curOffset)
80 {
81 radeon_mipmap_level *lvl = &mt->levels[level];
82 uint32_t row_align;
83
84 /* Find image size in bytes */
85 if (_mesa_is_format_compressed(mt->mesaFormat)) {
86 lvl->rowstride = get_aligned_compressed_row_stride(mt->mesaFormat, lvl->width, rmesa->texture_compressed_row_align);
87 lvl->size = get_compressed_image_size(mt->mesaFormat, lvl->rowstride, lvl->height);
88 } else if (mt->target == GL_TEXTURE_RECTANGLE_NV) {
89 row_align = rmesa->texture_rect_row_align - 1;
90 lvl->rowstride = (_mesa_format_row_stride(mt->mesaFormat, lvl->width) + row_align) & ~row_align;
91 lvl->size = lvl->rowstride * lvl->height;
92 } else if (mt->tilebits & RADEON_TXO_MICRO_TILE) {
93 /* tile pattern is 16 bytes x2. mipmaps stay 32 byte aligned,
94 * though the actual offset may be different (if texture is less than
95 * 32 bytes width) to the untiled case */
96 lvl->rowstride = (_mesa_format_row_stride(mt->mesaFormat, lvl->width) * 2 + 31) & ~31;
97 lvl->size = lvl->rowstride * ((lvl->height + 1) / 2) * lvl->depth;
98 } else {
99 row_align = rmesa->texture_row_align - 1;
100 lvl->rowstride = (_mesa_format_row_stride(mt->mesaFormat, lvl->width) + row_align) & ~row_align;
101 lvl->size = lvl->rowstride * lvl->height * lvl->depth;
102 }
103 assert(lvl->size > 0);
104
105 /* All images are aligned to a 32-byte offset */
106 *curOffset = (*curOffset + 0x1f) & ~0x1f;
107 lvl->faces[face].offset = *curOffset;
108 *curOffset += lvl->size;
109
110 if (RADEON_DEBUG & RADEON_TEXTURE)
111 fprintf(stderr,
112 "level %d, face %d: rs:%d %dx%d at %d\n",
113 level, face, lvl->rowstride, lvl->width, lvl->height, lvl->faces[face].offset);
114 }
115
116 static GLuint minify(GLuint size, GLuint levels)
117 {
118 size = size >> levels;
119 if (size < 1)
120 size = 1;
121 return size;
122 }
123
124
125 static void calculate_miptree_layout_r100(radeonContextPtr rmesa, radeon_mipmap_tree *mt)
126 {
127 GLuint curOffset;
128 GLuint i;
129 GLuint face;
130
131 assert(mt->numLevels <= rmesa->glCtx->Const.MaxTextureLevels);
132
133 curOffset = 0;
134 for(face = 0; face < mt->faces; face++) {
135
136 for(i = 0; i < mt->numLevels; i++) {
137 mt->levels[i].width = minify(mt->width0, i);
138 mt->levels[i].height = minify(mt->height0, i);
139 mt->levels[i].depth = minify(mt->depth0, i);
140 compute_tex_image_offset(rmesa, mt, face, i, &curOffset);
141 }
142 }
143
144 /* Note the required size in memory */
145 mt->totalsize = (curOffset + RADEON_OFFSET_MASK) & ~RADEON_OFFSET_MASK;
146 }
147
148 static void calculate_miptree_layout_r300(radeonContextPtr rmesa, radeon_mipmap_tree *mt)
149 {
150 GLuint curOffset;
151 GLuint i;
152
153 assert(mt->numLevels <= rmesa->glCtx->Const.MaxTextureLevels);
154
155 curOffset = 0;
156 for(i = 0; i < mt->numLevels; i++) {
157 GLuint face;
158
159 mt->levels[i].width = minify(mt->width0, i);
160 mt->levels[i].height = minify(mt->height0, i);
161 mt->levels[i].depth = minify(mt->depth0, i);
162
163 for(face = 0; face < mt->faces; face++)
164 compute_tex_image_offset(rmesa, mt, face, i, &curOffset);
165 }
166
167 /* Note the required size in memory */
168 mt->totalsize = (curOffset + RADEON_OFFSET_MASK) & ~RADEON_OFFSET_MASK;
169 }
170
171 /**
172 * Create a new mipmap tree, calculate its layout and allocate memory.
173 */
174 static radeon_mipmap_tree* radeon_miptree_create(radeonContextPtr rmesa,
175 GLenum target, gl_format mesaFormat, GLuint baseLevel, GLuint numLevels,
176 GLuint width0, GLuint height0, GLuint depth0, GLuint tilebits)
177 {
178 radeon_mipmap_tree *mt = CALLOC_STRUCT(_radeon_mipmap_tree);
179
180 mt->mesaFormat = mesaFormat;
181 mt->refcount = 1;
182 mt->target = target;
183 mt->faces = (target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
184 mt->baseLevel = baseLevel;
185 mt->numLevels = numLevels;
186 mt->width0 = width0;
187 mt->height0 = height0;
188 mt->depth0 = depth0;
189 mt->tilebits = tilebits;
190
191 if (rmesa->radeonScreen->chip_family >= CHIP_FAMILY_R300)
192 calculate_miptree_layout_r300(rmesa, mt);
193 else
194 calculate_miptree_layout_r100(rmesa, mt);
195
196 mt->bo = radeon_bo_open(rmesa->radeonScreen->bom,
197 0, mt->totalsize, 1024,
198 RADEON_GEM_DOMAIN_VRAM,
199 0);
200
201 return mt;
202 }
203
204 void radeon_miptree_reference(radeon_mipmap_tree *mt, radeon_mipmap_tree **ptr)
205 {
206 assert(!*ptr);
207
208 mt->refcount++;
209 assert(mt->refcount > 0);
210
211 *ptr = mt;
212 }
213
214 void radeon_miptree_unreference(radeon_mipmap_tree **ptr)
215 {
216 radeon_mipmap_tree *mt = *ptr;
217 if (!mt)
218 return;
219
220 assert(mt->refcount > 0);
221
222 mt->refcount--;
223 if (!mt->refcount) {
224 radeon_bo_unref(mt->bo);
225 free(mt);
226 }
227
228 *ptr = 0;
229 }
230
231 /**
232 * Calculate min and max LOD for the given texture object.
233 * @param[in] tObj texture object whose LOD values to calculate
234 * @param[out] pminLod minimal LOD
235 * @param[out] pmaxLod maximal LOD
236 */
237 static void calculate_min_max_lod(struct gl_texture_object *tObj,
238 unsigned *pminLod, unsigned *pmaxLod)
239 {
240 int minLod, maxLod;
241 /* Yes, this looks overly complicated, but it's all needed.
242 */
243 switch (tObj->Target) {
244 case GL_TEXTURE_1D:
245 case GL_TEXTURE_2D:
246 case GL_TEXTURE_3D:
247 case GL_TEXTURE_CUBE_MAP:
248 if (tObj->MinFilter == GL_NEAREST || tObj->MinFilter == GL_LINEAR) {
249 /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL.
250 */
251 minLod = maxLod = tObj->BaseLevel;
252 } else {
253 minLod = tObj->BaseLevel + (GLint)(tObj->MinLod);
254 minLod = MAX2(minLod, tObj->BaseLevel);
255 minLod = MIN2(minLod, tObj->MaxLevel);
256 maxLod = tObj->BaseLevel + (GLint)(tObj->MaxLod + 0.5);
257 maxLod = MIN2(maxLod, tObj->MaxLevel);
258 maxLod = MIN2(maxLod, tObj->Image[0][minLod]->MaxLog2 + minLod);
259 maxLod = MAX2(maxLod, minLod); /* need at least one level */
260 }
261 break;
262 case GL_TEXTURE_RECTANGLE_NV:
263 case GL_TEXTURE_4D_SGIS:
264 minLod = maxLod = 0;
265 break;
266 default:
267 return;
268 }
269
270 /* save these values */
271 *pminLod = minLod;
272 *pmaxLod = maxLod;
273 }
274
275 /**
276 * Checks whether the given miptree can hold the given texture image at the
277 * given face and level.
278 */
279 GLboolean radeon_miptree_matches_image(radeon_mipmap_tree *mt,
280 struct gl_texture_image *texImage, GLuint face, GLuint mtLevel)
281 {
282 radeon_mipmap_level *lvl;
283
284 if (face >= mt->faces || mtLevel > mt->numLevels)
285 return GL_FALSE;
286
287 if (texImage->TexFormat != mt->mesaFormat)
288 return GL_FALSE;
289
290 lvl = &mt->levels[mtLevel];
291 if (lvl->width != texImage->Width ||
292 lvl->height != texImage->Height ||
293 lvl->depth != texImage->Depth)
294 return GL_FALSE;
295
296 return GL_TRUE;
297 }
298
299 /**
300 * Checks whether the given miptree has the right format to store the given texture object.
301 */
302 static GLboolean radeon_miptree_matches_texture(radeon_mipmap_tree *mt, struct gl_texture_object *texObj)
303 {
304 struct gl_texture_image *firstImage;
305 unsigned numLevels;
306 radeon_mipmap_level *mtBaseLevel;
307
308 if (texObj->BaseLevel < mt->baseLevel)
309 return GL_FALSE;
310
311 mtBaseLevel = &mt->levels[texObj->BaseLevel - mt->baseLevel];
312 firstImage = texObj->Image[0][texObj->BaseLevel];
313 numLevels = MIN2(texObj->MaxLevel - texObj->BaseLevel + 1, firstImage->MaxLog2 + 1);
314
315 if (RADEON_DEBUG & RADEON_TEXTURE) {
316 fprintf(stderr, "Checking if miptree %p matches texObj %p\n", mt, texObj);
317 fprintf(stderr, "target %d vs %d\n", mt->target, texObj->Target);
318 fprintf(stderr, "format %d vs %d\n", mt->mesaFormat, firstImage->TexFormat);
319 fprintf(stderr, "numLevels %d vs %d\n", mt->numLevels, numLevels);
320 fprintf(stderr, "width0 %d vs %d\n", mtBaseLevel->width, firstImage->Width);
321 fprintf(stderr, "height0 %d vs %d\n", mtBaseLevel->height, firstImage->Height);
322 fprintf(stderr, "depth0 %d vs %d\n", mtBaseLevel->depth, firstImage->Depth);
323 if (mt->target == texObj->Target &&
324 mt->mesaFormat == firstImage->TexFormat &&
325 mt->numLevels >= numLevels &&
326 mtBaseLevel->width == firstImage->Width &&
327 mtBaseLevel->height == firstImage->Height &&
328 mtBaseLevel->depth == firstImage->Depth) {
329 fprintf(stderr, "MATCHED\n");
330 } else {
331 fprintf(stderr, "NOT MATCHED\n");
332 }
333 }
334
335 return (mt->target == texObj->Target &&
336 mt->mesaFormat == firstImage->TexFormat &&
337 mt->numLevels >= numLevels &&
338 mtBaseLevel->width == firstImage->Width &&
339 mtBaseLevel->height == firstImage->Height &&
340 mtBaseLevel->depth == firstImage->Depth);
341 }
342
343 /**
344 * Try to allocate a mipmap tree for the given texture object.
345 * @param[in] rmesa radeon context
346 * @param[in] t radeon texture object
347 */
348 void radeon_try_alloc_miptree(radeonContextPtr rmesa, radeonTexObj *t)
349 {
350 struct gl_texture_object *texObj = &t->base;
351 struct gl_texture_image *texImg = texObj->Image[0][texObj->BaseLevel];
352 GLuint numLevels;
353
354 assert(!t->mt);
355
356 if (!texImg)
357 return;
358
359 numLevels = MIN2(texObj->MaxLevel - texObj->BaseLevel + 1, texImg->MaxLog2 + 1);
360
361 t->mt = radeon_miptree_create(rmesa, t->base.Target,
362 texImg->TexFormat, texObj->BaseLevel,
363 numLevels, texImg->Width, texImg->Height,
364 texImg->Depth, t->tile_bits);
365 }
366
367 /* Although we use the image_offset[] array to store relative offsets
368 * to cube faces, Mesa doesn't know anything about this and expects
369 * each cube face to be treated as a separate image.
370 *
371 * These functions present that view to mesa:
372 */
373 void
374 radeon_miptree_depth_offsets(radeon_mipmap_tree *mt, GLuint level, GLuint *offsets)
375 {
376 if (mt->target != GL_TEXTURE_3D || mt->faces == 1) {
377 offsets[0] = 0;
378 } else {
379 int i;
380 for (i = 0; i < 6; i++) {
381 offsets[i] = mt->levels[level].faces[i].offset;
382 }
383 }
384 }
385
386 GLuint
387 radeon_miptree_image_offset(radeon_mipmap_tree *mt,
388 GLuint face, GLuint level)
389 {
390 if (mt->target == GL_TEXTURE_CUBE_MAP_ARB)
391 return (mt->levels[level].faces[face].offset);
392 else
393 return mt->levels[level].faces[0].offset;
394 }
395
396 /**
397 * Convert radeon miptree texture level to GL texture level
398 * @param[in] tObj texture object whom level is to be converted
399 * @param[in] level radeon miptree texture level
400 * @return GL texture level
401 */
402 unsigned radeon_miptree_level_to_gl_level(struct gl_texture_object *tObj, unsigned level)
403 {
404 return level + tObj->BaseLevel;
405 }
406
407 /**
408 * Convert GL texture level to radeon miptree texture level
409 * @param[in] tObj texture object whom level is to be converted
410 * @param[in] level GL texture level
411 * @return radeon miptree texture level
412 */
413 unsigned radeon_gl_level_to_miptree_level(struct gl_texture_object *tObj, unsigned level)
414 {
415 return level - tObj->BaseLevel;
416 }
417
418 /**
419 * Ensure that the given image is stored in the given miptree from now on.
420 */
421 static void migrate_image_to_miptree(radeon_mipmap_tree *mt,
422 radeon_texture_image *image,
423 int face, int mtLevel)
424 {
425 radeon_mipmap_level *dstlvl = &mt->levels[mtLevel];
426 unsigned char *dest;
427
428 assert(image->mt != mt);
429 assert(dstlvl->width == image->base.Width);
430 assert(dstlvl->height == image->base.Height);
431 assert(dstlvl->depth == image->base.Depth);
432
433 radeon_bo_map(mt->bo, GL_TRUE);
434 dest = mt->bo->ptr + dstlvl->faces[face].offset;
435
436 if (image->mt) {
437 /* Format etc. should match, so we really just need a memcpy().
438 * In fact, that memcpy() could be done by the hardware in many
439 * cases, provided that we have a proper memory manager.
440 */
441 assert(mt->mesaFormat == image->base.TexFormat);
442
443 radeon_mipmap_level *srclvl = &image->mt->levels[image->mtlevel];
444
445 assert(srclvl->size == dstlvl->size);
446 assert(srclvl->rowstride == dstlvl->rowstride);
447
448 radeon_bo_map(image->mt->bo, GL_FALSE);
449
450 memcpy(dest,
451 image->mt->bo->ptr + srclvl->faces[face].offset,
452 dstlvl->size);
453 radeon_bo_unmap(image->mt->bo);
454
455 radeon_miptree_unreference(&image->mt);
456 } else {
457 /* need to confirm this value is correct */
458 if (_mesa_is_format_compressed(image->base.TexFormat)) {
459 unsigned size = _mesa_format_image_size(image->base.TexFormat,
460 image->base.Width,
461 image->base.Height,
462 image->base.Depth);
463 memcpy(dest, image->base.Data, size);
464 } else {
465 uint32_t srcrowstride;
466 uint32_t height;
467
468 height = image->base.Height * image->base.Depth;
469 srcrowstride = image->base.Width * _mesa_get_format_bytes(image->base.TexFormat);
470 copy_rows(dest, dstlvl->rowstride, image->base.Data, srcrowstride,
471 height, srcrowstride);
472 }
473
474 _mesa_free_texmemory(image->base.Data);
475 image->base.Data = 0;
476 }
477
478 radeon_bo_unmap(mt->bo);
479
480 radeon_miptree_reference(mt, &image->mt);
481 image->mtface = face;
482 image->mtlevel = mtLevel;
483 }
484
485 /**
486 * Filter matching miptrees, and select one with the most of data.
487 * @param[in] texObj radeon texture object
488 * @param[in] firstLevel first texture level to check
489 * @param[in] lastLevel last texture level to check
490 */
491 static radeon_mipmap_tree * get_biggest_matching_miptree(radeonTexObj *texObj,
492 unsigned firstLevel,
493 unsigned lastLevel)
494 {
495 const unsigned numLevels = lastLevel - firstLevel + 1;
496 unsigned *mtSizes = calloc(numLevels, sizeof(unsigned));
497 radeon_mipmap_tree **mts = calloc(numLevels, sizeof(radeon_mipmap_tree *));
498 unsigned mtCount = 0;
499 unsigned maxMtIndex = 0;
500 radeon_mipmap_tree *tmp;
501
502 for (unsigned level = firstLevel; level <= lastLevel; ++level) {
503 radeon_texture_image *img = get_radeon_texture_image(texObj->base.Image[0][level]);
504 unsigned found = 0;
505 // TODO: why this hack??
506 if (!img)
507 break;
508
509 if (!img->mt || !radeon_miptree_matches_texture(img->mt, &texObj->base))
510 continue;
511
512 for (int i = 0; i < mtCount; ++i) {
513 if (mts[i] == img->mt) {
514 found = 1;
515 mtSizes[i] += img->mt->levels[img->mtlevel].size;
516 break;
517 }
518 }
519
520 if (!found) {
521 mtSizes[mtCount] += img->mt->levels[img->mtlevel].size;
522 mts[mtCount] = img->mt;
523 mtCount++;
524 }
525 }
526
527 if (mtCount == 0) {
528 return NULL;
529 }
530
531 for (int i = 1; i < mtCount; ++i) {
532 if (mtSizes[i] > mtSizes[maxMtIndex]) {
533 maxMtIndex = i;
534 }
535 }
536
537 tmp = mts[maxMtIndex];
538 free(mtSizes);
539 free(mts);
540
541 return tmp;
542 }
543
544 /**
545 * Validate texture mipmap tree.
546 * If individual images are stored in different mipmap trees
547 * use the mipmap tree that has the most of the correct data.
548 */
549 int radeon_validate_texture_miptree(GLcontext * ctx, struct gl_texture_object *texObj)
550 {
551 radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
552 radeonTexObj *t = radeon_tex_obj(texObj);
553
554 if (t->validated || t->image_override) {
555 return GL_TRUE;
556 }
557
558 if (texObj->Image[0][texObj->BaseLevel]->Border > 0)
559 return GL_FALSE;
560
561 _mesa_test_texobj_completeness(rmesa->glCtx, texObj);
562 if (!texObj->_Complete) {
563 return GL_FALSE;
564 }
565
566 calculate_min_max_lod(&t->base, &t->minLod, &t->maxLod);
567
568 if (RADEON_DEBUG & RADEON_TEXTURE)
569 fprintf(stderr, "%s: Validating texture %p now, minLod = %d, maxLod = %d\n",
570 __FUNCTION__, texObj ,t->minLod, t->maxLod);
571
572 radeon_mipmap_tree *dst_miptree;
573 dst_miptree = get_biggest_matching_miptree(t, t->minLod, t->maxLod);
574
575 if (!dst_miptree) {
576 radeon_miptree_unreference(&t->mt);
577 radeon_try_alloc_miptree(rmesa, t);
578 dst_miptree = t->mt;
579 }
580
581 const unsigned faces = texObj->Target == GL_TEXTURE_CUBE_MAP ? 6 : 1;
582 unsigned face, level;
583 radeon_texture_image *img;
584 /* Validate only the levels that will actually be used during rendering */
585 for (face = 0; face < faces; ++face) {
586 for (level = t->minLod; level <= t->maxLod; ++level) {
587 img = get_radeon_texture_image(texObj->Image[face][level]);
588
589 if (RADEON_DEBUG & RADEON_TEXTURE) {
590 fprintf(stderr, "Checking image level %d, face %d, mt %p ... ", level, face, img->mt);
591 }
592
593 if (img->mt != dst_miptree) {
594 if (RADEON_DEBUG & RADEON_TEXTURE) {
595 fprintf(stderr, "MIGRATING\n");
596 }
597 migrate_image_to_miptree(dst_miptree, img, face, radeon_gl_level_to_miptree_level(texObj, level));
598 } else if (RADEON_DEBUG & RADEON_TEXTURE) {
599 fprintf(stderr, "OK\n");
600 }
601 }
602 }
603
604 t->validated = GL_TRUE;
605
606 return GL_TRUE;
607 }
608
609 uint32_t get_base_teximage_offset(radeonTexObj *texObj)
610 {
611 if (!texObj->mt) {
612 return 0;
613 } else {
614 return radeon_miptree_image_offset(texObj->mt, 0, texObj->minLod);
615 }
616 }