Ejemplo n.º 1
0
/**
 * glTextureView (ARB_texture_view)
 * If an error is found, record it with _mesa_error()
 * \return none.
 */
void GLAPIENTRY
_mesa_TextureView(GLuint texture, GLenum target, GLuint origtexture,
                  GLenum internalformat,
                  GLuint minlevel, GLuint numlevels,
                  GLuint minlayer, GLuint numlayers)
{
    struct gl_texture_object *texObj;
    struct gl_texture_object *origTexObj;
    struct gl_texture_image *origTexImage;
    GLuint newViewMinLevel, newViewMinLayer;
    GLuint newViewNumLevels, newViewNumLayers;
    GLsizei width, height, depth;
    mesa_format texFormat;
    GLboolean sizeOK, dimensionsOK;
    GLenum faceTarget;

    GET_CURRENT_CONTEXT(ctx);

    if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE))
        _mesa_debug(ctx, "glTextureView %d %s %d %s %d %d %d %d\n",
                    texture, _mesa_lookup_enum_by_nr(target), origtexture,
                    _mesa_lookup_enum_by_nr(internalformat),
                    minlevel, numlevels, minlayer, numlayers);

    if (origtexture == 0) {
        _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(origtexture = %u)", origtexture);
        return;
    }

    /* Need original texture information to validate arguments */
    origTexObj = _mesa_lookup_texture(ctx, origtexture);

    /* If <origtexture> is not the name of a texture, INVALID_VALUE is generated. */
    if (!origTexObj) {
        _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(origtexture = %u)", origtexture);
        return;
    }

    /* If <origtexture>'s TEXTURE_IMMUTABLE_FORMAT value is not TRUE,
     * INVALID_OPERATION is generated.
     */
    if (!origTexObj->Immutable) {
        _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(origtexture not immutable)");
        return;
    }

    /* If <texture> is 0, INVALID_VALUE is generated. */
    if (texture == 0) {
        _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(texture = 0)");
        return;
    }

    /* If <texture> is not a valid name returned by GenTextures,
     * the error INVALID_OPERATION is generated.
     */
    texObj = _mesa_lookup_texture(ctx, texture);
    if (texObj == NULL) {
        _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(texture = %u non-gen name)", texture);
        return;
    }

    /* If <texture> has already been bound and given a target, then
     * the error INVALID_OPERATION is generated.
     */
    if (texObj->Target) {
        _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(texture = %u already bound)", texture);
        return;
    }

    /* Check for compatible target */
    if (!target_valid(ctx, origTexObj->Target, target)) {
        return; /* error was recorded */
    }

    /* minlevel and minlayer are relative to the view of origtexture
     * If minlevel or minlayer is greater than level or layer, respectively,
     * of origtexture return INVALID_VALUE.
     */
    newViewMinLevel = origTexObj->MinLevel + minlevel;
    newViewMinLayer = origTexObj->MinLayer + minlayer;
    if (newViewMinLevel >= (origTexObj->MinLevel + origTexObj->NumLevels)) {
        _mesa_error(ctx, GL_INVALID_VALUE,
                    "glTextureView(new minlevel (%d) > orig minlevel (%d) + orig numlevels (%d))",
                    newViewMinLevel, origTexObj->MinLevel, origTexObj->NumLevels);
        return;
    }

    if (newViewMinLayer >= (origTexObj->MinLayer + origTexObj->NumLayers)) {
        _mesa_error(ctx, GL_INVALID_VALUE,
                    "glTextureView(new minlayer (%d) > orig minlayer (%d) + orig numlayers (%d))",
                    newViewMinLayer, origTexObj->MinLayer, origTexObj->NumLayers);
        return;
    }

    if (!_mesa_texture_view_compatible_format(ctx,
            origTexObj->Image[0][0]->InternalFormat,
            internalformat)) {
        _mesa_error(ctx, GL_INVALID_OPERATION,
                    "glTextureView(internalformat %s not compatible with origtexture %s)",
                    _mesa_lookup_enum_by_nr(internalformat),
                    _mesa_lookup_enum_by_nr(origTexObj->Image[0][0]->InternalFormat));
        return;
    }

    texFormat = _mesa_choose_texture_format(ctx, texObj, target, 0,
                                            internalformat, GL_NONE, GL_NONE);
    assert(texFormat != MESA_FORMAT_NONE);
    if (texFormat == MESA_FORMAT_NONE) return;

    newViewNumLevels = MIN2(numlevels, origTexObj->NumLevels - minlevel);
    newViewNumLayers = MIN2(numlayers, origTexObj->NumLayers - minlayer);

    faceTarget = origTexObj->Target;
    if (faceTarget == GL_TEXTURE_CUBE_MAP)
        faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + minlayer;

    /* Get a reference to what will become this View's base level */
    origTexImage = _mesa_select_tex_image(origTexObj, faceTarget, minlevel);
    width = origTexImage->Width;
    height = origTexImage->Height;
    depth = origTexImage->Depth;

    /* Adjust width, height, depth to be appropriate for new target */
    switch (target) {
    case GL_TEXTURE_1D:
        height = 1;
        break;

    case GL_TEXTURE_3D:
        break;

    case GL_TEXTURE_1D_ARRAY:
        height = (GLsizei) newViewNumLayers;
        break;

    case GL_TEXTURE_2D:
    case GL_TEXTURE_2D_MULTISAMPLE:
    case GL_TEXTURE_RECTANGLE:
    case GL_TEXTURE_CUBE_MAP:
        depth = 1;
        break;

    case GL_TEXTURE_2D_ARRAY:
    case GL_TEXTURE_CUBE_MAP_ARRAY:
    case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
        depth = newViewNumLayers;
        break;
    }

    /* If the dimensions of the original texture are larger than the maximum
     * supported dimensions of the new target, the error INVALID_OPERATION is
     * generated. For example, if the original texture has a TEXTURE_2D_ARRAY
     * target and its width is greater than MAX_CUBE_MAP_TEXTURE_SIZE, an error
     * will be generated if TextureView is called to create a TEXTURE_CUBE_MAP
     * view.
     */
    dimensionsOK = _mesa_legal_texture_dimensions(ctx, target, 0,
                   width, height, depth, 0);
    if (!dimensionsOK) {
        _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(invalid width or height or depth)");
        return;
    }

    sizeOK = ctx->Driver.TestProxyTexImage(ctx, target, 0, texFormat,
                                           width, height, depth, 0);
    if (!sizeOK) {
        _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(invalid texture size)");
        return;
    }

    /* If <target> is TEXTURE_1D, TEXTURE_2D, TEXTURE_3D, TEXTURE_RECTANGLE,
     * or TEXTURE_2D_MULTISAMPLE and <numlayers> does not equal 1, the error
     * INVALID_VALUE is generated.
     */
    switch (target) {
    case GL_TEXTURE_1D:
    case GL_TEXTURE_2D:
    case GL_TEXTURE_3D:
    case GL_TEXTURE_RECTANGLE:
    case GL_TEXTURE_2D_MULTISAMPLE:
        if (numlayers != 1) {
            _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(numlayers %d != 1)", numlayers);
            return;
        }
        break;

    case GL_TEXTURE_CUBE_MAP:
        /* If the new texture's target is TEXTURE_CUBE_MAP, the clamped <numlayers>
         * must be equal to 6.
         */
        if (newViewNumLayers != 6) {
            _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(clamped numlayers %d != 6)",
                        newViewNumLayers);
            return;
        }
        break;

    case GL_TEXTURE_CUBE_MAP_ARRAY:
        /* If the new texture's target is TEXTURE_CUBE_MAP_ARRAY,
         * then <numlayers> counts layer-faces rather than layers,
         * and the clamped <numlayers> must be a multiple of 6.
         * Otherwise, the error INVALID_VALUE is generated.
         */
        if ((newViewNumLayers % 6) != 0) {
            _mesa_error(ctx, GL_INVALID_VALUE,
                        "glTextureView(clamped numlayers %d is not a multiple of 6)",
                        newViewNumLayers);
            return;
        }
        break;
    }

    /* If the new texture's target is TEXTURE_CUBE_MAP or
     * TEXTURE_CUBE_MAP_ARRAY, the width and height of the original texture's
     * levels must be equal otherwise the error INVALID_OPERATION is generated.
     */
    if ((target == GL_TEXTURE_CUBE_MAP || target == GL_TEXTURE_CUBE_MAP_ARRAY) &&
            (origTexImage->Width != origTexImage->Height)) {
        _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(origtexture width (%d) != height (%d))",
                    origTexImage->Width, origTexImage->Height);
        return;
    }

    /* When the original texture's target is TEXTURE_CUBE_MAP, the layer
     * parameters are interpreted in the same order as if it were a
     * TEXTURE_CUBE_MAP_ARRAY with 6 layer-faces.
     */

    /* If the internal format does not exactly match the internal format of the
     * original texture, the contents of the memory are reinterpreted in the
     * same manner as for image bindings described in
     * section 3.9.20 (Texture Image Loads and Stores).
     */

    /* TEXTURE_BASE_LEVEL and TEXTURE_MAX_LEVEL are interpreted
     * relative to the view and not relative to the original data store.
     */

    if (!initialize_texture_fields(ctx, target, texObj, newViewNumLevels,
                                   width, height, depth,
                                   internalformat, texFormat)) {
        return; /* Already recorded error */
    }

    texObj->MinLevel = newViewMinLevel;
    texObj->MinLayer = newViewMinLayer;
    texObj->NumLevels = newViewNumLevels;
    texObj->NumLayers = newViewNumLayers;
    texObj->Immutable = GL_TRUE;
    texObj->ImmutableLevels = origTexObj->ImmutableLevels;
    texObj->Target = target;

    if (ctx->Driver.TextureView != NULL && !ctx->Driver.TextureView(ctx, texObj, origTexObj)) {
        return; /* driver recorded error */
    }
}
Ejemplo n.º 2
0
/**
 * Helper that does the storage allocation for _mesa_TexStorage1/2/3D()
 * and _mesa_TextureStorage1/2/3D().
 */
