1848b8605Smrg/*
2848b8605Smrg * Mesa 3-D graphics library
3848b8605Smrg *
4848b8605Smrg * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5848b8605Smrg * Copyright (C) 2009-2011  VMware, Inc.  All Rights Reserved.
6848b8605Smrg *
7848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
8848b8605Smrg * copy of this software and associated documentation files (the "Software"),
9848b8605Smrg * to deal in the Software without restriction, including without limitation
10848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
12848b8605Smrg * Software is furnished to do so, subject to the following conditions:
13848b8605Smrg *
14848b8605Smrg * The above copyright notice and this permission notice shall be included
15848b8605Smrg * in all copies or substantial portions of the Software.
16848b8605Smrg *
17848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
24848b8605Smrg */
25848b8605Smrg
26848b8605Smrg
27848b8605Smrg/**
28848b8605Smrg * \file pbo.c
29848b8605Smrg * \brief Functions related to Pixel Buffer Objects.
30848b8605Smrg */
31848b8605Smrg
32848b8605Smrg
33848b8605Smrg
34b8e80941Smrg#include "errors.h"
35848b8605Smrg#include "glheader.h"
36848b8605Smrg#include "bufferobj.h"
37848b8605Smrg#include "glformats.h"
38848b8605Smrg#include "image.h"
39848b8605Smrg#include "imports.h"
40848b8605Smrg#include "mtypes.h"
41848b8605Smrg#include "pbo.h"
42848b8605Smrg
43848b8605Smrg
44848b8605Smrg
45848b8605Smrg/**
46848b8605Smrg * When we're about to read pixel data out of a PBO (via glDrawPixels,
47848b8605Smrg * glTexImage, etc) or write data into a PBO (via glReadPixels,
48848b8605Smrg * glGetTexImage, etc) we call this function to check that we're not
49848b8605Smrg * going to read/write out of bounds.
50848b8605Smrg *
51848b8605Smrg * XXX This would also be a convenient time to check that the PBO isn't
52848b8605Smrg * currently mapped.  Whoever calls this function should check for that.
53848b8605Smrg * Remember, we can't use a PBO when it's mapped!
54848b8605Smrg *
55848b8605Smrg * If we're not using a PBO, this is a no-op.
56848b8605Smrg *
57848b8605Smrg * \param width  width of image to read/write
58848b8605Smrg * \param height  height of image to read/write
59848b8605Smrg * \param depth  depth of image to read/write
60848b8605Smrg * \param format  format of image to read/write
61848b8605Smrg * \param type  datatype of image to read/write
62848b8605Smrg * \param clientMemSize  the maximum number of bytes to read/write
63848b8605Smrg * \param ptr  the user-provided pointer/offset
64848b8605Smrg * \return GL_TRUE if the buffer access is OK, GL_FALSE if the access would
65848b8605Smrg *         go out of bounds.
66848b8605Smrg */
67848b8605SmrgGLboolean
68848b8605Smrg_mesa_validate_pbo_access(GLuint dimensions,
69848b8605Smrg                          const struct gl_pixelstore_attrib *pack,
70848b8605Smrg                          GLsizei width, GLsizei height, GLsizei depth,
71848b8605Smrg                          GLenum format, GLenum type, GLsizei clientMemSize,
72848b8605Smrg                          const GLvoid *ptr)
73848b8605Smrg{
74848b8605Smrg   /* unsigned, to detect overflow/wrap-around */
75848b8605Smrg   uintptr_t start, end, offset, size;
76848b8605Smrg
77848b8605Smrg   /* If no PBO is bound, 'ptr' is a pointer to client memory containing
78848b8605Smrg      'clientMemSize' bytes.
79848b8605Smrg      If a PBO is bound, 'ptr' is an offset into the bound PBO.
80848b8605Smrg      In that case 'clientMemSize' is ignored: we just use the PBO's size.
81848b8605Smrg    */
82848b8605Smrg   if (!_mesa_is_bufferobj(pack->BufferObj)) {
83848b8605Smrg      offset = 0;
84b8e80941Smrg      size = (clientMemSize == INT_MAX) ? UINTPTR_MAX : clientMemSize;
85848b8605Smrg   } else {
86848b8605Smrg      offset = (uintptr_t)ptr;
87848b8605Smrg      size = pack->BufferObj->Size;
88848b8605Smrg      /* The ARB_pixel_buffer_object spec says:
89848b8605Smrg       *    "INVALID_OPERATION is generated by ColorTable, ColorSubTable,
90848b8605Smrg       *    ConvolutionFilter2D, ConvolutionFilter1D, SeparableFilter2D,
91848b8605Smrg       *    TexImage1D, TexImage2D, TexImage3D, TexSubImage1D,
92848b8605Smrg       *    TexSubImage2D, TexSubImage3D, and DrawPixels if the current
93848b8605Smrg       *    PIXEL_UNPACK_BUFFER_BINDING_ARB value is non-zero and the data
94848b8605Smrg       *    parameter is not evenly divisible into the number of basic machine
95848b8605Smrg       *    units needed to store in memory a datum indicated by the type
96848b8605Smrg       *    parameter."
97848b8605Smrg       */
98848b8605Smrg      if (type != GL_BITMAP &&
99848b8605Smrg          (offset % _mesa_sizeof_packed_type(type)))
100848b8605Smrg         return GL_FALSE;
101848b8605Smrg   }
102848b8605Smrg
103848b8605Smrg   if (size == 0)
104848b8605Smrg      /* no buffer! */
105848b8605Smrg      return GL_FALSE;
106848b8605Smrg
107b8e80941Smrg   /* If the size of the image is zero then no pixels are accessed so we
108b8e80941Smrg    * don't need to check anything else.
109b8e80941Smrg    */
110b8e80941Smrg   if (width == 0 || height == 0 || depth == 0)
111b8e80941Smrg      return GL_TRUE;
112b8e80941Smrg
113848b8605Smrg   /* get the offset to the first pixel we'll read/write */
114848b8605Smrg   start = _mesa_image_offset(dimensions, pack, width, height,
115848b8605Smrg                              format, type, 0, 0, 0);
116848b8605Smrg
117848b8605Smrg   /* get the offset to just past the last pixel we'll read/write */
118848b8605Smrg   end =  _mesa_image_offset(dimensions, pack, width, height,
119848b8605Smrg                             format, type, depth-1, height-1, width);
120848b8605Smrg
121848b8605Smrg   start += offset;
122848b8605Smrg   end += offset;
123848b8605Smrg
124848b8605Smrg   if (start > size) {
125848b8605Smrg      /* This will catch negative values / wrap-around */
126848b8605Smrg      return GL_FALSE;
127848b8605Smrg   }
128848b8605Smrg   if (end > size) {
129848b8605Smrg      /* Image read/write goes beyond end of buffer */
130848b8605Smrg      return GL_FALSE;
131848b8605Smrg   }
132848b8605Smrg
133848b8605Smrg   /* OK! */
134848b8605Smrg   return GL_TRUE;
135848b8605Smrg}
136848b8605Smrg
137848b8605Smrg
138848b8605Smrg/**
139848b8605Smrg * For commands that read from a PBO (glDrawPixels, glTexImage,
140848b8605Smrg * glPolygonStipple, etc), if we're reading from a PBO, map it read-only
141848b8605Smrg * and return the pointer into the PBO.  If we're not reading from a
142848b8605Smrg * PBO, return \p src as-is.
143848b8605Smrg * If non-null return, must call _mesa_unmap_pbo_source() when done.
144848b8605Smrg *
145848b8605Smrg * \return NULL if error, else pointer to start of data
146848b8605Smrg */
147848b8605Smrgconst GLvoid *
148848b8605Smrg_mesa_map_pbo_source(struct gl_context *ctx,
149848b8605Smrg                     const struct gl_pixelstore_attrib *unpack,
150848b8605Smrg                     const GLvoid *src)
151848b8605Smrg{
152848b8605Smrg   const GLubyte *buf;
153848b8605Smrg
154848b8605Smrg   if (_mesa_is_bufferobj(unpack->BufferObj)) {
155848b8605Smrg      /* unpack from PBO */
156848b8605Smrg      buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
157848b8605Smrg						   unpack->BufferObj->Size,
158848b8605Smrg						   GL_MAP_READ_BIT,
159848b8605Smrg						   unpack->BufferObj,
160848b8605Smrg                                                   MAP_INTERNAL);
161848b8605Smrg      if (!buf)
162848b8605Smrg         return NULL;
163848b8605Smrg
164848b8605Smrg      buf = ADD_POINTERS(buf, src);
165848b8605Smrg   }
166848b8605Smrg   else {
167848b8605Smrg      /* unpack from normal memory */
168848b8605Smrg      buf = src;
169848b8605Smrg   }
170848b8605Smrg
171848b8605Smrg   return buf;
172848b8605Smrg}
173848b8605Smrg
174848b8605Smrg/**
175b8e80941Smrg * Perform PBO validation for read operations with uncompressed textures.
176b8e80941Smrg * If any GL errors are detected, false is returned, otherwise returns true.
177848b8605Smrg * \sa _mesa_validate_pbo_access
178848b8605Smrg */
179b8e80941Smrgbool
180b8e80941Smrg_mesa_validate_pbo_source(struct gl_context *ctx, GLuint dimensions,
181b8e80941Smrg                          const struct gl_pixelstore_attrib *unpack,
182b8e80941Smrg                          GLsizei width, GLsizei height, GLsizei depth,
183b8e80941Smrg                          GLenum format, GLenum type,
184b8e80941Smrg                          GLsizei clientMemSize,
185b8e80941Smrg                          const GLvoid *ptr, const char *where)
186848b8605Smrg{
187b8e80941Smrg   assert(dimensions == 1 || dimensions == 2 || dimensions == 3);
188848b8605Smrg
189848b8605Smrg   if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
190848b8605Smrg                                  format, type, clientMemSize, ptr)) {
191848b8605Smrg      if (_mesa_is_bufferobj(unpack->BufferObj)) {
192848b8605Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
193b8e80941Smrg                     "%s(out of bounds PBO access)",
194b8e80941Smrg                     where);
195848b8605Smrg      } else {
196848b8605Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
197848b8605Smrg                     "%s(out of bounds access: bufSize (%d) is too small)",
198848b8605Smrg                     where, clientMemSize);
199848b8605Smrg      }
200b8e80941Smrg      return false;
201848b8605Smrg   }
202848b8605Smrg
203848b8605Smrg   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
204848b8605Smrg      /* non-PBO access: no further validation to be done */
205b8e80941Smrg      return true;
206848b8605Smrg   }
207848b8605Smrg
208848b8605Smrg   if (_mesa_check_disallowed_mapping(unpack->BufferObj)) {
209848b8605Smrg      /* buffer is already mapped - that's an error */
210b8e80941Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)",
211b8e80941Smrg                  where);
212b8e80941Smrg      return false;
213b8e80941Smrg   }
214b8e80941Smrg
215b8e80941Smrg   return true;
216b8e80941Smrg}
217b8e80941Smrg
218b8e80941Smrg/**
219b8e80941Smrg * Perform PBO validation for read operations with compressed textures.
220b8e80941Smrg * If any GL errors are detected, false is returned, otherwise returns true.
221b8e80941Smrg */
222b8e80941Smrgbool
223b8e80941Smrg_mesa_validate_pbo_source_compressed(struct gl_context *ctx, GLuint dimensions,
224b8e80941Smrg                                     const struct gl_pixelstore_attrib *unpack,
225b8e80941Smrg                                     GLsizei imageSize, const GLvoid *pixels,
226b8e80941Smrg                                     const char *where)
227b8e80941Smrg{
228b8e80941Smrg   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
229b8e80941Smrg      /* not using a PBO */
230b8e80941Smrg      return true;
231b8e80941Smrg   }
232b8e80941Smrg
233b8e80941Smrg   if ((const GLubyte *) pixels + imageSize >
234b8e80941Smrg       ((const GLubyte *) 0) + unpack->BufferObj->Size) {
235b8e80941Smrg      /* out of bounds read! */
236b8e80941Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid PBO access)",
237b8e80941Smrg                  where);
238b8e80941Smrg      return false;
239b8e80941Smrg   }
240b8e80941Smrg
241b8e80941Smrg   if (_mesa_check_disallowed_mapping(unpack->BufferObj)) {
242b8e80941Smrg      /* buffer is already mapped - that's an error */
243b8e80941Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)",
244b8e80941Smrg                  where);
245b8e80941Smrg      return false;
246b8e80941Smrg   }
247b8e80941Smrg
248b8e80941Smrg   return true;
249b8e80941Smrg}
250b8e80941Smrg
251b8e80941Smrg/**
252b8e80941Smrg * Perform PBO-read mapping.
253b8e80941Smrg * If any GL errors are detected, they'll be recorded and NULL returned.
254b8e80941Smrg * \sa _mesa_validate_pbo_source
255b8e80941Smrg * \sa _mesa_map_pbo_source
256b8e80941Smrg * A call to this function should have a matching call to
257b8e80941Smrg * _mesa_unmap_pbo_source().
258b8e80941Smrg */
259b8e80941Smrgconst GLvoid *
260b8e80941Smrg_mesa_map_validate_pbo_source(struct gl_context *ctx,
261b8e80941Smrg                              GLuint dimensions,
262b8e80941Smrg                              const struct gl_pixelstore_attrib *unpack,
263b8e80941Smrg                              GLsizei width, GLsizei height, GLsizei depth,
264b8e80941Smrg                              GLenum format, GLenum type,
265b8e80941Smrg                              GLsizei clientMemSize,
266b8e80941Smrg                              const GLvoid *ptr, const char *where)
267b8e80941Smrg{
268b8e80941Smrg   if (!_mesa_validate_pbo_source(ctx, dimensions, unpack,
269b8e80941Smrg                                  width, height, depth, format, type,
270b8e80941Smrg                                  clientMemSize, ptr, where)) {
271b8e80941Smrg     return NULL;
272848b8605Smrg   }
273848b8605Smrg
274848b8605Smrg   ptr = _mesa_map_pbo_source(ctx, unpack, ptr);
275848b8605Smrg   return ptr;
276848b8605Smrg}
277848b8605Smrg
278848b8605Smrg
279848b8605Smrg/**
280848b8605Smrg * Counterpart to _mesa_map_pbo_source()
281848b8605Smrg */
282848b8605Smrgvoid
283848b8605Smrg_mesa_unmap_pbo_source(struct gl_context *ctx,
284848b8605Smrg                       const struct gl_pixelstore_attrib *unpack)
285848b8605Smrg{
286b8e80941Smrg   assert(unpack != &ctx->Pack); /* catch pack/unpack mismatch */
287848b8605Smrg   if (_mesa_is_bufferobj(unpack->BufferObj)) {
288848b8605Smrg      ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL);
289848b8605Smrg   }
290848b8605Smrg}
291848b8605Smrg
292848b8605Smrg
293848b8605Smrg/**
294848b8605Smrg * For commands that write to a PBO (glReadPixels, glGetColorTable, etc),
295848b8605Smrg * if we're writing to a PBO, map it write-only and return the pointer
296848b8605Smrg * into the PBO.  If we're not writing to a PBO, return \p dst as-is.
297848b8605Smrg * If non-null return, must call _mesa_unmap_pbo_dest() when done.
298848b8605Smrg *
299848b8605Smrg * \return NULL if error, else pointer to start of data
300848b8605Smrg */
301848b8605Smrgvoid *
302848b8605Smrg_mesa_map_pbo_dest(struct gl_context *ctx,
303848b8605Smrg                   const struct gl_pixelstore_attrib *pack,
304848b8605Smrg                   GLvoid *dest)
305848b8605Smrg{
306848b8605Smrg   void *buf;
307848b8605Smrg
308848b8605Smrg   if (_mesa_is_bufferobj(pack->BufferObj)) {
309848b8605Smrg      /* pack into PBO */
310848b8605Smrg      buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
311848b8605Smrg						   pack->BufferObj->Size,
312848b8605Smrg						   GL_MAP_WRITE_BIT,
313848b8605Smrg						   pack->BufferObj,
314848b8605Smrg                                                   MAP_INTERNAL);
315848b8605Smrg      if (!buf)
316848b8605Smrg         return NULL;
317848b8605Smrg
318848b8605Smrg      buf = ADD_POINTERS(buf, dest);
319848b8605Smrg   }
320848b8605Smrg   else {
321848b8605Smrg      /* pack to normal memory */
322848b8605Smrg      buf = dest;
323848b8605Smrg   }
324848b8605Smrg
325848b8605Smrg   return buf;
326848b8605Smrg}
327848b8605Smrg
328848b8605Smrg
329848b8605Smrg/**
330848b8605Smrg * Combine PBO-write validation and mapping.
331848b8605Smrg * If any GL errors are detected, they'll be recorded and NULL returned.
332848b8605Smrg * \sa _mesa_validate_pbo_access
333848b8605Smrg * \sa _mesa_map_pbo_dest
334848b8605Smrg * A call to this function should have a matching call to
335848b8605Smrg * _mesa_unmap_pbo_dest().
336848b8605Smrg */
337848b8605SmrgGLvoid *
338848b8605Smrg_mesa_map_validate_pbo_dest(struct gl_context *ctx,
339848b8605Smrg                            GLuint dimensions,
340848b8605Smrg                            const struct gl_pixelstore_attrib *unpack,
341848b8605Smrg                            GLsizei width, GLsizei height, GLsizei depth,
342848b8605Smrg                            GLenum format, GLenum type, GLsizei clientMemSize,
343848b8605Smrg                            GLvoid *ptr, const char *where)
344848b8605Smrg{
345b8e80941Smrg   assert(dimensions == 1 || dimensions == 2 || dimensions == 3);
346848b8605Smrg
347848b8605Smrg   if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
348848b8605Smrg                                  format, type, clientMemSize, ptr)) {
349848b8605Smrg      if (_mesa_is_bufferobj(unpack->BufferObj)) {
350848b8605Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
351848b8605Smrg                     "%s(out of bounds PBO access)", where);
352848b8605Smrg      } else {
353848b8605Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
354848b8605Smrg                     "%s(out of bounds access: bufSize (%d) is too small)",
355848b8605Smrg                     where, clientMemSize);
356848b8605Smrg      }
357848b8605Smrg      return NULL;
358848b8605Smrg   }
359848b8605Smrg
360848b8605Smrg   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
361848b8605Smrg      /* non-PBO access: no further validation to be done */
362848b8605Smrg      return ptr;
363848b8605Smrg   }
364848b8605Smrg
365848b8605Smrg   if (_mesa_check_disallowed_mapping(unpack->BufferObj)) {
366848b8605Smrg      /* buffer is already mapped - that's an error */
367848b8605Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
368848b8605Smrg      return NULL;
369848b8605Smrg   }
370848b8605Smrg
371848b8605Smrg   ptr = _mesa_map_pbo_dest(ctx, unpack, ptr);
372848b8605Smrg   return ptr;
373848b8605Smrg}
374848b8605Smrg
375848b8605Smrg
376848b8605Smrg/**
377848b8605Smrg * Counterpart to _mesa_map_pbo_dest()
378848b8605Smrg */
379848b8605Smrgvoid
380848b8605Smrg_mesa_unmap_pbo_dest(struct gl_context *ctx,
381848b8605Smrg                     const struct gl_pixelstore_attrib *pack)
382848b8605Smrg{
383b8e80941Smrg   assert(pack != &ctx->Unpack); /* catch pack/unpack mismatch */
384848b8605Smrg   if (_mesa_is_bufferobj(pack->BufferObj)) {
385848b8605Smrg      ctx->Driver.UnmapBuffer(ctx, pack->BufferObj, MAP_INTERNAL);
386848b8605Smrg   }
387848b8605Smrg}
388848b8605Smrg
389848b8605Smrg
390848b8605Smrg/**
391848b8605Smrg * Check if an unpack PBO is active prior to fetching a texture image.
392848b8605Smrg * If so, do bounds checking and map the buffer into main memory.
393848b8605Smrg * Any errors detected will be recorded.
394848b8605Smrg * The caller _must_ call _mesa_unmap_teximage_pbo() too!
395848b8605Smrg */
396848b8605Smrgconst GLvoid *
397848b8605Smrg_mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions,
398848b8605Smrg			    GLsizei width, GLsizei height, GLsizei depth,
399848b8605Smrg			    GLenum format, GLenum type, const GLvoid *pixels,
400848b8605Smrg			    const struct gl_pixelstore_attrib *unpack,
401848b8605Smrg			    const char *funcName)
402848b8605Smrg{
403848b8605Smrg   GLubyte *buf;
404848b8605Smrg
405848b8605Smrg   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
406848b8605Smrg      /* no PBO */
407848b8605Smrg      return pixels;
408848b8605Smrg   }
409848b8605Smrg   if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
410848b8605Smrg                                  format, type, INT_MAX, pixels)) {
411848b8605Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(invalid PBO access)",
412848b8605Smrg                  funcName, dimensions);
413848b8605Smrg      return NULL;
414848b8605Smrg   }
415848b8605Smrg
416848b8605Smrg   buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
417848b8605Smrg                                                unpack->BufferObj->Size,
418848b8605Smrg						GL_MAP_READ_BIT,
419848b8605Smrg						unpack->BufferObj,
420848b8605Smrg                                                MAP_INTERNAL);
421848b8605Smrg   if (!buf) {
422848b8605Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(PBO is mapped)", funcName,
423848b8605Smrg                  dimensions);
424848b8605Smrg      return NULL;
425848b8605Smrg   }
426848b8605Smrg
427848b8605Smrg   return ADD_POINTERS(buf, pixels);
428848b8605Smrg}
429848b8605Smrg
430848b8605Smrg
431848b8605Smrg/**
432848b8605Smrg * Check if an unpack PBO is active prior to fetching a compressed texture
433848b8605Smrg * image.
434848b8605Smrg * If so, do bounds checking and map the buffer into main memory.
435848b8605Smrg * Any errors detected will be recorded.
436848b8605Smrg * The caller _must_ call _mesa_unmap_teximage_pbo() too!
437848b8605Smrg */
438848b8605Smrgconst GLvoid *
439848b8605Smrg_mesa_validate_pbo_compressed_teximage(struct gl_context *ctx,
440848b8605Smrg                                 GLuint dimensions, GLsizei imageSize,
441848b8605Smrg                                 const GLvoid *pixels,
442848b8605Smrg                                 const struct gl_pixelstore_attrib *packing,
443848b8605Smrg                                 const char *funcName)
444848b8605Smrg{
445848b8605Smrg   GLubyte *buf;
446848b8605Smrg
447b8e80941Smrg   if (!_mesa_validate_pbo_source_compressed(ctx, dimensions, packing,
448b8e80941Smrg                                             imageSize, pixels, funcName)) {
449b8e80941Smrg     /* error is already set during validation */
450b8e80941Smrg      return NULL;
451b8e80941Smrg   }
452b8e80941Smrg
453848b8605Smrg   if (!_mesa_is_bufferobj(packing->BufferObj)) {
454848b8605Smrg      /* not using a PBO - return pointer unchanged */
455848b8605Smrg      return pixels;
456848b8605Smrg   }
457848b8605Smrg
458848b8605Smrg   buf = (GLubyte*) ctx->Driver.MapBufferRange(ctx, 0,
459848b8605Smrg					       packing->BufferObj->Size,
460848b8605Smrg					       GL_MAP_READ_BIT,
461848b8605Smrg					       packing->BufferObj,
462848b8605Smrg                                               MAP_INTERNAL);
463b8e80941Smrg
464b8e80941Smrg   /* Validation above already checked that PBO is not mapped, so buffer
465b8e80941Smrg    * should not be null.
466b8e80941Smrg    */
467b8e80941Smrg   assert(buf);
468848b8605Smrg
469848b8605Smrg   return ADD_POINTERS(buf, pixels);
470848b8605Smrg}
471848b8605Smrg
472848b8605Smrg
473848b8605Smrg/**
474848b8605Smrg * This function must be called after either of the validate_pbo_*_teximage()
475848b8605Smrg * functions.  It unmaps the PBO buffer if it was mapped earlier.
476848b8605Smrg */
477848b8605Smrgvoid
478848b8605Smrg_mesa_unmap_teximage_pbo(struct gl_context *ctx,
479848b8605Smrg                         const struct gl_pixelstore_attrib *unpack)
480848b8605Smrg{
481848b8605Smrg   if (_mesa_is_bufferobj(unpack->BufferObj)) {
482848b8605Smrg      ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL);
483848b8605Smrg   }
484848b8605Smrg}
485