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