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