* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
#include "glheader.h"
#include "bufferobj.h"
+#include "glformats.h"
#include "image.h"
#include "imports.h"
#include "mtypes.h"
* When we're about to read pixel data out of a PBO (via glDrawPixels,
* glTexImage, etc) or write data into a PBO (via glReadPixels,
* glGetTexImage, etc) we call this function to check that we're not
- * going to read out of bounds.
+ * going to read/write out of bounds.
*
* XXX This would also be a convenient time to check that the PBO isn't
* currently mapped. Whoever calls this function should check for that.
* \param depth depth of image to read/write
* \param format format of image to read/write
* \param type datatype of image to read/write
+ * \param clientMemSize the maximum number of bytes to read/write
* \param ptr the user-provided pointer/offset
- * \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would
+ * \return GL_TRUE if the buffer access is OK, GL_FALSE if the access would
* go out of bounds.
*/
GLboolean
_mesa_validate_pbo_access(GLuint dimensions,
const struct gl_pixelstore_attrib *pack,
GLsizei width, GLsizei height, GLsizei depth,
- GLenum format, GLenum type, const GLvoid *ptr)
+ GLenum format, GLenum type, GLsizei clientMemSize,
+ const GLvoid *ptr)
{
- GLvoid *start, *end;
- const GLubyte *sizeAddr; /* buffer size, cast to a pointer */
-
- if (!_mesa_is_bufferobj(pack->BufferObj))
- return GL_TRUE; /* no PBO, OK */
+ /* unsigned, to detect overflow/wrap-around */
+ uintptr_t start, end, offset, size;
+
+ /* If no PBO is bound, 'ptr' is a pointer to client memory containing
+ 'clientMemSize' bytes.
+ If a PBO is bound, 'ptr' is an offset into the bound PBO.
+ In that case 'clientMemSize' is ignored: we just use the PBO's size.
+ */
+ if (!_mesa_is_bufferobj(pack->BufferObj)) {
+ offset = 0;
+ size = clientMemSize;
+ } else {
+ offset = (uintptr_t)ptr;
+ size = pack->BufferObj->Size;
+ /* The ARB_pixel_buffer_object spec says:
+ * "INVALID_OPERATION is generated by ColorTable, ColorSubTable,
+ * ConvolutionFilter2D, ConvolutionFilter1D, SeparableFilter2D,
+ * TexImage1D, TexImage2D, TexImage3D, TexSubImage1D,
+ * TexSubImage2D, TexSubImage3D, and DrawPixels if the current
+ * PIXEL_UNPACK_BUFFER_BINDING_ARB value is non-zero and the data
+ * parameter is not evenly divisible into the number of basic machine
+ * units needed to store in memory a datum indicated by the type
+ * parameter."
+ */
+ if (type != GL_BITMAP &&
+ (offset % _mesa_sizeof_packed_type(type)))
+ return GL_FALSE;
+ }
- if (pack->BufferObj->Size == 0)
+ if (size == 0)
/* no buffer! */
return GL_FALSE;
- /* get address of first pixel we'll read */
- start = _mesa_image_address(dimensions, pack, ptr, width, height,
- format, type, 0, 0, 0);
+ /* get the offset to the first pixel we'll read/write */
+ start = _mesa_image_offset(dimensions, pack, width, height,
+ format, type, 0, 0, 0);
- /* get address just past the last pixel we'll read */
- end = _mesa_image_address(dimensions, pack, ptr, width, height,
+ /* get the offset to just past the last pixel we'll read/write */
+ end = _mesa_image_offset(dimensions, pack, width, height,
format, type, depth-1, height-1, width);
+ start += offset;
+ end += offset;
- sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size;
-
- if ((const GLubyte *) start > sizeAddr) {
+ if (start > size) {
/* This will catch negative values / wrap-around */
return GL_FALSE;
}
- if ((const GLubyte *) end > sizeAddr) {
- /* Image read goes beyond end of buffer */
+ if (end > size) {
+ /* Image read/write goes beyond end of buffer */
return GL_FALSE;
}
if (_mesa_is_bufferobj(unpack->BufferObj)) {
/* unpack from PBO */
- buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
- GL_READ_ONLY_ARB,
- unpack->BufferObj);
+ buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
+ unpack->BufferObj->Size,
+ GL_MAP_READ_BIT,
+ unpack->BufferObj);
if (!buf)
return NULL;
GLuint dimensions,
const struct gl_pixelstore_attrib *unpack,
GLsizei width, GLsizei height, GLsizei depth,
- GLenum format, GLenum type, const GLvoid *ptr,
- const char *where)
+ GLenum format, GLenum type,
+ GLsizei clientMemSize,
+ const GLvoid *ptr, const char *where)
{
ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
- if (!_mesa_is_bufferobj(unpack->BufferObj)) {
- /* non-PBO access: no validation to be done */
- return ptr;
+ if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
+ format, type, clientMemSize, ptr)) {
+ if (_mesa_is_bufferobj(unpack->BufferObj)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(out of bounds PBO access)", where);
+ } else {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(out of bounds access: bufSize (%d) is too small)",
+ where, clientMemSize);
+ }
+ return NULL;
}
- if (!_mesa_validate_pbo_access(dimensions, unpack,
- width, height, depth, format, type, ptr)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(out of bounds PBO access)", where);
- return NULL;
+ if (!_mesa_is_bufferobj(unpack->BufferObj)) {
+ /* non-PBO access: no further validation to be done */
+ return ptr;
}
if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
{
ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */
if (_mesa_is_bufferobj(unpack->BufferObj)) {
- ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
- unpack->BufferObj);
+ ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj);
}
}
if (_mesa_is_bufferobj(pack->BufferObj)) {
/* pack into PBO */
- buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
- GL_WRITE_ONLY_ARB,
- pack->BufferObj);
+ buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
+ pack->BufferObj->Size,
+ GL_MAP_WRITE_BIT,
+ pack->BufferObj);
if (!buf)
return NULL;
GLuint dimensions,
const struct gl_pixelstore_attrib *unpack,
GLsizei width, GLsizei height, GLsizei depth,
- GLenum format, GLenum type, GLvoid *ptr,
- const char *where)
+ GLenum format, GLenum type, GLsizei clientMemSize,
+ GLvoid *ptr, const char *where)
{
ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
- if (!_mesa_is_bufferobj(unpack->BufferObj)) {
- /* non-PBO access: no validation to be done */
- return ptr;
+ if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
+ format, type, clientMemSize, ptr)) {
+ if (_mesa_is_bufferobj(unpack->BufferObj)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(out of bounds PBO access)", where);
+ } else {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(out of bounds access: bufSize (%d) is too small)",
+ where, clientMemSize);
+ }
+ return NULL;
}
- if (!_mesa_validate_pbo_access(dimensions, unpack,
- width, height, depth, format, type, ptr)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(out of bounds PBO access)", where);
- return NULL;
+ if (!_mesa_is_bufferobj(unpack->BufferObj)) {
+ /* non-PBO access: no further validation to be done */
+ return ptr;
}
if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
{
ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */
if (_mesa_is_bufferobj(pack->BufferObj)) {
- ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, pack->BufferObj);
+ ctx->Driver.UnmapBuffer(ctx, pack->BufferObj);
}
}
-
/**
* Check if an unpack PBO is active prior to fetching a texture image.
* If so, do bounds checking and map the buffer into main memory.
return pixels;
}
if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
- format, type, pixels)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access)");
+ format, type, INT_MAX, pixels)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(invalid PBO access)",
+ funcName, dimensions);
return NULL;
}
- buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
- GL_READ_ONLY_ARB, unpack->BufferObj);
+ buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
+ unpack->BufferObj->Size,
+ GL_MAP_READ_BIT,
+ unpack->BufferObj);
if (!buf) {
- _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped)");
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(PBO is mapped)", funcName,
+ dimensions);
return NULL;
}
*/
const GLvoid *
_mesa_validate_pbo_compressed_teximage(struct gl_context *ctx,
- GLsizei imageSize, const GLvoid *pixels,
+ GLuint dimensions, GLsizei imageSize,
+ const GLvoid *pixels,
const struct gl_pixelstore_attrib *packing,
const char *funcName)
{
if ((const GLubyte *) pixels + imageSize >
((const GLubyte *) 0) + packing->BufferObj->Size) {
/* out of bounds read! */
- _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access)");
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(invalid PBO access)",
+ funcName, dimensions);
return NULL;
}
- buf = (GLubyte*) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
- GL_READ_ONLY_ARB, packing->BufferObj);
+ buf = (GLubyte*) ctx->Driver.MapBufferRange(ctx, 0,
+ packing->BufferObj->Size,
+ GL_MAP_READ_BIT,
+ packing->BufferObj);
if (!buf) {
- _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped");
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(PBO is mapped)", funcName,
+ dimensions);
return NULL;
}
const struct gl_pixelstore_attrib *unpack)
{
if (_mesa_is_bufferobj(unpack->BufferObj)) {
- ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
- unpack->BufferObj);
+ ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj);
}
}
-
-