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/teximage.h"
36 #include "main/texobj.h"
37 #include "main/enums.h"
38 #include "radeon_texture.h"
39 #include "radeon_tile.h"
41 static unsigned get_aligned_compressed_row_stride(
46 const unsigned blockBytes
= _mesa_get_format_bytes(format
);
47 unsigned blockWidth
, blockHeight
;
50 _mesa_get_format_block_size(format
, &blockWidth
, &blockHeight
);
52 /* Count number of blocks required to store the given width.
53 * And then multiple it with bytes required to store a block.
55 stride
= (width
+ blockWidth
- 1) / blockWidth
* blockBytes
;
57 /* Round the given minimum stride to the next full blocksize.
58 * (minStride + blockBytes - 1) / blockBytes * blockBytes
60 if ( stride
< minStride
)
61 stride
= (minStride
+ blockBytes
- 1) / blockBytes
* blockBytes
;
63 radeon_print(RADEON_TEXTURE
, RADEON_TRACE
,
64 "%s width %u, minStride %u, block(bytes %u, width %u):"
66 __func__
, width
, minStride
,
67 blockBytes
, blockWidth
,
73 unsigned get_texture_image_size(
80 if (_mesa_is_format_compressed(format
)) {
81 unsigned blockWidth
, blockHeight
;
83 _mesa_get_format_block_size(format
, &blockWidth
, &blockHeight
);
85 return rowStride
* ((height
+ blockHeight
- 1) / blockHeight
) * depth
;
87 /* Need to align height to tile height */
88 unsigned tileWidth
, tileHeight
;
90 get_tile_size(format
, &tileWidth
, &tileHeight
);
93 height
= (height
+ tileHeight
) & ~tileHeight
;
96 return rowStride
* height
* depth
;
99 unsigned get_texture_image_row_stride(radeonContextPtr rmesa
, gl_format format
, unsigned width
, unsigned tiling
, GLuint target
)
101 if (_mesa_is_format_compressed(format
)) {
102 return get_aligned_compressed_row_stride(format
, width
, rmesa
->texture_compressed_row_align
);
106 if (!_mesa_is_pow_two(width
) || target
== GL_TEXTURE_RECTANGLE
) {
107 row_align
= rmesa
->texture_rect_row_align
- 1;
109 unsigned tileWidth
, tileHeight
;
110 get_tile_size(format
, &tileWidth
, &tileHeight
);
111 row_align
= tileWidth
* _mesa_get_format_bytes(format
) - 1;
113 row_align
= rmesa
->texture_row_align
- 1;
116 return (_mesa_format_row_stride(format
, width
) + row_align
) & ~row_align
;
121 * Compute sizes and fill in offset and blit information for the given
122 * image (determined by \p face and \p level).
124 * \param curOffset points to the offset at which the image is to be stored
125 * and is updated by this function according to the size of the image.
127 static void compute_tex_image_offset(radeonContextPtr rmesa
, radeon_mipmap_tree
*mt
,
128 GLuint face
, GLuint level
, GLuint
* curOffset
)
130 radeon_mipmap_level
*lvl
= &mt
->levels
[level
];
133 height
= _mesa_next_pow_two_32(lvl
->height
);
135 lvl
->rowstride
= get_texture_image_row_stride(rmesa
, mt
->mesaFormat
, lvl
->width
, mt
->tilebits
, mt
->target
);
136 lvl
->size
= get_texture_image_size(mt
->mesaFormat
, lvl
->rowstride
, height
, lvl
->depth
, mt
->tilebits
);
138 assert(lvl
->size
> 0);
140 lvl
->faces
[face
].offset
= *curOffset
;
141 *curOffset
+= lvl
->size
;
143 radeon_print(RADEON_TEXTURE
, RADEON_TRACE
,
144 "%s(%p) level %d, face %d: rs:%d %dx%d at %d\n",
147 lvl
->rowstride
, lvl
->width
, height
, lvl
->faces
[face
].offset
);
150 static void calculate_miptree_layout(radeonContextPtr rmesa
, radeon_mipmap_tree
*mt
)
152 GLuint curOffset
, i
, face
, level
;
154 assert(mt
->numLevels
<= rmesa
->glCtx
.Const
.MaxTextureLevels
);
157 for(face
= 0; face
< mt
->faces
; face
++) {
159 for(i
= 0, level
= mt
->baseLevel
; i
< mt
->numLevels
; i
++, level
++) {
160 mt
->levels
[level
].valid
= 1;
161 mt
->levels
[level
].width
= minify(mt
->width0
, i
);
162 mt
->levels
[level
].height
= minify(mt
->height0
, i
);
163 mt
->levels
[level
].depth
= minify(mt
->depth0
, i
);
164 compute_tex_image_offset(rmesa
, mt
, face
, level
, &curOffset
);
168 /* Note the required size in memory */
169 mt
->totalsize
= (curOffset
+ RADEON_OFFSET_MASK
) & ~RADEON_OFFSET_MASK
;
171 radeon_print(RADEON_TEXTURE
, RADEON_TRACE
,
172 "%s(%p, %p) total size %d\n",
173 __func__
, rmesa
, mt
, mt
->totalsize
);
177 * Create a new mipmap tree, calculate its layout and allocate memory.
179 radeon_mipmap_tree
* radeon_miptree_create(radeonContextPtr rmesa
,
180 GLenum target
, gl_format mesaFormat
, GLuint baseLevel
, GLuint numLevels
,
181 GLuint width0
, GLuint height0
, GLuint depth0
, GLuint tilebits
)
183 radeon_mipmap_tree
*mt
= CALLOC_STRUCT(_radeon_mipmap_tree
);
185 radeon_print(RADEON_TEXTURE
, RADEON_NORMAL
,
186 "%s(%p) new tree is %p.\n",
187 __func__
, rmesa
, mt
);
189 mt
->mesaFormat
= mesaFormat
;
192 mt
->faces
= _mesa_num_tex_faces(target
);
193 mt
->baseLevel
= baseLevel
;
194 mt
->numLevels
= numLevels
;
196 mt
->height0
= height0
;
198 mt
->tilebits
= tilebits
;
200 calculate_miptree_layout(rmesa
, mt
);
202 mt
->bo
= radeon_bo_open(rmesa
->radeonScreen
->bom
,
203 0, mt
->totalsize
, 1024,
204 RADEON_GEM_DOMAIN_VRAM
,
210 void radeon_miptree_reference(radeon_mipmap_tree
*mt
, radeon_mipmap_tree
**ptr
)
215 assert(mt
->refcount
> 0);
220 void radeon_miptree_unreference(radeon_mipmap_tree
**ptr
)
222 radeon_mipmap_tree
*mt
= *ptr
;
226 assert(mt
->refcount
> 0);
230 radeon_bo_unref(mt
->bo
);
238 * Calculate min and max LOD for the given texture object.
239 * @param[in] tObj texture object whose LOD values to calculate
240 * @param[out] pminLod minimal LOD
241 * @param[out] pmaxLod maximal LOD
243 static void calculate_min_max_lod(struct gl_sampler_object
*samp
, struct gl_texture_object
*tObj
,
244 unsigned *pminLod
, unsigned *pmaxLod
)
247 /* Yes, this looks overly complicated, but it's all needed.
249 switch (tObj
->Target
) {
253 case GL_TEXTURE_CUBE_MAP
:
254 if (samp
->MinFilter
== GL_NEAREST
|| samp
->MinFilter
== GL_LINEAR
) {
255 /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL.
257 minLod
= maxLod
= tObj
->BaseLevel
;
259 minLod
= tObj
->BaseLevel
+ (GLint
)(samp
->MinLod
);
260 minLod
= MAX2(minLod
, tObj
->BaseLevel
);
261 minLod
= MIN2(minLod
, tObj
->MaxLevel
);
262 maxLod
= tObj
->BaseLevel
+ (GLint
)(samp
->MaxLod
+ 0.5);
263 maxLod
= MIN2(maxLod
, tObj
->MaxLevel
);
264 maxLod
= MIN2(maxLod
, tObj
->Image
[0][minLod
]->MaxNumLevels
- 1 + minLod
);
265 maxLod
= MAX2(maxLod
, minLod
); /* need at least one level */
268 case GL_TEXTURE_RECTANGLE_NV
:
269 case GL_TEXTURE_4D_SGIS
:
276 radeon_print(RADEON_TEXTURE
, RADEON_TRACE
,
277 "%s(%p) target %s, min %d, max %d.\n",
279 _mesa_lookup_enum_by_nr(tObj
->Target
),
282 /* save these values */
288 * Checks whether the given miptree can hold the given texture image at the
289 * given face and level.
291 GLboolean
radeon_miptree_matches_image(radeon_mipmap_tree
*mt
,
292 struct gl_texture_image
*texImage
)
294 radeon_mipmap_level
*lvl
;
295 GLuint level
= texImage
->Level
;
296 if (texImage
->TexFormat
!= mt
->mesaFormat
)
299 lvl
= &mt
->levels
[level
];
301 lvl
->width
!= texImage
->Width
||
302 lvl
->height
!= texImage
->Height
||
303 lvl
->depth
!= texImage
->Depth
)
310 * Checks whether the given miptree has the right format to store the given texture object.
312 static GLboolean
radeon_miptree_matches_texture(radeon_mipmap_tree
*mt
, struct gl_texture_object
*texObj
)
314 struct gl_texture_image
*firstImage
;
316 radeon_mipmap_level
*mtBaseLevel
;
318 if (texObj
->BaseLevel
< mt
->baseLevel
)
321 mtBaseLevel
= &mt
->levels
[texObj
->BaseLevel
- mt
->baseLevel
];
322 firstImage
= texObj
->Image
[0][texObj
->BaseLevel
];
323 numLevels
= MIN2(texObj
->_MaxLevel
- texObj
->BaseLevel
+ 1, firstImage
->MaxNumLevels
);
325 if (radeon_is_debug_enabled(RADEON_TEXTURE
,RADEON_TRACE
)) {
326 fprintf(stderr
, "Checking if miptree %p matches texObj %p\n", mt
, texObj
);
327 fprintf(stderr
, "target %d vs %d\n", mt
->target
, texObj
->Target
);
328 fprintf(stderr
, "format %d vs %d\n", mt
->mesaFormat
, firstImage
->TexFormat
);
329 fprintf(stderr
, "numLevels %d vs %d\n", mt
->numLevels
, numLevels
);
330 fprintf(stderr
, "width0 %d vs %d\n", mtBaseLevel
->width
, firstImage
->Width
);
331 fprintf(stderr
, "height0 %d vs %d\n", mtBaseLevel
->height
, firstImage
->Height
);
332 fprintf(stderr
, "depth0 %d vs %d\n", mtBaseLevel
->depth
, firstImage
->Depth
);
333 if (mt
->target
== texObj
->Target
&&
334 mt
->mesaFormat
== firstImage
->TexFormat
&&
335 mt
->numLevels
>= numLevels
&&
336 mtBaseLevel
->width
== firstImage
->Width
&&
337 mtBaseLevel
->height
== firstImage
->Height
&&
338 mtBaseLevel
->depth
== firstImage
->Depth
) {
339 fprintf(stderr
, "MATCHED\n");
341 fprintf(stderr
, "NOT MATCHED\n");
345 return (mt
->target
== texObj
->Target
&&
346 mt
->mesaFormat
== firstImage
->TexFormat
&&
347 mt
->numLevels
>= numLevels
&&
348 mtBaseLevel
->width
== firstImage
->Width
&&
349 mtBaseLevel
->height
== firstImage
->Height
&&
350 mtBaseLevel
->depth
== firstImage
->Depth
);
354 * Try to allocate a mipmap tree for the given texture object.
355 * @param[in] rmesa radeon context
356 * @param[in] t radeon texture object
358 void radeon_try_alloc_miptree(radeonContextPtr rmesa
, radeonTexObj
*t
)
360 struct gl_texture_object
*texObj
= &t
->base
;
361 struct gl_texture_image
*texImg
= texObj
->Image
[0][texObj
->BaseLevel
];
366 radeon_warning("%s(%p) No image in given texture object(%p).\n",
372 numLevels
= MIN2(texObj
->MaxLevel
- texObj
->BaseLevel
+ 1, texImg
->MaxNumLevels
);
374 t
->mt
= radeon_miptree_create(rmesa
, t
->base
.Target
,
375 texImg
->TexFormat
, texObj
->BaseLevel
,
376 numLevels
, texImg
->Width
, texImg
->Height
,
377 texImg
->Depth
, t
->tile_bits
);
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 * Ensure that the given image is stored in the given miptree from now on.
393 static void migrate_image_to_miptree(radeon_mipmap_tree
*mt
,
394 radeon_texture_image
*image
,
397 radeon_mipmap_level
*dstlvl
= &mt
->levels
[level
];
400 assert(image
->mt
!= mt
);
401 assert(dstlvl
->valid
);
402 assert(dstlvl
->width
== image
->base
.Base
.Width
);
403 assert(dstlvl
->height
== image
->base
.Base
.Height
);
404 assert(dstlvl
->depth
== image
->base
.Base
.Depth
);
406 radeon_print(RADEON_TEXTURE
, RADEON_VERBOSE
,
407 "%s miptree %p, image %p, face %d, level %d.\n",
408 __func__
, mt
, image
, face
, level
);
410 radeon_bo_map(mt
->bo
, GL_TRUE
);
411 dest
= mt
->bo
->ptr
+ dstlvl
->faces
[face
].offset
;
414 /* Format etc. should match, so we really just need a memcpy().
415 * In fact, that memcpy() could be done by the hardware in many
416 * cases, provided that we have a proper memory manager.
418 assert(mt
->mesaFormat
== image
->base
.Base
.TexFormat
);
420 radeon_mipmap_level
*srclvl
= &image
->mt
->levels
[image
->base
.Base
.Level
];
422 assert(image
->base
.Base
.Level
== level
);
423 assert(srclvl
->size
== dstlvl
->size
);
424 assert(srclvl
->rowstride
== dstlvl
->rowstride
);
426 radeon_bo_map(image
->mt
->bo
, GL_FALSE
);
429 image
->mt
->bo
->ptr
+ srclvl
->faces
[face
].offset
,
431 radeon_bo_unmap(image
->mt
->bo
);
433 radeon_miptree_unreference(&image
->mt
);
436 radeon_bo_unmap(mt
->bo
);
438 radeon_miptree_reference(mt
, &image
->mt
);
442 * Filter matching miptrees, and select one with the most of data.
443 * @param[in] texObj radeon texture object
444 * @param[in] firstLevel first texture level to check
445 * @param[in] lastLevel last texture level to check
447 static radeon_mipmap_tree
* get_biggest_matching_miptree(radeonTexObj
*texObj
,
451 const unsigned numLevels
= lastLevel
- firstLevel
+ 1;
452 unsigned *mtSizes
= calloc(numLevels
, sizeof(unsigned));
453 radeon_mipmap_tree
**mts
= calloc(numLevels
, sizeof(radeon_mipmap_tree
*));
454 unsigned mtCount
= 0;
455 unsigned maxMtIndex
= 0;
456 radeon_mipmap_tree
*tmp
;
460 for (level
= firstLevel
; level
<= lastLevel
; ++level
) {
461 radeon_texture_image
*img
= get_radeon_texture_image(texObj
->base
.Image
[0][level
]);
463 // TODO: why this hack??
470 for (i
= 0; i
< mtCount
; ++i
) {
471 if (mts
[i
] == img
->mt
) {
473 mtSizes
[i
] += img
->mt
->levels
[img
->base
.Base
.Level
].size
;
478 if (!found
&& radeon_miptree_matches_texture(img
->mt
, &texObj
->base
)) {
479 mtSizes
[mtCount
] = img
->mt
->levels
[img
->base
.Base
.Level
].size
;
480 mts
[mtCount
] = img
->mt
;
491 for (i
= 1; i
< mtCount
; ++i
) {
492 if (mtSizes
[i
] > mtSizes
[maxMtIndex
]) {
497 tmp
= mts
[maxMtIndex
];
505 * Validate texture mipmap tree.
506 * If individual images are stored in different mipmap trees
507 * use the mipmap tree that has the most of the correct data.
509 int radeon_validate_texture_miptree(struct gl_context
* ctx
,
510 struct gl_sampler_object
*samp
,
511 struct gl_texture_object
*texObj
)
513 radeonContextPtr rmesa
= RADEON_CONTEXT(ctx
);
514 radeonTexObj
*t
= radeon_tex_obj(texObj
);
515 radeon_mipmap_tree
*dst_miptree
;
517 if (samp
== &texObj
->Sampler
&& (t
->validated
|| t
->image_override
)) {
521 calculate_min_max_lod(samp
, &t
->base
, &t
->minLod
, &t
->maxLod
);
523 radeon_print(RADEON_TEXTURE
, RADEON_NORMAL
,
524 "%s: Validating texture %p now, minLod = %d, maxLod = %d\n",
525 __FUNCTION__
, texObj
,t
->minLod
, t
->maxLod
);
527 dst_miptree
= get_biggest_matching_miptree(t
, t
->base
.BaseLevel
, t
->base
._MaxLevel
);
529 radeon_miptree_unreference(&t
->mt
);
531 radeon_try_alloc_miptree(rmesa
, t
);
532 radeon_print(RADEON_TEXTURE
, RADEON_NORMAL
,
533 "%s: No matching miptree found, allocated new one %p\n",
534 __FUNCTION__
, t
->mt
);
537 radeon_miptree_reference(dst_miptree
, &t
->mt
);
538 radeon_print(RADEON_TEXTURE
, RADEON_NORMAL
,
539 "%s: Using miptree %p\n", __FUNCTION__
, t
->mt
);
542 const unsigned faces
= _mesa_num_tex_faces(texObj
->Target
);
543 unsigned face
, level
;
544 radeon_texture_image
*img
;
545 /* Validate only the levels that will actually be used during rendering */
546 for (face
= 0; face
< faces
; ++face
) {
547 for (level
= t
->minLod
; level
<= t
->maxLod
; ++level
) {
548 img
= get_radeon_texture_image(texObj
->Image
[face
][level
]);
550 radeon_print(RADEON_TEXTURE
, RADEON_TRACE
,
551 "Checking image level %d, face %d, mt %p ... ",
552 level
, face
, img
->mt
);
554 if (img
->mt
!= t
->mt
&& !img
->used_as_render_target
) {
555 radeon_print(RADEON_TEXTURE
, RADEON_TRACE
,
558 struct radeon_bo
*src_bo
= (img
->mt
) ? img
->mt
->bo
: img
->bo
;
559 if (src_bo
&& radeon_bo_is_referenced_by_cs(src_bo
, rmesa
->cmdbuf
.cs
)) {
560 radeon_firevertices(rmesa
);
562 migrate_image_to_miptree(t
->mt
, img
, face
, level
);
564 radeon_print(RADEON_TEXTURE
, RADEON_TRACE
, "OK\n");
568 t
->validated
= GL_TRUE
;
573 uint32_t get_base_teximage_offset(radeonTexObj
*texObj
)
578 return radeon_miptree_image_offset(texObj
->mt
, 0, texObj
->minLod
);