* 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 "errors.h"
#include "glheader.h"
#include "bufferobj.h"
+#include "glformats.h"
#include "image.h"
-#include "imports.h"
#include "mtypes.h"
+#include "macros.h"
#include "pbo.h"
GLenum format, GLenum type, GLsizei clientMemSize,
const GLvoid *ptr)
{
- const GLvoid *start, *end, *offset;
- const GLubyte *sizeAddr; /* buffer size, cast to a pointer */
+ /* 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)) {
+ if (!pack->BufferObj) {
offset = 0;
- sizeAddr = ((const GLubyte *) 0) + clientMemSize;
+ size = (clientMemSize == INT_MAX) ? UINTPTR_MAX : clientMemSize;
} else {
- offset = ptr;
- sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size;
+ 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,
* parameter."
*/
if (type != GL_BITMAP &&
- ((GLintptr)offset % _mesa_sizeof_packed_type(type)))
+ (offset % _mesa_sizeof_packed_type(type)))
return GL_FALSE;
}
- if (sizeAddr == 0)
+ if (size == 0)
/* no buffer! */
return GL_FALSE;
+ /* If the size of the image is zero then no pixels are accessed so we
+ * don't need to check anything else.
+ */
+ if (width == 0 || height == 0 || depth == 0)
+ return GL_TRUE;
+
/* get the offset to the first pixel we'll read/write */
- start = _mesa_image_address(dimensions, pack, offset, width, height,
- format, type, 0, 0, 0);
+ start = _mesa_image_offset(dimensions, pack, width, height,
+ format, type, 0, 0, 0);
/* get the offset to just past the last pixel we'll read/write */
- end = _mesa_image_address(dimensions, pack, offset, width, height,
- format, type, depth-1, height-1, width);
+ end = _mesa_image_offset(dimensions, pack, width, height,
+ format, type, depth-1, height-1, width);
- if ((const GLubyte *) start > sizeAddr) {
+ start += offset;
+ end += offset;
+
+ if (start > size) {
/* This will catch negative values / wrap-around */
return GL_FALSE;
}
- if ((const GLubyte *) end > sizeAddr) {
+ if (end > size) {
/* Image read/write goes beyond end of buffer */
return GL_FALSE;
}
{
const GLubyte *buf;
- if (_mesa_is_bufferobj(unpack->BufferObj)) {
+ if (unpack->BufferObj) {
/* unpack from PBO */
buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
unpack->BufferObj->Size,
GL_MAP_READ_BIT,
- unpack->BufferObj);
+ unpack->BufferObj,
+ MAP_INTERNAL);
if (!buf)
return NULL;
return buf;
}
-
/**
- * Combine PBO-read validation and mapping.
- * If any GL errors are detected, they'll be recorded and NULL returned.
+ * Perform PBO validation for read operations with uncompressed textures.
+ * If any GL errors are detected, false is returned, otherwise returns true.
* \sa _mesa_validate_pbo_access
- * \sa _mesa_map_pbo_source
- * A call to this function should have a matching call to
- * _mesa_unmap_pbo_source().
*/
-const GLvoid *
-_mesa_map_validate_pbo_source(struct gl_context *ctx,
- GLuint dimensions,
- const struct gl_pixelstore_attrib *unpack,
- GLsizei width, GLsizei height, GLsizei depth,
- GLenum format, GLenum type, GLsizei clientMemSize,
- const GLvoid *ptr, const char *where)
+bool
+_mesa_validate_pbo_source(struct gl_context *ctx, GLuint dimensions,
+ const struct gl_pixelstore_attrib *unpack,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLenum format, GLenum type,
+ GLsizei clientMemSize,
+ const GLvoid *ptr, const char *where)
{
- ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
+ assert(dimensions == 1 || dimensions == 2 || dimensions == 3);
if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
format, type, clientMemSize, ptr)) {
- if (_mesa_is_bufferobj(unpack->BufferObj)) {
+ if (unpack->BufferObj) {
_mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(out of bounds PBO access)", where);
+ "%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;
+ return false;
}
- if (!_mesa_is_bufferobj(unpack->BufferObj)) {
+ if (!unpack->BufferObj) {
/* non-PBO access: no further validation to be done */
- return ptr;
+ return true;
}
- if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
+ if (_mesa_check_disallowed_mapping(unpack->BufferObj)) {
/* buffer is already mapped - that's an error */
- _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
- return NULL;
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)",
+ where);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Perform PBO validation for read operations with compressed textures.
+ * If any GL errors are detected, false is returned, otherwise returns true.
+ */
+bool
+_mesa_validate_pbo_source_compressed(struct gl_context *ctx, GLuint dimensions,
+ const struct gl_pixelstore_attrib *unpack,
+ GLsizei imageSize, const GLvoid *pixels,
+ const char *where)
+{
+ if (!unpack->BufferObj) {
+ /* not using a PBO */
+ return true;
+ }
+
+ if ((const GLubyte *) pixels + imageSize >
+ ((const GLubyte *) 0) + unpack->BufferObj->Size) {
+ /* out of bounds read! */
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid PBO access)",
+ where);
+ return false;
+ }
+
+ if (_mesa_check_disallowed_mapping(unpack->BufferObj)) {
+ /* buffer is already mapped - that's an error */
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)",
+ where);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Perform PBO-read mapping.
+ * If any GL errors are detected, they'll be recorded and NULL returned.
+ * \sa _mesa_validate_pbo_source
+ * \sa _mesa_map_pbo_source
+ * A call to this function should have a matching call to
+ * _mesa_unmap_pbo_source().
+ */
+const GLvoid *
+_mesa_map_validate_pbo_source(struct gl_context *ctx,
+ GLuint dimensions,
+ const struct gl_pixelstore_attrib *unpack,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLenum format, GLenum type,
+ GLsizei clientMemSize,
+ const GLvoid *ptr, const char *where)
+{
+ if (!_mesa_validate_pbo_source(ctx, dimensions, unpack,
+ width, height, depth, format, type,
+ clientMemSize, ptr, where)) {
+ return NULL;
}
ptr = _mesa_map_pbo_source(ctx, unpack, ptr);
_mesa_unmap_pbo_source(struct gl_context *ctx,
const struct gl_pixelstore_attrib *unpack)
{
- ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */
- if (_mesa_is_bufferobj(unpack->BufferObj)) {
- ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj);
+ assert(unpack != &ctx->Pack); /* catch pack/unpack mismatch */
+ if (unpack->BufferObj) {
+ ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL);
}
}
{
void *buf;
- if (_mesa_is_bufferobj(pack->BufferObj)) {
+ if (pack->BufferObj) {
/* pack into PBO */
buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
pack->BufferObj->Size,
GL_MAP_WRITE_BIT,
- pack->BufferObj);
+ pack->BufferObj,
+ MAP_INTERNAL);
if (!buf)
return NULL;
*/
GLvoid *
_mesa_map_validate_pbo_dest(struct gl_context *ctx,
- GLuint dimensions,
- const struct gl_pixelstore_attrib *unpack,
- GLsizei width, GLsizei height, GLsizei depth,
- GLenum format, GLenum type, GLsizei clientMemSize,
- GLvoid *ptr, const char *where)
+ GLuint dimensions,
+ const struct gl_pixelstore_attrib *unpack,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLenum format, GLenum type, GLsizei clientMemSize,
+ GLvoid *ptr, const char *where)
{
- ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
+ assert(dimensions == 1 || dimensions == 2 || dimensions == 3);
if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
format, type, clientMemSize, ptr)) {
- if (_mesa_is_bufferobj(unpack->BufferObj)) {
+ if (unpack->BufferObj) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"%s(out of bounds PBO access)", where);
} else {
return NULL;
}
- if (!_mesa_is_bufferobj(unpack->BufferObj)) {
+ if (!unpack->BufferObj) {
/* non-PBO access: no further validation to be done */
return ptr;
}
- if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
+ if (_mesa_check_disallowed_mapping(unpack->BufferObj)) {
/* buffer is already mapped - that's an error */
_mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
return NULL;
_mesa_unmap_pbo_dest(struct gl_context *ctx,
const struct gl_pixelstore_attrib *pack)
{
- ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */
- if (_mesa_is_bufferobj(pack->BufferObj)) {
- ctx->Driver.UnmapBuffer(ctx, pack->BufferObj);
+ assert(pack != &ctx->Unpack); /* catch pack/unpack mismatch */
+ if (pack->BufferObj) {
+ ctx->Driver.UnmapBuffer(ctx, pack->BufferObj, MAP_INTERNAL);
}
}
{
GLubyte *buf;
- if (!_mesa_is_bufferobj(unpack->BufferObj)) {
+ if (!unpack->BufferObj) {
/* no PBO */
return pixels;
}
if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
- format, type, INT_MAX, 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.MapBufferRange(ctx, 0, unpack->BufferObj->Size,
+ buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
+ unpack->BufferObj->Size,
GL_MAP_READ_BIT,
- unpack->BufferObj);
+ unpack->BufferObj,
+ MAP_INTERNAL);
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)
{
GLubyte *buf;
- if (!_mesa_is_bufferobj(packing->BufferObj)) {
+ if (!_mesa_validate_pbo_source_compressed(ctx, dimensions, packing,
+ imageSize, pixels, funcName)) {
+ /* error is already set during validation */
+ return NULL;
+ }
+
+ if (!packing->BufferObj) {
/* not using a PBO - return pointer unchanged */
return pixels;
}
- 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)");
- return NULL;
- }
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");
- return NULL;
- }
+ packing->BufferObj,
+ MAP_INTERNAL);
+
+ /* Validation above already checked that PBO is not mapped, so buffer
+ * should not be null.
+ */
+ assert(buf);
return ADD_POINTERS(buf, pixels);
}
_mesa_unmap_teximage_pbo(struct gl_context *ctx,
const struct gl_pixelstore_attrib *unpack)
{
- if (_mesa_is_bufferobj(unpack->BufferObj)) {
- ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj);
+ if (unpack->BufferObj) {
+ ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL);
}
}
-
-