radeon_mipmap_tree.c revision 06d3732a9094030fc33120f16f162e0d405f132c
12faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes/* 22faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * Copyright (C) 2009 Maciej Cencora. 32faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * Copyright (C) 2008 Nicolai Haehnle. 42faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * 52faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * All Rights Reserved. 62faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * 72faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * Permission is hereby granted, free of charge, to any person obtaining 82faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * a copy of this software and associated documentation files (the 92faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * "Software"), to deal in the Software without restriction, including 102faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * without limitation the rights to use, copy, modify, merge, publish, 112faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * distribute, sublicense, and/or sell copies of the Software, and to 122faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * permit persons to whom the Software is furnished to do so, subject to 132faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * the following conditions: 142faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * 152faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * The above copyright notice and this permission notice (including the 16e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom * next paragraph) shall be included in all copies or substantial 17fc0e3219edc9a5bf81b166e82fd5db2796eb6a0dBrian Carlstrom * portions of the Software. 18fc0e3219edc9a5bf81b166e82fd5db2796eb6a0dBrian Carlstrom * 19e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 23e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 240f3c55331439970e01af67f80ac117c473bc04cfElliott Hughes * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom * 27e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom */ 28df1ce91ba97bc79a0637e5504b39318fb1c9f577Ian Rogers 29e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom#include "radeon_mipmap_tree.h" 307c3d13aebdd8611cae58a1048bffb13cbdc465cbBrian Carlstrom 317c3d13aebdd8611cae58a1048bffb13cbdc465cbBrian Carlstrom#include <errno.h> 327c3d13aebdd8611cae58a1048bffb13cbdc465cbBrian Carlstrom#include <unistd.h> 33a72ec820f8cb8e04b0ba87a62e36b05a2c92ef36Elliott Hughes 3481f3ca17e9e8d360cc4a1b6c3155cf01ba3be3bcBrian Carlstrom#include "main/simple_list.h" 357020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison#include "main/texcompress.h" 3681f3ca17e9e8d360cc4a1b6c3155cf01ba3be3bcBrian Carlstrom#include "main/teximage.h" 3728db0129e5d7ef642cf8845c86c0e11832817085Brian Carlstrom#include "main/texobj.h" 38700c8d31733534a3d978b75a03f6f7e177dc7e81Brian Carlstrom#include "radeon_texture.h" 3981f3ca17e9e8d360cc4a1b6c3155cf01ba3be3bcBrian Carlstrom 40e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstromstatic unsigned get_aligned_compressed_row_stride( 41e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom gl_format format, 42e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom unsigned width, 43e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom unsigned minStride) 44e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom{ 454f6ad8ab428038129b2d0d6c40b7fd625cca15e1Ian Rogers const unsigned blockSize = _mesa_get_format_bytes(format); 464f6ad8ab428038129b2d0d6c40b7fd625cca15e1Ian Rogers unsigned blockWidth, blockHeight, numXBlocks; 474f6ad8ab428038129b2d0d6c40b7fd625cca15e1Ian Rogers 484f6ad8ab428038129b2d0d6c40b7fd625cca15e1Ian Rogers _mesa_get_format_block_size(format, &blockWidth, &blockHeight); 49e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom numXBlocks = (width + blockWidth - 1) / blockWidth; 50e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom 51468532ea115657709bc32ee498e701a4c71762d4Ian Rogers while (numXBlocks * blockSize < minStride) 52468532ea115657709bc32ee498e701a4c71762d4Ian Rogers { 53468532ea115657709bc32ee498e701a4c71762d4Ian Rogers ++numXBlocks; 54468532ea115657709bc32ee498e701a4c71762d4Ian Rogers } 55468532ea115657709bc32ee498e701a4c71762d4Ian Rogers 56468532ea115657709bc32ee498e701a4c71762d4Ian Rogers return numXBlocks * blockSize; 57468532ea115657709bc32ee498e701a4c71762d4Ian Rogers} 58468532ea115657709bc32ee498e701a4c71762d4Ian Rogers 59468532ea115657709bc32ee498e701a4c71762d4Ian Rogersstatic unsigned get_compressed_image_size( 60468532ea115657709bc32ee498e701a4c71762d4Ian Rogers gl_format format, 61468532ea115657709bc32ee498e701a4c71762d4Ian Rogers unsigned rowStride, 62468532ea115657709bc32ee498e701a4c71762d4Ian Rogers unsigned height) 630aba0ba155bef7346bde19e53581200b89ae8a7aJeff Hao{ 640aba0ba155bef7346bde19e53581200b89ae8a7aJeff Hao unsigned blockWidth, blockHeight; 650aba0ba155bef7346bde19e53581200b89ae8a7aJeff Hao 6688474b416eb257078e590bf9bc7957cee604a186Jeff Hao _mesa_get_format_block_size(format, &blockWidth, &blockHeight); 6788474b416eb257078e590bf9bc7957cee604a186Jeff Hao 6888474b416eb257078e590bf9bc7957cee604a186Jeff Hao return rowStride * ((height + blockHeight - 1) / blockHeight); 69468532ea115657709bc32ee498e701a4c71762d4Ian Rogers} 70468532ea115657709bc32ee498e701a4c71762d4Ian Rogers 71468532ea115657709bc32ee498e701a4c71762d4Ian Rogersstatic int find_next_power_of_two(GLuint value) 72468532ea115657709bc32ee498e701a4c71762d4Ian Rogers{ 732da882315a61072664f7ce3c212307342e907207Andreas Gampe int i, tmp; 742da882315a61072664f7ce3c212307342e907207Andreas Gampe 752da882315a61072664f7ce3c212307342e907207Andreas Gampe i = 0; 760aba0ba155bef7346bde19e53581200b89ae8a7aJeff Hao tmp = value - 1; 770aba0ba155bef7346bde19e53581200b89ae8a7aJeff Hao while (tmp) { 780aba0ba155bef7346bde19e53581200b89ae8a7aJeff Hao tmp >>= 1; 7988474b416eb257078e590bf9bc7957cee604a186Jeff Hao i++; 8088474b416eb257078e590bf9bc7957cee604a186Jeff Hao } 8188474b416eb257078e590bf9bc7957cee604a186Jeff Hao return (1 << i); 82468532ea115657709bc32ee498e701a4c71762d4Ian Rogers} 83468532ea115657709bc32ee498e701a4c71762d4Ian Rogers 84468532ea115657709bc32ee498e701a4c71762d4Ian Rogers/** 85468532ea115657709bc32ee498e701a4c71762d4Ian Rogers * Compute sizes and fill in offset and blit information for the given 860aba0ba155bef7346bde19e53581200b89ae8a7aJeff Hao * image (determined by \p face and \p level). 877020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison * 8828db0129e5d7ef642cf8845c86c0e11832817085Brian Carlstrom * \param curOffset points to the offset at which the image is to be stored 89700c8d31733534a3d978b75a03f6f7e177dc7e81Brian Carlstrom * and is updated by this function according to the size of the image. 9081f3ca17e9e8d360cc4a1b6c3155cf01ba3be3bcBrian Carlstrom */ 9181f3ca17e9e8d360cc4a1b6c3155cf01ba3be3bcBrian Carlstromstatic void compute_tex_image_offset(radeonContextPtr rmesa, radeon_mipmap_tree *mt, 9281f3ca17e9e8d360cc4a1b6c3155cf01ba3be3bcBrian Carlstrom GLuint face, GLuint level, GLuint* curOffset) 93e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom{ 94e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom radeon_mipmap_level *lvl = &mt->levels[level]; 95e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom uint32_t row_align; 96e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom GLuint height; 97e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom 98a72ec820f8cb8e04b0ba87a62e36b05a2c92ef36Elliott Hughes height = find_next_power_of_two(lvl->height); 99a72ec820f8cb8e04b0ba87a62e36b05a2c92ef36Elliott Hughes 1007020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison /* Find image size in bytes */ 101e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom if (_mesa_is_format_compressed(mt->mesaFormat)) { 102e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom lvl->rowstride = get_aligned_compressed_row_stride(mt->mesaFormat, lvl->width, rmesa->texture_compressed_row_align); 103468532ea115657709bc32ee498e701a4c71762d4Ian Rogers lvl->size = get_compressed_image_size(mt->mesaFormat, lvl->rowstride, height); 104468532ea115657709bc32ee498e701a4c71762d4Ian Rogers } else if (mt->target == GL_TEXTURE_RECTANGLE_NV) { 105468532ea115657709bc32ee498e701a4c71762d4Ian Rogers row_align = rmesa->texture_rect_row_align - 1; 10688474b416eb257078e590bf9bc7957cee604a186Jeff Hao lvl->rowstride = (_mesa_format_row_stride(mt->mesaFormat, lvl->width) + row_align) & ~row_align; 1070aba0ba155bef7346bde19e53581200b89ae8a7aJeff Hao lvl->size = lvl->rowstride * height; 108468532ea115657709bc32ee498e701a4c71762d4Ian Rogers } else if (mt->tilebits & RADEON_TXO_MICRO_TILE) { 1092da882315a61072664f7ce3c212307342e907207Andreas Gampe /* tile pattern is 16 bytes x2. mipmaps stay 32 byte aligned, 11088474b416eb257078e590bf9bc7957cee604a186Jeff Hao * though the actual offset may be different (if texture is less than 1110aba0ba155bef7346bde19e53581200b89ae8a7aJeff Hao * 32 bytes width) to the untiled case */ 112468532ea115657709bc32ee498e701a4c71762d4Ian Rogers lvl->rowstride = (_mesa_format_row_stride(mt->mesaFormat, lvl->width) * 2 + 31) & ~31; 113e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom lvl->size = lvl->rowstride * ((height + 1) / 2) * lvl->depth; 11428db0129e5d7ef642cf8845c86c0e11832817085Brian Carlstrom } else { 115700c8d31733534a3d978b75a03f6f7e177dc7e81Brian Carlstrom row_align = rmesa->texture_row_align - 1; 11681f3ca17e9e8d360cc4a1b6c3155cf01ba3be3bcBrian Carlstrom lvl->rowstride = (_mesa_format_row_stride(mt->mesaFormat, lvl->width) + row_align) & ~row_align; 11781f3ca17e9e8d360cc4a1b6c3155cf01ba3be3bcBrian Carlstrom lvl->size = lvl->rowstride * height * lvl->depth; 11881f3ca17e9e8d360cc4a1b6c3155cf01ba3be3bcBrian Carlstrom } 119e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom assert(lvl->size > 0); 120e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom 121e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom /* All images are aligned to a 32-byte offset */ 1228a630577ed2d9e9571c3434c505e5de223b23c07Vladimir Marko *curOffset = (*curOffset + 0x1f) & ~0x1f; 123ba150c37d582eeeb8c11ba5245edc281cf31793cBrian Carlstrom lvl->faces[face].offset = *curOffset; 1248a630577ed2d9e9571c3434c505e5de223b23c07Vladimir Marko *curOffset += lvl->size; 125ba150c37d582eeeb8c11ba5245edc281cf31793cBrian Carlstrom 126ba150c37d582eeeb8c11ba5245edc281cf31793cBrian Carlstrom if (RADEON_DEBUG & RADEON_TEXTURE) 127ba150c37d582eeeb8c11ba5245edc281cf31793cBrian Carlstrom fprintf(stderr, 128ba150c37d582eeeb8c11ba5245edc281cf31793cBrian Carlstrom "level %d, face %d: rs:%d %dx%d at %d\n", 129ba150c37d582eeeb8c11ba5245edc281cf31793cBrian Carlstrom level, face, lvl->rowstride, lvl->width, height, lvl->faces[face].offset); 130ba150c37d582eeeb8c11ba5245edc281cf31793cBrian Carlstrom} 131ba150c37d582eeeb8c11ba5245edc281cf31793cBrian Carlstrom 132ba150c37d582eeeb8c11ba5245edc281cf31793cBrian Carlstromstatic GLuint minify(GLuint size, GLuint levels) 133ba150c37d582eeeb8c11ba5245edc281cf31793cBrian Carlstrom{ 134ba150c37d582eeeb8c11ba5245edc281cf31793cBrian Carlstrom size = size >> levels; 135df1ce91ba97bc79a0637e5504b39318fb1c9f577Ian Rogers if (size < 1) 1363320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom size = 1; 1373320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom return size; 138971bf3f9184010d68b9a3ad30b396fa401af91a3Logan Chien} 1393320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom 1403320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom 1413320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstromstatic void calculate_miptree_layout_r100(radeonContextPtr rmesa, radeon_mipmap_tree *mt) 1423320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom{ 143df62950e7a32031b82360c407d46a37b94188fbbBrian Carlstrom GLuint curOffset, i, face, level; 144971bf3f9184010d68b9a3ad30b396fa401af91a3Logan Chien 1453320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom assert(mt->numLevels <= rmesa->glCtx->Const.MaxTextureLevels); 1463320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom 1473320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom curOffset = 0; 1483320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom for(face = 0; face < mt->faces; face++) { 1493320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom 1503320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom for(i = 0, level = mt->baseLevel; i < mt->numLevels; i++, level++) { 151e7d856b911222aa000ca2be0f8f63f5b292141c3Brian Carlstrom mt->levels[level].valid = 1; 1523320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom mt->levels[level].width = minify(mt->width0, i); 1533320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom mt->levels[level].height = minify(mt->height0, i); 15496c6ab93336b972a38bd2448bcccf19188b8389bVladimir Marko mt->levels[level].depth = minify(mt->depth0, i); 15596c6ab93336b972a38bd2448bcccf19188b8389bVladimir Marko compute_tex_image_offset(rmesa, mt, face, level, &curOffset); 15696c6ab93336b972a38bd2448bcccf19188b8389bVladimir Marko } 15796c6ab93336b972a38bd2448bcccf19188b8389bVladimir Marko } 15896c6ab93336b972a38bd2448bcccf19188b8389bVladimir Marko 1598a630577ed2d9e9571c3434c505e5de223b23c07Vladimir Marko /* Note the required size in memory */ 1608a630577ed2d9e9571c3434c505e5de223b23c07Vladimir Marko mt->totalsize = (curOffset + RADEON_OFFSET_MASK) & ~RADEON_OFFSET_MASK; 16196c6ab93336b972a38bd2448bcccf19188b8389bVladimir Marko} 16296c6ab93336b972a38bd2448bcccf19188b8389bVladimir Marko 16396c6ab93336b972a38bd2448bcccf19188b8389bVladimir Markostatic void calculate_miptree_layout_r300(radeonContextPtr rmesa, radeon_mipmap_tree *mt) 1648a630577ed2d9e9571c3434c505e5de223b23c07Vladimir Marko{ 1658a630577ed2d9e9571c3434c505e5de223b23c07Vladimir Marko GLuint curOffset, i, level; 1668a630577ed2d9e9571c3434c505e5de223b23c07Vladimir Marko 1678a630577ed2d9e9571c3434c505e5de223b23c07Vladimir Marko assert(mt->numLevels <= rmesa->glCtx->Const.MaxTextureLevels); 16896c6ab93336b972a38bd2448bcccf19188b8389bVladimir Marko 16996c6ab93336b972a38bd2448bcccf19188b8389bVladimir Marko curOffset = 0; 17096c6ab93336b972a38bd2448bcccf19188b8389bVladimir Marko for(i = 0, level = mt->baseLevel; i < mt->numLevels; i++, level++) { 17196c6ab93336b972a38bd2448bcccf19188b8389bVladimir Marko GLuint face; 172e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom 173e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom mt->levels[level].valid = 1; 174fc0e3219edc9a5bf81b166e82fd5db2796eb6a0dBrian Carlstrom mt->levels[level].width = minify(mt->width0, i); 175 mt->levels[level].height = minify(mt->height0, i); 176 mt->levels[level].depth = minify(mt->depth0, i); 177 178 for(face = 0; face < mt->faces; face++) 179 compute_tex_image_offset(rmesa, mt, face, level, &curOffset); 180 } 181 182 /* Note the required size in memory */ 183 mt->totalsize = (curOffset + RADEON_OFFSET_MASK) & ~RADEON_OFFSET_MASK; 184} 185 186/** 187 * Create a new mipmap tree, calculate its layout and allocate memory. 188 */ 189static radeon_mipmap_tree* radeon_miptree_create(radeonContextPtr rmesa, 190 GLenum target, gl_format mesaFormat, GLuint baseLevel, GLuint numLevels, 191 GLuint width0, GLuint height0, GLuint depth0, GLuint tilebits) 192{ 193 radeon_mipmap_tree *mt = CALLOC_STRUCT(_radeon_mipmap_tree); 194 195 mt->mesaFormat = mesaFormat; 196 mt->refcount = 1; 197 mt->target = target; 198 mt->faces = (target == GL_TEXTURE_CUBE_MAP) ? 6 : 1; 199 mt->baseLevel = baseLevel; 200 mt->numLevels = numLevels; 201 mt->width0 = width0; 202 mt->height0 = height0; 203 mt->depth0 = depth0; 204 mt->tilebits = tilebits; 205 206 if (rmesa->radeonScreen->chip_family >= CHIP_FAMILY_R300) 207 calculate_miptree_layout_r300(rmesa, mt); 208 else 209 calculate_miptree_layout_r100(rmesa, mt); 210 211 mt->bo = radeon_bo_open(rmesa->radeonScreen->bom, 212 0, mt->totalsize, 1024, 213 RADEON_GEM_DOMAIN_VRAM, 214 0); 215 216 return mt; 217} 218 219void radeon_miptree_reference(radeon_mipmap_tree *mt, radeon_mipmap_tree **ptr) 220{ 221 assert(!*ptr); 222 223 mt->refcount++; 224 assert(mt->refcount > 0); 225 226 *ptr = mt; 227} 228 229void radeon_miptree_unreference(radeon_mipmap_tree **ptr) 230{ 231 radeon_mipmap_tree *mt = *ptr; 232 if (!mt) 233 return; 234 235 assert(mt->refcount > 0); 236 237 mt->refcount--; 238 if (!mt->refcount) { 239 radeon_bo_unref(mt->bo); 240 free(mt); 241 } 242 243 *ptr = 0; 244} 245 246/** 247 * Calculate min and max LOD for the given texture object. 248 * @param[in] tObj texture object whose LOD values to calculate 249 * @param[out] pminLod minimal LOD 250 * @param[out] pmaxLod maximal LOD 251 */ 252static void calculate_min_max_lod(struct gl_texture_object *tObj, 253 unsigned *pminLod, unsigned *pmaxLod) 254{ 255 int minLod, maxLod; 256 /* Yes, this looks overly complicated, but it's all needed. 257 */ 258 switch (tObj->Target) { 259 case GL_TEXTURE_1D: 260 case GL_TEXTURE_2D: 261 case GL_TEXTURE_3D: 262 case GL_TEXTURE_CUBE_MAP: 263 if (tObj->MinFilter == GL_NEAREST || tObj->MinFilter == GL_LINEAR) { 264 /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL. 265 */ 266 minLod = maxLod = tObj->BaseLevel; 267 } else { 268 minLod = tObj->BaseLevel + (GLint)(tObj->MinLod); 269 minLod = MAX2(minLod, tObj->BaseLevel); 270 minLod = MIN2(minLod, tObj->MaxLevel); 271 maxLod = tObj->BaseLevel + (GLint)(tObj->MaxLod + 0.5); 272 maxLod = MIN2(maxLod, tObj->MaxLevel); 273 maxLod = MIN2(maxLod, tObj->Image[0][minLod]->MaxLog2 + minLod); 274 maxLod = MAX2(maxLod, minLod); /* need at least one level */ 275 } 276 break; 277 case GL_TEXTURE_RECTANGLE_NV: 278 case GL_TEXTURE_4D_SGIS: 279 minLod = maxLod = 0; 280 break; 281 default: 282 return; 283 } 284 285 /* save these values */ 286 *pminLod = minLod; 287 *pmaxLod = maxLod; 288} 289 290/** 291 * Checks whether the given miptree can hold the given texture image at the 292 * given face and level. 293 */ 294GLboolean radeon_miptree_matches_image(radeon_mipmap_tree *mt, 295 struct gl_texture_image *texImage, GLuint face, GLuint level) 296{ 297 radeon_mipmap_level *lvl; 298 299 if (face >= mt->faces) 300 return GL_FALSE; 301 302 if (texImage->TexFormat != mt->mesaFormat) 303 return GL_FALSE; 304 305 lvl = &mt->levels[level]; 306 if (!lvl->valid || 307 lvl->width != texImage->Width || 308 lvl->height != texImage->Height || 309 lvl->depth != texImage->Depth) 310 return GL_FALSE; 311 312 return GL_TRUE; 313} 314 315/** 316 * Checks whether the given miptree has the right format to store the given texture object. 317 */ 318static GLboolean radeon_miptree_matches_texture(radeon_mipmap_tree *mt, struct gl_texture_object *texObj) 319{ 320 struct gl_texture_image *firstImage; 321 unsigned numLevels; 322 radeon_mipmap_level *mtBaseLevel; 323 324 if (texObj->BaseLevel < mt->baseLevel) 325 return GL_FALSE; 326 327 mtBaseLevel = &mt->levels[texObj->BaseLevel - mt->baseLevel]; 328 firstImage = texObj->Image[0][texObj->BaseLevel]; 329 numLevels = MIN2(texObj->MaxLevel - texObj->BaseLevel + 1, firstImage->MaxLog2 + 1); 330 331 if (RADEON_DEBUG & RADEON_TEXTURE) { 332 fprintf(stderr, "Checking if miptree %p matches texObj %p\n", mt, texObj); 333 fprintf(stderr, "target %d vs %d\n", mt->target, texObj->Target); 334 fprintf(stderr, "format %d vs %d\n", mt->mesaFormat, firstImage->TexFormat); 335 fprintf(stderr, "numLevels %d vs %d\n", mt->numLevels, numLevels); 336 fprintf(stderr, "width0 %d vs %d\n", mtBaseLevel->width, firstImage->Width); 337 fprintf(stderr, "height0 %d vs %d\n", mtBaseLevel->height, firstImage->Height); 338 fprintf(stderr, "depth0 %d vs %d\n", mtBaseLevel->depth, firstImage->Depth); 339 if (mt->target == texObj->Target && 340 mt->mesaFormat == firstImage->TexFormat && 341 mt->numLevels >= numLevels && 342 mtBaseLevel->width == firstImage->Width && 343 mtBaseLevel->height == firstImage->Height && 344 mtBaseLevel->depth == firstImage->Depth) { 345 fprintf(stderr, "MATCHED\n"); 346 } else { 347 fprintf(stderr, "NOT MATCHED\n"); 348 } 349 } 350 351 return (mt->target == texObj->Target && 352 mt->mesaFormat == firstImage->TexFormat && 353 mt->numLevels >= numLevels && 354 mtBaseLevel->width == firstImage->Width && 355 mtBaseLevel->height == firstImage->Height && 356 mtBaseLevel->depth == firstImage->Depth); 357} 358 359/** 360 * Try to allocate a mipmap tree for the given texture object. 361 * @param[in] rmesa radeon context 362 * @param[in] t radeon texture object 363 */ 364void radeon_try_alloc_miptree(radeonContextPtr rmesa, radeonTexObj *t) 365{ 366 struct gl_texture_object *texObj = &t->base; 367 struct gl_texture_image *texImg = texObj->Image[0][texObj->BaseLevel]; 368 GLuint numLevels; 369 370 assert(!t->mt); 371 372 if (!texImg) 373 return; 374 375 numLevels = MIN2(texObj->MaxLevel - texObj->BaseLevel + 1, texImg->MaxLog2 + 1); 376 377 t->mt = radeon_miptree_create(rmesa, t->base.Target, 378 texImg->TexFormat, texObj->BaseLevel, 379 numLevels, texImg->Width, texImg->Height, 380 texImg->Depth, t->tile_bits); 381} 382 383/* Although we use the image_offset[] array to store relative offsets 384 * to cube faces, Mesa doesn't know anything about this and expects 385 * each cube face to be treated as a separate image. 386 * 387 * These functions present that view to mesa: 388 */ 389void 390radeon_miptree_depth_offsets(radeon_mipmap_tree *mt, GLuint level, GLuint *offsets) 391{ 392 if (mt->target != GL_TEXTURE_3D || mt->faces == 1) { 393 offsets[0] = 0; 394 } else { 395 int i; 396 for (i = 0; i < 6; i++) { 397 offsets[i] = mt->levels[level].faces[i].offset; 398 } 399 } 400} 401 402GLuint 403radeon_miptree_image_offset(radeon_mipmap_tree *mt, 404 GLuint face, GLuint level) 405{ 406 if (mt->target == GL_TEXTURE_CUBE_MAP_ARB) 407 return (mt->levels[level].faces[face].offset); 408 else 409 return mt->levels[level].faces[0].offset; 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 level) 418{ 419 radeon_mipmap_level *dstlvl = &mt->levels[level]; 420 unsigned char *dest; 421 422 assert(image->mt != mt); 423 assert(dstlvl->valid); 424 assert(dstlvl->width == image->base.Width); 425 assert(dstlvl->height == image->base.Height); 426 assert(dstlvl->depth == image->base.Depth); 427 428 radeon_bo_map(mt->bo, GL_TRUE); 429 dest = mt->bo->ptr + dstlvl->faces[face].offset; 430 431 if (image->mt) { 432 /* Format etc. should match, so we really just need a memcpy(). 433 * In fact, that memcpy() could be done by the hardware in many 434 * cases, provided that we have a proper memory manager. 435 */ 436 assert(mt->mesaFormat == image->base.TexFormat); 437 438 radeon_mipmap_level *srclvl = &image->mt->levels[image->mtlevel]; 439 440 assert(image->mtlevel == level); 441 assert(srclvl->size == dstlvl->size); 442 assert(srclvl->rowstride == dstlvl->rowstride); 443 444 radeon_bo_map(image->mt->bo, GL_FALSE); 445 446 memcpy(dest, 447 image->mt->bo->ptr + srclvl->faces[face].offset, 448 dstlvl->size); 449 radeon_bo_unmap(image->mt->bo); 450 451 radeon_miptree_unreference(&image->mt); 452 } else { 453 /* need to confirm this value is correct */ 454 if (_mesa_is_format_compressed(image->base.TexFormat)) { 455 unsigned size = _mesa_format_image_size(image->base.TexFormat, 456 image->base.Width, 457 image->base.Height, 458 image->base.Depth); 459 memcpy(dest, image->base.Data, size); 460 } else { 461 uint32_t srcrowstride; 462 uint32_t height; 463 464 height = image->base.Height * image->base.Depth; 465 srcrowstride = image->base.Width * _mesa_get_format_bytes(image->base.TexFormat); 466 copy_rows(dest, dstlvl->rowstride, image->base.Data, srcrowstride, 467 height, srcrowstride); 468 } 469 470 _mesa_free_texmemory(image->base.Data); 471 image->base.Data = 0; 472 } 473 474 radeon_bo_unmap(mt->bo); 475 476 radeon_miptree_reference(mt, &image->mt); 477 image->mtface = face; 478 image->mtlevel = level; 479} 480 481/** 482 * Filter matching miptrees, and select one with the most of data. 483 * @param[in] texObj radeon texture object 484 * @param[in] firstLevel first texture level to check 485 * @param[in] lastLevel last texture level to check 486 */ 487static radeon_mipmap_tree * get_biggest_matching_miptree(radeonTexObj *texObj, 488 unsigned firstLevel, 489 unsigned lastLevel) 490{ 491 const unsigned numLevels = lastLevel - firstLevel + 1; 492 unsigned *mtSizes = calloc(numLevels, sizeof(unsigned)); 493 radeon_mipmap_tree **mts = calloc(numLevels, sizeof(radeon_mipmap_tree *)); 494 unsigned mtCount = 0; 495 unsigned maxMtIndex = 0; 496 radeon_mipmap_tree *tmp; 497 498 for (unsigned level = firstLevel; level <= lastLevel; ++level) { 499 radeon_texture_image *img = get_radeon_texture_image(texObj->base.Image[0][level]); 500 unsigned found = 0; 501 // TODO: why this hack?? 502 if (!img) 503 break; 504 505 if (!img->mt) 506 continue; 507 508 for (int i = 0; i < mtCount; ++i) { 509 if (mts[i] == img->mt) { 510 found = 1; 511 mtSizes[i] += img->mt->levels[img->mtlevel].size; 512 break; 513 } 514 } 515 516 if (!found && radeon_miptree_matches_texture(img->mt, &texObj->base)) { 517 mtSizes[mtCount] = img->mt->levels[img->mtlevel].size; 518 mts[mtCount] = img->mt; 519 mtCount++; 520 } 521 } 522 523 if (mtCount == 0) { 524 return NULL; 525 } 526 527 for (int i = 1; i < mtCount; ++i) { 528 if (mtSizes[i] > mtSizes[maxMtIndex]) { 529 maxMtIndex = i; 530 } 531 } 532 533 tmp = mts[maxMtIndex]; 534 free(mtSizes); 535 free(mts); 536 537 return tmp; 538} 539 540/** 541 * Validate texture mipmap tree. 542 * If individual images are stored in different mipmap trees 543 * use the mipmap tree that has the most of the correct data. 544 */ 545int radeon_validate_texture_miptree(GLcontext * ctx, struct gl_texture_object *texObj) 546{ 547 radeonContextPtr rmesa = RADEON_CONTEXT(ctx); 548 radeonTexObj *t = radeon_tex_obj(texObj); 549 550 if (t->validated || t->image_override) { 551 return GL_TRUE; 552 } 553 554 if (texObj->Image[0][texObj->BaseLevel]->Border > 0) 555 return GL_FALSE; 556 557 _mesa_test_texobj_completeness(rmesa->glCtx, texObj); 558 if (!texObj->_Complete) { 559 return GL_FALSE; 560 } 561 562 calculate_min_max_lod(&t->base, &t->minLod, &t->maxLod); 563 564 if (RADEON_DEBUG & RADEON_TEXTURE) 565 fprintf(stderr, "%s: Validating texture %p now, minLod = %d, maxLod = %d\n", 566 __FUNCTION__, texObj ,t->minLod, t->maxLod); 567 568 radeon_mipmap_tree *dst_miptree; 569 dst_miptree = get_biggest_matching_miptree(t, t->minLod, t->maxLod); 570 571 if (!dst_miptree) { 572 radeon_miptree_unreference(&t->mt); 573 radeon_try_alloc_miptree(rmesa, t); 574 dst_miptree = t->mt; 575 if (RADEON_DEBUG & RADEON_TEXTURE) { 576 fprintf(stderr, "%s: No matching miptree found, allocated new one %p\n", __FUNCTION__, t->mt); 577 } 578 } else if (RADEON_DEBUG & RADEON_TEXTURE) { 579 fprintf(stderr, "%s: Using miptree %p\n", __FUNCTION__, t->mt); 580 } 581 582 const unsigned faces = texObj->Target == GL_TEXTURE_CUBE_MAP ? 6 : 1; 583 unsigned face, level; 584 radeon_texture_image *img; 585 /* Validate only the levels that will actually be used during rendering */ 586 for (face = 0; face < faces; ++face) { 587 for (level = t->minLod; level <= t->maxLod; ++level) { 588 img = get_radeon_texture_image(texObj->Image[face][level]); 589 590 if (RADEON_DEBUG & RADEON_TEXTURE) { 591 fprintf(stderr, "Checking image level %d, face %d, mt %p ... ", level, face, img->mt); 592 } 593 594 if (img->mt != dst_miptree) { 595 if (RADEON_DEBUG & RADEON_TEXTURE) { 596 fprintf(stderr, "MIGRATING\n"); 597 } 598 struct radeon_bo *src_bo = (img->mt) ? img->mt->bo : img->bo; 599 if (src_bo && radeon_bo_is_referenced_by_cs(src_bo, rmesa->cmdbuf.cs)) { 600 radeon_firevertices(rmesa); 601 } 602 migrate_image_to_miptree(dst_miptree, img, face, level); 603 } else if (RADEON_DEBUG & RADEON_TEXTURE) { 604 fprintf(stderr, "OK\n"); 605 } 606 } 607 } 608 609 t->validated = GL_TRUE; 610 611 return GL_TRUE; 612} 613 614uint32_t get_base_teximage_offset(radeonTexObj *texObj) 615{ 616 if (!texObj->mt) { 617 return 0; 618 } else { 619 return radeon_miptree_image_offset(texObj->mt, 0, texObj->minLod); 620 } 621}