Пример #1
0
static bool
copy_format_compatible(const struct gl_context *ctx,
                       GLenum srcFormat, GLenum dstFormat)
{
   /*
    * From ARB_copy_image spec:
    *    For the purposes of CopyImageSubData, two internal formats
    *    are considered compatible if any of the following conditions are
    *    met:
    *    * the formats are the same,
    *    * the formats are considered compatible according to the
    *      compatibility rules used for texture views as defined in
    *      section 3.9.X. In particular, if both internal formats are listed
    *      in the same entry of Table 3.X.2, they are considered compatible, or
    *    * one format is compressed and the other is uncompressed and
    *      Table 4.X.1 lists the two formats in the same row.
    */

   if (_mesa_texture_view_compatible_format(ctx, srcFormat, dstFormat)) {
      /* Also checks if formats are equal. */
      return true;
   } else if (_mesa_is_compressed_format(ctx, srcFormat)) {
      return compressed_format_compatible(ctx, srcFormat, dstFormat);
   } else if (_mesa_is_compressed_format(ctx, dstFormat)) {
      return compressed_format_compatible(ctx, dstFormat, srcFormat);
   }

   return false;
}
Пример #2
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 */
    }
}
Пример #3
0
void GLAPIENTRY
_mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel,
                       GLint srcX, GLint srcY, GLint srcZ,
                       GLuint dstName, GLenum dstTarget, GLint dstLevel,
                       GLint dstX, GLint dstY, GLint dstZ,
                       GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth)
{
   GET_CURRENT_CONTEXT(ctx);
   GLuint tmpTexNames[2] = { 0, 0 };
   struct gl_texture_object *srcTexObj, *dstTexObj;
   struct gl_texture_image *srcTexImage, *dstTexImage;
   GLuint src_bw, src_bh, dst_bw, dst_bh;
   int i, srcNewZ, dstNewZ, Bpt;

   if (MESA_VERBOSE & VERBOSE_API)
      _mesa_debug(ctx, "glCopyImageSubData(%u, %s, %d, %d, %d, %d, "
                                          "%u, %s, %d, %d, %d, %d, "
                                          "%d, %d, %d)\n",
                  srcName, _mesa_lookup_enum_by_nr(srcTarget), srcLevel,
                  srcX, srcY, srcZ,
                  dstName, _mesa_lookup_enum_by_nr(dstTarget), dstLevel,
                  dstX, dstY, dstZ,
                  srcWidth, srcHeight, srcWidth);

   if (!ctx->Extensions.ARB_copy_image) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glCopyImageSubData(extension not available)");
      return;
   }

   if (!prepare_target(ctx, srcName, &srcTarget, srcLevel,
                       &srcTexObj, &srcTexImage, &tmpTexNames[0], "src"))
      goto cleanup;

   if (!prepare_target(ctx, dstName, &dstTarget, dstLevel,
                       &dstTexObj, &dstTexImage, &tmpTexNames[1], "dst"))
      goto cleanup;

   _mesa_get_format_block_size(srcTexImage->TexFormat, &src_bw, &src_bh);
   if ((srcX % src_bw != 0) || (srcY % src_bh != 0) ||
       (srcWidth % src_bw != 0) || (srcHeight % src_bh != 0)) {
      _mesa_error(ctx, GL_INVALID_VALUE,
                  "glCopyImageSubData(unaligned src rectangle)");
      goto cleanup;
   }

   _mesa_get_format_block_size(dstTexImage->TexFormat, &dst_bw, &dst_bh);
   if ((dstX % dst_bw != 0) || (dstY % dst_bh != 0)) {
      _mesa_error(ctx, GL_INVALID_VALUE,
                  "glCopyImageSubData(unaligned dst rectangle)");
      goto cleanup;
   }

   /* Very simple sanity check.  This is sufficient if one of the textures
    * is compressed. */
   Bpt = _mesa_get_format_bytes(srcTexImage->TexFormat);
   if (_mesa_get_format_bytes(dstTexImage->TexFormat) != Bpt) {
      _mesa_error(ctx, GL_INVALID_VALUE,
                  "glCopyImageSubData(internalFormat mismatch)");
      goto cleanup;
   }

   if (!check_region_bounds(ctx, srcTexImage, srcX, srcY, srcZ,
                            srcWidth, srcHeight, srcDepth, "src"))
      goto cleanup;

   if (!check_region_bounds(ctx, dstTexImage, dstX, dstY, dstZ,
                            (srcWidth / src_bw) * dst_bw,
                            (srcHeight / src_bh) * dst_bh, srcDepth, "dst"))
      goto cleanup;

   if (_mesa_is_format_compressed(srcTexImage->TexFormat)) {
      /* XXX: Technically, we should probaby do some more specific checking
       * here.  However, this should be sufficient for all compressed
       * formats that mesa supports since it is a direct memory copy.
       */
   } else if (_mesa_is_format_compressed(dstTexImage->TexFormat)) {
   } else if (_mesa_texture_view_compatible_format(ctx,
                                                   srcTexImage->InternalFormat,
                                                   dstTexImage->InternalFormat)) {
   } else {
      return; /* Error logged by _mesa_texture_view_compatible_format */
   }

   for (i = 0; i < srcDepth; ++i) {
      if (srcTexObj->Target == GL_TEXTURE_CUBE_MAP) {
         srcTexImage = srcTexObj->Image[i + srcZ][srcLevel];
         srcNewZ = 0;
      } else {
         srcNewZ = srcZ + i;
      }

      if (dstTexObj->Target == GL_TEXTURE_CUBE_MAP) {
         dstTexImage = dstTexObj->Image[i + dstZ][dstLevel];
         dstNewZ = 0;
      } else {
         dstNewZ = dstZ + i;
      }

      ctx->Driver.CopyImageSubData(ctx, srcTexImage, srcX, srcY, srcNewZ,
                                   dstTexImage, dstX, dstY, dstNewZ,
                                   srcWidth, srcHeight);
   }

cleanup:
   _mesa_DeleteTextures(2, tmpTexNames);
}