1848b8605Smrg/* 2848b8605Smrg * Mesa 3-D graphics library 3848b8605Smrg * 4848b8605Smrg * Copyright (C) 2011 VMware, Inc. 5848b8605Smrg * 6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7848b8605Smrg * copy of this software and associated documentation files (the "Software"), 8848b8605Smrg * to deal in the Software without restriction, including without limitation 9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 11848b8605Smrg * Software is furnished to do so, subject to the following conditions: 12848b8605Smrg * 13848b8605Smrg * The above copyright notice and this permission notice shall be included 14848b8605Smrg * in all copies or substantial portions of the Software. 15848b8605Smrg * 16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 23848b8605Smrg */ 24848b8605Smrg 25848b8605Smrg/** 26848b8605Smrg * Functions for mapping/unmapping texture images. 27848b8605Smrg */ 28848b8605Smrg 29848b8605Smrg 30848b8605Smrg#include "main/context.h" 31848b8605Smrg#include "main/fbobject.h" 32848b8605Smrg#include "main/teximage.h" 33848b8605Smrg#include "main/texobj.h" 34848b8605Smrg#include "swrast/swrast.h" 35848b8605Smrg#include "swrast/s_context.h" 36848b8605Smrg 37848b8605Smrg 38848b8605Smrg/** 39848b8605Smrg * Allocate a new swrast_texture_image (a subclass of gl_texture_image). 40848b8605Smrg * Called via ctx->Driver.NewTextureImage(). 41848b8605Smrg */ 42848b8605Smrgstruct gl_texture_image * 43848b8605Smrg_swrast_new_texture_image( struct gl_context *ctx ) 44848b8605Smrg{ 45848b8605Smrg (void) ctx; 46848b8605Smrg return (struct gl_texture_image *) CALLOC_STRUCT(swrast_texture_image); 47848b8605Smrg} 48848b8605Smrg 49848b8605Smrg 50848b8605Smrg/** 51848b8605Smrg * Free a swrast_texture_image (a subclass of gl_texture_image). 52848b8605Smrg * Called via ctx->Driver.DeleteTextureImage(). 53848b8605Smrg */ 54848b8605Smrgvoid 55848b8605Smrg_swrast_delete_texture_image(struct gl_context *ctx, 56848b8605Smrg struct gl_texture_image *texImage) 57848b8605Smrg{ 58848b8605Smrg /* Nothing special for the subclass yet */ 59848b8605Smrg _mesa_delete_texture_image(ctx, texImage); 60848b8605Smrg} 61848b8605Smrg 62848b8605Smrgstatic unsigned int 63b8e80941Smrgtexture_slices(const struct gl_texture_image *texImage) 64848b8605Smrg{ 65848b8605Smrg if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) 66848b8605Smrg return texImage->Height; 67848b8605Smrg else 68848b8605Smrg return texImage->Depth; 69848b8605Smrg} 70848b8605Smrg 71848b8605Smrgunsigned int 72848b8605Smrg_swrast_teximage_slice_height(struct gl_texture_image *texImage) 73848b8605Smrg{ 74848b8605Smrg /* For 1D array textures, the slices are all 1 pixel high, and Height is 75848b8605Smrg * the number of slices. 76848b8605Smrg */ 77848b8605Smrg if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) 78848b8605Smrg return 1; 79848b8605Smrg else 80848b8605Smrg return texImage->Height; 81848b8605Smrg} 82848b8605Smrg 83848b8605Smrg/** 84848b8605Smrg * Called via ctx->Driver.AllocTextureImageBuffer() 85848b8605Smrg */ 86848b8605SmrgGLboolean 87848b8605Smrg_swrast_alloc_texture_image_buffer(struct gl_context *ctx, 88848b8605Smrg struct gl_texture_image *texImage) 89848b8605Smrg{ 90848b8605Smrg struct swrast_texture_image *swImg = swrast_texture_image(texImage); 91848b8605Smrg GLuint bytesPerSlice; 92848b8605Smrg GLuint slices = texture_slices(texImage); 93848b8605Smrg GLuint i; 94848b8605Smrg 95848b8605Smrg if (!_swrast_init_texture_image(texImage)) 96848b8605Smrg return GL_FALSE; 97848b8605Smrg 98848b8605Smrg bytesPerSlice = _mesa_format_image_size(texImage->TexFormat, texImage->Width, 99848b8605Smrg _swrast_teximage_slice_height(texImage), 1); 100848b8605Smrg 101848b8605Smrg assert(!swImg->Buffer); 102848b8605Smrg swImg->Buffer = _mesa_align_malloc(bytesPerSlice * slices, 512); 103848b8605Smrg if (!swImg->Buffer) 104848b8605Smrg return GL_FALSE; 105848b8605Smrg 106848b8605Smrg /* RowStride and ImageSlices[] describe how to address texels in 'Data' */ 107848b8605Smrg swImg->RowStride = _mesa_format_row_stride(texImage->TexFormat, 108848b8605Smrg texImage->Width); 109848b8605Smrg 110848b8605Smrg for (i = 0; i < slices; i++) { 111848b8605Smrg swImg->ImageSlices[i] = swImg->Buffer + bytesPerSlice * i; 112848b8605Smrg } 113848b8605Smrg 114848b8605Smrg return GL_TRUE; 115848b8605Smrg} 116848b8605Smrg 117848b8605Smrg 118848b8605Smrg/** 119848b8605Smrg * Code that overrides ctx->Driver.AllocTextureImageBuffer may use this to 120848b8605Smrg * initialize the fields of swrast_texture_image without allocating the image 121848b8605Smrg * buffer or initializing RowStride or the contents of ImageSlices. 122848b8605Smrg * 123848b8605Smrg * Returns GL_TRUE on success, GL_FALSE on memory allocation failure. 124848b8605Smrg */ 125848b8605SmrgGLboolean 126848b8605Smrg_swrast_init_texture_image(struct gl_texture_image *texImage) 127848b8605Smrg{ 128848b8605Smrg struct swrast_texture_image *swImg = swrast_texture_image(texImage); 129848b8605Smrg 130848b8605Smrg if ((texImage->Width == 1 || _mesa_is_pow_two(texImage->Width2)) && 131848b8605Smrg (texImage->Height == 1 || _mesa_is_pow_two(texImage->Height2)) && 132848b8605Smrg (texImage->Depth == 1 || _mesa_is_pow_two(texImage->Depth2))) 133848b8605Smrg swImg->_IsPowerOfTwo = GL_TRUE; 134848b8605Smrg else 135848b8605Smrg swImg->_IsPowerOfTwo = GL_FALSE; 136848b8605Smrg 137848b8605Smrg /* Compute Width/Height/DepthScale for mipmap lod computation */ 138848b8605Smrg if (texImage->TexObject->Target == GL_TEXTURE_RECTANGLE_NV) { 139848b8605Smrg /* scale = 1.0 since texture coords directly map to texels */ 140848b8605Smrg swImg->WidthScale = 1.0; 141848b8605Smrg swImg->HeightScale = 1.0; 142848b8605Smrg swImg->DepthScale = 1.0; 143848b8605Smrg } 144848b8605Smrg else { 145848b8605Smrg swImg->WidthScale = (GLfloat) texImage->Width; 146848b8605Smrg swImg->HeightScale = (GLfloat) texImage->Height; 147848b8605Smrg swImg->DepthScale = (GLfloat) texImage->Depth; 148848b8605Smrg } 149848b8605Smrg 150848b8605Smrg assert(!swImg->ImageSlices); 151848b8605Smrg swImg->ImageSlices = calloc(texture_slices(texImage), sizeof(void *)); 152848b8605Smrg if (!swImg->ImageSlices) 153848b8605Smrg return GL_FALSE; 154848b8605Smrg 155848b8605Smrg return GL_TRUE; 156848b8605Smrg} 157848b8605Smrg 158848b8605Smrg 159848b8605Smrg/** 160848b8605Smrg * Called via ctx->Driver.FreeTextureImageBuffer() 161848b8605Smrg */ 162848b8605Smrgvoid 163848b8605Smrg_swrast_free_texture_image_buffer(struct gl_context *ctx, 164848b8605Smrg struct gl_texture_image *texImage) 165848b8605Smrg{ 166848b8605Smrg struct swrast_texture_image *swImage = swrast_texture_image(texImage); 167848b8605Smrg 168848b8605Smrg _mesa_align_free(swImage->Buffer); 169848b8605Smrg swImage->Buffer = NULL; 170848b8605Smrg 171848b8605Smrg free(swImage->ImageSlices); 172848b8605Smrg swImage->ImageSlices = NULL; 173848b8605Smrg} 174848b8605Smrg 175848b8605Smrg 176848b8605Smrg/** 177848b8605Smrg * Error checking for debugging only. 178848b8605Smrg */ 179848b8605Smrgstatic void 180848b8605Smrgcheck_map_teximage(const struct gl_texture_image *texImage, 181848b8605Smrg GLuint slice, GLuint x, GLuint y, GLuint w, GLuint h) 182848b8605Smrg{ 183848b8605Smrg 184848b8605Smrg if (texImage->TexObject->Target == GL_TEXTURE_1D) 185848b8605Smrg assert(y == 0 && h == 1); 186848b8605Smrg 187848b8605Smrg assert(x < texImage->Width || texImage->Width == 0); 188848b8605Smrg assert(y < texImage->Height || texImage->Height == 0); 189848b8605Smrg assert(x + w <= texImage->Width); 190848b8605Smrg assert(y + h <= texImage->Height); 191b8e80941Smrg assert(slice < texture_slices(texImage)); 192848b8605Smrg} 193848b8605Smrg 194848b8605Smrg/** 195848b8605Smrg * Map a 2D slice of a texture image into user space. 196848b8605Smrg * (x,y,w,h) defines a region of interest (ROI). Reading/writing texels 197848b8605Smrg * outside of the ROI is undefined. 198848b8605Smrg * 199848b8605Smrg * \param texImage the texture image 200848b8605Smrg * \param slice the 3D image slice or array texture slice 201848b8605Smrg * \param x, y, w, h region of interest 202848b8605Smrg * \param mode bitmask of GL_MAP_READ_BIT, GL_MAP_WRITE_BIT 203848b8605Smrg * \param mapOut returns start of mapping of region of interest 204848b8605Smrg * \param rowStrideOut returns row stride (in bytes) 205848b8605Smrg */ 206848b8605Smrgvoid 207848b8605Smrg_swrast_map_teximage(struct gl_context *ctx, 208848b8605Smrg struct gl_texture_image *texImage, 209848b8605Smrg GLuint slice, 210848b8605Smrg GLuint x, GLuint y, GLuint w, GLuint h, 211848b8605Smrg GLbitfield mode, 212848b8605Smrg GLubyte **mapOut, 213848b8605Smrg GLint *rowStrideOut) 214848b8605Smrg{ 215848b8605Smrg struct swrast_texture_image *swImage = swrast_texture_image(texImage); 216848b8605Smrg GLubyte *map; 217848b8605Smrg GLint stride, texelSize; 218848b8605Smrg GLuint bw, bh; 219848b8605Smrg 220848b8605Smrg check_map_teximage(texImage, slice, x, y, w, h); 221848b8605Smrg 222848b8605Smrg if (!swImage->Buffer) { 223848b8605Smrg /* Either glTexImage was called with a NULL <pixels> argument or 224848b8605Smrg * we ran out of memory when allocating texture memory, 225848b8605Smrg */ 226848b8605Smrg *mapOut = NULL; 227848b8605Smrg *rowStrideOut = 0; 228848b8605Smrg return; 229848b8605Smrg } 230848b8605Smrg 231848b8605Smrg texelSize = _mesa_get_format_bytes(texImage->TexFormat); 232848b8605Smrg stride = _mesa_format_row_stride(texImage->TexFormat, texImage->Width); 233848b8605Smrg _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh); 234848b8605Smrg 235848b8605Smrg assert(x % bw == 0); 236848b8605Smrg assert(y % bh == 0); 237848b8605Smrg 238848b8605Smrg /* This function can only be used with a swrast-allocated buffer, in which 239848b8605Smrg * case ImageSlices is populated with pointers into Buffer. 240848b8605Smrg */ 241848b8605Smrg assert(swImage->Buffer); 242848b8605Smrg assert(swImage->Buffer == swImage->ImageSlices[0]); 243848b8605Smrg 244848b8605Smrg map = swImage->ImageSlices[slice]; 245848b8605Smrg 246848b8605Smrg /* apply x/y offset to map address */ 247848b8605Smrg map += stride * (y / bh) + texelSize * (x / bw); 248848b8605Smrg 249848b8605Smrg *mapOut = map; 250848b8605Smrg *rowStrideOut = stride; 251848b8605Smrg} 252848b8605Smrg 253848b8605Smrgvoid 254848b8605Smrg_swrast_unmap_teximage(struct gl_context *ctx, 255848b8605Smrg struct gl_texture_image *texImage, 256848b8605Smrg GLuint slice) 257848b8605Smrg{ 258848b8605Smrg /* nop */ 259848b8605Smrg} 260848b8605Smrg 261848b8605Smrg 262848b8605Smrgvoid 263848b8605Smrg_swrast_map_texture(struct gl_context *ctx, struct gl_texture_object *texObj) 264848b8605Smrg{ 265848b8605Smrg const GLuint faces = _mesa_num_tex_faces(texObj->Target); 266848b8605Smrg GLuint face, level; 267848b8605Smrg 268848b8605Smrg for (face = 0; face < faces; face++) { 269848b8605Smrg for (level = texObj->BaseLevel; level < MAX_TEXTURE_LEVELS; level++) { 270848b8605Smrg struct gl_texture_image *texImage = texObj->Image[face][level]; 271848b8605Smrg struct swrast_texture_image *swImage = swrast_texture_image(texImage); 272848b8605Smrg unsigned int i, slices; 273848b8605Smrg 274848b8605Smrg if (!texImage) 275848b8605Smrg continue; 276848b8605Smrg 277848b8605Smrg /* In the case of a swrast-allocated texture buffer, the ImageSlices 278848b8605Smrg * and RowStride are always available. 279848b8605Smrg */ 280848b8605Smrg if (swImage->Buffer) { 281848b8605Smrg assert(swImage->ImageSlices[0] == swImage->Buffer); 282848b8605Smrg continue; 283848b8605Smrg } 284848b8605Smrg 285848b8605Smrg if (!swImage->ImageSlices) { 286848b8605Smrg swImage->ImageSlices = 287848b8605Smrg calloc(texture_slices(texImage), sizeof(void *)); 288848b8605Smrg if (!swImage->ImageSlices) 289848b8605Smrg continue; 290848b8605Smrg } 291848b8605Smrg 292848b8605Smrg slices = texture_slices(texImage); 293848b8605Smrg 294848b8605Smrg for (i = 0; i < slices; i++) { 295848b8605Smrg GLubyte *map; 296848b8605Smrg GLint rowStride; 297848b8605Smrg 298848b8605Smrg if (swImage->ImageSlices[i]) 299848b8605Smrg continue; 300848b8605Smrg 301848b8605Smrg ctx->Driver.MapTextureImage(ctx, texImage, i, 302848b8605Smrg 0, 0, 303848b8605Smrg texImage->Width, texImage->Height, 304848b8605Smrg GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, 305848b8605Smrg &map, &rowStride); 306848b8605Smrg 307848b8605Smrg swImage->ImageSlices[i] = map; 308848b8605Smrg /* A swrast-using driver has to return the same rowstride for 309848b8605Smrg * every slice of the same texture, since we don't track them 310848b8605Smrg * separately. 311848b8605Smrg */ 312848b8605Smrg if (i == 0) 313848b8605Smrg swImage->RowStride = rowStride; 314848b8605Smrg else 315848b8605Smrg assert(swImage->RowStride == rowStride); 316848b8605Smrg } 317848b8605Smrg } 318848b8605Smrg } 319848b8605Smrg} 320848b8605Smrg 321848b8605Smrg 322848b8605Smrgvoid 323848b8605Smrg_swrast_unmap_texture(struct gl_context *ctx, struct gl_texture_object *texObj) 324848b8605Smrg{ 325848b8605Smrg const GLuint faces = _mesa_num_tex_faces(texObj->Target); 326848b8605Smrg GLuint face, level; 327848b8605Smrg 328848b8605Smrg for (face = 0; face < faces; face++) { 329848b8605Smrg for (level = texObj->BaseLevel; level < MAX_TEXTURE_LEVELS; level++) { 330848b8605Smrg struct gl_texture_image *texImage = texObj->Image[face][level]; 331848b8605Smrg struct swrast_texture_image *swImage = swrast_texture_image(texImage); 332848b8605Smrg unsigned int i, slices; 333848b8605Smrg 334848b8605Smrg if (!texImage) 335848b8605Smrg continue; 336848b8605Smrg 337848b8605Smrg if (swImage->Buffer) 338848b8605Smrg return; 339848b8605Smrg 340848b8605Smrg if (!swImage->ImageSlices) 341848b8605Smrg continue; 342848b8605Smrg 343848b8605Smrg slices = texture_slices(texImage); 344848b8605Smrg 345848b8605Smrg for (i = 0; i < slices; i++) { 346848b8605Smrg if (swImage->ImageSlices[i]) { 347848b8605Smrg ctx->Driver.UnmapTextureImage(ctx, texImage, i); 348848b8605Smrg swImage->ImageSlices[i] = NULL; 349848b8605Smrg } 350848b8605Smrg } 351848b8605Smrg } 352848b8605Smrg } 353848b8605Smrg} 354848b8605Smrg 355848b8605Smrg 356848b8605Smrg/** 357848b8605Smrg * Map all textures for reading prior to software rendering. 358848b8605Smrg */ 359848b8605Smrgvoid 360848b8605Smrg_swrast_map_textures(struct gl_context *ctx) 361848b8605Smrg{ 362848b8605Smrg int unit; 363848b8605Smrg 364848b8605Smrg for (unit = 0; unit <= ctx->Texture._MaxEnabledTexImageUnit; unit++) { 365848b8605Smrg struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current; 366848b8605Smrg 367848b8605Smrg if (texObj) 368848b8605Smrg _swrast_map_texture(ctx, texObj); 369848b8605Smrg } 370848b8605Smrg} 371848b8605Smrg 372848b8605Smrg 373848b8605Smrg/** 374848b8605Smrg * Unmap all textures for reading prior to software rendering. 375848b8605Smrg */ 376848b8605Smrgvoid 377848b8605Smrg_swrast_unmap_textures(struct gl_context *ctx) 378848b8605Smrg{ 379848b8605Smrg int unit; 380848b8605Smrg for (unit = 0; unit <= ctx->Texture._MaxEnabledTexImageUnit; unit++) { 381848b8605Smrg struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current; 382848b8605Smrg 383848b8605Smrg if (texObj) 384848b8605Smrg _swrast_unmap_texture(ctx, texObj); 385848b8605Smrg } 386848b8605Smrg} 387