radeon_mipmap_tree.c revision 63c00c53a3019b801c5eee8a12f7862422f79f10
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, i, face, level; 128 129 assert(mt->numLevels <= rmesa->glCtx->Const.MaxTextureLevels); 130 131 curOffset = 0; 132 for(face = 0; face < mt->faces; face++) { 133 134 for(i = 0, level = mt->baseLevel; i < mt->numLevels; i++, level++) { 135 mt->levels[level].valid = 1; 136 mt->levels[level].width = minify(mt->width0, i); 137 mt->levels[level].height = minify(mt->height0, i); 138 mt->levels[level].depth = minify(mt->depth0, i); 139 compute_tex_image_offset(rmesa, mt, face, level, &curOffset); 140 } 141 } 142 143 /* Note the required size in memory */ 144 mt->totalsize = (curOffset + RADEON_OFFSET_MASK) & ~RADEON_OFFSET_MASK; 145} 146 147static void calculate_miptree_layout_r300(radeonContextPtr rmesa, radeon_mipmap_tree *mt) 148{ 149 GLuint curOffset, i, level; 150 151 assert(mt->numLevels <= rmesa->glCtx->Const.MaxTextureLevels); 152 153 curOffset = 0; 154 for(i = 0, level = mt->baseLevel; i < mt->numLevels; i++, level++) { 155 GLuint face; 156 157 mt->levels[level].valid = 1; 158 mt->levels[level].width = minify(mt->width0, i); 159 mt->levels[level].height = minify(mt->height0, i); 160 mt->levels[level].depth = minify(mt->depth0, i); 161 162 for(face = 0; face < mt->faces; face++) 163 compute_tex_image_offset(rmesa, mt, face, level, &curOffset); 164 } 165 166 /* Note the required size in memory */ 167 mt->totalsize = (curOffset + RADEON_OFFSET_MASK) & ~RADEON_OFFSET_MASK; 168} 169 170/** 171 * Create a new mipmap tree, calculate its layout and allocate memory. 172 */ 173static radeon_mipmap_tree* radeon_miptree_create(radeonContextPtr rmesa, 174 GLenum target, gl_format mesaFormat, GLuint baseLevel, GLuint numLevels, 175 GLuint width0, GLuint height0, GLuint depth0, GLuint tilebits) 176{ 177 radeon_mipmap_tree *mt = CALLOC_STRUCT(_radeon_mipmap_tree); 178 179 mt->mesaFormat = mesaFormat; 180 mt->refcount = 1; 181 mt->target = target; 182 mt->faces = (target == GL_TEXTURE_CUBE_MAP) ? 6 : 1; 183 mt->baseLevel = baseLevel; 184 mt->numLevels = numLevels; 185 mt->width0 = width0; 186 mt->height0 = height0; 187 mt->depth0 = depth0; 188 mt->tilebits = tilebits; 189 190 if (rmesa->radeonScreen->chip_family >= CHIP_FAMILY_R300) 191 calculate_miptree_layout_r300(rmesa, mt); 192 else 193 calculate_miptree_layout_r100(rmesa, mt); 194 195 mt->bo = radeon_bo_open(rmesa->radeonScreen->bom, 196 0, mt->totalsize, 1024, 197 RADEON_GEM_DOMAIN_VRAM, 198 0); 199 200 return mt; 201} 202 203void radeon_miptree_reference(radeon_mipmap_tree *mt, radeon_mipmap_tree **ptr) 204{ 205 assert(!*ptr); 206 207 mt->refcount++; 208 assert(mt->refcount > 0); 209 210 *ptr = mt; 211} 212 213void radeon_miptree_unreference(radeon_mipmap_tree **ptr) 214{ 215 radeon_mipmap_tree *mt = *ptr; 216 if (!mt) 217 return; 218 219 assert(mt->refcount > 0); 220 221 mt->refcount--; 222 if (!mt->refcount) { 223 radeon_bo_unref(mt->bo); 224 free(mt); 225 } 226 227 *ptr = 0; 228} 229 230/** 231 * Calculate min and max LOD for the given texture object. 232 * @param[in] tObj texture object whose LOD values to calculate 233 * @param[out] pminLod minimal LOD 234 * @param[out] pmaxLod maximal LOD 235 */ 236static void calculate_min_max_lod(struct gl_texture_object *tObj, 237 unsigned *pminLod, unsigned *pmaxLod) 238{ 239 int minLod, maxLod; 240 /* Yes, this looks overly complicated, but it's all needed. 241 */ 242 switch (tObj->Target) { 243 case GL_TEXTURE_1D: 244 case GL_TEXTURE_2D: 245 case GL_TEXTURE_3D: 246 case GL_TEXTURE_CUBE_MAP: 247 if (tObj->MinFilter == GL_NEAREST || tObj->MinFilter == GL_LINEAR) { 248 /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL. 249 */ 250 minLod = maxLod = tObj->BaseLevel; 251 } else { 252 minLod = tObj->BaseLevel + (GLint)(tObj->MinLod); 253 minLod = MAX2(minLod, tObj->BaseLevel); 254 minLod = MIN2(minLod, tObj->MaxLevel); 255 maxLod = tObj->BaseLevel + (GLint)(tObj->MaxLod + 0.5); 256 maxLod = MIN2(maxLod, tObj->MaxLevel); 257 maxLod = MIN2(maxLod, tObj->Image[0][minLod]->MaxLog2 + minLod); 258 maxLod = MAX2(maxLod, minLod); /* need at least one level */ 259 } 260 break; 261 case GL_TEXTURE_RECTANGLE_NV: 262 case GL_TEXTURE_4D_SGIS: 263 minLod = maxLod = 0; 264 break; 265 default: 266 return; 267 } 268 269 /* save these values */ 270 *pminLod = minLod; 271 *pmaxLod = maxLod; 272} 273 274/** 275 * Checks whether the given miptree can hold the given texture image at the 276 * given face and level. 277 */ 278GLboolean radeon_miptree_matches_image(radeon_mipmap_tree *mt, 279 struct gl_texture_image *texImage, GLuint face, GLuint level) 280{ 281 radeon_mipmap_level *lvl; 282 283 if (face >= mt->faces) 284 return GL_FALSE; 285 286 if (texImage->TexFormat != mt->mesaFormat) 287 return GL_FALSE; 288 289 lvl = &mt->levels[level]; 290 if (!lvl->valid || 291 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 * Ensure that the given image is stored in the given miptree from now on. 398 */ 399static void migrate_image_to_miptree(radeon_mipmap_tree *mt, 400 radeon_texture_image *image, 401 int face, int level) 402{ 403 radeon_mipmap_level *dstlvl = &mt->levels[level]; 404 unsigned char *dest; 405 406 assert(image->mt != mt); 407 assert(dstlvl->valid); 408 assert(dstlvl->width == image->base.Width); 409 assert(dstlvl->height == image->base.Height); 410 assert(dstlvl->depth == image->base.Depth); 411 412 radeon_bo_map(mt->bo, GL_TRUE); 413 dest = mt->bo->ptr + dstlvl->faces[face].offset; 414 415 if (image->mt) { 416 /* Format etc. should match, so we really just need a memcpy(). 417 * In fact, that memcpy() could be done by the hardware in many 418 * cases, provided that we have a proper memory manager. 419 */ 420 assert(mt->mesaFormat == image->base.TexFormat); 421 422 radeon_mipmap_level *srclvl = &image->mt->levels[image->mtlevel]; 423 424 assert(image->mtlevel == level); 425 assert(srclvl->size == dstlvl->size); 426 assert(srclvl->rowstride == dstlvl->rowstride); 427 428 radeon_bo_map(image->mt->bo, GL_FALSE); 429 430 memcpy(dest, 431 image->mt->bo->ptr + srclvl->faces[face].offset, 432 dstlvl->size); 433 radeon_bo_unmap(image->mt->bo); 434 435 radeon_miptree_unreference(&image->mt); 436 } else { 437 /* need to confirm this value is correct */ 438 if (_mesa_is_format_compressed(image->base.TexFormat)) { 439 unsigned size = _mesa_format_image_size(image->base.TexFormat, 440 image->base.Width, 441 image->base.Height, 442 image->base.Depth); 443 memcpy(dest, image->base.Data, size); 444 } else { 445 uint32_t srcrowstride; 446 uint32_t height; 447 448 height = image->base.Height * image->base.Depth; 449 srcrowstride = image->base.Width * _mesa_get_format_bytes(image->base.TexFormat); 450 copy_rows(dest, dstlvl->rowstride, image->base.Data, srcrowstride, 451 height, srcrowstride); 452 } 453 454 _mesa_free_texmemory(image->base.Data); 455 image->base.Data = 0; 456 } 457 458 radeon_bo_unmap(mt->bo); 459 460 radeon_miptree_reference(mt, &image->mt); 461 image->mtface = face; 462 image->mtlevel = level; 463} 464 465/** 466 * Filter matching miptrees, and select one with the most of data. 467 * @param[in] texObj radeon texture object 468 * @param[in] firstLevel first texture level to check 469 * @param[in] lastLevel last texture level to check 470 */ 471static radeon_mipmap_tree * get_biggest_matching_miptree(radeonTexObj *texObj, 472 unsigned firstLevel, 473 unsigned lastLevel) 474{ 475 const unsigned numLevels = lastLevel - firstLevel + 1; 476 unsigned *mtSizes = calloc(numLevels, sizeof(unsigned)); 477 radeon_mipmap_tree **mts = calloc(numLevels, sizeof(radeon_mipmap_tree *)); 478 unsigned mtCount = 0; 479 unsigned maxMtIndex = 0; 480 radeon_mipmap_tree *tmp; 481 482 for (unsigned level = firstLevel; level <= lastLevel; ++level) { 483 radeon_texture_image *img = get_radeon_texture_image(texObj->base.Image[0][level]); 484 unsigned found = 0; 485 // TODO: why this hack?? 486 if (!img) 487 break; 488 489 if (!img->mt) 490 continue; 491 492 for (int i = 0; i < mtCount; ++i) { 493 if (mts[i] == img->mt) { 494 found = 1; 495 mtSizes[i] += img->mt->levels[img->mtlevel].size; 496 break; 497 } 498 } 499 500 if (!found && radeon_miptree_matches_texture(img->mt, &texObj->base)) { 501 mtSizes[mtCount] = img->mt->levels[img->mtlevel].size; 502 mts[mtCount] = img->mt; 503 mtCount++; 504 } 505 } 506 507 if (mtCount == 0) { 508 return NULL; 509 } 510 511 for (int i = 1; i < mtCount; ++i) { 512 if (mtSizes[i] > mtSizes[maxMtIndex]) { 513 maxMtIndex = i; 514 } 515 } 516 517 tmp = mts[maxMtIndex]; 518 free(mtSizes); 519 free(mts); 520 521 return tmp; 522} 523 524/** 525 * Validate texture mipmap tree. 526 * If individual images are stored in different mipmap trees 527 * use the mipmap tree that has the most of the correct data. 528 */ 529int radeon_validate_texture_miptree(GLcontext * ctx, struct gl_texture_object *texObj) 530{ 531 radeonContextPtr rmesa = RADEON_CONTEXT(ctx); 532 radeonTexObj *t = radeon_tex_obj(texObj); 533 534 if (t->validated || t->image_override) { 535 return GL_TRUE; 536 } 537 538 if (texObj->Image[0][texObj->BaseLevel]->Border > 0) 539 return GL_FALSE; 540 541 _mesa_test_texobj_completeness(rmesa->glCtx, texObj); 542 if (!texObj->_Complete) { 543 return GL_FALSE; 544 } 545 546 calculate_min_max_lod(&t->base, &t->minLod, &t->maxLod); 547 548 if (RADEON_DEBUG & RADEON_TEXTURE) 549 fprintf(stderr, "%s: Validating texture %p now, minLod = %d, maxLod = %d\n", 550 __FUNCTION__, texObj ,t->minLod, t->maxLod); 551 552 radeon_mipmap_tree *dst_miptree; 553 dst_miptree = get_biggest_matching_miptree(t, t->minLod, t->maxLod); 554 555 if (!dst_miptree) { 556 radeon_miptree_unreference(&t->mt); 557 radeon_try_alloc_miptree(rmesa, t); 558 dst_miptree = t->mt; 559 if (RADEON_DEBUG & RADEON_TEXTURE) { 560 fprintf(stderr, "%s: No matching miptree found, allocated new one %p\n", __FUNCTION__, t->mt); 561 } 562 } else if (RADEON_DEBUG & RADEON_TEXTURE) { 563 fprintf(stderr, "%s: Using miptree %p\n", __FUNCTION__, t->mt); 564 } 565 566 const unsigned faces = texObj->Target == GL_TEXTURE_CUBE_MAP ? 6 : 1; 567 unsigned face, level; 568 radeon_texture_image *img; 569 /* Validate only the levels that will actually be used during rendering */ 570 for (face = 0; face < faces; ++face) { 571 for (level = t->minLod; level <= t->maxLod; ++level) { 572 img = get_radeon_texture_image(texObj->Image[face][level]); 573 574 if (RADEON_DEBUG & RADEON_TEXTURE) { 575 fprintf(stderr, "Checking image level %d, face %d, mt %p ... ", level, face, img->mt); 576 } 577 578 if (img->mt != dst_miptree) { 579 if (RADEON_DEBUG & RADEON_TEXTURE) { 580 fprintf(stderr, "MIGRATING\n"); 581 } 582 struct radeon_bo *src_bo = (img->mt) ? img->mt->bo : img->bo; 583 if (src_bo && radeon_bo_is_referenced_by_cs(src_bo, rmesa->cmdbuf.cs)) { 584 radeon_firevertices(rmesa); 585 } 586 migrate_image_to_miptree(dst_miptree, img, face, level); 587 } else if (RADEON_DEBUG & RADEON_TEXTURE) { 588 fprintf(stderr, "OK\n"); 589 } 590 } 591 } 592 593 t->validated = GL_TRUE; 594 595 return GL_TRUE; 596} 597 598uint32_t get_base_teximage_offset(radeonTexObj *texObj) 599{ 600 if (!texObj->mt) { 601 return 0; 602 } else { 603 return radeon_miptree_image_offset(texObj->mt, 0, texObj->minLod); 604 } 605}