static void
texture_storage(struct gl_context *ctx, GLuint dims,
                struct gl_texture_object *texObj,
                GLenum target, GLsizei levels,
                GLenum internalformat, GLsizei width,
                GLsizei height, GLsizei depth, bool dsa)
{
   GLboolean sizeOK, dimensionsOK;
   mesa_format texFormat;
   const char* suffix = dsa ? "ture" : "";

   assert(texObj);

   if (tex_storage_error_check(ctx, texObj, dims, target, levels,
                               internalformat, width, height, depth, dsa)) {
      return; /* error was recorded */
   }

   texFormat = _mesa_choose_texture_format(ctx, texObj, target, 0,
                                           internalformat, GL_NONE, GL_NONE);

   /* check that width, height, depth are legal for the mipmap level */
   dimensionsOK = _mesa_legal_texture_dimensions(ctx, target, 0,
                                                  width, height, depth, 0);

   sizeOK = ctx->Driver.TestProxyTexImage(ctx, target, levels, 0, texFormat,
                                          1, width, height, depth);

   if (_mesa_is_proxy_texture(target)) {
      if (dimensionsOK && sizeOK) {
         initialize_texture_fields(ctx, texObj, levels, width, height, depth,
                                   internalformat, texFormat);
      }
      else {
         /* clear all image fields for [levels] */
         clear_texture_fields(ctx, texObj);
      }
   }
   else {
      if (!dimensionsOK) {
         _mesa_error(ctx, GL_INVALID_VALUE,
                     "glTex%sStorage%uD(invalid width, height or depth)",
                     suffix, dims);
         return;
      }

      if (!sizeOK) {
         _mesa_error(ctx, GL_OUT_OF_MEMORY,
                     "glTex%sStorage%uD(texture too large)",
                     suffix, dims);
      }

      assert(levels > 0);
      assert(width > 0);
      assert(height > 0);
      assert(depth > 0);

      if (!initialize_texture_fields(ctx, texObj, levels, width, height, depth,
                                     internalformat, texFormat)) {
         return;
      }

      /* Do actual texture memory allocation */
      if (!ctx->Driver.AllocTextureStorage(ctx, texObj, levels,
                                           width, height, depth)) {
         /* Reset the texture images' info to zeros.
          * Strictly speaking, we probably don't have to do this since
          * generating GL_OUT_OF_MEMORY can leave things in an undefined
          * state but this puts things in a consistent state.
          */
         clear_texture_fields(ctx, texObj);
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTex%sStorage%uD",
                     suffix, dims);
         return;
      }

      _mesa_set_texture_view_state(ctx, texObj, target, levels);

      update_fbo_texture(ctx, texObj);
   }
}
Ejemplo n.º 3
0
/**
 * Helper used by _mesa_TexStorage1/2/3D().
 */
