texstorage.c revision a8fcb7927b2f50886eb33e81aa7feeb96bc300e4
1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 2011 VMware, Inc. 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 "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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 20 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 */ 23 24 25/** 26 * \file texstorage.c 27 * GL_ARB_texture_storage functions 28 */ 29 30 31 32#include "glheader.h" 33#include "context.h" 34#include "enums.h" 35#include "imports.h" 36#include "macros.h" 37#include "mfeatures.h" 38#include "teximage.h" 39#include "texstorage.h" 40#include "mtypes.h" 41 42 43 44/** 45 * Check if the given texture target is a legal texture object target 46 * for a glTexStorage() command. 47 * This is a bit different than legal_teximage_target() when it comes 48 * to cube maps. 49 */ 50static GLboolean 51legal_texobj_target(struct gl_context *ctx, GLuint dims, GLenum target) 52{ 53 switch (dims) { 54 case 1: 55 switch (target) { 56 case GL_TEXTURE_1D: 57 case GL_PROXY_TEXTURE_1D: 58 return GL_TRUE; 59 default: 60 return GL_FALSE; 61 } 62 case 2: 63 switch (target) { 64 case GL_TEXTURE_2D: 65 case GL_PROXY_TEXTURE_2D: 66 return GL_TRUE; 67 case GL_TEXTURE_CUBE_MAP: 68 case GL_PROXY_TEXTURE_CUBE_MAP: 69 return ctx->Extensions.ARB_texture_cube_map; 70 case GL_TEXTURE_RECTANGLE: 71 case GL_PROXY_TEXTURE_RECTANGLE: 72 return ctx->Extensions.NV_texture_rectangle; 73 case GL_TEXTURE_1D_ARRAY: 74 case GL_PROXY_TEXTURE_1D_ARRAY: 75 return (ctx->Extensions.MESA_texture_array || 76 ctx->Extensions.EXT_texture_array); 77 default: 78 return GL_FALSE; 79 } 80 case 3: 81 switch (target) { 82 case GL_TEXTURE_3D: 83 case GL_PROXY_TEXTURE_3D: 84 return GL_TRUE; 85 case GL_TEXTURE_2D_ARRAY: 86 case GL_PROXY_TEXTURE_2D_ARRAY: 87 return (ctx->Extensions.MESA_texture_array || 88 ctx->Extensions.EXT_texture_array); 89 default: 90 return GL_FALSE; 91 } 92 default: 93 _mesa_problem(ctx, "invalid dims=%u in legal_texobj_target()", dims); 94 return GL_FALSE; 95 } 96} 97 98 99/** 100 * Compute the size of the next mipmap level. 101 */ 102static void 103next_mipmap_level_size(GLenum target, 104 GLint *width, GLint *height, GLint *depth) 105{ 106 if (*width > 1) { 107 *width /= 2; 108 } 109 110 if ((*height > 1) && (target != GL_TEXTURE_1D_ARRAY)) { 111 *height /= 2; 112 } 113 114 if ((*depth > 1) && (target != GL_TEXTURE_2D_ARRAY)) { 115 *depth /= 2; 116 } 117} 118 119 120/** 121 * Do actual memory allocation for glTexStorage1/2/3D(). 122 */ 123static void 124setup_texstorage(struct gl_context *ctx, 125 struct gl_texture_object *texObj, 126 GLuint dims, 127 GLsizei levels, GLenum internalFormat, 128 GLsizei width, GLsizei height, GLsizei depth) 129{ 130 const GLenum target = texObj->Target; 131 const GLuint numFaces = (target == GL_TEXTURE_CUBE_MAP) ? 6 : 1; 132 gl_format texFormat; 133 GLint level, levelWidth = width, levelHeight = height, levelDepth = depth; 134 GLuint face; 135 136 assert(levels > 0); 137 assert(width > 0); 138 assert(height > 0); 139 assert(depth > 0); 140 141 texFormat = _mesa_choose_texture_format(ctx, texObj, target, 0, 142 internalFormat, GL_NONE, GL_NONE); 143 144 /* Set up all the texture object's gl_texture_images */ 145 for (level = 0; level < levels; level++) { 146 for (face = 0; face < numFaces; face++) { 147 const GLenum faceTarget = 148 (target == GL_TEXTURE_CUBE_MAP) 149 ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + face : target; 150 struct gl_texture_image *texImage = 151 _mesa_get_tex_image(ctx, texObj, faceTarget, level); 152 153 if (!texImage) { 154 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage%uD", dims); 155 return; 156 } 157 158 _mesa_init_teximage_fields(ctx, target, texImage, 159 levelWidth, levelHeight, levelDepth, 160 0, internalFormat, texFormat); 161 } 162 163 next_mipmap_level_size(target, &levelWidth, &levelHeight, &levelDepth); 164 } 165 166 assert(levelWidth > 0); 167 assert(levelHeight > 0); 168 assert(levelDepth > 0); 169 170 if (!_mesa_is_proxy_texture(texObj->Target)) { 171 /* Do actual texture memory allocation */ 172 if (!ctx->Driver.AllocTextureStorage(ctx, texObj, levels, 173 width, height, depth)) { 174 /* Reset the texture images' info to zeros. 175 * Strictly speaking, we probably don't have to do this since 176 * generating GL_OUT_OF_MEMORY can leave things in an undefined 177 * state but this puts things in a consistent state. 178 */ 179 for (level = 0; level < levels; level++) { 180 for (face = 0; face < numFaces; face++) { 181 struct gl_texture_image *texImage = texObj->Image[face][level]; 182 if (texImage) { 183 _mesa_init_teximage_fields(ctx, target, texImage, 184 0, 0, 0, 0, 185 GL_NONE, MESA_FORMAT_NONE); 186 } 187 } 188 } 189 190 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexStorage%uD", dims); 191 192 return; 193 } 194 } 195 196 texObj->Immutable = GL_TRUE; 197} 198 199 200/** 201 * Clear all fields of texture object to zeros. Used for proxy texture tests. 202 */ 203static void 204clear_image_fields(struct gl_context *ctx, 205 GLuint dims, 206 struct gl_texture_object *texObj) 207{ 208 const GLenum target = texObj->Target; 209 const GLuint numFaces = (target == GL_TEXTURE_CUBE_MAP) ? 6 : 1; 210 GLint level; 211 GLuint face; 212 213 for (level = 0; level < Elements(texObj->Image[0]); level++) { 214 for (face = 0; face < numFaces; face++) { 215 const GLenum faceTarget = 216 (target == GL_TEXTURE_CUBE_MAP) 217 ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + face : target; 218 struct gl_texture_image *texImage = 219 _mesa_get_tex_image(ctx, texObj, faceTarget, level); 220 221 if (!texImage) { 222 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexStorage%uD", dims); 223 return; 224 } 225 226 _mesa_init_teximage_fields(ctx, target, texImage, 227 0, 0, 0, 0, GL_NONE, MESA_FORMAT_NONE); 228 } 229 } 230} 231 232 233/** 234 * Do error checking for calls to glTexStorage1/2/3D(). 235 * If an error is found, record it with _mesa_error(), unless the target 236 * is a proxy texture. 237 * \return GL_TRUE if any error, GL_FALSE otherwise. 238 */ 239static GLboolean 240tex_storage_error_check(struct gl_context *ctx, GLuint dims, GLenum target, 241 GLsizei levels, GLenum internalformat, 242 GLsizei width, GLsizei height, GLsizei depth) 243{ 244 const GLboolean isProxy = _mesa_is_proxy_texture(target); 245 struct gl_texture_object *texObj; 246 GLuint maxDim; 247 248 /* size check */ 249 if (width < 1 || height < 1 || depth < 1) { 250 if (!isProxy) { 251 _mesa_error(ctx, GL_INVALID_VALUE, 252 "glTexStorage%uD(width, height or depth < 1)", dims); 253 } 254 return GL_TRUE; 255 } 256 257 /* levels check */ 258 if (levels < 1 || height < 1 || depth < 1) { 259 if (!isProxy) { 260 _mesa_error(ctx, GL_INVALID_VALUE, "glTexStorage%uD(levels < 1)", 261 dims); 262 } 263 return GL_TRUE; 264 } 265 266 /* target check */ 267 if (!legal_texobj_target(ctx, dims, target)) { 268 _mesa_error(ctx, GL_INVALID_ENUM, 269 "glTexStorage%uD(illegal target=%s)", 270 dims, _mesa_lookup_enum_by_nr(target)); 271 return GL_TRUE; 272 } 273 274 /* check levels against maximum */ 275 if (levels > _mesa_max_texture_levels(ctx, target)) { 276 if (!isProxy) { 277 _mesa_error(ctx, GL_INVALID_OPERATION, 278 "glTexStorage%uD(levels too large)", dims); 279 } 280 return GL_TRUE; 281 } 282 283 /* check levels against width/height/depth */ 284 maxDim = MAX3(width, height, depth); 285 if (levels > _mesa_logbase2(maxDim) + 1) { 286 if (!isProxy) { 287 _mesa_error(ctx, GL_INVALID_OPERATION, 288 "glTexStorage%uD(too many levels for max texture dimension)", 289 dims); 290 } 291 return GL_TRUE; 292 } 293 294 /* non-default texture object check */ 295 texObj = _mesa_get_current_tex_object(ctx, target); 296 if (!texObj || (texObj->Name == 0 && !isProxy)) { 297 if (!isProxy) { 298 _mesa_error(ctx, GL_INVALID_OPERATION, 299 "glTexStorage%uD(texture object 0)", dims); 300 } 301 return GL_TRUE; 302 } 303 304 /* Check if texObj->Immutable is set */ 305 if (texObj->Immutable) { 306 if (!isProxy) { 307 _mesa_error(ctx, GL_INVALID_OPERATION, "glTexStorage%uD(immutable)", 308 dims); 309 } 310 return GL_TRUE; 311 } 312 313 return GL_FALSE; 314} 315 316 317/** 318 * Helper used by _mesa_TexStorage1/2/3D(). 319 */ 320static void 321texstorage(GLuint dims, GLenum target, GLsizei levels, GLenum internalformat, 322 GLsizei width, GLsizei height, GLsizei depth) 323{ 324 struct gl_texture_object *texObj; 325 GLboolean error; 326 327 GET_CURRENT_CONTEXT(ctx); 328 329 texObj = _mesa_get_current_tex_object(ctx, target); 330 331 error = tex_storage_error_check(ctx, dims, target, levels, 332 internalformat, width, height, depth); 333 if (!error) { 334 setup_texstorage(ctx, texObj, dims, levels, internalformat, 335 width, height, depth); 336 } 337 else if (_mesa_is_proxy_texture(target)) { 338 /* clear all image fields for [levels] */ 339 clear_image_fields(ctx, dims, texObj); 340 } 341} 342 343 344void GLAPIENTRY 345_mesa_TexStorage1D(GLenum target, GLsizei levels, GLenum internalformat, 346 GLsizei width) 347{ 348 texstorage(1, target, levels, internalformat, width, 1, 1); 349} 350 351 352void GLAPIENTRY 353_mesa_TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, 354 GLsizei width, GLsizei height) 355{ 356 texstorage(2, target, levels, internalformat, width, height, 1); 357} 358 359 360void GLAPIENTRY 361_mesa_TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, 362 GLsizei width, GLsizei height, GLsizei depth) 363{ 364 texstorage(3, target, levels, internalformat, width, height, depth); 365} 366 367 368 369/* 370 * Note: we don't support GL_EXT_direct_state_access and the spec says 371 * we don't need the following functions. However, glew checks for the 372 * presence of all six functions and will say that GL_ARB_texture_storage 373 * is not supported if these functions are missing. 374 */ 375 376 377void GLAPIENTRY 378_mesa_TextureStorage1DEXT(GLuint texture, GLenum target, GLsizei levels, 379 GLenum internalformat, 380 GLsizei width) 381{ 382 /* no-op */ 383} 384 385 386void GLAPIENTRY 387_mesa_TextureStorage2DEXT(GLuint texture, GLenum target, GLsizei levels, 388 GLenum internalformat, 389 GLsizei width, GLsizei height) 390{ 391 /* no-op */ 392} 393 394 395 396void GLAPIENTRY 397_mesa_TextureStorage3DEXT(GLuint texture, GLenum target, GLsizei levels, 398 GLenum internalformat, 399 GLsizei width, GLsizei height, GLsizei depth) 400{ 401 /* no-op */ 402} 403