Merge remote-tracking branch 'origin/master' into pipe-video
[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/write 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 clientMemSize the maximum number of bytes to read/write
60 * \param ptr the user-provided pointer/offset
61 * \return GL_TRUE if the buffer access is OK, GL_FALSE if the access would
62 * go out of bounds.
63 */
64 GLboolean
65 _mesa_validate_pbo_access(GLuint dimensions,
66 const struct gl_pixelstore_attrib *pack,
67 GLsizei width, GLsizei height, GLsizei depth,
68 GLenum format, GLenum type, GLsizei clientMemSize,
69 const GLvoid *ptr)
70 {
71 const GLvoid *start, *end, *offset;
72 const GLubyte *sizeAddr; /* buffer size, cast to a pointer */
73
74 /* If no PBO is bound, 'ptr' is a pointer to client memory containing
75 'clientMemSize' bytes.
76 If a PBO is bound, 'ptr' is an offset into the bound PBO.
77 In that case 'clientMemSize' is ignored: we just use the PBO's size.
78 */
79 if (!_mesa_is_bufferobj(pack->BufferObj)) {
80 offset = 0;
81 sizeAddr = ((const GLubyte *) 0) + clientMemSize;
82 } else {
83 offset = ptr;
84 sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size;
85 }
86
87 if (sizeAddr == 0)
88 /* no buffer! */
89 return GL_FALSE;
90
91 /* get the offset to the first pixel we'll read/write */
92 start = _mesa_image_address(dimensions, pack, offset, width, height,
93 format, type, 0, 0, 0);
94
95 /* get the offset to just past the last pixel we'll read/write */
96 end = _mesa_image_address(dimensions, pack, offset, width, height,
97 format, type, depth-1, height-1, width);
98
99 if ((const GLubyte *) start > sizeAddr) {
100 /* This will catch negative values / wrap-around */
101 return GL_FALSE;
102 }
103 if ((const GLubyte *) end > sizeAddr) {
104 /* Image read/write goes beyond end of buffer */
105 return GL_FALSE;
106 }
107
108 /* OK! */
109 return GL_TRUE;
110 }
111
112
113 /**
114 * For commands that read from a PBO (glDrawPixels, glTexImage,
115 * glPolygonStipple, etc), if we're reading from a PBO, map it read-only
116 * and return the pointer into the PBO. If we're not reading from a
117 * PBO, return \p src as-is.
118 * If non-null return, must call _mesa_unmap_pbo_source() when done.
119 *
120 * \return NULL if error, else pointer to start of data
121 */
122 const GLvoid *
123 _mesa_map_pbo_source(struct gl_context *ctx,
124 const struct gl_pixelstore_attrib *unpack,
125 const GLvoid *src)
126 {
127 const GLubyte *buf;
128
129 if (_mesa_is_bufferobj(unpack->BufferObj)) {
130 /* unpack from PBO */
131 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
132 GL_READ_ONLY_ARB,
133 unpack->BufferObj);
134 if (!buf)
135 return NULL;
136
137 buf = ADD_POINTERS(buf, src);
138 }
139 else {
140 /* unpack from normal memory */
141 buf = src;
142 }
143
144 return buf;
145 }
146
147
148 /**
149 * Combine PBO-read validation and mapping.
150 * If any GL errors are detected, they'll be recorded and NULL returned.
151 * \sa _mesa_validate_pbo_access
152 * \sa _mesa_map_pbo_source
153 * A call to this function should have a matching call to
154 * _mesa_unmap_pbo_source().
155 */
156 const GLvoid *
157 _mesa_map_validate_pbo_source(struct gl_context *ctx,
158 GLuint dimensions,
159 const struct gl_pixelstore_attrib *unpack,
160 GLsizei width, GLsizei height, GLsizei depth,
161 GLenum format, GLenum type, GLsizei clientMemSize,
162 const GLvoid *ptr, const char *where)
163 {
164 ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
165
166 if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
167 format, type, clientMemSize, ptr)) {
168 if (_mesa_is_bufferobj(unpack->BufferObj)) {
169 _mesa_error(ctx, GL_INVALID_OPERATION,
170 "%s(out of bounds PBO access)", where);
171 } else {
172 _mesa_error(ctx, GL_INVALID_OPERATION,
173 "%s(out of bounds access: bufSize (%d) is too small)",
174 where, clientMemSize);
175 }
176 return NULL;
177 }
178
179 if (!_mesa_is_bufferobj(unpack->BufferObj)) {
180 /* non-PBO access: no further validation to be done */
181 return ptr;
182 }
183
184 if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
185 /* buffer is already mapped - that's an error */
186 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
187 return NULL;
188 }
189
190 ptr = _mesa_map_pbo_source(ctx, unpack, ptr);
191 return ptr;
192 }
193
194
195 /**
196 * Counterpart to _mesa_map_pbo_source()
197 */
198 void
199 _mesa_unmap_pbo_source(struct gl_context *ctx,
200 const struct gl_pixelstore_attrib *unpack)
201 {
202 ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */
203 if (_mesa_is_bufferobj(unpack->BufferObj)) {
204 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
205 unpack->BufferObj);
206 }
207 }
208
209
210 /**
211 * For commands that write to a PBO (glReadPixels, glGetColorTable, etc),
212 * if we're writing to a PBO, map it write-only and return the pointer
213 * into the PBO. If we're not writing to a PBO, return \p dst as-is.
214 * If non-null return, must call _mesa_unmap_pbo_dest() when done.
215 *
216 * \return NULL if error, else pointer to start of data
217 */
218 void *
219 _mesa_map_pbo_dest(struct gl_context *ctx,
220 const struct gl_pixelstore_attrib *pack,
221 GLvoid *dest)
222 {
223 void *buf;
224
225 if (_mesa_is_bufferobj(pack->BufferObj)) {
226 /* pack into PBO */
227 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
228 GL_WRITE_ONLY_ARB,
229 pack->BufferObj);
230 if (!buf)
231 return NULL;
232
233 buf = ADD_POINTERS(buf, dest);
234 }
235 else {
236 /* pack to normal memory */
237 buf = dest;
238 }
239
240 return buf;
241 }
242
243
244 /**
245 * Combine PBO-write validation and mapping.
246 * If any GL errors are detected, they'll be recorded and NULL returned.
247 * \sa _mesa_validate_pbo_access
248 * \sa _mesa_map_pbo_dest
249 * A call to this function should have a matching call to
250 * _mesa_unmap_pbo_dest().
251 */
252 GLvoid *
253 _mesa_map_validate_pbo_dest(struct gl_context *ctx,
254 GLuint dimensions,
255 const struct gl_pixelstore_attrib *unpack,
256 GLsizei width, GLsizei height, GLsizei depth,
257 GLenum format, GLenum type, GLsizei clientMemSize,
258 GLvoid *ptr, const char *where)
259 {
260 ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
261
262 if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
263 format, type, clientMemSize, ptr)) {
264 if (_mesa_is_bufferobj(unpack->BufferObj)) {
265 _mesa_error(ctx, GL_INVALID_OPERATION,
266 "%s(out of bounds PBO access)", where);
267 } else {
268 _mesa_error(ctx, GL_INVALID_OPERATION,
269 "%s(out of bounds access: bufSize (%d) is too small)",
270 where, clientMemSize);
271 }
272 return NULL;
273 }
274
275 if (!_mesa_is_bufferobj(unpack->BufferObj)) {
276 /* non-PBO access: no further validation to be done */
277 return ptr;
278 }
279
280 if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
281 /* buffer is already mapped - that's an error */
282 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
283 return NULL;
284 }
285
286 ptr = _mesa_map_pbo_dest(ctx, unpack, ptr);
287 return ptr;
288 }
289
290
291 /**
292 * Counterpart to _mesa_map_pbo_dest()
293 */
294 void
295 _mesa_unmap_pbo_dest(struct gl_context *ctx,
296 const struct gl_pixelstore_attrib *pack)
297 {
298 ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */
299 if (_mesa_is_bufferobj(pack->BufferObj)) {
300 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, pack->BufferObj);
301 }
302 }
303
304
305 /**
306 * Check if an unpack PBO is active prior to fetching a texture image.
307 * If so, do bounds checking and map the buffer into main memory.
308 * Any errors detected will be recorded.
309 * The caller _must_ call _mesa_unmap_teximage_pbo() too!
310 */
311 const GLvoid *
312 _mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions,
313 GLsizei width, GLsizei height, GLsizei depth,
314 GLenum format, GLenum type, const GLvoid *pixels,
315 const struct gl_pixelstore_attrib *unpack,
316 const char *funcName)
317 {
318 GLubyte *buf;
319
320 if (!_mesa_is_bufferobj(unpack->BufferObj)) {
321 /* no PBO */
322 return pixels;
323 }
324 if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
325 format, type, INT_MAX, pixels)) {
326 _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access)");
327 return NULL;
328 }
329
330 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
331 GL_READ_ONLY_ARB, unpack->BufferObj);
332 if (!buf) {
333 _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped)");
334 return NULL;
335 }
336
337 return ADD_POINTERS(buf, pixels);
338 }
339
340
341 /**
342 * Check if an unpack PBO is active prior to fetching a compressed texture
343 * image.
344 * If so, do bounds checking and map the buffer into main memory.
345 * Any errors detected will be recorded.
346 * The caller _must_ call _mesa_unmap_teximage_pbo() too!
347 */
348 const GLvoid *
349 _mesa_validate_pbo_compressed_teximage(struct gl_context *ctx,
350 GLsizei imageSize, const GLvoid *pixels,
351 const struct gl_pixelstore_attrib *packing,
352 const char *funcName)
353 {
354 GLubyte *buf;
355
356 if (!_mesa_is_bufferobj(packing->BufferObj)) {
357 /* not using a PBO - return pointer unchanged */
358 return pixels;
359 }
360 if ((const GLubyte *) pixels + imageSize >
361 ((const GLubyte *) 0) + packing->BufferObj->Size) {
362 /* out of bounds read! */
363 _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access)");
364 return NULL;
365 }
366
367 buf = (GLubyte*) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
368 GL_READ_ONLY_ARB, packing->BufferObj);
369 if (!buf) {
370 _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped");
371 return NULL;
372 }
373
374 return ADD_POINTERS(buf, pixels);
375 }
376
377
378 /**
379 * This function must be called after either of the validate_pbo_*_teximage()
380 * functions. It unmaps the PBO buffer if it was mapped earlier.
381 */
382 void
383 _mesa_unmap_teximage_pbo(struct gl_context *ctx,
384 const struct gl_pixelstore_attrib *unpack)
385 {
386 if (_mesa_is_bufferobj(unpack->BufferObj)) {
387 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
388 unpack->BufferObj);
389 }
390 }
391
392