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