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