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