intel_mipmap_tree.c revision 7c71ef3a3d0cf2620525f468960cdc76a0fb0d33
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 "enums.h" 32 33#define FILE_DEBUG_FLAG DEBUG_MIPTREE 34 35static GLenum 36target_to_target(GLenum target) 37{ 38 switch (target) { 39 case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: 40 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: 41 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: 42 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: 43 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: 44 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: 45 return GL_TEXTURE_CUBE_MAP_ARB; 46 default: 47 return target; 48 } 49} 50 51struct intel_mipmap_tree * 52intel_miptree_create(struct intel_context *intel, 53 GLenum target, 54 GLenum internal_format, 55 GLuint first_level, 56 GLuint last_level, 57 GLuint width0, 58 GLuint height0, 59 GLuint depth0, GLuint cpp, GLuint compress_byte) 60{ 61 GLboolean ok; 62 struct intel_mipmap_tree *mt = calloc(sizeof(*mt), 1); 63 64 DBG("%s target %s format %s level %d..%d\n", __FUNCTION__, 65 _mesa_lookup_enum_by_nr(target), 66 _mesa_lookup_enum_by_nr(internal_format), first_level, last_level); 67 68 mt->target = target_to_target(target); 69 mt->internal_format = internal_format; 70 mt->first_level = first_level; 71 mt->last_level = last_level; 72 mt->width0 = width0; 73 mt->height0 = height0; 74 mt->depth0 = depth0; 75 mt->cpp = compress_byte ? compress_byte : cpp; 76 mt->compressed = compress_byte ? 1 : 0; 77 mt->refcount = 1; 78 79 switch (intel->intelScreen->deviceID) { 80 case PCI_CHIP_I945_G: 81 case PCI_CHIP_I945_GM: 82 case PCI_CHIP_I945_GME: 83 case PCI_CHIP_G33_G: 84 case PCI_CHIP_Q33_G: 85 case PCI_CHIP_Q35_G: 86 ok = i945_miptree_layout(mt); 87 break; 88 case PCI_CHIP_I915_G: 89 case PCI_CHIP_I915_GM: 90 case PCI_CHIP_I830_M: 91 case PCI_CHIP_I855_GM: 92 case PCI_CHIP_I865_G: 93 default: 94 /* All the i830 chips and the i915 use this layout: 95 */ 96 ok = i915_miptree_layout(mt); 97 break; 98 } 99 100 if (ok) { 101 if (!mt->compressed) { 102 int align; 103 104 if (intel->ttm) { 105 /* XXX: Align pitch to multiple of 64 bytes for now to allow 106 * render-to-texture to work in all cases. This should probably be 107 * replaced at some point by some scheme to only do this when really 108 * necessary. 109 */ 110 align = 63; 111 } else { 112 align = 3; 113 } 114 115 mt->pitch = (mt->pitch * cpp + align) & ~align; 116 117 /* XXX: At least the i915 seems very upset when the pitch is a multiple 118 * of 1024 and sometimes 512 bytes - performance can drop by several 119 * times. Go to the next multiple of the required alignment for now. 120 */ 121 if (!(mt->pitch & 511)) 122 mt->pitch += align + 1; 123 124 mt->pitch /= cpp; 125 } 126 127 mt->region = intel_region_alloc(intel, 128 mt->cpp, mt->pitch, mt->total_height); 129 } 130 131 if (!mt->region) { 132 free(mt); 133 return NULL; 134 } 135 136 return mt; 137} 138 139 140void 141intel_miptree_reference(struct intel_mipmap_tree **dst, 142 struct intel_mipmap_tree *src) 143{ 144 src->refcount++; 145 *dst = src; 146 DBG("%s %p refcount now %d\n", __FUNCTION__, src, src->refcount); 147} 148 149void 150intel_miptree_release(struct intel_context *intel, 151 struct intel_mipmap_tree **mt) 152{ 153 if (!*mt) 154 return; 155 156 DBG("%s %p refcount will be %d\n", __FUNCTION__, *mt, (*mt)->refcount - 1); 157 if (--(*mt)->refcount <= 0) { 158 GLuint i; 159 160 DBG("%s deleting %p\n", __FUNCTION__, *mt); 161 162 intel_region_release(&((*mt)->region)); 163 164 for (i = 0; i < MAX_TEXTURE_LEVELS; i++) 165 if ((*mt)->level[i].image_offset) 166 free((*mt)->level[i].image_offset); 167 168 free(*mt); 169 } 170 *mt = NULL; 171} 172 173 174 175 176/* Can the image be pulled into a unified mipmap tree. This mirrors 177 * the completeness test in a lot of ways. 178 * 179 * Not sure whether I want to pass gl_texture_image here. 180 */ 181GLboolean 182intel_miptree_match_image(struct intel_mipmap_tree *mt, 183 struct gl_texture_image *image, 184 GLuint face, GLuint level) 185{ 186 /* Images with borders are never pulled into mipmap trees. 187 */ 188 if (image->Border) 189 return GL_FALSE; 190 191 if (image->InternalFormat != mt->internal_format || 192 image->IsCompressed != mt->compressed) 193 return GL_FALSE; 194 195 /* Test image dimensions against the base level image adjusted for 196 * minification. This will also catch images not present in the 197 * tree, changed targets, etc. 198 */ 199 if (image->Width != mt->level[level].width || 200 image->Height != mt->level[level].height || 201 image->Depth != mt->level[level].depth) 202 return GL_FALSE; 203 204 return GL_TRUE; 205} 206 207 208void 209intel_miptree_set_level_info(struct intel_mipmap_tree *mt, 210 GLuint level, 211 GLuint nr_images, 212 GLuint x, GLuint y, GLuint w, GLuint h, GLuint d) 213{ 214 215 mt->level[level].width = w; 216 mt->level[level].height = h; 217 mt->level[level].depth = d; 218 mt->level[level].level_offset = (x + y * mt->pitch) * mt->cpp; 219 mt->level[level].nr_images = nr_images; 220 221 DBG("%s level %d size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__, 222 level, w, h, d, x, y, mt->level[level].level_offset); 223 224 /* Not sure when this would happen, but anyway: 225 */ 226 if (mt->level[level].image_offset) { 227 free(mt->level[level].image_offset); 228 mt->level[level].image_offset = NULL; 229 } 230 231 assert(nr_images); 232 233 mt->level[level].image_offset = malloc(nr_images * sizeof(GLuint)); 234 mt->level[level].image_offset[0] = 0; 235} 236 237 238 239void 240intel_miptree_set_image_offset(struct intel_mipmap_tree *mt, 241 GLuint level, GLuint img, GLuint x, GLuint y) 242{ 243 if (img == 0 && level == 0) 244 assert(x == 0 && y == 0); 245 246 assert(img < mt->level[level].nr_images); 247 248 mt->level[level].image_offset[img] = (x + y * mt->pitch); 249 250 DBG("%s level %d img %d pos %d,%d image_offset %x\n", 251 __FUNCTION__, level, img, x, y, mt->level[level].image_offset[img]); 252} 253 254 255/* Although we use the image_offset[] array to store relative offsets 256 * to cube faces, Mesa doesn't know anything about this and expects 257 * each cube face to be treated as a separate image. 258 * 259 * These functions present that view to mesa: 260 */ 261const GLuint * 262intel_miptree_depth_offsets(struct intel_mipmap_tree *mt, GLuint level) 263{ 264 static const GLuint zero = 0; 265 266 if (mt->target != GL_TEXTURE_3D || mt->level[level].nr_images == 1) 267 return &zero; 268 else 269 return mt->level[level].image_offset; 270} 271 272 273GLuint 274intel_miptree_image_offset(struct intel_mipmap_tree * mt, 275 GLuint face, GLuint level) 276{ 277 if (mt->target == GL_TEXTURE_CUBE_MAP_ARB) 278 return (mt->level[level].level_offset + 279 mt->level[level].image_offset[face] * mt->cpp); 280 else 281 return mt->level[level].level_offset; 282} 283 284 285 286/** 287 * Map a teximage in a mipmap tree. 288 * \param row_stride returns row stride in bytes 289 * \param image_stride returns image stride in bytes (for 3D textures). 290 * \return address of mapping 291 */ 292GLubyte * 293intel_miptree_image_map(struct intel_context * intel, 294 struct intel_mipmap_tree * mt, 295 GLuint face, 296 GLuint level, 297 GLuint * row_stride, GLuint * image_offsets) 298{ 299 DBG("%s \n", __FUNCTION__); 300 301 if (row_stride) 302 *row_stride = mt->pitch * mt->cpp; 303 304 if (image_offsets) 305 memcpy(image_offsets, mt->level[level].image_offset, 306 mt->level[level].depth * sizeof(GLuint)); 307 308 return (intel_region_map(intel, mt->region) + 309 intel_miptree_image_offset(mt, face, level)); 310} 311 312void 313intel_miptree_image_unmap(struct intel_context *intel, 314 struct intel_mipmap_tree *mt) 315{ 316 DBG("%s\n", __FUNCTION__); 317 intel_region_unmap(intel, mt->region); 318} 319 320 321 322/* Upload data for a particular image. 323 */ 324void 325intel_miptree_image_data(struct intel_context *intel, 326 struct intel_mipmap_tree *dst, 327 GLuint face, 328 GLuint level, 329 void *src, 330 GLuint src_row_pitch, GLuint src_image_pitch) 331{ 332 GLuint depth = dst->level[level].depth; 333 GLuint dst_offset = intel_miptree_image_offset(dst, face, level); 334 const GLuint *dst_depth_offset = intel_miptree_depth_offsets(dst, level); 335 GLuint i; 336 GLuint height = 0; 337 338 DBG("%s\n", __FUNCTION__); 339 for (i = 0; i < depth; i++) { 340 height = dst->level[level].height; 341 if(dst->compressed) 342 height /= 4; 343 intel_region_data(intel, dst->region, 344 dst_offset + dst_depth_offset[i], /* dst_offset */ 345 0, 0, /* dstx, dsty */ 346 src, 347 src_row_pitch, 348 0, 0, /* source x, y */ 349 dst->level[level].width, height); /* width, height */ 350 351 src += src_image_pitch * dst->cpp; 352 } 353} 354 355extern GLuint intel_compressed_alignment(GLenum); 356/* Copy mipmap image between trees 357 */ 358void 359intel_miptree_image_copy(struct intel_context *intel, 360 struct intel_mipmap_tree *dst, 361 GLuint face, GLuint level, 362 struct intel_mipmap_tree *src) 363{ 364 GLuint width = src->level[level].width; 365 GLuint height = src->level[level].height; 366 GLuint depth = src->level[level].depth; 367 GLuint dst_offset = intel_miptree_image_offset(dst, face, level); 368 GLuint src_offset = intel_miptree_image_offset(src, face, level); 369 const GLuint *dst_depth_offset = intel_miptree_depth_offsets(dst, level); 370 const GLuint *src_depth_offset = intel_miptree_depth_offsets(src, level); 371 GLuint i; 372 373 if (dst->compressed) { 374 GLuint alignment = intel_compressed_alignment(dst->internal_format); 375 height = (height + 3) / 4; 376 width = ((width + alignment - 1) & ~(alignment - 1)); 377 } 378 379 for (i = 0; i < depth; i++) { 380 intel_region_copy(intel, 381 dst->region, dst_offset + dst_depth_offset[i], 382 0, 383 0, 384 src->region, src_offset + src_depth_offset[i], 385 0, 0, width, height); 386 } 387 388} 389