1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 5 * Copyright (C) 1999-2013 VMware, Inc. All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 * OTHER DEALINGS IN THE SOFTWARE. 24 */ 25 26 27/* 28 * glGenerateMipmap function 29 */ 30 31#include "context.h" 32#include "enums.h" 33#include "genmipmap.h" 34#include "glformats.h" 35#include "macros.h" 36#include "mtypes.h" 37#include "teximage.h" 38#include "texobj.h" 39#include "hash.h" 40 41bool 42_mesa_is_valid_generate_texture_mipmap_target(struct gl_context *ctx, 43 GLenum target) 44{ 45 bool error; 46 47 switch (target) { 48 case GL_TEXTURE_1D: 49 error = _mesa_is_gles(ctx); 50 break; 51 case GL_TEXTURE_2D: 52 error = false; 53 break; 54 case GL_TEXTURE_3D: 55 error = ctx->API == API_OPENGLES; 56 break; 57 case GL_TEXTURE_CUBE_MAP: 58 error = !ctx->Extensions.ARB_texture_cube_map; 59 break; 60 case GL_TEXTURE_1D_ARRAY: 61 error = _mesa_is_gles(ctx) || !ctx->Extensions.EXT_texture_array; 62 break; 63 case GL_TEXTURE_2D_ARRAY: 64 error = (_mesa_is_gles(ctx) && ctx->Version < 30) 65 || !ctx->Extensions.EXT_texture_array; 66 break; 67 case GL_TEXTURE_CUBE_MAP_ARRAY: 68 error = !_mesa_has_texture_cube_map_array(ctx); 69 break; 70 default: 71 error = true; 72 } 73 74 return !error; 75} 76 77bool 78_mesa_is_valid_generate_texture_mipmap_internalformat(struct gl_context *ctx, 79 GLenum internalformat) 80{ 81 if (_mesa_is_gles3(ctx)) { 82 /* From the ES 3.2 specification's description of GenerateMipmap(): 83 * "An INVALID_OPERATION error is generated if the levelbase array was 84 * not specified with an unsized internal format from table 8.3 or a 85 * sized internal format that is both color-renderable and 86 * texture-filterable according to table 8.10." 87 * 88 * GL_EXT_texture_format_BGRA8888 adds a GL_BGRA_EXT unsized internal 89 * format, and includes it in a very similar looking table. So we 90 * include it here as well. 91 */ 92 return internalformat == GL_RGBA || internalformat == GL_RGB || 93 internalformat == GL_LUMINANCE_ALPHA || 94 internalformat == GL_LUMINANCE || internalformat == GL_ALPHA || 95 internalformat == GL_BGRA_EXT || 96 (_mesa_is_es3_color_renderable(ctx, internalformat) && 97 _mesa_is_es3_texture_filterable(ctx, internalformat)); 98 } 99 100 return (!_mesa_is_enum_format_integer(internalformat) && 101 !_mesa_is_depthstencil_format(internalformat) && 102 !_mesa_is_astc_format(internalformat) && 103 !_mesa_is_stencil_format(internalformat)); 104} 105 106/** 107 * Implements glGenerateMipmap and glGenerateTextureMipmap. 108 * Generates all the mipmap levels below the base level. 109 * Error-checking is done only if caller is not NULL. 110 */ 111static ALWAYS_INLINE void 112generate_texture_mipmap(struct gl_context *ctx, 113 struct gl_texture_object *texObj, GLenum target, 114 const char* caller) 115{ 116 struct gl_texture_image *srcImage; 117 118 FLUSH_VERTICES(ctx, 0, 0); 119 120 if (texObj->Attrib.BaseLevel >= texObj->Attrib.MaxLevel) { 121 /* nothing to do */ 122 return; 123 } 124 125 if (caller && texObj->Target == GL_TEXTURE_CUBE_MAP && 126 !_mesa_cube_complete(texObj)) { 127 _mesa_error(ctx, GL_INVALID_OPERATION, 128 "%s(incomplete cube map)", caller); 129 return; 130 } 131 132 _mesa_lock_texture(ctx, texObj); 133 134 texObj->External = GL_FALSE; 135 136 srcImage = _mesa_select_tex_image(texObj, target, texObj->Attrib.BaseLevel); 137 if (caller) { 138 if (!srcImage) { 139 _mesa_unlock_texture(ctx, texObj); 140 _mesa_error(ctx, GL_INVALID_OPERATION, 141 "%s(zero size base image)", caller); 142 return; 143 } 144 145 if (!_mesa_is_valid_generate_texture_mipmap_internalformat(ctx, 146 srcImage->InternalFormat)) { 147 _mesa_unlock_texture(ctx, texObj); 148 _mesa_error(ctx, GL_INVALID_OPERATION, 149 "%s(invalid internal format %s)", caller, 150 _mesa_enum_to_string(srcImage->InternalFormat)); 151 return; 152 } 153 154 /* The GLES 2.0 spec says: 155 * 156 * "If the level zero array is stored in a compressed internal format, 157 * the error INVALID_OPERATION is generated." 158 * 159 * and this text is gone from the GLES 3.0 spec. 160 */ 161 if (ctx->API == API_OPENGLES2 && ctx->Version < 30 && 162 _mesa_is_format_compressed(srcImage->TexFormat)) { 163 _mesa_unlock_texture(ctx, texObj); 164 _mesa_error(ctx, GL_INVALID_OPERATION, "generate mipmaps on compressed texture"); 165 return; 166 } 167 } 168 169 if (srcImage->Width == 0 || srcImage->Height == 0) { 170 _mesa_unlock_texture(ctx, texObj); 171 return; 172 } 173 174 if (target == GL_TEXTURE_CUBE_MAP) { 175 GLuint face; 176 for (face = 0; face < 6; face++) { 177 ctx->Driver.GenerateMipmap(ctx, 178 GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, texObj); 179 } 180 } 181 else { 182 ctx->Driver.GenerateMipmap(ctx, target, texObj); 183 } 184 _mesa_unlock_texture(ctx, texObj); 185} 186 187/** 188 * Generate all the mipmap levels below the base level. 189 * Note: this GL function would be more useful if one could specify a 190 * cube face, a set of array slices, etc. 191 */ 192void GLAPIENTRY 193_mesa_GenerateMipmap_no_error(GLenum target) 194{ 195 GET_CURRENT_CONTEXT(ctx); 196 197 struct gl_texture_object *texObj = _mesa_get_current_tex_object(ctx, target); 198 generate_texture_mipmap(ctx, texObj, target, NULL); 199} 200 201void GLAPIENTRY 202_mesa_GenerateMipmap(GLenum target) 203{ 204 struct gl_texture_object *texObj; 205 GET_CURRENT_CONTEXT(ctx); 206 207 if (!_mesa_is_valid_generate_texture_mipmap_target(ctx, target)) { 208 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmap(target=%s)", 209 _mesa_enum_to_string(target)); 210 return; 211 } 212 213 texObj = _mesa_get_current_tex_object(ctx, target); 214 if (!texObj) 215 return; 216 217 generate_texture_mipmap(ctx, texObj, target, "glGenerateMipmap"); 218} 219 220/** 221 * Generate all the mipmap levels below the base level. 222 */ 223void GLAPIENTRY 224_mesa_GenerateTextureMipmap_no_error(GLuint texture) 225{ 226 GET_CURRENT_CONTEXT(ctx); 227 228 struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, texture); 229 generate_texture_mipmap(ctx, texObj, texObj->Target, NULL); 230} 231 232static void 233validate_params_and_generate_mipmap(struct gl_texture_object *texObj, const char* caller) 234{ 235 GET_CURRENT_CONTEXT(ctx); 236 237 if (!texObj) 238 return; 239 240 if (!_mesa_is_valid_generate_texture_mipmap_target(ctx, texObj->Target)) { 241 _mesa_error(ctx, GL_INVALID_ENUM, "%s(target=%s)", 242 caller, 243 _mesa_enum_to_string(texObj->Target)); 244 return; 245 } 246 247 generate_texture_mipmap(ctx, texObj, texObj->Target, caller); 248} 249 250void GLAPIENTRY 251_mesa_GenerateTextureMipmap(GLuint texture) 252{ 253 struct gl_texture_object *texObj; 254 GET_CURRENT_CONTEXT(ctx); 255 256 texObj = _mesa_lookup_texture_err(ctx, texture, "glGenerateTextureMipmap"); 257 validate_params_and_generate_mipmap(texObj, "glGenerateTextureMipmap"); 258} 259 260void GLAPIENTRY 261_mesa_GenerateTextureMipmapEXT(GLuint texture, GLenum target) 262{ 263 struct gl_texture_object *texObj; 264 GET_CURRENT_CONTEXT(ctx); 265 266 texObj = _mesa_lookup_or_create_texture(ctx, target, texture, 267 false, true, 268 "glGenerateTextureMipmapEXT"); 269 validate_params_and_generate_mipmap(texObj, 270 "glGenerateTextureMipmapEXT"); 271} 272 273void GLAPIENTRY 274_mesa_GenerateMultiTexMipmapEXT(GLenum texunit, GLenum target) 275{ 276 struct gl_texture_object *texObj; 277 GET_CURRENT_CONTEXT(ctx); 278 279 texObj = _mesa_get_texobj_by_target_and_texunit(ctx, target, 280 texunit - GL_TEXTURE0, 281 true, 282 "glGenerateMultiTexMipmapEXT"); 283 validate_params_and_generate_mipmap(texObj, 284 "glGenerateMultiTexMipmapEXT"); 285} 286