Subversion Repositories Kolibri OS

Rev

Go to most recent revision | 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;
  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.       if (!buf)
  154.          return NULL;
  155.  
  156.       buf = ADD_POINTERS(buf, src);
  157.    }
  158.    else {
  159.       /* unpack from normal memory */
  160.       buf = src;
  161.    }
  162.  
  163.    return buf;
  164. }
  165.  
  166.  
  167. /**
  168.  * Combine PBO-read validation and mapping.
  169.  * If any GL errors are detected, they'll be recorded and NULL returned.
  170.  * \sa _mesa_validate_pbo_access
  171.  * \sa _mesa_map_pbo_source
  172.  * A call to this function should have a matching call to
  173.  * _mesa_unmap_pbo_source().
  174.  */
  175. const GLvoid *
  176. _mesa_map_validate_pbo_source(struct gl_context *ctx,
  177.                               GLuint dimensions,
  178.                               const struct gl_pixelstore_attrib *unpack,
  179.                               GLsizei width, GLsizei height, GLsizei depth,
  180.                               GLenum format, GLenum type,
  181.                               GLsizei clientMemSize,
  182.                               const GLvoid *ptr, const char *where)
  183. {
  184.    ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
  185.  
  186.    if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
  187.                                   format, type, clientMemSize, ptr)) {
  188.       if (_mesa_is_bufferobj(unpack->BufferObj)) {
  189.          _mesa_error(ctx, GL_INVALID_OPERATION,
  190.                      "%s(out of bounds PBO access)", where);
  191.       } else {
  192.          _mesa_error(ctx, GL_INVALID_OPERATION,
  193.                      "%s(out of bounds access: bufSize (%d) is too small)",
  194.                      where, clientMemSize);
  195.       }
  196.       return NULL;
  197.    }
  198.  
  199.    if (!_mesa_is_bufferobj(unpack->BufferObj)) {
  200.       /* non-PBO access: no further validation to be done */
  201.       return ptr;
  202.    }
  203.  
  204.    if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
  205.       /* buffer is already mapped - that's an error */
  206.       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
  207.       return NULL;
  208.    }
  209.  
  210.    ptr = _mesa_map_pbo_source(ctx, unpack, ptr);
  211.    return ptr;
  212. }
  213.  
  214.  
  215. /**
  216.  * Counterpart to _mesa_map_pbo_source()
  217.  */
  218. void
  219. _mesa_unmap_pbo_source(struct gl_context *ctx,
  220.                        const struct gl_pixelstore_attrib *unpack)
  221. {
  222.    ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */
  223.    if (_mesa_is_bufferobj(unpack->BufferObj)) {
  224.       ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj);
  225.    }
  226. }
  227.  
  228.  
  229. /**
  230.  * For commands that write to a PBO (glReadPixels, glGetColorTable, etc),
  231.  * if we're writing to a PBO, map it write-only and return the pointer
  232.  * into the PBO.  If we're not writing to a PBO, return \p dst as-is.
  233.  * If non-null return, must call _mesa_unmap_pbo_dest() when done.
  234.  *
  235.  * \return NULL if error, else pointer to start of data
  236.  */
  237. void *
  238. _mesa_map_pbo_dest(struct gl_context *ctx,
  239.                    const struct gl_pixelstore_attrib *pack,
  240.                    GLvoid *dest)
  241. {
  242.    void *buf;
  243.  
  244.    if (_mesa_is_bufferobj(pack->BufferObj)) {
  245.       /* pack into PBO */
  246.       buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
  247.                                                    pack->BufferObj->Size,
  248.                                                    GL_MAP_WRITE_BIT,
  249.                                                    pack->BufferObj);
  250.       if (!buf)
  251.          return NULL;
  252.  
  253.       buf = ADD_POINTERS(buf, dest);
  254.    }
  255.    else {
  256.       /* pack to normal memory */
  257.       buf = dest;
  258.    }
  259.  
  260.    return buf;
  261. }
  262.  
  263.  
  264. /**
  265.  * Combine PBO-write validation and mapping.
  266.  * If any GL errors are detected, they'll be recorded and NULL returned.
  267.  * \sa _mesa_validate_pbo_access
  268.  * \sa _mesa_map_pbo_dest
  269.  * A call to this function should have a matching call to
  270.  * _mesa_unmap_pbo_dest().
  271.  */
  272. GLvoid *
  273. _mesa_map_validate_pbo_dest(struct gl_context *ctx,
  274.                             GLuint dimensions,
  275.                             const struct gl_pixelstore_attrib *unpack,
  276.                             GLsizei width, GLsizei height, GLsizei depth,
  277.                             GLenum format, GLenum type, GLsizei clientMemSize,
  278.                             GLvoid *ptr, const char *where)
  279. {
  280.    ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
  281.  
  282.    if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
  283.                                   format, type, clientMemSize, ptr)) {
  284.       if (_mesa_is_bufferobj(unpack->BufferObj)) {
  285.          _mesa_error(ctx, GL_INVALID_OPERATION,
  286.                      "%s(out of bounds PBO access)", where);
  287.       } else {
  288.          _mesa_error(ctx, GL_INVALID_OPERATION,
  289.                      "%s(out of bounds access: bufSize (%d) is too small)",
  290.                      where, clientMemSize);
  291.       }
  292.       return NULL;
  293.    }
  294.  
  295.    if (!_mesa_is_bufferobj(unpack->BufferObj)) {
  296.       /* non-PBO access: no further validation to be done */
  297.       return ptr;
  298.    }
  299.  
  300.    if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
  301.       /* buffer is already mapped - that's an error */
  302.       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
  303.       return NULL;
  304.    }
  305.  
  306.    ptr = _mesa_map_pbo_dest(ctx, unpack, ptr);
  307.    return ptr;
  308. }
  309.  
  310.  
  311. /**
  312.  * Counterpart to _mesa_map_pbo_dest()
  313.  */
  314. void
  315. _mesa_unmap_pbo_dest(struct gl_context *ctx,
  316.                      const struct gl_pixelstore_attrib *pack)
  317. {
  318.    ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */
  319.    if (_mesa_is_bufferobj(pack->BufferObj)) {
  320.       ctx->Driver.UnmapBuffer(ctx, pack->BufferObj);
  321.    }
  322. }
  323.  
  324.  
  325. /**
  326.  * Check if an unpack PBO is active prior to fetching a texture image.
  327.  * If so, do bounds checking and map the buffer into main memory.
  328.  * Any errors detected will be recorded.
  329.  * The caller _must_ call _mesa_unmap_teximage_pbo() too!
  330.  */
  331. const GLvoid *
  332. _mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions,
  333.                             GLsizei width, GLsizei height, GLsizei depth,
  334.                             GLenum format, GLenum type, const GLvoid *pixels,
  335.                             const struct gl_pixelstore_attrib *unpack,
  336.                             const char *funcName)
  337. {
  338.    GLubyte *buf;
  339.  
  340.    if (!_mesa_is_bufferobj(unpack->BufferObj)) {
  341.       /* no PBO */
  342.       return pixels;
  343.    }
  344.    if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
  345.                                   format, type, INT_MAX, pixels)) {
  346.       _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(invalid PBO access)",
  347.                   funcName, dimensions);
  348.       return NULL;
  349.    }
  350.  
  351.    buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
  352.                                                 unpack->BufferObj->Size,
  353.                                                 GL_MAP_READ_BIT,
  354.                                                 unpack->BufferObj);
  355.    if (!buf) {
  356.       _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(PBO is mapped)", funcName,
  357.                   dimensions);
  358.       return NULL;
  359.    }
  360.  
  361.    return ADD_POINTERS(buf, pixels);
  362. }
  363.  
  364.  
  365. /**
  366.  * Check if an unpack PBO is active prior to fetching a compressed texture
  367.  * image.
  368.  * If so, do bounds checking and map the buffer into main memory.
  369.  * Any errors detected will be recorded.
  370.  * The caller _must_ call _mesa_unmap_teximage_pbo() too!
  371.  */
  372. const GLvoid *
  373. _mesa_validate_pbo_compressed_teximage(struct gl_context *ctx,
  374.                                  GLuint dimensions, GLsizei imageSize,
  375.                                  const GLvoid *pixels,
  376.                                  const struct gl_pixelstore_attrib *packing,
  377.                                  const char *funcName)
  378. {
  379.    GLubyte *buf;
  380.  
  381.    if (!_mesa_is_bufferobj(packing->BufferObj)) {
  382.       /* not using a PBO - return pointer unchanged */
  383.       return pixels;
  384.    }
  385.    if ((const GLubyte *) pixels + imageSize >
  386.        ((const GLubyte *) 0) + packing->BufferObj->Size) {
  387.       /* out of bounds read! */
  388.       _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(invalid PBO access)",
  389.                   funcName, dimensions);
  390.       return NULL;
  391.    }
  392.  
  393.    buf = (GLubyte*) ctx->Driver.MapBufferRange(ctx, 0,
  394.                                                packing->BufferObj->Size,
  395.                                                GL_MAP_READ_BIT,
  396.                                                packing->BufferObj);
  397.    if (!buf) {
  398.       _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(PBO is mapped)", funcName,
  399.                   dimensions);
  400.       return NULL;
  401.    }
  402.  
  403.    return ADD_POINTERS(buf, pixels);
  404. }
  405.  
  406.  
  407. /**
  408.  * This function must be called after either of the validate_pbo_*_teximage()
  409.  * functions.  It unmaps the PBO buffer if it was mapped earlier.
  410.  */
  411. void
  412. _mesa_unmap_teximage_pbo(struct gl_context *ctx,
  413.                          const struct gl_pixelstore_attrib *unpack)
  414. {
  415.    if (_mesa_is_bufferobj(unpack->BufferObj)) {
  416.       ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj);
  417.    }
  418. }
  419.