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