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