Merge remote branch 'origin/nvc0'
[mesa.git] / src / mesa / main / pbo.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
5 * Copyright (C) 2009-2011 VMware, Inc. All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 /**
27 * \file pbo.c
28 * \brief Functions related to Pixel Buffer Objects.
29 */
30
31
32
33 #include "glheader.h"
34 #include "bufferobj.h"
35 #include "image.h"
36 #include "imports.h"
37 #include "mtypes.h"
38 #include "pbo.h"
39
40
41
42 /**
43 * When we're about to read pixel data out of a PBO (via glDrawPixels,
44 * glTexImage, etc) or write data into a PBO (via glReadPixels,
45 * glGetTexImage, etc) we call this function to check that we're not
46 * going to read out of bounds.
47 *
48 * XXX This would also be a convenient time to check that the PBO isn't
49 * currently mapped. Whoever calls this function should check for that.
50 * Remember, we can't use a PBO when it's mapped!
51 *
52 * If we're not using a PBO, this is a no-op.
53 *
54 * \param width width of image to read/write
55 * \param height height of image to read/write
56 * \param depth depth of image to read/write
57 * \param format format of image to read/write
58 * \param type datatype of image to read/write
59 * \param ptr the user-provided pointer/offset
60 * \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would
61 * go out of bounds.
62 */
63 GLboolean
64 _mesa_validate_pbo_access(GLuint dimensions,
65 const struct gl_pixelstore_attrib *pack,
66 GLsizei width, GLsizei height, GLsizei depth,
67 GLenum format, GLenum type, const GLvoid *ptr)
68 {
69 GLvoid *start, *end;
70 const GLubyte *sizeAddr; /* buffer size, cast to a pointer */
71
72 if (!_mesa_is_bufferobj(pack->BufferObj))
73 return GL_TRUE; /* no PBO, OK */
74
75 if (pack->BufferObj->Size == 0)
76 /* no buffer! */
77 return GL_FALSE;
78
79 /* get address of first pixel we'll read */
80 start = _mesa_image_address(dimensions, pack, ptr, width, height,
81 format, type, 0, 0, 0);
82
83 /* get address just past the last pixel we'll read */
84 end = _mesa_image_address(dimensions, pack, ptr, width, height,
85 format, type, depth-1, height-1, width);
86
87
88 sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size;
89
90 if ((const GLubyte *) start > sizeAddr) {
91 /* This will catch negative values / wrap-around */
92 return GL_FALSE;
93 }
94 if ((const GLubyte *) end > sizeAddr) {
95 /* Image read goes beyond end of buffer */
96 return GL_FALSE;
97 }
98
99 /* OK! */
100 return GL_TRUE;
101 }
102
103
104 /**
105 * For commands that read from a PBO (glDrawPixels, glTexImage,
106 * glPolygonStipple, etc), if we're reading from a PBO, map it read-only
107 * and return the pointer into the PBO. If we're not reading from a
108 * PBO, return \p src as-is.
109 * If non-null return, must call _mesa_unmap_pbo_source() when done.
110 *
111 * \return NULL if error, else pointer to start of data
112 */
113 const GLvoid *
114 _mesa_map_pbo_source(struct gl_context *ctx,
115 const struct gl_pixelstore_attrib *unpack,
116 const GLvoid *src)
117 {
118 const GLubyte *buf;
119
120 if (_mesa_is_bufferobj(unpack->BufferObj)) {
121 /* unpack from PBO */
122 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
123 GL_READ_ONLY_ARB,
124 unpack->BufferObj);
125 if (!buf)
126 return NULL;
127
128 buf = ADD_POINTERS(buf, src);
129 }
130 else {
131 /* unpack from normal memory */
132 buf = src;
133 }
134
135 return buf;
136 }
137
138
139 /**
140 * Combine PBO-read validation and mapping.
141 * If any GL errors are detected, they'll be recorded and NULL returned.
142 * \sa _mesa_validate_pbo_access
143 * \sa _mesa_map_pbo_source
144 * A call to this function should have a matching call to
145 * _mesa_unmap_pbo_source().
146 */
147 const GLvoid *
148 _mesa_map_validate_pbo_source(struct gl_context *ctx,
149 GLuint dimensions,
150 const struct gl_pixelstore_attrib *unpack,
151 GLsizei width, GLsizei height, GLsizei depth,
152 GLenum format, GLenum type, const GLvoid *ptr,
153 const char *where)
154 {
155 ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
156
157 if (!_mesa_is_bufferobj(unpack->BufferObj)) {
158 /* non-PBO access: no validation to be done */
159 return ptr;
160 }
161
162 if (!_mesa_validate_pbo_access(dimensions, unpack,
163 width, height, depth, format, type, ptr)) {
164 _mesa_error(ctx, GL_INVALID_OPERATION,
165 "%s(out of bounds PBO access)", where);
166 return NULL;
167 }
168
169 if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
170 /* buffer is already mapped - that's an error */
171 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
172 return NULL;
173 }
174
175 ptr = _mesa_map_pbo_source(ctx, unpack, ptr);
176 return ptr;
177 }
178
179
180 /**
181 * Counterpart to _mesa_map_pbo_source()
182 */
183 void
184 _mesa_unmap_pbo_source(struct gl_context *ctx,
185 const struct gl_pixelstore_attrib *unpack)
186 {
187 ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */
188 if (_mesa_is_bufferobj(unpack->BufferObj)) {
189 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
190 unpack->BufferObj);
191 }
192 }
193
194
195 /**
196 * For commands that write to a PBO (glReadPixels, glGetColorTable, etc),
197 * if we're writing to a PBO, map it write-only and return the pointer
198 * into the PBO. If we're not writing to a PBO, return \p dst as-is.
199 * If non-null return, must call _mesa_unmap_pbo_dest() when done.
200 *
201 * \return NULL if error, else pointer to start of data
202 */
203 void *
204 _mesa_map_pbo_dest(struct gl_context *ctx,
205 const struct gl_pixelstore_attrib *pack,
206 GLvoid *dest)
207 {
208 void *buf;
209
210 if (_mesa_is_bufferobj(pack->BufferObj)) {
211 /* pack into PBO */
212 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
213 GL_WRITE_ONLY_ARB,
214 pack->BufferObj);
215 if (!buf)
216 return NULL;
217
218 buf = ADD_POINTERS(buf, dest);
219 }
220 else {
221 /* pack to normal memory */
222 buf = dest;
223 }
224
225 return buf;
226 }
227
228
229 /**
230 * Combine PBO-write validation and mapping.
231 * If any GL errors are detected, they'll be recorded and NULL returned.
232 * \sa _mesa_validate_pbo_access
233 * \sa _mesa_map_pbo_dest
234 * A call to this function should have a matching call to
235 * _mesa_unmap_pbo_dest().
236 */
237 GLvoid *
238 _mesa_map_validate_pbo_dest(struct gl_context *ctx,
239 GLuint dimensions,
240 const struct gl_pixelstore_attrib *unpack,
241 GLsizei width, GLsizei height, GLsizei depth,
242 GLenum format, GLenum type, GLvoid *ptr,
243 const char *where)
244 {
245 ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
246
247 if (!_mesa_is_bufferobj(unpack->BufferObj)) {
248 /* non-PBO access: no validation to be done */
249 return ptr;
250 }
251
252 if (!_mesa_validate_pbo_access(dimensions, unpack,
253 width, height, depth, format, type, ptr)) {
254 _mesa_error(ctx, GL_INVALID_OPERATION,
255 "%s(out of bounds PBO access)", where);
256 return NULL;
257 }
258
259 if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
260 /* buffer is already mapped - that's an error */
261 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
262 return NULL;
263 }
264
265 ptr = _mesa_map_pbo_dest(ctx, unpack, ptr);
266 return ptr;
267 }
268
269
270 /**
271 * Counterpart to _mesa_map_pbo_dest()
272 */
273 void
274 _mesa_unmap_pbo_dest(struct gl_context *ctx,
275 const struct gl_pixelstore_attrib *pack)
276 {
277 ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */
278 if (_mesa_is_bufferobj(pack->BufferObj)) {
279 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, pack->BufferObj);
280 }
281 }
282
283
284
285 /**
286 * Check if an unpack PBO is active prior to fetching a texture image.
287 * If so, do bounds checking and map the buffer into main memory.
288 * Any errors detected will be recorded.
289 * The caller _must_ call _mesa_unmap_teximage_pbo() too!
290 */
291 const GLvoid *
292 _mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions,
293 GLsizei width, GLsizei height, GLsizei depth,
294 GLenum format, GLenum type, const GLvoid *pixels,
295 const struct gl_pixelstore_attrib *unpack,
296 const char *funcName)
297 {
298 GLubyte *buf;
299
300 if (!_mesa_is_bufferobj(unpack->BufferObj)) {
301 /* no PBO */
302 return pixels;
303 }
304 if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
305 format, type, pixels)) {
306 _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access)");
307 return NULL;
308 }
309
310 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
311 GL_READ_ONLY_ARB, unpack->BufferObj);
312 if (!buf) {
313 _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped)");
314 return NULL;
315 }
316
317 return ADD_POINTERS(buf, pixels);
318 }
319
320
321 /**
322 * Check if an unpack PBO is active prior to fetching a compressed texture
323 * image.
324 * If so, do bounds checking and map the buffer into main memory.
325 * Any errors detected will be recorded.
326 * The caller _must_ call _mesa_unmap_teximage_pbo() too!
327 */
328 const GLvoid *
329 _mesa_validate_pbo_compressed_teximage(struct gl_context *ctx,
330 GLsizei imageSize, const GLvoid *pixels,
331 const struct gl_pixelstore_attrib *packing,
332 const char *funcName)
333 {
334 GLubyte *buf;
335
336 if (!_mesa_is_bufferobj(packing->BufferObj)) {
337 /* not using a PBO - return pointer unchanged */
338 return pixels;
339 }
340 if ((const GLubyte *) pixels + imageSize >
341 ((const GLubyte *) 0) + packing->BufferObj->Size) {
342 /* out of bounds read! */
343 _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access)");
344 return NULL;
345 }
346
347 buf = (GLubyte*) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
348 GL_READ_ONLY_ARB, packing->BufferObj);
349 if (!buf) {
350 _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped");
351 return NULL;
352 }
353
354 return ADD_POINTERS(buf, pixels);
355 }
356
357
358 /**
359 * This function must be called after either of the validate_pbo_*_teximage()
360 * functions. It unmaps the PBO buffer if it was mapped earlier.
361 */
362 void
363 _mesa_unmap_teximage_pbo(struct gl_context *ctx,
364 const struct gl_pixelstore_attrib *unpack)
365 {
366 if (_mesa_is_bufferobj(unpack->BufferObj)) {
367 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
368 unpack->BufferObj);
369 }
370 }
371
372