intel_mipmap_tree.c revision 6e0f9001fe3fb191c2928bd09aa9e9d05ddf4ea9
1/************************************************************************** 2 * 3 * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28#include "intel_context.h" 29#include "intel_mipmap_tree.h" 30#include "intel_regions.h" 31#include "intel_tex_layout.h" 32#include "intel_tex.h" 33#include "intel_blit.h" 34#include "main/enums.h" 35#include "main/formats.h" 36#include "main/teximage.h" 37 38#define FILE_DEBUG_FLAG DEBUG_MIPTREE 39 40 41static GLenum 42target_to_target(GLenum target) 43{ 44 switch (target) { 45 case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: 46 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: 47 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: 48 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: 49 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: 50 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: 51 return GL_TEXTURE_CUBE_MAP_ARB; 52 default: 53 return target; 54 } 55} 56 57 58static struct intel_mipmap_tree * 59intel_miptree_create_internal(struct intel_context *intel, 60 GLenum target, 61 gl_format format, 62 GLuint first_level, 63 GLuint last_level, 64 GLuint width0, 65 GLuint height0, 66 GLuint depth0) 67{ 68 struct intel_mipmap_tree *mt = calloc(sizeof(*mt), 1); 69 int compress_byte = 0; 70 71 DBG("%s target %s format %s level %d..%d <-- %p\n", __FUNCTION__, 72 _mesa_lookup_enum_by_nr(target), 73 _mesa_get_format_name(format), 74 first_level, last_level, mt); 75 76 if (_mesa_is_format_compressed(format)) 77 compress_byte = intel_compressed_num_bytes(format); 78 79 mt->target = target_to_target(target); 80 mt->format = format; 81 mt->first_level = first_level; 82 mt->last_level = last_level; 83 mt->width0 = width0; 84 mt->height0 = height0; 85 mt->depth0 = depth0; 86 mt->cpp = compress_byte ? compress_byte : _mesa_get_format_bytes(mt->format); 87 mt->compressed = compress_byte ? 1 : 0; 88 mt->refcount = 1; 89 90#ifdef I915 91 (void) intel; 92 if (intel->is_945) 93 i945_miptree_layout(mt); 94 else 95 i915_miptree_layout(mt); 96#else 97 brw_miptree_layout(intel, mt); 98#endif 99 100 return mt; 101} 102 103 104struct intel_mipmap_tree * 105intel_miptree_create(struct intel_context *intel, 106 GLenum target, 107 gl_format format, 108 GLuint first_level, 109 GLuint last_level, 110 GLuint width0, 111 GLuint height0, 112 GLuint depth0, 113 bool expect_accelerated_upload) 114{ 115 struct intel_mipmap_tree *mt; 116 uint32_t tiling = I915_TILING_NONE; 117 GLenum base_format = _mesa_get_format_base_format(format); 118 119 if (intel->use_texture_tiling && !_mesa_is_format_compressed(format)) { 120 if (intel->gen >= 4 && 121 (base_format == GL_DEPTH_COMPONENT || 122 base_format == GL_DEPTH_STENCIL_EXT)) 123 tiling = I915_TILING_Y; 124 else if (width0 >= 64) 125 tiling = I915_TILING_X; 126 } 127 128 mt = intel_miptree_create_internal(intel, target, format, 129 first_level, last_level, width0, 130 height0, depth0); 131 /* 132 * pitch == 0 || height == 0 indicates the null texture 133 */ 134 if (!mt || !mt->total_width || !mt->total_height) { 135 free(mt); 136 return NULL; 137 } 138 139 mt->region = intel_region_alloc(intel->intelScreen, 140 tiling, 141 mt->cpp, 142 mt->total_width, 143 mt->total_height, 144 expect_accelerated_upload); 145 146 if (!mt->region) { 147 free(mt); 148 return NULL; 149 } 150 151 return mt; 152} 153 154 155struct intel_mipmap_tree * 156intel_miptree_create_for_region(struct intel_context *intel, 157 GLenum target, 158 gl_format format, 159 struct intel_region *region) 160{ 161 struct intel_mipmap_tree *mt; 162 163 mt = intel_miptree_create_internal(intel, target, format, 164 0, 0, 165 region->width, region->height, 1); 166 if (!mt) 167 return mt; 168 169 intel_region_reference(&mt->region, region); 170 171 return mt; 172} 173 174void 175intel_miptree_reference(struct intel_mipmap_tree **dst, 176 struct intel_mipmap_tree *src) 177{ 178 if (*dst == src) 179 return; 180 181 intel_miptree_release(dst); 182 183 if (src) { 184 src->refcount++; 185 DBG("%s %p refcount now %d\n", __FUNCTION__, src, src->refcount); 186 } 187 188 *dst = src; 189} 190 191 192void 193intel_miptree_release(struct intel_mipmap_tree **mt) 194{ 195 if (!*mt) 196 return; 197 198 DBG("%s %p refcount will be %d\n", __FUNCTION__, *mt, (*mt)->refcount - 1); 199 if (--(*mt)->refcount <= 0) { 200 GLuint i; 201 202 DBG("%s deleting %p\n", __FUNCTION__, *mt); 203 204 intel_region_release(&((*mt)->region)); 205 intel_region_release(&((*mt)->hiz_region)); 206 207 for (i = 0; i < MAX_TEXTURE_LEVELS; i++) { 208 free((*mt)->level[i].x_offset); 209 free((*mt)->level[i].y_offset); 210 } 211 212 free(*mt); 213 } 214 *mt = NULL; 215} 216 217void 218intel_miptree_get_dimensions_for_image(struct gl_texture_image *image, 219 int *width, int *height, int *depth) 220{ 221 switch (image->TexObject->Target) { 222 case GL_TEXTURE_1D_ARRAY: 223 *width = image->Width; 224 *height = 1; 225 *depth = image->Height; 226 break; 227 default: 228 *width = image->Width; 229 *height = image->Height; 230 *depth = image->Depth; 231 break; 232 } 233} 234 235/** 236 * Can the image be pulled into a unified mipmap tree? This mirrors 237 * the completeness test in a lot of ways. 238 * 239 * Not sure whether I want to pass gl_texture_image here. 240 */ 241bool 242intel_miptree_match_image(struct intel_mipmap_tree *mt, 243 struct gl_texture_image *image) 244{ 245 struct intel_texture_image *intelImage = intel_texture_image(image); 246 GLuint level = intelImage->base.Base.Level; 247 int width, height, depth; 248 249 /* Images with borders are never pulled into mipmap trees. */ 250 if (image->Border) 251 return false; 252 253 if (image->TexFormat != mt->format) 254 return false; 255 256 intel_miptree_get_dimensions_for_image(image, &width, &height, &depth); 257 258 /* Test image dimensions against the base level image adjusted for 259 * minification. This will also catch images not present in the 260 * tree, changed targets, etc. 261 */ 262 if (width != mt->level[level].width || 263 height != mt->level[level].height || 264 depth != mt->level[level].depth) 265 return false; 266 267 return true; 268} 269 270 271void 272intel_miptree_set_level_info(struct intel_mipmap_tree *mt, 273 GLuint level, 274 GLuint nr_images, 275 GLuint x, GLuint y, 276 GLuint w, GLuint h, GLuint d) 277{ 278 mt->level[level].width = w; 279 mt->level[level].height = h; 280 mt->level[level].depth = d; 281 mt->level[level].level_x = x; 282 mt->level[level].level_y = y; 283 mt->level[level].nr_images = nr_images; 284 285 DBG("%s level %d size: %d,%d,%d offset %d,%d\n", __FUNCTION__, 286 level, w, h, d, x, y); 287 288 assert(nr_images); 289 assert(!mt->level[level].x_offset); 290 291 mt->level[level].x_offset = malloc(nr_images * sizeof(GLuint)); 292 mt->level[level].x_offset[0] = mt->level[level].level_x; 293 mt->level[level].y_offset = malloc(nr_images * sizeof(GLuint)); 294 mt->level[level].y_offset[0] = mt->level[level].level_y; 295} 296 297 298void 299intel_miptree_set_image_offset(struct intel_mipmap_tree *mt, 300 GLuint level, GLuint img, 301 GLuint x, GLuint y) 302{ 303 if (img == 0 && level == 0) 304 assert(x == 0 && y == 0); 305 306 assert(img < mt->level[level].nr_images); 307 308 mt->level[level].x_offset[img] = mt->level[level].level_x + x; 309 mt->level[level].y_offset[img] = mt->level[level].level_y + y; 310 311 DBG("%s level %d img %d pos %d,%d\n", 312 __FUNCTION__, level, img, 313 mt->level[level].x_offset[img], mt->level[level].y_offset[img]); 314} 315 316 317void 318intel_miptree_get_image_offset(struct intel_mipmap_tree *mt, 319 GLuint level, GLuint face, GLuint depth, 320 GLuint *x, GLuint *y) 321{ 322 switch (mt->target) { 323 case GL_TEXTURE_CUBE_MAP_ARB: 324 *x = mt->level[level].x_offset[face]; 325 *y = mt->level[level].y_offset[face]; 326 break; 327 case GL_TEXTURE_3D: 328 case GL_TEXTURE_2D_ARRAY_EXT: 329 case GL_TEXTURE_1D_ARRAY_EXT: 330 assert(depth < mt->level[level].nr_images); 331 *x = mt->level[level].x_offset[depth]; 332 *y = mt->level[level].y_offset[depth]; 333 break; 334 default: 335 *x = mt->level[level].x_offset[0]; 336 *y = mt->level[level].y_offset[0]; 337 break; 338 } 339} 340 341/** 342 * Copies the image's current data to the given miptree, and associates that 343 * miptree with the image. 344 */ 345void 346intel_miptree_copy_teximage(struct intel_context *intel, 347 struct intel_texture_image *intelImage, 348 struct intel_mipmap_tree *dst_mt) 349{ 350 struct intel_mipmap_tree *src_mt = intelImage->mt; 351 int level = intelImage->base.Base.Level; 352 int face = intelImage->base.Base.Face; 353 GLuint width = src_mt->level[level].width; 354 GLuint height = src_mt->level[level].height; 355 GLuint depth = src_mt->level[level].depth; 356 int slice; 357 void *src, *dst; 358 359 if (dst_mt->compressed) { 360 unsigned int align_w, align_h; 361 362 intel_get_texture_alignment_unit(intelImage->base.Base.TexFormat, 363 &align_w, &align_h); 364 height = ALIGN(height, align_h) / align_h; 365 width = ALIGN(width, align_w); 366 } 367 368 for (slice = 0; slice < depth; slice++) { 369 unsigned int dst_x, dst_y, src_x, src_y; 370 371 intel_miptree_get_image_offset(dst_mt, level, face, slice, 372 &dst_x, &dst_y); 373 374 if (src_mt) { 375 /* Copy potentially with the blitter: 376 */ 377 intel_miptree_get_image_offset(src_mt, level, face, slice, 378 &src_x, &src_y); 379 380 DBG("validate blit mt %p %d,%d/%d -> mt %p %d,%d/%d (%dx%d)\n", 381 src_mt, src_x, src_y, src_mt->region->pitch * src_mt->region->cpp, 382 dst_mt, dst_x, dst_y, dst_mt->region->pitch * dst_mt->region->cpp, 383 width, height); 384 385 if (!intelEmitCopyBlit(intel, 386 dst_mt->region->cpp, 387 src_mt->region->pitch, src_mt->region->bo, 388 0, src_mt->region->tiling, 389 dst_mt->region->pitch, dst_mt->region->bo, 390 0, dst_mt->region->tiling, 391 src_x, src_y, 392 dst_x, dst_y, 393 width, height, 394 GL_COPY)) { 395 396 fallback_debug("miptree validate blit for %s failed\n", 397 _mesa_get_format_name(intelImage->base.Base.TexFormat)); 398 dst = intel_region_map(intel, dst_mt->region, GL_MAP_WRITE_BIT); 399 src = intel_region_map(intel, src_mt->region, GL_MAP_READ_BIT); 400 401 _mesa_copy_rect(dst, 402 dst_mt->cpp, 403 dst_mt->region->pitch, 404 dst_x, dst_y, 405 width, height, 406 src, src_mt->region->pitch, 407 src_x, src_y); 408 409 intel_region_unmap(intel, dst_mt->region); 410 intel_region_unmap(intel, src_mt->region); 411 } 412 } else { 413 dst = intel_region_map(intel, dst_mt->region, GL_MAP_WRITE_BIT); 414 415 DBG("validate upload mt %p -> mt %p %d,%d/%d (%dx%d)\n", 416 src, 417 dst_mt, dst_x, dst_y, dst_mt->region->pitch * dst_mt->region->cpp, 418 width, height); 419 420 src = intelImage->base.Data; 421 src += (intelImage->base.RowStride * 422 intelImage->base.Base.Height * 423 dst_mt->region->cpp * 424 slice); 425 426 _mesa_copy_rect(dst, 427 dst_mt->region->cpp, 428 dst_mt->region->pitch, 429 dst_x, dst_y, 430 width, height, 431 src, 432 intelImage->base.RowStride, 433 0, 0); 434 435 intel_region_unmap(intel, dst_mt->region); 436 } 437 } 438 439 if (!src_mt) { 440 _mesa_free_texmemory(intelImage->base.Data); 441 intelImage->base.Data = NULL; 442 } 443 444 intel_miptree_reference(&intelImage->mt, dst_mt); 445} 446