static void
texstorage(GLuint dims, GLenum target, GLsizei levels, GLenum internalformat,
           GLsizei width, GLsizei height, GLsizei depth)
{
   struct gl_texture_object *texObj;
   GLboolean sizeOK, dimensionsOK;
   gl_format texFormat;

   GET_CURRENT_CONTEXT(ctx);

   if (tex_storage_error_check(ctx, dims, target, levels,
                               internalformat, width, height, depth)) {
      return; /* error was recorded */
   }

   texObj = _mesa_get_current_tex_object(ctx, target);
   assert(texObj);

   texFormat = _mesa_choose_texture_format(ctx, texObj, target, 0,
                                           internalformat, GL_NONE, GL_NONE);
   assert(texFormat != MESA_FORMAT_NONE);

   /* check that width, height, depth are legal for the mipmap level */
   dimensionsOK = _mesa_legal_texture_dimensions(ctx, target, 0,
                                                  width, height, depth, 0);

   sizeOK = ctx->Driver.TestProxyTexImage(ctx, target, 0, texFormat,
                                          width, height, depth, 0);

   if (_mesa_is_proxy_texture(texObj->Target)) {
      if (dimensionsOK && sizeOK) {
         initialize_texture_fields(ctx, texObj, levels, width, height, depth,
                                   internalformat, texFormat);
      }
      else {
         /* clear all image fields for [levels] */
         clear_texture_fields(ctx, texObj);
      }
   }
   else {
      if (!dimensionsOK) {
         _mesa_error(ctx, GL_INVALID_VALUE,
                     "glTexStorage%uD(invalid width, height or depth)", dims);
         return;
      }

      if (!sizeOK) {
         _mesa_error(ctx, GL_OUT_OF_MEMORY,
                     "glTexStorage%uD(texture too large)", dims);
      }

      assert(levels > 0);
      assert(width > 0);
      assert(height > 0);
      assert(depth > 0);

      if (!initialize_texture_fields(ctx, texObj, levels, width, height, depth,
                                     internalformat, texFormat)) {
         return;
      }

      /* Do actual texture memory allocation */
      if (!ctx->Driver.AllocTextureStorage(ctx, texObj, levels,
                                           width, height, depth)) {
         /* Reset the texture images' info to zeros.
          * Strictly speaking, we probably don't have to do this since
          * generating GL_OUT_OF_MEMORY can leave things in an undefined
          * state but this puts things in a consistent state.
          */
         clear_texture_fields(ctx, texObj);
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexStorage%uD", dims);
         return;
      }

      texObj->Immutable = GL_TRUE;
      texObj->ImmutableLevels = levels;
   }
}