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