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 "texobj.h"
40 #include "texstorage.h"
41 #include "mtypes.h"
42 
43 
44 
45 /**
46  * Check if the given texture target is a legal texture object target
47  * for a glTexStorage() command.
48  * This is a bit different than legal_teximage_target() when it comes
49  * to cube maps.
50  */
51 static GLboolean
legal_texobj_target(struct gl_context * ctx,GLuint dims,GLenum target)52 legal_texobj_target(struct gl_context *ctx, GLuint dims, GLenum target)
53 {
54    switch (dims) {
55    case 1:
56       switch (target) {
57       case GL_TEXTURE_1D:
58       case GL_PROXY_TEXTURE_1D:
59          return GL_TRUE;
60       default:
61          return GL_FALSE;
62       }
63    case 2:
64       switch (target) {
65       case GL_TEXTURE_2D:
66       case GL_PROXY_TEXTURE_2D:
67          return GL_TRUE;
68       case GL_TEXTURE_CUBE_MAP:
69       case GL_PROXY_TEXTURE_CUBE_MAP:
70          return ctx->Extensions.ARB_texture_cube_map;
71       case GL_TEXTURE_RECTANGLE:
72       case GL_PROXY_TEXTURE_RECTANGLE:
73          return ctx->Extensions.NV_texture_rectangle;
74       case GL_TEXTURE_1D_ARRAY:
75       case GL_PROXY_TEXTURE_1D_ARRAY:
76          return (ctx->Extensions.MESA_texture_array ||
77                  ctx->Extensions.EXT_texture_array);
78       default:
79          return GL_FALSE;
80       }
81    case 3:
82       switch (target) {
83       case GL_TEXTURE_3D:
84       case GL_PROXY_TEXTURE_3D:
85          return GL_TRUE;
86       case GL_TEXTURE_2D_ARRAY:
87       case GL_PROXY_TEXTURE_2D_ARRAY:
88          return (ctx->Extensions.MESA_texture_array ||
89                  ctx->Extensions.EXT_texture_array);
90       default:
91          return GL_FALSE;
92       }
93    default:
94       _mesa_problem(ctx, "invalid dims=%u in legal_texobj_target()", dims);
95       return GL_FALSE;
96    }
97 }
98 
99 
100 /**
101  * Compute the size of the next mipmap level.
102  */
103 static void
next_mipmap_level_size(GLenum target,GLint * width,GLint * height,GLint * depth)104 next_mipmap_level_size(GLenum target,
105                        GLint *width, GLint *height, GLint *depth)
106 {
107    if (*width > 1) {
108       *width /= 2;
109    }
110 
111    if ((*height > 1) && (target != GL_TEXTURE_1D_ARRAY)) {
112       *height /= 2;
113    }
114 
115    if ((*depth > 1) && (target != GL_TEXTURE_2D_ARRAY)) {
116       *depth /= 2;
117    }
118 }
119 
120 
121 /**
122  * Do actual memory allocation for glTexStorage1/2/3D().
123  */
124 static void
setup_texstorage(struct gl_context * ctx,struct gl_texture_object * texObj,GLuint dims,GLsizei levels,GLenum internalFormat,GLsizei width,GLsizei height,GLsizei depth)125 setup_texstorage(struct gl_context *ctx,
126                  struct gl_texture_object *texObj,
127                  GLuint dims,
128                  GLsizei levels, GLenum internalFormat,
129                  GLsizei width, GLsizei height, GLsizei depth)
130 {
131    const GLenum target = texObj->Target;
132    const GLuint numFaces = _mesa_num_tex_faces(target);
133    gl_format texFormat;
134    GLint level, levelWidth = width, levelHeight = height, levelDepth = depth;
135    GLuint face;
136 
137    assert(levels > 0);
138    assert(width > 0);
139    assert(height > 0);
140    assert(depth > 0);
141 
142    texFormat = _mesa_choose_texture_format(ctx, texObj, target, 0,
143                                            internalFormat, GL_NONE, GL_NONE);
144 
145    /* Set up all the texture object's gl_texture_images */
146    for (level = 0; level < levels; level++) {
147       for (face = 0; face < numFaces; face++) {
148          const GLenum faceTarget =
149             (target == GL_TEXTURE_CUBE_MAP)
150             ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + face : target;
151          struct gl_texture_image *texImage =
152             _mesa_get_tex_image(ctx, texObj, faceTarget, level);
153 
154 	 if (!texImage) {
155 	    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage%uD", dims);
156             return;
157 	 }
158 
159          _mesa_init_teximage_fields(ctx, texImage,
160                                     levelWidth, levelHeight, levelDepth,
161                                     0, internalFormat, texFormat);
162       }
163 
164       next_mipmap_level_size(target, &levelWidth, &levelHeight, &levelDepth);
165    }
166 
167    assert(levelWidth > 0);
168    assert(levelHeight > 0);
169    assert(levelDepth > 0);
170 
171    if (!_mesa_is_proxy_texture(texObj->Target)) {
172       /* Do actual texture memory allocation */
173       if (!ctx->Driver.AllocTextureStorage(ctx, texObj, levels,
174                                            width, height, depth)) {
175          /* Reset the texture images' info to zeros.
176           * Strictly speaking, we probably don't have to do this since
177           * generating GL_OUT_OF_MEMORY can leave things in an undefined
178           * state but this puts things in a consistent state.
179           */
180          for (level = 0; level < levels; level++) {
181             for (face = 0; face < numFaces; face++) {
182                struct gl_texture_image *texImage = texObj->Image[face][level];
183                if (texImage) {
184                   _mesa_init_teximage_fields(ctx, texImage,
185                                              0, 0, 0, 0,
186                                              GL_NONE, MESA_FORMAT_NONE);
187                }
188             }
189          }
190 
191          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexStorage%uD", dims);
192 
193          return;
194       }
195 
196       /* Only set this field for non-proxy texture objects */
197       texObj->Immutable = GL_TRUE;
198    }
199 }
200 
201 
202 /**
203  * Clear all fields of texture object to zeros.  Used for proxy texture tests.
204  */
205 static void
clear_image_fields(struct gl_context * ctx,GLuint dims,struct gl_texture_object * texObj)206 clear_image_fields(struct gl_context *ctx,
207                    GLuint dims,
208                    struct gl_texture_object *texObj)
209 {
210    const GLenum target = texObj->Target;
211    const GLuint numFaces = _mesa_num_tex_faces(target);
212    GLint level;
213    GLuint face;
214 
215    for (level = 0; level < Elements(texObj->Image[0]); level++) {
216       for (face = 0; face < numFaces; face++) {
217          const GLenum faceTarget =
218             (target == GL_TEXTURE_CUBE_MAP)
219             ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + face : target;
220          struct gl_texture_image *texImage =
221             _mesa_get_tex_image(ctx, texObj, faceTarget, level);
222 
223 	 if (!texImage) {
224 	    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexStorage%uD", dims);
225             return;
226 	 }
227 
228          _mesa_init_teximage_fields(ctx, texImage,
229                                     0, 0, 0, 0, GL_NONE, MESA_FORMAT_NONE);
230       }
231    }
232 }
233 
234 
235 /**
236  * Do error checking for calls to glTexStorage1/2/3D().
237  * If an error is found, record it with _mesa_error(), unless the target
238  * is a proxy texture.
239  * \return GL_TRUE if any error, GL_FALSE otherwise.
240  */
241 static GLboolean
tex_storage_error_check(struct gl_context * ctx,GLuint dims,GLenum target,GLsizei levels,GLenum internalformat,GLsizei width,GLsizei height,GLsizei depth)242 tex_storage_error_check(struct gl_context *ctx, GLuint dims, GLenum target,
243                         GLsizei levels, GLenum internalformat,
244                         GLsizei width, GLsizei height, GLsizei depth)
245 {
246    struct gl_texture_object *texObj;
247    GLboolean legalFormat;
248 
249    /* check internal format - note that only sized formats are allowed */
250    switch (internalformat) {
251    case GL_ALPHA:
252    case GL_LUMINANCE:
253    case GL_LUMINANCE_ALPHA:
254    case GL_INTENSITY:
255    case GL_RED:
256    case GL_RG:
257    case GL_RGB:
258    case GL_RGBA:
259    case GL_BGRA:
260    case GL_DEPTH_COMPONENT:
261    case GL_DEPTH_STENCIL:
262    case GL_COMPRESSED_ALPHA:
263    case GL_COMPRESSED_LUMINANCE_ALPHA:
264    case GL_COMPRESSED_LUMINANCE:
265    case GL_COMPRESSED_INTENSITY:
266    case GL_COMPRESSED_RGB:
267    case GL_COMPRESSED_RGBA:
268    case GL_COMPRESSED_SRGB:
269    case GL_COMPRESSED_SRGB_ALPHA:
270    case GL_COMPRESSED_SLUMINANCE:
271    case GL_COMPRESSED_SLUMINANCE_ALPHA:
272    case GL_RED_INTEGER:
273    case GL_GREEN_INTEGER:
274    case GL_BLUE_INTEGER:
275    case GL_ALPHA_INTEGER:
276    case GL_RGB_INTEGER:
277    case GL_RGBA_INTEGER:
278    case GL_BGR_INTEGER:
279    case GL_BGRA_INTEGER:
280    case GL_LUMINANCE_INTEGER_EXT:
281    case GL_LUMINANCE_ALPHA_INTEGER_EXT:
282       /* these unsized formats are illegal */
283       legalFormat = GL_FALSE;
284       break;
285    default:
286       legalFormat = _mesa_base_tex_format(ctx, internalformat) > 0;
287    }
288 
289    if (!legalFormat) {
290       _mesa_error(ctx, GL_INVALID_ENUM,
291                   "glTexStorage%uD(internalformat = %s)", dims,
292                   _mesa_lookup_enum_by_nr(internalformat));
293       return GL_TRUE;
294    }
295 
296    /* size check */
297    if (width < 1 || height < 1 || depth < 1) {
298       _mesa_error(ctx, GL_INVALID_VALUE,
299                   "glTexStorage%uD(width, height or depth < 1)", dims);
300       return GL_TRUE;
301    }
302 
303    /* levels check */
304    if (levels < 1 || height < 1 || depth < 1) {
305       _mesa_error(ctx, GL_INVALID_VALUE, "glTexStorage%uD(levels < 1)",
306                   dims);
307       return GL_TRUE;
308    }
309 
310    /* target check */
311    if (!legal_texobj_target(ctx, dims, target)) {
312       _mesa_error(ctx, GL_INVALID_ENUM,
313                   "glTexStorage%uD(illegal target=%s)",
314                   dims, _mesa_lookup_enum_by_nr(target));
315       return GL_TRUE;
316    }
317 
318    /* check levels against maximum */
319    if (levels > _mesa_max_texture_levels(ctx, target)) {
320       _mesa_error(ctx, GL_INVALID_OPERATION,
321                   "glTexStorage%uD(levels too large)", dims);
322       return GL_TRUE;
323    }
324 
325    /* check levels against width/height/depth */
326    if (levels > _mesa_get_tex_max_num_levels(target, width, height, depth)) {
327       _mesa_error(ctx, GL_INVALID_OPERATION,
328                   "glTexStorage%uD(too many levels for max texture dimension)",
329                   dims);
330       return GL_TRUE;
331    }
332 
333    /* non-default texture object check */
334    texObj = _mesa_get_current_tex_object(ctx, target);
335    if (!texObj || (texObj->Name == 0)) {
336       _mesa_error(ctx, GL_INVALID_OPERATION,
337                   "glTexStorage%uD(texture object 0)", dims);
338       return GL_TRUE;
339    }
340 
341    /* Check if texObj->Immutable is set */
342    if (texObj->Immutable) {
343       _mesa_error(ctx, GL_INVALID_OPERATION, "glTexStorage%uD(immutable)",
344                   dims);
345       return GL_TRUE;
346    }
347 
348    return GL_FALSE;
349 }
350 
351 
352 /**
353  * Helper used by _mesa_TexStorage1/2/3D().
354  */
355 static void
texstorage(GLuint dims,GLenum target,GLsizei levels,GLenum internalformat,GLsizei width,GLsizei height,GLsizei depth)356 texstorage(GLuint dims, GLenum target, GLsizei levels, GLenum internalformat,
357            GLsizei width, GLsizei height, GLsizei depth)
358 {
359    struct gl_texture_object *texObj;
360    GLboolean sizeOK;
361    GLenum proxyTarget = _mesa_get_proxy_target(target);
362 
363    GET_CURRENT_CONTEXT(ctx);
364 
365    texObj = _mesa_get_current_tex_object(ctx, target);
366 
367    if (tex_storage_error_check(ctx, dims, target, levels,
368                                internalformat, width, height, depth)) {
369       return; /* error was recorded */
370    }
371 
372    sizeOK = ctx->Driver.TestProxyTexImage(ctx, proxyTarget, 0,
373                                           internalformat, GL_NONE, GL_NONE,
374                                           width, height, depth, 0);
375 
376    if (!sizeOK) {
377       if (_mesa_is_proxy_texture(texObj->Target)) {
378          /* clear all image fields for [levels] */
379          clear_image_fields(ctx, dims, texObj);
380       }
381       else {
382          _mesa_error(ctx, GL_INVALID_VALUE,
383                      "glTexStorage%uD(invalid width, height or depth)",
384                      dims);
385          return;
386       }
387    }
388    else {
389       setup_texstorage(ctx, texObj, dims, levels, internalformat,
390                        width, height, depth);
391    }
392 }
393 
394 
395 void GLAPIENTRY
_mesa_TexStorage1D(GLenum target,GLsizei levels,GLenum internalformat,GLsizei width)396 _mesa_TexStorage1D(GLenum target, GLsizei levels, GLenum internalformat,
397                    GLsizei width)
398 {
399    texstorage(1, target, levels, internalformat, width, 1, 1);
400 }
401 
402 
403 void GLAPIENTRY
_mesa_TexStorage2D(GLenum target,GLsizei levels,GLenum internalformat,GLsizei width,GLsizei height)404 _mesa_TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat,
405                    GLsizei width, GLsizei height)
406 {
407    texstorage(2, target, levels, internalformat, width, height, 1);
408 }
409 
410 
411 void GLAPIENTRY
_mesa_TexStorage3D(GLenum target,GLsizei levels,GLenum internalformat,GLsizei width,GLsizei height,GLsizei depth)412 _mesa_TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat,
413                    GLsizei width, GLsizei height, GLsizei depth)
414 {
415    texstorage(3, target, levels, internalformat, width, height, depth);
416 }
417 
418 
419 
420 /*
421  * Note: we don't support GL_EXT_direct_state_access and the spec says
422  * we don't need the following functions.  However, glew checks for the
423  * presence of all six functions and will say that GL_ARB_texture_storage
424  * is not supported if these functions are missing.
425  */
426 
427 
428 void GLAPIENTRY
_mesa_TextureStorage1DEXT(GLuint texture,GLenum target,GLsizei levels,GLenum internalformat,GLsizei width)429 _mesa_TextureStorage1DEXT(GLuint texture, GLenum target, GLsizei levels,
430                           GLenum internalformat,
431                           GLsizei width)
432 {
433    /* no-op */
434 }
435 
436 
437 void GLAPIENTRY
_mesa_TextureStorage2DEXT(GLuint texture,GLenum target,GLsizei levels,GLenum internalformat,GLsizei width,GLsizei height)438 _mesa_TextureStorage2DEXT(GLuint texture, GLenum target, GLsizei levels,
439                           GLenum internalformat,
440                           GLsizei width, GLsizei height)
441 {
442    /* no-op */
443 }
444 
445 
446 
447 void GLAPIENTRY
_mesa_TextureStorage3DEXT(GLuint texture,GLenum target,GLsizei levels,GLenum internalformat,GLsizei width,GLsizei height,GLsizei depth)448 _mesa_TextureStorage3DEXT(GLuint texture, GLenum target, GLsizei levels,
449                           GLenum internalformat,
450                           GLsizei width, GLsizei height, GLsizei depth)
451 {
452    /* no-op */
453 }
454