2 * Copyright (C) 2009 Maciej Cencora.
3 * Copyright (C) 2008 Nicolai Haehnle.
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:
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.
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.
29 #include "radeon_mipmap_tree.h"
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"
41 static GLuint
radeon_compressed_texture_size(GLcontext
*ctx
,
42 GLsizei width
, GLsizei height
, GLsizei depth
,
45 GLuint size
= _mesa_format_image_size(mesaFormat
, width
, height
, depth
);
47 if (mesaFormat
== MESA_FORMAT_RGB_DXT1
||
48 mesaFormat
== MESA_FORMAT_RGBA_DXT1
) {
49 if (width
+ 3 < 8) /* width one block */
51 else if (width
+ 3 < 16)
54 /* DXT3/5, 16 bytes per block */
55 // WARN_ONCE("DXT 3/5 suffers from multitexturing problems!\n");
64 * Compute sizes and fill in offset and blit information for the given
65 * image (determined by \p face and \p level).
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.
70 static void compute_tex_image_offset(radeonContextPtr rmesa
, radeon_mipmap_tree
*mt
,
71 GLuint face
, GLuint level
, GLuint
* curOffset
)
73 radeon_mipmap_level
*lvl
= &mt
->levels
[level
];
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
;
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
;
97 assert(lvl
->size
> 0);
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
;
104 if (RADEON_DEBUG
& RADEON_TEXTURE
)
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
);
110 static GLuint
minify(GLuint size
, GLuint levels
)
112 size
= size
>> levels
;
119 static void calculate_miptree_layout_r100(radeonContextPtr rmesa
, radeon_mipmap_tree
*mt
)
125 assert(mt
->numLevels
<= rmesa
->glCtx
->Const
.MaxTextureLevels
);
128 for(face
= 0; face
< mt
->faces
; face
++) {
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
);
138 /* Note the required size in memory */
139 mt
->totalsize
= (curOffset
+ RADEON_OFFSET_MASK
) & ~RADEON_OFFSET_MASK
;
142 static void calculate_miptree_layout_r300(radeonContextPtr rmesa
, radeon_mipmap_tree
*mt
)
147 assert(mt
->numLevels
<= rmesa
->glCtx
->Const
.MaxTextureLevels
);
150 for(i
= 0; i
< mt
->numLevels
; i
++) {
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
);
157 for(face
= 0; face
< mt
->faces
; face
++)
158 compute_tex_image_offset(rmesa
, mt
, face
, i
, &curOffset
);
161 /* Note the required size in memory */
162 mt
->totalsize
= (curOffset
+ RADEON_OFFSET_MASK
) & ~RADEON_OFFSET_MASK
;
166 * Create a new mipmap tree, calculate its layout and allocate memory.
168 static 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
)
172 radeon_mipmap_tree
*mt
= CALLOC_STRUCT(_radeon_mipmap_tree
);
174 mt
->mesaFormat
= mesaFormat
;
177 mt
->faces
= (target
== GL_TEXTURE_CUBE_MAP
) ? 6 : 1;
178 mt
->baseLevel
= baseLevel
;
179 mt
->numLevels
= numLevels
;
181 mt
->height0
= height0
;
183 mt
->tilebits
= tilebits
;
185 if (rmesa
->radeonScreen
->chip_family
>= CHIP_FAMILY_R300
)
186 calculate_miptree_layout_r300(rmesa
, mt
);
188 calculate_miptree_layout_r100(rmesa
, mt
);
190 mt
->bo
= radeon_bo_open(rmesa
->radeonScreen
->bom
,
191 0, mt
->totalsize
, 1024,
192 RADEON_GEM_DOMAIN_VRAM
,
198 void radeon_miptree_reference(radeon_mipmap_tree
*mt
, radeon_mipmap_tree
**ptr
)
203 assert(mt
->refcount
> 0);
208 void radeon_miptree_unreference(radeon_mipmap_tree
**ptr
)
210 radeon_mipmap_tree
*mt
= *ptr
;
214 assert(mt
->refcount
> 0);
218 radeon_bo_unref(mt
->bo
);
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
231 static void calculate_min_max_lod(struct gl_texture_object
*tObj
,
232 unsigned *pminLod
, unsigned *pmaxLod
)
235 /* Yes, this looks overly complicated, but it's all needed.
237 switch (tObj
->Target
) {
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.
245 minLod
= maxLod
= tObj
->BaseLevel
;
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 */
256 case GL_TEXTURE_RECTANGLE_NV
:
257 case GL_TEXTURE_4D_SGIS
:
264 /* save these values */
270 * Checks whether the given miptree can hold the given texture image at the
271 * given face and level.
273 GLboolean
radeon_miptree_matches_image(radeon_mipmap_tree
*mt
,
274 struct gl_texture_image
*texImage
, GLuint face
, GLuint mtLevel
)
276 radeon_mipmap_level
*lvl
;
278 if (face
>= mt
->faces
|| mtLevel
> mt
->numLevels
)
281 if (texImage
->TexFormat
!= mt
->mesaFormat
)
284 lvl
= &mt
->levels
[mtLevel
];
285 if (lvl
->width
!= texImage
->Width
||
286 lvl
->height
!= texImage
->Height
||
287 lvl
->depth
!= texImage
->Depth
)
294 * Checks whether the given miptree has the right format to store the given texture object.
296 static GLboolean
radeon_miptree_matches_texture(radeon_mipmap_tree
*mt
, struct gl_texture_object
*texObj
)
298 struct gl_texture_image
*firstImage
;
300 radeon_mipmap_level
*mtBaseLevel
;
302 if (texObj
->BaseLevel
< mt
->baseLevel
)
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);
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");
325 fprintf(stderr
, "NOT MATCHED\n");
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
);
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
342 void radeon_try_alloc_miptree(radeonContextPtr rmesa
, radeonTexObj
*t
)
344 struct gl_texture_object
*texObj
= &t
->base
;
345 struct gl_texture_image
*texImg
= texObj
->Image
[0][texObj
->BaseLevel
];
353 numLevels
= MIN2(texObj
->MaxLevel
- texObj
->BaseLevel
+ 1, texImg
->MaxLog2
+ 1);
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
);
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.
365 * These functions present that view to mesa:
368 radeon_miptree_depth_offsets(radeon_mipmap_tree
*mt
, GLuint level
, GLuint
*offsets
)
370 if (mt
->target
!= GL_TEXTURE_3D
|| mt
->faces
== 1) {
374 for (i
= 0; i
< 6; i
++) {
375 offsets
[i
] = mt
->levels
[level
].faces
[i
].offset
;
381 radeon_miptree_image_offset(radeon_mipmap_tree
*mt
,
382 GLuint face
, GLuint level
)
384 if (mt
->target
== GL_TEXTURE_CUBE_MAP_ARB
)
385 return (mt
->levels
[level
].faces
[face
].offset
);
387 return mt
->levels
[level
].faces
[0].offset
;
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
396 unsigned radeon_miptree_level_to_gl_level(struct gl_texture_object
*tObj
, unsigned level
)
398 return level
+ tObj
->BaseLevel
;
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
407 unsigned radeon_gl_level_to_miptree_level(struct gl_texture_object
*tObj
, unsigned level
)
409 return level
- tObj
->BaseLevel
;
413 * Ensure that the given image is stored in the given miptree from now on.
415 static void migrate_image_to_miptree(radeon_mipmap_tree
*mt
,
416 radeon_texture_image
*image
,
417 int face
, int mtLevel
)
419 radeon_mipmap_level
*dstlvl
= &mt
->levels
[mtLevel
];
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
);
427 radeon_bo_map(mt
->bo
, GL_TRUE
);
428 dest
= mt
->bo
->ptr
+ dstlvl
->faces
[face
].offset
;
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.
435 assert(mt
->mesaFormat
== image
->base
.TexFormat
);
437 radeon_mipmap_level
*srclvl
= &image
->mt
->levels
[image
->mtlevel
];
439 assert(srclvl
->size
== dstlvl
->size
);
440 assert(srclvl
->rowstride
== dstlvl
->rowstride
);
442 radeon_bo_map(image
->mt
->bo
, GL_FALSE
);
445 image
->mt
->bo
->ptr
+ srclvl
->faces
[face
].offset
,
447 radeon_bo_unmap(image
->mt
->bo
);
449 radeon_miptree_unreference(&image
->mt
);
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
,
457 memcpy(dest
, image
->base
.Data
, size
);
459 uint32_t srcrowstride
;
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
);
468 _mesa_free_texmemory(image
->base
.Data
);
469 image
->base
.Data
= 0;
472 radeon_bo_unmap(mt
->bo
);
474 radeon_miptree_reference(mt
, &image
->mt
);
475 image
->mtface
= face
;
476 image
->mtlevel
= mtLevel
;
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
485 static radeon_mipmap_tree
* get_biggest_matching_miptree(radeonTexObj
*texObj
,
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;
495 for (unsigned level
= firstLevel
; level
<= lastLevel
; ++level
) {
496 radeon_texture_image
*img
= get_radeon_texture_image(texObj
->base
.Image
[0][level
]);
498 // TODO: why this hack??
502 if (!img
->mt
|| !radeon_miptree_matches_texture(img
->mt
, &texObj
->base
))
505 for (int i
= 0; i
< mtCount
; ++i
) {
506 if (mts
[i
] == img
->mt
) {
508 mtSizes
[i
] += img
->mt
->levels
[img
->mtlevel
].size
;
514 mtSizes
[mtCount
] += img
->mt
->levels
[img
->mtlevel
].size
;
515 mts
[mtCount
++] = img
->mt
;
524 for (int i
= 1; i
< mtCount
; ++i
) {
525 if (mtSizes
[i
] > mtSizes
[maxMtIndex
]) {
530 return mts
[maxMtIndex
];
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.
538 int radeon_validate_texture_miptree(GLcontext
* ctx
, struct gl_texture_object
*texObj
)
540 radeonContextPtr rmesa
= RADEON_CONTEXT(ctx
);
541 radeonTexObj
*t
= radeon_tex_obj(texObj
);
543 if (t
->validated
|| t
->image_override
) {
547 if (texObj
->Image
[0][texObj
->BaseLevel
]->Border
> 0)
550 /* TODO: is this really necessary? */
551 _mesa_test_texobj_completeness(rmesa
->glCtx
, texObj
);
552 assert(texObj
->_Complete
);
554 calculate_min_max_lod(&t
->base
, &t
->minLod
, &t
->maxLod
);
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
);
560 radeon_mipmap_tree
*dst_miptree
;
561 dst_miptree
= get_biggest_matching_miptree(t
, t
->minLod
, t
->maxLod
);
564 radeon_miptree_unreference(&t
->mt
);
565 radeon_try_alloc_miptree(rmesa
, t
);
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
]);
577 if (RADEON_DEBUG
& RADEON_TEXTURE
) {
578 fprintf(stderr
, "Checking image level %d, face %d, mt %p ... ", level
, face
, img
->mt
);
581 if (img
->mt
!= dst_miptree
) {
582 if (RADEON_DEBUG
& RADEON_TEXTURE
) {
583 fprintf(stderr
, "MIGRATING\n");
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");
592 t
->validated
= GL_TRUE
;
597 uint32_t get_base_teximage_offset(radeonTexObj
*texObj
)
602 return radeon_miptree_image_offset(texObj
->mt
, 0, texObj
->minLod
);