1af69d88dSmrg/* 2af69d88dSmrg * Mesa 3-D graphics library 3af69d88dSmrg * 4af69d88dSmrg * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 5af69d88dSmrg * Copyright (C) 1999-2013 VMware, Inc. All Rights Reserved. 6af69d88dSmrg * 7af69d88dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 8af69d88dSmrg * copy of this software and associated documentation files (the "Software"), 9af69d88dSmrg * to deal in the Software without restriction, including without limitation 10af69d88dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11af69d88dSmrg * and/or sell copies of the Software, and to permit persons to whom the 12af69d88dSmrg * Software is furnished to do so, subject to the following conditions: 13af69d88dSmrg * 14af69d88dSmrg * The above copyright notice and this permission notice shall be included 15af69d88dSmrg * in all copies or substantial portions of the Software. 16af69d88dSmrg * 17af69d88dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18af69d88dSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19af69d88dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE. 24af69d88dSmrg */ 25af69d88dSmrg 26af69d88dSmrg 27af69d88dSmrg/* 28af69d88dSmrg * glGenerateMipmap function 29af69d88dSmrg */ 30af69d88dSmrg 31af69d88dSmrg#include "context.h" 32af69d88dSmrg#include "enums.h" 33af69d88dSmrg#include "genmipmap.h" 34af69d88dSmrg#include "glformats.h" 35af69d88dSmrg#include "macros.h" 36af69d88dSmrg#include "mtypes.h" 37af69d88dSmrg#include "teximage.h" 38af69d88dSmrg#include "texobj.h" 3901e04c3fSmrg#include "hash.h" 40af69d88dSmrg 4101e04c3fSmrgbool 4201e04c3fSmrg_mesa_is_valid_generate_texture_mipmap_target(struct gl_context *ctx, 4301e04c3fSmrg GLenum target) 44af69d88dSmrg{ 4501e04c3fSmrg bool error; 46af69d88dSmrg 47af69d88dSmrg switch (target) { 48af69d88dSmrg case GL_TEXTURE_1D: 49af69d88dSmrg error = _mesa_is_gles(ctx); 50af69d88dSmrg break; 51af69d88dSmrg case GL_TEXTURE_2D: 5201e04c3fSmrg error = false; 53af69d88dSmrg break; 54af69d88dSmrg case GL_TEXTURE_3D: 55af69d88dSmrg error = ctx->API == API_OPENGLES; 56af69d88dSmrg break; 57af69d88dSmrg case GL_TEXTURE_CUBE_MAP: 58af69d88dSmrg error = !ctx->Extensions.ARB_texture_cube_map; 59af69d88dSmrg break; 60af69d88dSmrg case GL_TEXTURE_1D_ARRAY: 61af69d88dSmrg error = _mesa_is_gles(ctx) || !ctx->Extensions.EXT_texture_array; 62af69d88dSmrg break; 63af69d88dSmrg case GL_TEXTURE_2D_ARRAY: 64af69d88dSmrg error = (_mesa_is_gles(ctx) && ctx->Version < 30) 65af69d88dSmrg || !ctx->Extensions.EXT_texture_array; 66af69d88dSmrg break; 67af69d88dSmrg case GL_TEXTURE_CUBE_MAP_ARRAY: 6801e04c3fSmrg error = !_mesa_has_texture_cube_map_array(ctx); 69af69d88dSmrg break; 70af69d88dSmrg default: 7101e04c3fSmrg error = true; 72af69d88dSmrg } 73af69d88dSmrg 7401e04c3fSmrg return !error; 7501e04c3fSmrg} 7601e04c3fSmrg 7701e04c3fSmrgbool 7801e04c3fSmrg_mesa_is_valid_generate_texture_mipmap_internalformat(struct gl_context *ctx, 7901e04c3fSmrg GLenum internalformat) 8001e04c3fSmrg{ 8101e04c3fSmrg if (_mesa_is_gles3(ctx)) { 8201e04c3fSmrg /* From the ES 3.2 specification's description of GenerateMipmap(): 8301e04c3fSmrg * "An INVALID_OPERATION error is generated if the levelbase array was 8401e04c3fSmrg * not specified with an unsized internal format from table 8.3 or a 8501e04c3fSmrg * sized internal format that is both color-renderable and 8601e04c3fSmrg * texture-filterable according to table 8.10." 8701e04c3fSmrg * 8801e04c3fSmrg * GL_EXT_texture_format_BGRA8888 adds a GL_BGRA_EXT unsized internal 8901e04c3fSmrg * format, and includes it in a very similar looking table. So we 9001e04c3fSmrg * include it here as well. 9101e04c3fSmrg */ 9201e04c3fSmrg return internalformat == GL_RGBA || internalformat == GL_RGB || 9301e04c3fSmrg internalformat == GL_LUMINANCE_ALPHA || 9401e04c3fSmrg internalformat == GL_LUMINANCE || internalformat == GL_ALPHA || 9501e04c3fSmrg internalformat == GL_BGRA_EXT || 9601e04c3fSmrg (_mesa_is_es3_color_renderable(ctx, internalformat) && 9701e04c3fSmrg _mesa_is_es3_texture_filterable(ctx, internalformat)); 98af69d88dSmrg } 99af69d88dSmrg 10001e04c3fSmrg return (!_mesa_is_enum_format_integer(internalformat) && 10101e04c3fSmrg !_mesa_is_depthstencil_format(internalformat) && 10201e04c3fSmrg !_mesa_is_astc_format(internalformat) && 10301e04c3fSmrg !_mesa_is_stencil_format(internalformat)); 10401e04c3fSmrg} 10501e04c3fSmrg 10601e04c3fSmrg/** 10701e04c3fSmrg * Implements glGenerateMipmap and glGenerateTextureMipmap. 10801e04c3fSmrg * Generates all the mipmap levels below the base level. 1097ec681f3Smrg * Error-checking is done only if caller is not NULL. 11001e04c3fSmrg */ 11101e04c3fSmrgstatic ALWAYS_INLINE void 11201e04c3fSmrggenerate_texture_mipmap(struct gl_context *ctx, 11301e04c3fSmrg struct gl_texture_object *texObj, GLenum target, 1147ec681f3Smrg const char* caller) 11501e04c3fSmrg{ 11601e04c3fSmrg struct gl_texture_image *srcImage; 11701e04c3fSmrg 1187ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 119af69d88dSmrg 1207ec681f3Smrg if (texObj->Attrib.BaseLevel >= texObj->Attrib.MaxLevel) { 121af69d88dSmrg /* nothing to do */ 122af69d88dSmrg return; 123af69d88dSmrg } 124af69d88dSmrg 1257ec681f3Smrg if (caller && texObj->Target == GL_TEXTURE_CUBE_MAP && 126af69d88dSmrg !_mesa_cube_complete(texObj)) { 127af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 1287ec681f3Smrg "%s(incomplete cube map)", caller); 129af69d88dSmrg return; 130af69d88dSmrg } 131af69d88dSmrg 132af69d88dSmrg _mesa_lock_texture(ctx, texObj); 133af69d88dSmrg 1347ec681f3Smrg texObj->External = GL_FALSE; 1357ec681f3Smrg 1367ec681f3Smrg srcImage = _mesa_select_tex_image(texObj, target, texObj->Attrib.BaseLevel); 1377ec681f3Smrg if (caller) { 13801e04c3fSmrg if (!srcImage) { 13901e04c3fSmrg _mesa_unlock_texture(ctx, texObj); 14001e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 1417ec681f3Smrg "%s(zero size base image)", caller); 14201e04c3fSmrg return; 14301e04c3fSmrg } 14401e04c3fSmrg 14501e04c3fSmrg if (!_mesa_is_valid_generate_texture_mipmap_internalformat(ctx, 14601e04c3fSmrg srcImage->InternalFormat)) { 14701e04c3fSmrg _mesa_unlock_texture(ctx, texObj); 14801e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 1497ec681f3Smrg "%s(invalid internal format %s)", caller, 15001e04c3fSmrg _mesa_enum_to_string(srcImage->InternalFormat)); 15101e04c3fSmrg return; 15201e04c3fSmrg } 1537ec681f3Smrg 1547ec681f3Smrg /* The GLES 2.0 spec says: 1557ec681f3Smrg * 1567ec681f3Smrg * "If the level zero array is stored in a compressed internal format, 1577ec681f3Smrg * the error INVALID_OPERATION is generated." 1587ec681f3Smrg * 1597ec681f3Smrg * and this text is gone from the GLES 3.0 spec. 1607ec681f3Smrg */ 1617ec681f3Smrg if (ctx->API == API_OPENGLES2 && ctx->Version < 30 && 1627ec681f3Smrg _mesa_is_format_compressed(srcImage->TexFormat)) { 1637ec681f3Smrg _mesa_unlock_texture(ctx, texObj); 1647ec681f3Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "generate mipmaps on compressed texture"); 1657ec681f3Smrg return; 1667ec681f3Smrg } 167af69d88dSmrg } 168af69d88dSmrg 16901e04c3fSmrg if (srcImage->Width == 0 || srcImage->Height == 0) { 170af69d88dSmrg _mesa_unlock_texture(ctx, texObj); 171af69d88dSmrg return; 172af69d88dSmrg } 173af69d88dSmrg 174af69d88dSmrg if (target == GL_TEXTURE_CUBE_MAP) { 175af69d88dSmrg GLuint face; 17601e04c3fSmrg for (face = 0; face < 6; face++) { 17701e04c3fSmrg ctx->Driver.GenerateMipmap(ctx, 17801e04c3fSmrg GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, texObj); 17901e04c3fSmrg } 180af69d88dSmrg } 181af69d88dSmrg else { 182af69d88dSmrg ctx->Driver.GenerateMipmap(ctx, target, texObj); 183af69d88dSmrg } 184af69d88dSmrg _mesa_unlock_texture(ctx, texObj); 185af69d88dSmrg} 18601e04c3fSmrg 18701e04c3fSmrg/** 18801e04c3fSmrg * Generate all the mipmap levels below the base level. 18901e04c3fSmrg * Note: this GL function would be more useful if one could specify a 19001e04c3fSmrg * cube face, a set of array slices, etc. 19101e04c3fSmrg */ 19201e04c3fSmrgvoid GLAPIENTRY 19301e04c3fSmrg_mesa_GenerateMipmap_no_error(GLenum target) 19401e04c3fSmrg{ 19501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 19601e04c3fSmrg 19701e04c3fSmrg struct gl_texture_object *texObj = _mesa_get_current_tex_object(ctx, target); 1987ec681f3Smrg generate_texture_mipmap(ctx, texObj, target, NULL); 19901e04c3fSmrg} 20001e04c3fSmrg 20101e04c3fSmrgvoid GLAPIENTRY 20201e04c3fSmrg_mesa_GenerateMipmap(GLenum target) 20301e04c3fSmrg{ 20401e04c3fSmrg struct gl_texture_object *texObj; 20501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 20601e04c3fSmrg 20701e04c3fSmrg if (!_mesa_is_valid_generate_texture_mipmap_target(ctx, target)) { 20801e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmap(target=%s)", 20901e04c3fSmrg _mesa_enum_to_string(target)); 21001e04c3fSmrg return; 21101e04c3fSmrg } 21201e04c3fSmrg 21301e04c3fSmrg texObj = _mesa_get_current_tex_object(ctx, target); 21401e04c3fSmrg if (!texObj) 21501e04c3fSmrg return; 21601e04c3fSmrg 2177ec681f3Smrg generate_texture_mipmap(ctx, texObj, target, "glGenerateMipmap"); 21801e04c3fSmrg} 21901e04c3fSmrg 22001e04c3fSmrg/** 22101e04c3fSmrg * Generate all the mipmap levels below the base level. 22201e04c3fSmrg */ 22301e04c3fSmrgvoid GLAPIENTRY 22401e04c3fSmrg_mesa_GenerateTextureMipmap_no_error(GLuint texture) 22501e04c3fSmrg{ 22601e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 22701e04c3fSmrg 22801e04c3fSmrg struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, texture); 2297ec681f3Smrg generate_texture_mipmap(ctx, texObj, texObj->Target, NULL); 23001e04c3fSmrg} 23101e04c3fSmrg 2327ec681f3Smrgstatic void 2337ec681f3Smrgvalidate_params_and_generate_mipmap(struct gl_texture_object *texObj, const char* caller) 23401e04c3fSmrg{ 23501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 23601e04c3fSmrg 23701e04c3fSmrg if (!texObj) 23801e04c3fSmrg return; 23901e04c3fSmrg 24001e04c3fSmrg if (!_mesa_is_valid_generate_texture_mipmap_target(ctx, texObj->Target)) { 2417ec681f3Smrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(target=%s)", 2427ec681f3Smrg caller, 24301e04c3fSmrg _mesa_enum_to_string(texObj->Target)); 24401e04c3fSmrg return; 24501e04c3fSmrg } 24601e04c3fSmrg 2477ec681f3Smrg generate_texture_mipmap(ctx, texObj, texObj->Target, caller); 2487ec681f3Smrg} 2497ec681f3Smrg 2507ec681f3Smrgvoid GLAPIENTRY 2517ec681f3Smrg_mesa_GenerateTextureMipmap(GLuint texture) 2527ec681f3Smrg{ 2537ec681f3Smrg struct gl_texture_object *texObj; 2547ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 2557ec681f3Smrg 2567ec681f3Smrg texObj = _mesa_lookup_texture_err(ctx, texture, "glGenerateTextureMipmap"); 2577ec681f3Smrg validate_params_and_generate_mipmap(texObj, "glGenerateTextureMipmap"); 2587ec681f3Smrg} 2597ec681f3Smrg 2607ec681f3Smrgvoid GLAPIENTRY 2617ec681f3Smrg_mesa_GenerateTextureMipmapEXT(GLuint texture, GLenum target) 2627ec681f3Smrg{ 2637ec681f3Smrg struct gl_texture_object *texObj; 2647ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 2657ec681f3Smrg 2667ec681f3Smrg texObj = _mesa_lookup_or_create_texture(ctx, target, texture, 2677ec681f3Smrg false, true, 2687ec681f3Smrg "glGenerateTextureMipmapEXT"); 2697ec681f3Smrg validate_params_and_generate_mipmap(texObj, 2707ec681f3Smrg "glGenerateTextureMipmapEXT"); 2717ec681f3Smrg} 2727ec681f3Smrg 2737ec681f3Smrgvoid GLAPIENTRY 2747ec681f3Smrg_mesa_GenerateMultiTexMipmapEXT(GLenum texunit, GLenum target) 2757ec681f3Smrg{ 2767ec681f3Smrg struct gl_texture_object *texObj; 2777ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 2787ec681f3Smrg 2797ec681f3Smrg texObj = _mesa_get_texobj_by_target_and_texunit(ctx, target, 2807ec681f3Smrg texunit - GL_TEXTURE0, 2817ec681f3Smrg true, 2827ec681f3Smrg "glGenerateMultiTexMipmapEXT"); 2837ec681f3Smrg validate_params_and_generate_mipmap(texObj, 2847ec681f3Smrg "glGenerateMultiTexMipmapEXT"); 28501e04c3fSmrg} 286