Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Mesa 3-D graphics library
  3.  *
  4.  * Copyright (C) 2014 Intel Corporation.  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 OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  20.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  21.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  22.  * OTHER DEALINGS IN THE SOFTWARE.
  23.  *
  24.  * Authors:
  25.  *    Jason Ekstrand <jason.ekstrand@intel.com>
  26.  */
  27.  
  28. #include "glheader.h"
  29. #include "errors.h"
  30. #include "enums.h"
  31. #include "copyimage.h"
  32. #include "teximage.h"
  33. #include "texobj.h"
  34. #include "fbobject.h"
  35. #include "textureview.h"
  36. #include "glformats.h"
  37.  
  38. enum mesa_block_class {
  39.    BLOCK_CLASS_128_BITS,
  40.    BLOCK_CLASS_64_BITS
  41. };
  42.  
  43. static bool
  44. prepare_target(struct gl_context *ctx, GLuint name, GLenum *target, int level,
  45.                struct gl_texture_object **tex_obj,
  46.                struct gl_texture_image **tex_image, GLuint *tmp_tex,
  47.                const char *dbg_prefix)
  48. {
  49.    struct gl_renderbuffer *rb;
  50.  
  51.    if (name == 0) {
  52.       _mesa_error(ctx, GL_INVALID_VALUE,
  53.                   "glCopyImageSubData(%sName = %d)", dbg_prefix, name);
  54.       return false;
  55.    }
  56.  
  57.    /*
  58.     * INVALID_ENUM is generated
  59.     *  * if either <srcTarget> or <dstTarget>
  60.     *   - is not RENDERBUFFER or a valid non-proxy texture target
  61.     *   - is TEXTURE_BUFFER, or
  62.     *   - is one of the cubemap face selectors described in table 3.17,
  63.     */
  64.    switch (*target) {
  65.    case GL_RENDERBUFFER:
  66.       /* Not a texture target, but valid */
  67.    case GL_TEXTURE_1D:
  68.    case GL_TEXTURE_1D_ARRAY:
  69.    case GL_TEXTURE_2D:
  70.    case GL_TEXTURE_3D:
  71.    case GL_TEXTURE_CUBE_MAP:
  72.    case GL_TEXTURE_RECTANGLE:
  73.    case GL_TEXTURE_2D_ARRAY:
  74.    case GL_TEXTURE_CUBE_MAP_ARRAY:
  75.    case GL_TEXTURE_2D_MULTISAMPLE:
  76.    case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
  77.       /* These are all valid */
  78.       break;
  79.    case GL_TEXTURE_EXTERNAL_OES:
  80.       /* Only exists in ES */
  81.    case GL_TEXTURE_BUFFER:
  82.    default:
  83.       _mesa_error(ctx, GL_INVALID_ENUM,
  84.                   "glCopyImageSubData(%sTarget = %s)", dbg_prefix,
  85.                   _mesa_lookup_enum_by_nr(*target));
  86.       return false;
  87.    }
  88.  
  89.    if (*target == GL_RENDERBUFFER) {
  90.       rb = _mesa_lookup_renderbuffer(ctx, name);
  91.       if (!rb) {
  92.          _mesa_error(ctx, GL_INVALID_VALUE,
  93.                      "glCopyImageSubData(%sName = %u)", dbg_prefix, name);
  94.          return false;
  95.       }
  96.  
  97.       if (!rb->Name) {
  98.          _mesa_error(ctx, GL_INVALID_OPERATION,
  99.                      "glCopyImageSubData(%sName incomplete)", dbg_prefix);
  100.          return false;
  101.       }
  102.  
  103.       if (level != 0) {
  104.          _mesa_error(ctx, GL_INVALID_VALUE,
  105.                      "glCopyImageSubData(%sLevel = %u)", dbg_prefix, level);
  106.          return false;
  107.       }
  108.  
  109.       if (rb->NumSamples > 1)
  110.          *target = GL_TEXTURE_2D_MULTISAMPLE;
  111.       else
  112.          *target = GL_TEXTURE_2D;
  113.  
  114.       *tmp_tex = 0;
  115.       _mesa_GenTextures(1, tmp_tex);
  116.       if (*tmp_tex == 0)
  117.          return false; /* Error already set by GenTextures */
  118.  
  119.       _mesa_BindTexture(*target, *tmp_tex);
  120.       *tex_obj = _mesa_lookup_texture(ctx, *tmp_tex);
  121.       *tex_image = _mesa_get_tex_image(ctx, *tex_obj, *target, 0);
  122.  
  123.       if (!ctx->Driver.BindRenderbufferTexImage(ctx, rb, *tex_image)) {
  124.          _mesa_problem(ctx, "Failed to create texture from renderbuffer");
  125.          return false;
  126.       }
  127.  
  128.       if (ctx->Driver.FinishRenderTexture && !rb->NeedsFinishRenderTexture) {
  129.          rb->NeedsFinishRenderTexture = true;
  130.          ctx->Driver.FinishRenderTexture(ctx, rb);
  131.       }
  132.    } else {
  133.       *tex_obj = _mesa_lookup_texture(ctx, name);
  134.       if (!*tex_obj) {
  135.          _mesa_error(ctx, GL_INVALID_VALUE,
  136.                      "glCopyImageSubData(%sName = %u)", dbg_prefix, name);
  137.          return false;
  138.       }
  139.  
  140.       _mesa_test_texobj_completeness(ctx, *tex_obj);
  141.       if (!(*tex_obj)->_BaseComplete ||
  142.           (level != 0 && !(*tex_obj)->_MipmapComplete)) {
  143.          _mesa_error(ctx, GL_INVALID_OPERATION,
  144.                      "glCopyImageSubData(%sName incomplete)", dbg_prefix);
  145.          return false;
  146.       }
  147.  
  148.       if ((*tex_obj)->Target != *target) {
  149.          _mesa_error(ctx, GL_INVALID_ENUM,
  150.                      "glCopyImageSubData(%sTarget = %s)", dbg_prefix,
  151.                      _mesa_lookup_enum_by_nr(*target));
  152.          return false;
  153.       }
  154.  
  155.       if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
  156.          _mesa_error(ctx, GL_INVALID_VALUE,
  157.                      "glCopyImageSubData(%sLevel = %d)", dbg_prefix, level);
  158.          return false;
  159.       }
  160.  
  161.       *tex_image = _mesa_select_tex_image(*tex_obj, *target, level);
  162.       if (!*tex_image) {
  163.          _mesa_error(ctx, GL_INVALID_VALUE,
  164.                      "glCopyImageSubData(%sLevel = %u)", dbg_prefix, level);
  165.          return false;
  166.       }
  167.    }
  168.  
  169.    return true;
  170. }
  171.  
  172. static bool
  173. check_region_bounds(struct gl_context *ctx, struct gl_texture_image *tex_image,
  174.                     int x, int y, int z, int width, int height, int depth,
  175.                     const char *dbg_prefix)
  176. {
  177.    if (width < 0 || height < 0 || depth < 0) {
  178.       _mesa_error(ctx, GL_INVALID_VALUE,
  179.                   "glCopyImageSubData(%sWidth, %sHeight, or %sDepth is negative)",
  180.                   dbg_prefix, dbg_prefix, dbg_prefix);
  181.       return false;
  182.    }
  183.  
  184.    if (x < 0 || y < 0 || z < 0) {
  185.       _mesa_error(ctx, GL_INVALID_VALUE,
  186.                   "glCopyImageSubData(%sX, %sY, or %sZ is negative)",
  187.                   dbg_prefix, dbg_prefix, dbg_prefix);
  188.       return false;
  189.    }
  190.  
  191.    if (x + width > tex_image->Width) {
  192.       _mesa_error(ctx, GL_INVALID_VALUE,
  193.                   "glCopyImageSubData(%sX or %sWidth exceeds image bounds)",
  194.                   dbg_prefix, dbg_prefix);
  195.       return false;
  196.    }
  197.  
  198.    switch (tex_image->TexObject->Target) {
  199.    case GL_TEXTURE_1D:
  200.    case GL_TEXTURE_1D_ARRAY:
  201.       if (y != 0 || height != 1) {
  202.          _mesa_error(ctx, GL_INVALID_VALUE,
  203.                      "glCopyImageSubData(%sY or %sHeight exceeds image bounds)",
  204.                      dbg_prefix, dbg_prefix);
  205.          return false;
  206.       }
  207.       break;
  208.    default:
  209.       if (y + height > tex_image->Height) {
  210.          _mesa_error(ctx, GL_INVALID_VALUE,
  211.                      "glCopyImageSubData(%sY or %sHeight exceeds image bounds)",
  212.                      dbg_prefix, dbg_prefix);
  213.          return false;
  214.       }
  215.       break;
  216.    }
  217.  
  218.    switch (tex_image->TexObject->Target) {
  219.    case GL_TEXTURE_1D:
  220.    case GL_TEXTURE_2D:
  221.    case GL_TEXTURE_2D_MULTISAMPLE:
  222.    case GL_TEXTURE_RECTANGLE:
  223.       if (z != 0 || depth != 1) {
  224.          _mesa_error(ctx, GL_INVALID_VALUE,
  225.                      "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
  226.                      dbg_prefix, dbg_prefix);
  227.          return false;
  228.       }
  229.       break;
  230.    case GL_TEXTURE_CUBE_MAP:
  231.       if (z < 0 || z + depth > 6) {
  232.          _mesa_error(ctx, GL_INVALID_VALUE,
  233.                      "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
  234.                      dbg_prefix, dbg_prefix);
  235.          return false;
  236.       }
  237.       break;
  238.    case GL_TEXTURE_1D_ARRAY:
  239.       if (z < 0 || z + depth > tex_image->Height) {
  240.          _mesa_error(ctx, GL_INVALID_VALUE,
  241.                      "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
  242.                      dbg_prefix, dbg_prefix);
  243.          return false;
  244.       }
  245.       break;
  246.    case GL_TEXTURE_CUBE_MAP_ARRAY:
  247.    case GL_TEXTURE_2D_ARRAY:
  248.    case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
  249.    case GL_TEXTURE_3D:
  250.       if (z < 0 || z + depth > tex_image->Depth) {
  251.          _mesa_error(ctx, GL_INVALID_VALUE,
  252.                      "glCopyImageSubData(%sZ or %sDepth exceeds image bounds)",
  253.                      dbg_prefix, dbg_prefix);
  254.          return false;
  255.       }
  256.       break;
  257.    }
  258.  
  259.    return true;
  260. }
  261.  
  262. static bool
  263. compressed_format_compatible(struct gl_context *ctx,
  264.                              GLenum compressedFormat, GLenum otherFormat)
  265. {
  266.    enum mesa_block_class compressedClass, otherClass;
  267.  
  268.    /* Two view-incompatible compressed formats are never compatible. */
  269.    if (_mesa_is_compressed_format(ctx, otherFormat)) {
  270.       return false;
  271.    }
  272.  
  273.    /*
  274.     * From ARB_copy_image spec:
  275.     *    Table 4.X.1 (Compatible internal formats for copying between
  276.     *                 compressed and uncompressed internal formats)
  277.     *    ---------------------------------------------------------------------
  278.     *    | Texel / | Uncompressed      |                                     |
  279.     *    | Block   | internal format   | Compressed internal format          |
  280.     *    | size    |                   |                                     |
  281.     *    ---------------------------------------------------------------------
  282.     *    | 128-bit | RGBA32UI,         | COMPRESSED_RGBA_S3TC_DXT3_EXT,      |
  283.     *    |         | RGBA32I,          | COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,|
  284.     *    |         | RGBA32F           | COMPRESSED_RGBA_S3TC_DXT5_EXT,      |
  285.     *    |         |                   | COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,|
  286.     *    |         |                   | COMPRESSED_RG_RGTC2,                |
  287.     *    |         |                   | COMPRESSED_SIGNED_RG_RGTC2,         |
  288.     *    |         |                   | COMPRESSED_RGBA_BPTC_UNORM,         |
  289.     *    |         |                   | COMPRESSED_SRGB_ALPHA_BPTC_UNORM,   |
  290.     *    |         |                   | COMPRESSED_RGB_BPTC_SIGNED_FLOAT,   |
  291.     *    |         |                   | COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT  |
  292.     *    ---------------------------------------------------------------------
  293.     *    | 64-bit  | RGBA16F, RG32F,   | COMPRESSED_RGB_S3TC_DXT1_EXT,       |
  294.     *    |         | RGBA16UI, RG32UI, | COMPRESSED_SRGB_S3TC_DXT1_EXT,      |
  295.     *    |         | RGBA16I, RG32I,   | COMPRESSED_RGBA_S3TC_DXT1_EXT,      |
  296.     *    |         | RGBA16,           | COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,|
  297.     *    |         | RGBA16_SNORM      | COMPRESSED_RED_RGTC1,               |
  298.     *    |         |                   | COMPRESSED_SIGNED_RED_RGTC1         |
  299.     *    ---------------------------------------------------------------------
  300.     */
  301.  
  302.    switch (compressedFormat) {
  303.       case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
  304.       case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
  305.       case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
  306.       case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
  307.       case GL_COMPRESSED_RG_RGTC2:
  308.       case GL_COMPRESSED_SIGNED_RG_RGTC2:
  309.       case GL_COMPRESSED_RGBA_BPTC_UNORM:
  310.       case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
  311.       case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT:
  312.       case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
  313.          compressedClass = BLOCK_CLASS_128_BITS;
  314.          break;
  315.       case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
  316.       case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
  317.       case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
  318.       case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
  319.       case GL_COMPRESSED_RED_RGTC1:
  320.       case GL_COMPRESSED_SIGNED_RED_RGTC1:
  321.          compressedClass = BLOCK_CLASS_64_BITS;
  322.          break;
  323.       default:
  324.          return false;
  325.    }
  326.  
  327.    switch (otherFormat) {
  328.       case GL_RGBA32UI:
  329.       case GL_RGBA32I:
  330.       case GL_RGBA32F:
  331.          otherClass = BLOCK_CLASS_128_BITS;
  332.          break;
  333.       case GL_RGBA16F:
  334.       case GL_RG32F:
  335.       case GL_RGBA16UI:
  336.       case GL_RG32UI:
  337.       case GL_RGBA16I:
  338.       case GL_RG32I:
  339.       case GL_RGBA16:
  340.       case GL_RGBA16_SNORM:
  341.          otherClass = BLOCK_CLASS_64_BITS;
  342.          break;
  343.       default:
  344.          return false;
  345.    }
  346.  
  347.    return compressedClass == otherClass;
  348. }
  349.  
  350. static bool
  351. copy_format_compatible(struct gl_context *ctx,
  352.                                 GLenum srcFormat, GLenum dstFormat)
  353. {
  354.    /*
  355.     * From ARB_copy_image spec:
  356.     *    For the purposes of CopyImageSubData, two internal formats
  357.     *    are considered compatible if any of the following conditions are
  358.     *    met:
  359.     *    * the formats are the same,
  360.     *    * the formats are considered compatible according to the
  361.     *      compatibility rules used for texture views as defined in
  362.     *      section 3.9.X. In particular, if both internal formats are listed
  363.     *      in the same entry of Table 3.X.2, they are considered compatible, or
  364.     *    * one format is compressed and the other is uncompressed and
  365.     *      Table 4.X.1 lists the two formats in the same row.
  366.     */
  367.  
  368.    if (_mesa_texture_view_compatible_format(ctx, srcFormat, dstFormat)) {
  369.       /* Also checks if formats are equal. */
  370.       return true;
  371.    } else if (_mesa_is_compressed_format(ctx, srcFormat)) {
  372.       return compressed_format_compatible(ctx, srcFormat, dstFormat);
  373.    } else if (_mesa_is_compressed_format(ctx, dstFormat)) {
  374.       return compressed_format_compatible(ctx, dstFormat, srcFormat);
  375.    }
  376.  
  377.    return false;
  378. }
  379.  
  380. void GLAPIENTRY
  381. _mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel,
  382.                        GLint srcX, GLint srcY, GLint srcZ,
  383.                        GLuint dstName, GLenum dstTarget, GLint dstLevel,
  384.                        GLint dstX, GLint dstY, GLint dstZ,
  385.                        GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth)
  386. {
  387.    GET_CURRENT_CONTEXT(ctx);
  388.    GLuint tmpTexNames[2] = { 0, 0 };
  389.    struct gl_texture_object *srcTexObj, *dstTexObj;
  390.    struct gl_texture_image *srcTexImage, *dstTexImage;
  391.    GLuint src_bw, src_bh, dst_bw, dst_bh;
  392.    int i, srcNewZ, dstNewZ;
  393.  
  394.    if (MESA_VERBOSE & VERBOSE_API)
  395.       _mesa_debug(ctx, "glCopyImageSubData(%u, %s, %d, %d, %d, %d, "
  396.                                           "%u, %s, %d, %d, %d, %d, "
  397.                                           "%d, %d, %d)\n",
  398.                   srcName, _mesa_lookup_enum_by_nr(srcTarget), srcLevel,
  399.                   srcX, srcY, srcZ,
  400.                   dstName, _mesa_lookup_enum_by_nr(dstTarget), dstLevel,
  401.                   dstX, dstY, dstZ,
  402.                   srcWidth, srcHeight, srcWidth);
  403.  
  404.    if (!ctx->Extensions.ARB_copy_image) {
  405.       _mesa_error(ctx, GL_INVALID_OPERATION,
  406.                   "glCopyImageSubData(extension not available)");
  407.       return;
  408.    }
  409.  
  410.    if (!prepare_target(ctx, srcName, &srcTarget, srcLevel,
  411.                        &srcTexObj, &srcTexImage, &tmpTexNames[0], "src"))
  412.       goto cleanup;
  413.  
  414.    if (!prepare_target(ctx, dstName, &dstTarget, dstLevel,
  415.                        &dstTexObj, &dstTexImage, &tmpTexNames[1], "dst"))
  416.       goto cleanup;
  417.  
  418.    _mesa_get_format_block_size(srcTexImage->TexFormat, &src_bw, &src_bh);
  419.    if ((srcX % src_bw != 0) || (srcY % src_bh != 0) ||
  420.        (srcWidth % src_bw != 0) || (srcHeight % src_bh != 0)) {
  421.       _mesa_error(ctx, GL_INVALID_VALUE,
  422.                   "glCopyImageSubData(unaligned src rectangle)");
  423.       goto cleanup;
  424.    }
  425.  
  426.    _mesa_get_format_block_size(dstTexImage->TexFormat, &dst_bw, &dst_bh);
  427.    if ((dstX % dst_bw != 0) || (dstY % dst_bh != 0)) {
  428.       _mesa_error(ctx, GL_INVALID_VALUE,
  429.                   "glCopyImageSubData(unaligned dst rectangle)");
  430.       goto cleanup;
  431.    }
  432.  
  433.    if (!check_region_bounds(ctx, srcTexImage, srcX, srcY, srcZ,
  434.                             srcWidth, srcHeight, srcDepth, "src"))
  435.       goto cleanup;
  436.  
  437.    if (!check_region_bounds(ctx, dstTexImage, dstX, dstY, dstZ,
  438.                             (srcWidth / src_bw) * dst_bw,
  439.                             (srcHeight / src_bh) * dst_bh, srcDepth, "dst"))
  440.       goto cleanup;
  441.  
  442.    if (!copy_format_compatible(ctx, srcTexImage->InternalFormat,
  443.                                dstTexImage->InternalFormat)) {
  444.       _mesa_error(ctx, GL_INVALID_OPERATION,
  445.                   "glCopyImageSubData(internalFormat mismatch)");
  446.       goto cleanup;
  447.    }
  448.  
  449.    for (i = 0; i < srcDepth; ++i) {
  450.       if (srcTexObj->Target == GL_TEXTURE_CUBE_MAP) {
  451.          srcTexImage = srcTexObj->Image[i + srcZ][srcLevel];
  452.          srcNewZ = 0;
  453.       } else {
  454.          srcNewZ = srcZ + i;
  455.       }
  456.  
  457.       if (dstTexObj->Target == GL_TEXTURE_CUBE_MAP) {
  458.          dstTexImage = dstTexObj->Image[i + dstZ][dstLevel];
  459.          dstNewZ = 0;
  460.       } else {
  461.          dstNewZ = dstZ + i;
  462.       }
  463.  
  464.       ctx->Driver.CopyImageSubData(ctx, srcTexImage, srcX, srcY, srcNewZ,
  465.                                    dstTexImage, dstX, dstY, dstNewZ,
  466.                                    srcWidth, srcHeight);
  467.    }
  468.  
  469. cleanup:
  470.    _mesa_DeleteTextures(2, tmpTexNames);
  471. }
  472.