Home | History | Annotate | Download | only in main
      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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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