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