1 /* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 2011 VMware, Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 /** 26 * Functions for mapping/unmapping texture images. 27 */ 28 29 30 #include "main/context.h" 31 #include "main/fbobject.h" 32 #include "main/teximage.h" 33 #include "main/texobj.h" 34 #include "swrast/swrast.h" 35 #include "swrast/s_context.h" 36 37 38 /** 39 * Allocate a new swrast_texture_image (a subclass of gl_texture_image). 40 * Called via ctx->Driver.NewTextureImage(). 41 */ 42 struct gl_texture_image * 43 _swrast_new_texture_image( struct gl_context *ctx ) 44 { 45 (void) ctx; 46 return (struct gl_texture_image *) CALLOC_STRUCT(swrast_texture_image); 47 } 48 49 50 /** 51 * Free a swrast_texture_image (a subclass of gl_texture_image). 52 * Called via ctx->Driver.DeleteTextureImage(). 53 */ 54 void 55 _swrast_delete_texture_image(struct gl_context *ctx, 56 struct gl_texture_image *texImage) 57 { 58 /* Nothing special for the subclass yet */ 59 _mesa_delete_texture_image(ctx, texImage); 60 } 61 62 static unsigned int 63 texture_slices(const struct gl_texture_image *texImage) 64 { 65 if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) 66 return texImage->Height; 67 else 68 return texImage->Depth; 69 } 70 71 unsigned int 72 _swrast_teximage_slice_height(struct gl_texture_image *texImage) 73 { 74 /* For 1D array textures, the slices are all 1 pixel high, and Height is 75 * the number of slices. 76 */ 77 if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) 78 return 1; 79 else 80 return texImage->Height; 81 } 82 83 /** 84 * Called via ctx->Driver.AllocTextureImageBuffer() 85 */ 86 GLboolean 87 _swrast_alloc_texture_image_buffer(struct gl_context *ctx, 88 struct gl_texture_image *texImage) 89 { 90 struct swrast_texture_image *swImg = swrast_texture_image(texImage); 91 GLuint bytesPerSlice; 92 GLuint slices = texture_slices(texImage); 93 GLuint i; 94 95 if (!_swrast_init_texture_image(texImage)) 96 return GL_FALSE; 97 98 bytesPerSlice = _mesa_format_image_size(texImage->TexFormat, texImage->Width, 99 _swrast_teximage_slice_height(texImage), 1); 100 101 assert(!swImg->Buffer); 102 swImg->Buffer = _mesa_align_malloc(bytesPerSlice * slices, 512); 103 if (!swImg->Buffer) 104 return GL_FALSE; 105 106 /* RowStride and ImageSlices[] describe how to address texels in 'Data' */ 107 swImg->RowStride = _mesa_format_row_stride(texImage->TexFormat, 108 texImage->Width); 109 110 for (i = 0; i < slices; i++) { 111 swImg->ImageSlices[i] = swImg->Buffer + bytesPerSlice * i; 112 } 113 114 return GL_TRUE; 115 } 116 117 118 /** 119 * Code that overrides ctx->Driver.AllocTextureImageBuffer may use this to 120 * initialize the fields of swrast_texture_image without allocating the image 121 * buffer or initializing RowStride or the contents of ImageSlices. 122 * 123 * Returns GL_TRUE on success, GL_FALSE on memory allocation failure. 124 */ 125 GLboolean 126 _swrast_init_texture_image(struct gl_texture_image *texImage) 127 { 128 struct swrast_texture_image *swImg = swrast_texture_image(texImage); 129 130 if ((texImage->Width == 1 || _mesa_is_pow_two(texImage->Width2)) && 131 (texImage->Height == 1 || _mesa_is_pow_two(texImage->Height2)) && 132 (texImage->Depth == 1 || _mesa_is_pow_two(texImage->Depth2))) 133 swImg->_IsPowerOfTwo = GL_TRUE; 134 else 135 swImg->_IsPowerOfTwo = GL_FALSE; 136 137 /* Compute Width/Height/DepthScale for mipmap lod computation */ 138 if (texImage->TexObject->Target == GL_TEXTURE_RECTANGLE_NV) { 139 /* scale = 1.0 since texture coords directly map to texels */ 140 swImg->WidthScale = 1.0; 141 swImg->HeightScale = 1.0; 142 swImg->DepthScale = 1.0; 143 } 144 else { 145 swImg->WidthScale = (GLfloat) texImage->Width; 146 swImg->HeightScale = (GLfloat) texImage->Height; 147 swImg->DepthScale = (GLfloat) texImage->Depth; 148 } 149 150 assert(!swImg->ImageSlices); 151 swImg->ImageSlices = calloc(texture_slices(texImage), sizeof(void *)); 152 if (!swImg->ImageSlices) 153 return GL_FALSE; 154 155 return GL_TRUE; 156 } 157 158 159 /** 160 * Called via ctx->Driver.FreeTextureImageBuffer() 161 */ 162 void 163 _swrast_free_texture_image_buffer(struct gl_context *ctx, 164 struct gl_texture_image *texImage) 165 { 166 struct swrast_texture_image *swImage = swrast_texture_image(texImage); 167 168 _mesa_align_free(swImage->Buffer); 169 swImage->Buffer = NULL; 170 171 free(swImage->ImageSlices); 172 swImage->ImageSlices = NULL; 173 } 174 175 176 /** 177 * Error checking for debugging only. 178 */ 179 static void 180 check_map_teximage(const struct gl_texture_image *texImage, 181 GLuint slice, GLuint x, GLuint y, GLuint w, GLuint h) 182 { 183 184 if (texImage->TexObject->Target == GL_TEXTURE_1D) 185 assert(y == 0 && h == 1); 186 187 assert(x < texImage->Width || texImage->Width == 0); 188 assert(y < texImage->Height || texImage->Height == 0); 189 assert(x + w <= texImage->Width); 190 assert(y + h <= texImage->Height); 191 assert(slice < texture_slices(texImage)); 192 } 193 194 /** 195 * Map a 2D slice of a texture image into user space. 196 * (x,y,w,h) defines a region of interest (ROI). Reading/writing texels 197 * outside of the ROI is undefined. 198 * 199 * \param texImage the texture image 200 * \param slice the 3D image slice or array texture slice 201 * \param x, y, w, h region of interest 202 * \param mode bitmask of GL_MAP_READ_BIT, GL_MAP_WRITE_BIT 203 * \param mapOut returns start of mapping of region of interest 204 * \param rowStrideOut returns row stride (in bytes) 205 */ 206 void 207 _swrast_map_teximage(struct gl_context *ctx, 208 struct gl_texture_image *texImage, 209 GLuint slice, 210 GLuint x, GLuint y, GLuint w, GLuint h, 211 GLbitfield mode, 212 GLubyte **mapOut, 213 GLint *rowStrideOut) 214 { 215 struct swrast_texture_image *swImage = swrast_texture_image(texImage); 216 GLubyte *map; 217 GLint stride, texelSize; 218 GLuint bw, bh; 219 220 check_map_teximage(texImage, slice, x, y, w, h); 221 222 if (!swImage->Buffer) { 223 /* Either glTexImage was called with a NULL <pixels> argument or 224 * we ran out of memory when allocating texture memory, 225 */ 226 *mapOut = NULL; 227 *rowStrideOut = 0; 228 return; 229 } 230 231 texelSize = _mesa_get_format_bytes(texImage->TexFormat); 232 stride = _mesa_format_row_stride(texImage->TexFormat, texImage->Width); 233 _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh); 234 235 assert(x % bw == 0); 236 assert(y % bh == 0); 237 238 /* This function can only be used with a swrast-allocated buffer, in which 239 * case ImageSlices is populated with pointers into Buffer. 240 */ 241 assert(swImage->Buffer); 242 assert(swImage->Buffer == swImage->ImageSlices[0]); 243 244 map = swImage->ImageSlices[slice]; 245 246 /* apply x/y offset to map address */ 247 map += stride * (y / bh) + texelSize * (x / bw); 248 249 *mapOut = map; 250 *rowStrideOut = stride; 251 } 252 253 void 254 _swrast_unmap_teximage(struct gl_context *ctx, 255 struct gl_texture_image *texImage, 256 GLuint slice) 257 { 258 /* nop */ 259 } 260 261 262 void 263 _swrast_map_texture(struct gl_context *ctx, struct gl_texture_object *texObj) 264 { 265 const GLuint faces = _mesa_num_tex_faces(texObj->Target); 266 GLuint face, level; 267 268 for (face = 0; face < faces; face++) { 269 for (level = texObj->BaseLevel; level < MAX_TEXTURE_LEVELS; level++) { 270 struct gl_texture_image *texImage = texObj->Image[face][level]; 271 struct swrast_texture_image *swImage = swrast_texture_image(texImage); 272 unsigned int i, slices; 273 274 if (!texImage) 275 continue; 276 277 /* In the case of a swrast-allocated texture buffer, the ImageSlices 278 * and RowStride are always available. 279 */ 280 if (swImage->Buffer) { 281 assert(swImage->ImageSlices[0] == swImage->Buffer); 282 continue; 283 } 284 285 if (!swImage->ImageSlices) { 286 swImage->ImageSlices = 287 calloc(texture_slices(texImage), sizeof(void *)); 288 if (!swImage->ImageSlices) 289 continue; 290 } 291 292 slices = texture_slices(texImage); 293 294 for (i = 0; i < slices; i++) { 295 GLubyte *map; 296 GLint rowStride; 297 298 if (swImage->ImageSlices[i]) 299 continue; 300 301 ctx->Driver.MapTextureImage(ctx, texImage, i, 302 0, 0, 303 texImage->Width, texImage->Height, 304 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, 305 &map, &rowStride); 306 307 swImage->ImageSlices[i] = map; 308 /* A swrast-using driver has to return the same rowstride for 309 * every slice of the same texture, since we don't track them 310 * separately. 311 */ 312 if (i == 0) 313 swImage->RowStride = rowStride; 314 else 315 assert(swImage->RowStride == rowStride); 316 } 317 } 318 } 319 } 320 321 322 void 323 _swrast_unmap_texture(struct gl_context *ctx, struct gl_texture_object *texObj) 324 { 325 const GLuint faces = _mesa_num_tex_faces(texObj->Target); 326 GLuint face, level; 327 328 for (face = 0; face < faces; face++) { 329 for (level = texObj->BaseLevel; level < MAX_TEXTURE_LEVELS; level++) { 330 struct gl_texture_image *texImage = texObj->Image[face][level]; 331 struct swrast_texture_image *swImage = swrast_texture_image(texImage); 332 unsigned int i, slices; 333 334 if (!texImage) 335 continue; 336 337 if (swImage->Buffer) 338 return; 339 340 if (!swImage->ImageSlices) 341 continue; 342 343 slices = texture_slices(texImage); 344 345 for (i = 0; i < slices; i++) { 346 if (swImage->ImageSlices[i]) { 347 ctx->Driver.UnmapTextureImage(ctx, texImage, i); 348 swImage->ImageSlices[i] = NULL; 349 } 350 } 351 } 352 } 353 } 354 355 356 /** 357 * Map all textures for reading prior to software rendering. 358 */ 359 void 360 _swrast_map_textures(struct gl_context *ctx) 361 { 362 int unit; 363 364 for (unit = 0; unit <= ctx->Texture._MaxEnabledTexImageUnit; unit++) { 365 struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current; 366 367 if (texObj) 368 _swrast_map_texture(ctx, texObj); 369 } 370 } 371 372 373 /** 374 * Unmap all textures for reading prior to software rendering. 375 */ 376 void 377 _swrast_unmap_textures(struct gl_context *ctx) 378 { 379 int unit; 380 for (unit = 0; unit <= ctx->Texture._MaxEnabledTexImageUnit; unit++) { 381 struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current; 382 383 if (texObj) 384 _swrast_unmap_texture(ctx, texObj); 385 } 386 } 387