radeon_mipmap_tree.c revision e8f0c8ab9d3509dc399ea58c320056ed90895792
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 40static 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 59static 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 */ 78static 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 116static GLuint minify(GLuint size, GLuint levels) 117{ 118 size = size >> levels; 119 if (size < 1) 120 size = 1; 121 return size; 122} 123 124 125static 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 148static 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 */ 174static 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 204void 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 214void 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 */ 237static 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 */ 279GLboolean 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 */ 302static 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 */ 348void 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 */ 373void 374radeon_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 386GLuint 387radeon_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 */ 402unsigned 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 */ 413unsigned 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 */ 421static 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 */ 491static 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 */ 549int 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 if (RADEON_DEBUG & RADEON_TEXTURE) { 580 fprintf(stderr, "%s: No matching miptree found, allocated new one %p\n", __FUNCTION__, t->mt); 581 } 582 } else if (RADEON_DEBUG & RADEON_TEXTURE) { 583 fprintf(stderr, "%s: Using miptree %p\n", __FUNCTION__, t->mt); 584 } 585 586 const unsigned faces = texObj->Target == GL_TEXTURE_CUBE_MAP ? 6 : 1; 587 unsigned face, level; 588 radeon_texture_image *img; 589 /* Validate only the levels that will actually be used during rendering */ 590 for (face = 0; face < faces; ++face) { 591 for (level = t->minLod; level <= t->maxLod; ++level) { 592 img = get_radeon_texture_image(texObj->Image[face][level]); 593 594 if (RADEON_DEBUG & RADEON_TEXTURE) { 595 fprintf(stderr, "Checking image level %d, face %d, mt %p ... ", level, face, img->mt); 596 } 597 598 if (img->mt != dst_miptree) { 599 if (RADEON_DEBUG & RADEON_TEXTURE) { 600 fprintf(stderr, "MIGRATING\n"); 601 } 602 struct radeon_bo *src_bo = (img->mt) ? img->mt->bo : img->bo; 603 if (src_bo && radeon_bo_is_referenced_by_cs(src_bo, rmesa->cmdbuf.cs)) { 604 radeon_firevertices(rmesa); 605 } 606 migrate_image_to_miptree(dst_miptree, img, face, radeon_gl_level_to_miptree_level(texObj, level)); 607 } else if (RADEON_DEBUG & RADEON_TEXTURE) { 608 fprintf(stderr, "OK\n"); 609 } 610 } 611 } 612 613 t->validated = GL_TRUE; 614 615 return GL_TRUE; 616} 617 618uint32_t get_base_teximage_offset(radeonTexObj *texObj) 619{ 620 if (!texObj->mt) { 621 return 0; 622 } else { 623 return radeon_miptree_image_offset(texObj->mt, 0, texObj->minLod); 624 } 625}