Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Mesa 3-D graphics library
  3.  *
  4.  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
  5.  * Copyright (C) 2009-2011  VMware, Inc.  All Rights Reserved.
  6.  *
  7.  * Permission is hereby granted, free of charge, to any person obtaining a
  8.  * copy of this software and associated documentation files (the "Software"),
  9.  * to deal in the Software without restriction, including without limitation
  10.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11.  * and/or sell copies of the Software, and to permit persons to whom the
  12.  * Software is furnished to do so, subject to the following conditions:
  13.  *
  14.  * The above copyright notice and this permission notice shall be included
  15.  * in all copies or substantial portions of the Software.
  16.  *
  17.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  18.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  20.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  21.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  22.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  23.  * OTHER DEALINGS IN THE SOFTWARE.
  24.  */
  25.  
  26.  
  27. /**
  28.  * \file pbo.c
  29.  * \brief Functions related to Pixel Buffer Objects.
  30.  */
  31.  
  32.  
  33.  
  34. #include "glheader.h"
  35. #include "bufferobj.h"
  36. #include "glformats.h"
  37. #include "image.h"
  38. #include "imports.h"
  39. #include "mtypes.h"
  40. #include "pbo.h"
  41.  
  42.  
  43.  
  44. /**
  45.  * When we're about to read pixel data out of a PBO (via glDrawPixels,
  46.  * glTexImage, etc) or write data into a PBO (via glReadPixels,
  47.  * glGetTexImage, etc) we call this function to check that we're not
  48.  * going to read/write out of bounds.
  49.  *
  50.  * XXX This would also be a convenient time to check that the PBO isn't
  51.  * currently mapped.  Whoever calls this function should check for that.
  52.  * Remember, we can't use a PBO when it's mapped!
  53.  *
  54.  * If we're not using a PBO, this is a no-op.
  55.  *
  56.  * \param width  width of image to read/write
  57.  * \param height  height of image to read/write
  58.  * \param depth  depth of image to read/write
  59.  * \param format  format of image to read/write
  60.  * \param type  datatype of image to read/write
  61.  * \param clientMemSize  the maximum number of bytes to read/write
  62.  * \param ptr  the user-provided pointer/offset
  63.  * \return GL_TRUE if the buffer access is OK, GL_FALSE if the access would
  64.  *         go out of bounds.
  65.  */
  66. GLboolean
  67. _mesa_validate_pbo_access(GLuint dimensions,
  68.                           const struct gl_pixelstore_attrib *pack,
  69.                           GLsizei width, GLsizei height, GLsizei depth,
  70.                           GLenum format, GLenum type, GLsizei clientMemSize,
  71.                           const GLvoid *ptr)
  72. {
  73.    /* unsigned, to detect overflow/wrap-around */
  74.    uintptr_t start, end, offset, size;
  75.  
  76.    /* If no PBO is bound, 'ptr' is a pointer to client memory containing
  77.       'clientMemSize' bytes.
  78.       If a PBO is bound, 'ptr' is an offset into the bound PBO.
  79.       In that case 'clientMemSize' is ignored: we just use the PBO's size.
  80.     */
  81.    if (!_mesa_is_bufferobj(pack->BufferObj)) {
  82.       offset = 0;
  83.       size = (clientMemSize == INT_MAX) ? UINTPTR_MAX : clientMemSize;
  84.    } else {
  85.       offset = (uintptr_t)ptr;
  86.       size = pack->BufferObj->Size;
  87.       /* The ARB_pixel_buffer_object spec says:
  88.        *    "INVALID_OPERATION is generated by ColorTable, ColorSubTable,
  89.        *    ConvolutionFilter2D, ConvolutionFilter1D, SeparableFilter2D,
  90.        *    TexImage1D, TexImage2D, TexImage3D, TexSubImage1D,
  91.        *    TexSubImage2D, TexSubImage3D, and DrawPixels if the current
  92.        *    PIXEL_UNPACK_BUFFER_BINDING_ARB value is non-zero and the data
  93.        *    parameter is not evenly divisible into the number of basic machine
  94.        *    units needed to store in memory a datum indicated by the type
  95.        *    parameter."
  96.        */
  97.       if (type != GL_BITMAP &&
  98.           (offset % _mesa_sizeof_packed_type(type)))
  99.          return GL_FALSE;
  100.    }
  101.  
  102.    if (size == 0)
  103.       /* no buffer! */
  104.       return GL_FALSE;
  105.  
  106.    /* get the offset to the first pixel we'll read/write */
  107.    start = _mesa_image_offset(dimensions, pack, width, height,
  108.                               format, type, 0, 0, 0);
  109.  
  110.    /* get the offset to just past the last pixel we'll read/write */
  111.    end =  _mesa_image_offset(dimensions, pack, width, height,
  112.                              format, type, depth-1, height-1, width);
  113.  
  114.    start += offset;
  115.    end += offset;
  116.  
  117.    if (start > size) {
  118.       /* This will catch negative values / wrap-around */
  119.       return GL_FALSE;
  120.    }
  121.    if (end > size) {
  122.       /* Image read/write goes beyond end of buffer */
  123.       return GL_FALSE;
  124.    }
  125.  
  126.    /* OK! */
  127.    return GL_TRUE;
  128. }
  129.  
  130.  
  131. /**
  132.  * For commands that read from a PBO (glDrawPixels, glTexImage,
  133.  * glPolygonStipple, etc), if we're reading from a PBO, map it read-only
  134.  * and return the pointer into the PBO.  If we're not reading from a
  135.  * PBO, return \p src as-is.
  136.  * If non-null return, must call _mesa_unmap_pbo_source() when done.
  137.  *
  138.  * \return NULL if error, else pointer to start of data
  139.  */
  140. const GLvoid *
  141. _mesa_map_pbo_source(struct gl_context *ctx,
  142.                      const struct gl_pixelstore_attrib *unpack,
  143.                      const GLvoid *src)
  144. {
  145.    const GLubyte *buf;
  146.  
  147.    if (_mesa_is_bufferobj(unpack->BufferObj)) {
  148.       /* unpack from PBO */
  149.       buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
  150.                                                    unpack->BufferObj->Size,
  151.                                                    GL_MAP_READ_BIT,
  152.                                                    unpack->BufferObj,
  153.                                                    MAP_INTERNAL);
  154.       if (!buf)
  155.          return NULL;
  156.  
  157.       buf = ADD_POINTERS(buf, src);
  158.    }
  159.    else {
  160.       /* unpack from normal memory */
  161.       buf = src;
  162.    }
  163.  
  164.    return buf;
  165. }
  166.  
  167. /**
  168.  * Perform PBO validation for read operations with uncompressed textures.
  169.  * If any GL errors are detected, false is returned, otherwise returns true.
  170.  * \sa _mesa_validate_pbo_access
  171.  */
  172. bool
  173. _mesa_validate_pbo_source(struct gl_context *ctx, GLuint dimensions,
  174.                           const struct gl_pixelstore_attrib *unpack,
  175.                           GLsizei width, GLsizei height, GLsizei depth,
  176.                           GLenum format, GLenum type,
  177.                           GLsizei clientMemSize,
  178.                           const GLvoid *ptr, const char *where)
  179. {
  180.    assert(dimensions == 1 || dimensions == 2 || dimensions == 3);
  181.  
  182.    if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
  183.                                   format, type, clientMemSize, ptr)) {
  184.       if (_mesa_is_bufferobj(unpack->BufferObj)) {
  185.          _mesa_error(ctx, GL_INVALID_OPERATION,
  186.                      "%s(out of bounds PBO access)",
  187.                      where);
  188.       } else {
  189.          _mesa_error(ctx, GL_INVALID_OPERATION,
  190.                      "%s(out of bounds access: bufSize (%d) is too small)",
  191.                      where, clientMemSize);
  192.       }
  193.       return false;
  194.    }
  195.  
  196.    if (!_mesa_is_bufferobj(unpack->BufferObj)) {
  197.       /* non-PBO access: no further validation to be done */
  198.       return true;
  199.    }
  200.  
  201.    if (_mesa_check_disallowed_mapping(unpack->BufferObj)) {
  202.       /* buffer is already mapped - that's an error */
  203.       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)",
  204.                   where);
  205.       return false;
  206.    }
  207.  
  208.    return true;
  209. }
  210.  
  211. /**
  212.  * Perform PBO validation for read operations with compressed textures.
  213.  * If any GL errors are detected, false is returned, otherwise returns true.
  214.  */
  215. bool
  216. _mesa_validate_pbo_source_compressed(struct gl_context *ctx, GLuint dimensions,
  217.                                      const struct gl_pixelstore_attrib *unpack,
  218.                                      GLsizei imageSize, const GLvoid *pixels,
  219.                                      const char *where)
  220. {
  221.    if (!_mesa_is_bufferobj(unpack->BufferObj)) {
  222.       /* not using a PBO */
  223.       return true;
  224.    }
  225.  
  226.    if ((const GLubyte *) pixels + imageSize >
  227.        ((const GLubyte *) 0) + unpack->BufferObj->Size) {
  228.       /* out of bounds read! */
  229.       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid PBO access)",
  230.                   where);
  231.       return false;
  232.    }
  233.  
  234.    if (_mesa_check_disallowed_mapping(unpack->BufferObj)) {
  235.       /* buffer is already mapped - that's an error */
  236.       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)",
  237.                   where);
  238.       return false;
  239.    }
  240.  
  241.    return true;
  242. }
  243.  
  244. /**
  245.  * Perform PBO-read mapping.
  246.  * If any GL errors are detected, they'll be recorded and NULL returned.
  247.  * \sa _mesa_validate_pbo_source
  248.  * \sa _mesa_map_pbo_source
  249.  * A call to this function should have a matching call to
  250.  * _mesa_unmap_pbo_source().
  251.  */
  252. const GLvoid *
  253. _mesa_map_validate_pbo_source(struct gl_context *ctx,
  254.                               GLuint dimensions,
  255.                               const struct gl_pixelstore_attrib *unpack,
  256.                               GLsizei width, GLsizei height, GLsizei depth,
  257.                               GLenum format, GLenum type,
  258.                               GLsizei clientMemSize,
  259.                               const GLvoid *ptr, const char *where)
  260. {
  261.    if (!_mesa_validate_pbo_source(ctx, dimensions, unpack,
  262.                                   width, height, depth, format, type,
  263.                                   clientMemSize, ptr, where)) {
  264.      return NULL;
  265.    }
  266.  
  267.    ptr = _mesa_map_pbo_source(ctx, unpack, ptr);
  268.    return ptr;
  269. }
  270.  
  271.  
  272. /**
  273.  * Counterpart to _mesa_map_pbo_source()
  274.  */
  275. void
  276. _mesa_unmap_pbo_source(struct gl_context *ctx,
  277.                        const struct gl_pixelstore_attrib *unpack)
  278. {
  279.    assert(unpack != &ctx->Pack); /* catch pack/unpack mismatch */
  280.    if (_mesa_is_bufferobj(unpack->BufferObj)) {
  281.       ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL);
  282.    }
  283. }
  284.  
  285.  
  286. /**
  287.  * For commands that write to a PBO (glReadPixels, glGetColorTable, etc),
  288.  * if we're writing to a PBO, map it write-only and return the pointer
  289.  * into the PBO.  If we're not writing to a PBO, return \p dst as-is.
  290.  * If non-null return, must call _mesa_unmap_pbo_dest() when done.
  291.  *
  292.  * \return NULL if error, else pointer to start of data
  293.  */
  294. void *
  295. _mesa_map_pbo_dest(struct gl_context *ctx,
  296.                    const struct gl_pixelstore_attrib *pack,
  297.                    GLvoid *dest)
  298. {
  299.    void *buf;
  300.  
  301.    if (_mesa_is_bufferobj(pack->BufferObj)) {
  302.       /* pack into PBO */
  303.       buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
  304.                                                    pack->BufferObj->Size,
  305.                                                    GL_MAP_WRITE_BIT,
  306.                                                    pack->BufferObj,
  307.                                                    MAP_INTERNAL);
  308.       if (!buf)
  309.          return NULL;
  310.  
  311.       buf = ADD_POINTERS(buf, dest);
  312.    }
  313.    else {
  314.       /* pack to normal memory */
  315.       buf = dest;
  316.    }
  317.  
  318.    return buf;
  319. }
  320.  
  321.  
  322. /**
  323.  * Combine PBO-write validation and mapping.
  324.  * If any GL errors are detected, they'll be recorded and NULL returned.
  325.  * \sa _mesa_validate_pbo_access
  326.  * \sa _mesa_map_pbo_dest
  327.  * A call to this function should have a matching call to
  328.  * _mesa_unmap_pbo_dest().
  329.  */
  330. GLvoid *
  331. _mesa_map_validate_pbo_dest(struct gl_context *ctx,
  332.                             GLuint dimensions,
  333.                             const struct gl_pixelstore_attrib *unpack,
  334.                             GLsizei width, GLsizei height, GLsizei depth,
  335.                             GLenum format, GLenum type, GLsizei clientMemSize,
  336.                             GLvoid *ptr, const char *where)
  337. {
  338.    assert(dimensions == 1 || dimensions == 2 || dimensions == 3);
  339.  
  340.    if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
  341.                                   format, type, clientMemSize, ptr)) {
  342.       if (_mesa_is_bufferobj(unpack->BufferObj)) {
  343.          _mesa_error(ctx, GL_INVALID_OPERATION,
  344.                      "%s(out of bounds PBO access)", where);
  345.       } else {
  346.          _mesa_error(ctx, GL_INVALID_OPERATION,
  347.                      "%s(out of bounds access: bufSize (%d) is too small)",
  348.                      where, clientMemSize);
  349.       }
  350.       return NULL;
  351.    }
  352.  
  353.    if (!_mesa_is_bufferobj(unpack->BufferObj)) {
  354.       /* non-PBO access: no further validation to be done */
  355.       return ptr;
  356.    }
  357.  
  358.    if (_mesa_check_disallowed_mapping(unpack->BufferObj)) {
  359.       /* buffer is already mapped - that's an error */
  360.       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
  361.       return NULL;
  362.    }
  363.  
  364.    ptr = _mesa_map_pbo_dest(ctx, unpack, ptr);
  365.    return ptr;
  366. }
  367.  
  368.  
  369. /**
  370.  * Counterpart to _mesa_map_pbo_dest()
  371.  */
  372. void
  373. _mesa_unmap_pbo_dest(struct gl_context *ctx,
  374.                      const struct gl_pixelstore_attrib *pack)
  375. {
  376.    assert(pack != &ctx->Unpack); /* catch pack/unpack mismatch */
  377.    if (_mesa_is_bufferobj(pack->BufferObj)) {
  378.       ctx->Driver.UnmapBuffer(ctx, pack->BufferObj, MAP_INTERNAL);
  379.    }
  380. }
  381.  
  382.  
  383. /**
  384.  * Check if an unpack PBO is active prior to fetching a texture image.
  385.  * If so, do bounds checking and map the buffer into main memory.
  386.  * Any errors detected will be recorded.
  387.  * The caller _must_ call _mesa_unmap_teximage_pbo() too!
  388.  */
  389. const GLvoid *
  390. _mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions,
  391.                             GLsizei width, GLsizei height, GLsizei depth,
  392.                             GLenum format, GLenum type, const GLvoid *pixels,
  393.                             const struct gl_pixelstore_attrib *unpack,
  394.                             const char *funcName)
  395. {
  396.    GLubyte *buf;
  397.  
  398.    if (!_mesa_is_bufferobj(unpack->BufferObj)) {
  399.       /* no PBO */
  400.       return pixels;
  401.    }
  402.    if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
  403.                                   format, type, INT_MAX, pixels)) {
  404.       _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(invalid PBO access)",
  405.                   funcName, dimensions);
  406.       return NULL;
  407.    }
  408.  
  409.    buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
  410.                                                 unpack->BufferObj->Size,
  411.                                                 GL_MAP_READ_BIT,
  412.                                                 unpack->BufferObj,
  413.                                                 MAP_INTERNAL);
  414.    if (!buf) {
  415.       _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(PBO is mapped)", funcName,
  416.                   dimensions);
  417.       return NULL;
  418.    }
  419.  
  420.    return ADD_POINTERS(buf, pixels);
  421. }
  422.  
  423.  
  424. /**
  425.  * Check if an unpack PBO is active prior to fetching a compressed texture
  426.  * image.
  427.  * If so, do bounds checking and map the buffer into main memory.
  428.  * Any errors detected will be recorded.
  429.  * The caller _must_ call _mesa_unmap_teximage_pbo() too!
  430.  */
  431. const GLvoid *
  432. _mesa_validate_pbo_compressed_teximage(struct gl_context *ctx,
  433.                                  GLuint dimensions, GLsizei imageSize,
  434.                                  const GLvoid *pixels,
  435.                                  const struct gl_pixelstore_attrib *packing,
  436.                                  const char *funcName)
  437. {
  438.    GLubyte *buf;
  439.  
  440.    if (!_mesa_validate_pbo_source_compressed(ctx, dimensions, packing,
  441.                                              imageSize, pixels, funcName)) {
  442.      /* error is already set during validation */
  443.       return NULL;
  444.    }
  445.  
  446.    if (!_mesa_is_bufferobj(packing->BufferObj)) {
  447.       /* not using a PBO - return pointer unchanged */
  448.       return pixels;
  449.    }
  450.  
  451.    buf = (GLubyte*) ctx->Driver.MapBufferRange(ctx, 0,
  452.                                                packing->BufferObj->Size,
  453.                                                GL_MAP_READ_BIT,
  454.                                                packing->BufferObj,
  455.                                                MAP_INTERNAL);
  456.  
  457.    /* Validation above already checked that PBO is not mapped, so buffer
  458.     * should not be null.
  459.     */
  460.    assert(buf);
  461.  
  462.    return ADD_POINTERS(buf, pixels);
  463. }
  464.  
  465.  
  466. /**
  467.  * This function must be called after either of the validate_pbo_*_teximage()
  468.  * functions.  It unmaps the PBO buffer if it was mapped earlier.
  469.  */
  470. void
  471. _mesa_unmap_teximage_pbo(struct gl_context *ctx,
  472.                          const struct gl_pixelstore_attrib *unpack)
  473. {
  474.    if (_mesa_is_bufferobj(unpack->BufferObj)) {
  475.       ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL);
  476.    }
  477. }
  478.