OSDN Git Service

mesa: move PBO-related functions into a new file
[android-x86/external-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