Ejemplo n.º 1
0
/**
 * Preparation prior to glTexImage.  Basically check the 'surface_based'
 * field and switch to a "normal" tex image if necessary.
 */
static void
prep_teximage(struct gl_context *ctx, struct gl_texture_image *texImage,
              GLenum format, GLenum type)
{
   struct gl_texture_object *texObj = texImage->TexObject;
   struct st_texture_object *stObj = st_texture_object(texObj);

   /* switch to "normal" */
   if (stObj->surface_based) {
      const GLenum target = texObj->Target;
      const GLuint level = texImage->Level;
      gl_format texFormat;

      _mesa_clear_texture_object(ctx, texObj);
      pipe_resource_reference(&stObj->pt, NULL);

      /* oops, need to init this image again */
      texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
                                              texImage->InternalFormat, format,
                                              type);

      _mesa_init_teximage_fields(ctx, texImage,
                                 texImage->Width, texImage->Height,
                                 texImage->Depth, texImage->Border,
                                 texImage->InternalFormat, texFormat);

      stObj->surface_based = GL_FALSE;
   }
}
/* This function makes a texture view without bothering with all of the API
 * checks.  Most of them are the same for CopyTexSubImage so checking would
 * be redundant.  The one major difference is that we don't check for
 * whether the texture is immutable or not.  However, since the view will
 * be created and then immediately destroyed, this should not be a problem.
 */
static bool
make_view(struct gl_context *ctx, struct gl_texture_image *tex_image,
          struct gl_texture_image **view_tex_image, GLuint *view_tex_name,
          GLenum internal_format)
{
   struct gl_texture_object *tex_obj = tex_image->TexObject;
   struct gl_texture_object *view_tex_obj;
   mesa_format tex_format;

   /* Set up the new texture object */
   _mesa_GenTextures(1, view_tex_name);
   view_tex_obj = _mesa_lookup_texture(ctx, *view_tex_name);
   if (!view_tex_obj)
      return false;

   tex_format = _mesa_choose_texture_format(ctx, view_tex_obj, tex_obj->Target,
                                           0, internal_format,
                                           GL_NONE, GL_NONE);

   if (!ctx->Driver.TestProxyTexImage(ctx, tex_obj->Target, 0, tex_format,
                                      tex_image->Width, tex_image->Height,
                                      tex_image->Depth, 0)) {
      _mesa_DeleteTextures(1, view_tex_name);
      *view_tex_name = 0;
      return false;
   }

   view_tex_obj->Target = tex_obj->Target;

   *view_tex_image = _mesa_get_tex_image(ctx, view_tex_obj, tex_obj->Target, 0);

   if (!*view_tex_image) {
      _mesa_DeleteTextures(1, view_tex_name);
      *view_tex_name = 0;
      return false;
   }

   _mesa_init_teximage_fields(ctx, *view_tex_image,
                              tex_image->Width, tex_image->Height,
                              tex_image->Depth,
                              0, internal_format, tex_format);

   view_tex_obj->MinLevel = tex_image->Level;
   view_tex_obj->NumLevels = 1;
   view_tex_obj->MinLayer = tex_obj->MinLayer;
   view_tex_obj->NumLayers = tex_obj->NumLayers;
   view_tex_obj->Immutable = tex_obj->Immutable;
   view_tex_obj->ImmutableLevels = tex_obj->ImmutableLevels;
   view_tex_obj->Target = tex_obj->Target;

   if (ctx->Driver.TextureView != NULL &&
       !ctx->Driver.TextureView(ctx, view_tex_obj, tex_obj)) {
      _mesa_DeleteTextures(1, view_tex_name);
      *view_tex_name = 0;
      return false; /* driver recorded error */
   }

   return true;
}
Ejemplo n.º 3
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.º 4
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.º 5
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;
   }
}
Ejemplo n.º 6
0
/**
 * Do actual memory allocation for glTexStorage1/2/3D().
 */
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)
{
   const GLenum target = texObj->Target;
   const GLuint numFaces = (target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
   gl_format texFormat;
   GLint level, levelWidth = width, levelHeight = height, levelDepth = depth;
   GLuint face;

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

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

   /* Set up all the texture object's gl_texture_images */
   for (level = 0; level < levels; level++) {
      for (face = 0; face < numFaces; face++) {
         const GLenum faceTarget =
            (target == GL_TEXTURE_CUBE_MAP)
            ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + face : target;
         struct gl_texture_image *texImage =
            _mesa_get_tex_image(ctx, texObj, faceTarget, level);

	 if (!texImage) {
	    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage%uD", dims);
            return;
	 }

         _mesa_init_teximage_fields(ctx, target, texImage,
                                    levelWidth, levelHeight, levelDepth,
                                    0, internalFormat, texFormat);
      }

      next_mipmap_level_size(target, &levelWidth, &levelHeight, &levelDepth);
   }

   assert(levelWidth > 0);
   assert(levelHeight > 0);
   assert(levelDepth > 0);

   if (!_mesa_is_proxy_texture(texObj->Target)) {
      /* 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.
          */
         for (level = 0; level < levels; level++) {
            for (face = 0; face < numFaces; face++) {
               struct gl_texture_image *texImage = texObj->Image[face][level];
               if (texImage) {
                  _mesa_init_teximage_fields(ctx, target, texImage,
                                             0, 0, 0, 0,
                                             GL_NONE, MESA_FORMAT_NONE);
               }
            }
         }

         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexStorage%uD", dims);

         return;
      }
   }

   texObj->Immutable = GL_TRUE;
}