Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 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 OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
 * OTHER DEALINGS IN THE SOFTWARE.
24
 */
25
 
26
 
27
/**
28
 * \file pbo.c
29
 * \brief Functions related to Pixel Buffer Objects.
30
 */
31
 
32
 
33
 
34
#include "glheader.h"
35
#include "bufferobj.h"
36
#include "glformats.h"
37
#include "image.h"
38
#include "imports.h"
39
#include "mtypes.h"
40
#include "pbo.h"
41
 
42
 
43
 
44
/**
45
 * When we're about to read pixel data out of a PBO (via glDrawPixels,
46
 * glTexImage, etc) or write data into a PBO (via glReadPixels,
47
 * glGetTexImage, etc) we call this function to check that we're not
48
 * going to read/write out of bounds.
49
 *
50
 * XXX This would also be a convenient time to check that the PBO isn't
51
 * currently mapped.  Whoever calls this function should check for that.
52
 * Remember, we can't use a PBO when it's mapped!
53
 *
54
 * If we're not using a PBO, this is a no-op.
55
 *
56
 * \param width  width of image to read/write
57
 * \param height  height of image to read/write
58
 * \param depth  depth of image to read/write
59
 * \param format  format of image to read/write
60
 * \param type  datatype of image to read/write
61
 * \param clientMemSize  the maximum number of bytes to read/write
62
 * \param ptr  the user-provided pointer/offset
63
 * \return GL_TRUE if the buffer access is OK, GL_FALSE if the access would
64
 *         go out of bounds.
65
 */
66
GLboolean
67
_mesa_validate_pbo_access(GLuint dimensions,
68
                          const struct gl_pixelstore_attrib *pack,
69
                          GLsizei width, GLsizei height, GLsizei depth,
70
                          GLenum format, GLenum type, GLsizei clientMemSize,
71
                          const GLvoid *ptr)
72
{
73
   /* unsigned, to detect overflow/wrap-around */
74
   uintptr_t start, end, offset, size;
75
 
76
   /* If no PBO is bound, 'ptr' is a pointer to client memory containing
77
      'clientMemSize' bytes.
78
      If a PBO is bound, 'ptr' is an offset into the bound PBO.
79
      In that case 'clientMemSize' is ignored: we just use the PBO's size.
80
    */
81
   if (!_mesa_is_bufferobj(pack->BufferObj)) {
82
      offset = 0;
83
      size = clientMemSize;
84
   } else {
85
      offset = (uintptr_t)ptr;
86
      size = pack->BufferObj->Size;
87
      /* The ARB_pixel_buffer_object spec says:
88
       *    "INVALID_OPERATION is generated by ColorTable, ColorSubTable,
89
       *    ConvolutionFilter2D, ConvolutionFilter1D, SeparableFilter2D,
90
       *    TexImage1D, TexImage2D, TexImage3D, TexSubImage1D,
91
       *    TexSubImage2D, TexSubImage3D, and DrawPixels if the current
92
       *    PIXEL_UNPACK_BUFFER_BINDING_ARB value is non-zero and the data
93
       *    parameter is not evenly divisible into the number of basic machine
94
       *    units needed to store in memory a datum indicated by the type
95
       *    parameter."
96
       */
97
      if (type != GL_BITMAP &&
98
          (offset % _mesa_sizeof_packed_type(type)))
99
         return GL_FALSE;
100
   }
101
 
102
   if (size == 0)
103
      /* no buffer! */
104
      return GL_FALSE;
105
 
106
   /* get the offset to the first pixel we'll read/write */
107
   start = _mesa_image_offset(dimensions, pack, width, height,
108
                              format, type, 0, 0, 0);
109
 
110
   /* get the offset to just past the last pixel we'll read/write */
111
   end =  _mesa_image_offset(dimensions, pack, width, height,
112
                             format, type, depth-1, height-1, width);
113
 
114
   start += offset;
115
   end += offset;
116
 
117
   if (start > size) {
118
      /* This will catch negative values / wrap-around */
119
      return GL_FALSE;
120
   }
121
   if (end > size) {
122
      /* Image read/write goes beyond end of buffer */
123
      return GL_FALSE;
124
   }
125
 
126
   /* OK! */
127
   return GL_TRUE;
128
}
129
 
130
 
131
/**
132
 * For commands that read from a PBO (glDrawPixels, glTexImage,
133
 * glPolygonStipple, etc), if we're reading from a PBO, map it read-only
134
 * and return the pointer into the PBO.  If we're not reading from a
135
 * PBO, return \p src as-is.
136
 * If non-null return, must call _mesa_unmap_pbo_source() when done.
137
 *
138
 * \return NULL if error, else pointer to start of data
139
 */
140
const GLvoid *
141
_mesa_map_pbo_source(struct gl_context *ctx,
142
                     const struct gl_pixelstore_attrib *unpack,
143
                     const GLvoid *src)
144
{
145
   const GLubyte *buf;
146
 
147
   if (_mesa_is_bufferobj(unpack->BufferObj)) {
148
      /* unpack from PBO */
149
      buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
150
						   unpack->BufferObj->Size,
151
						   GL_MAP_READ_BIT,
152
						   unpack->BufferObj);
153
      if (!buf)
154
         return NULL;
155
 
156
      buf = ADD_POINTERS(buf, src);
157
   }
158
   else {
159
      /* unpack from normal memory */
160
      buf = src;
161
   }
162
 
163
   return buf;
164
}
165
 
166
 
167
/**
168
 * Combine PBO-read validation and mapping.
169
 * If any GL errors are detected, they'll be recorded and NULL returned.
170
 * \sa _mesa_validate_pbo_access
171
 * \sa _mesa_map_pbo_source
172
 * A call to this function should have a matching call to
173
 * _mesa_unmap_pbo_source().
174
 */
175
const GLvoid *
176
_mesa_map_validate_pbo_source(struct gl_context *ctx,
177
                              GLuint dimensions,
178
                              const struct gl_pixelstore_attrib *unpack,
179
                              GLsizei width, GLsizei height, GLsizei depth,
180
                              GLenum format, GLenum type,
181
                              GLsizei clientMemSize,
182
                              const GLvoid *ptr, const char *where)
183
{
184
   ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
185
 
186
   if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
187
                                  format, type, clientMemSize, ptr)) {
188
      if (_mesa_is_bufferobj(unpack->BufferObj)) {
189
         _mesa_error(ctx, GL_INVALID_OPERATION,
190
                     "%s(out of bounds PBO access)", where);
191
      } else {
192
         _mesa_error(ctx, GL_INVALID_OPERATION,
193
                     "%s(out of bounds access: bufSize (%d) is too small)",
194
                     where, clientMemSize);
195
      }
196
      return NULL;
197
   }
198
 
199
   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
200
      /* non-PBO access: no further validation to be done */
201
      return ptr;
202
   }
203
 
204
   if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
205
      /* buffer is already mapped - that's an error */
206
      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
207
      return NULL;
208
   }
209
 
210
   ptr = _mesa_map_pbo_source(ctx, unpack, ptr);
211
   return ptr;
212
}
213
 
214
 
215
/**
216
 * Counterpart to _mesa_map_pbo_source()
217
 */
218
void
219
_mesa_unmap_pbo_source(struct gl_context *ctx,
220
                       const struct gl_pixelstore_attrib *unpack)
221
{
222
   ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */
223
   if (_mesa_is_bufferobj(unpack->BufferObj)) {
224
      ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj);
225
   }
226
}
227
 
228
 
229
/**
230
 * For commands that write to a PBO (glReadPixels, glGetColorTable, etc),
231
 * if we're writing to a PBO, map it write-only and return the pointer
232
 * into the PBO.  If we're not writing to a PBO, return \p dst as-is.
233
 * If non-null return, must call _mesa_unmap_pbo_dest() when done.
234
 *
235
 * \return NULL if error, else pointer to start of data
236
 */
237
void *
238
_mesa_map_pbo_dest(struct gl_context *ctx,
239
                   const struct gl_pixelstore_attrib *pack,
240
                   GLvoid *dest)
241
{
242
   void *buf;
243
 
244
   if (_mesa_is_bufferobj(pack->BufferObj)) {
245
      /* pack into PBO */
246
      buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
247
						   pack->BufferObj->Size,
248
						   GL_MAP_WRITE_BIT,
249
						   pack->BufferObj);
250
      if (!buf)
251
         return NULL;
252
 
253
      buf = ADD_POINTERS(buf, dest);
254
   }
255
   else {
256
      /* pack to normal memory */
257
      buf = dest;
258
   }
259
 
260
   return buf;
261
}
262
 
263
 
264
/**
265
 * Combine PBO-write validation and mapping.
266
 * If any GL errors are detected, they'll be recorded and NULL returned.
267
 * \sa _mesa_validate_pbo_access
268
 * \sa _mesa_map_pbo_dest
269
 * A call to this function should have a matching call to
270
 * _mesa_unmap_pbo_dest().
271
 */
272
GLvoid *
273
_mesa_map_validate_pbo_dest(struct gl_context *ctx,
274
                            GLuint dimensions,
275
                            const struct gl_pixelstore_attrib *unpack,
276
                            GLsizei width, GLsizei height, GLsizei depth,
277
                            GLenum format, GLenum type, GLsizei clientMemSize,
278
                            GLvoid *ptr, const char *where)
279
{
280
   ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
281
 
282
   if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
283
                                  format, type, clientMemSize, ptr)) {
284
      if (_mesa_is_bufferobj(unpack->BufferObj)) {
285
         _mesa_error(ctx, GL_INVALID_OPERATION,
286
                     "%s(out of bounds PBO access)", where);
287
      } else {
288
         _mesa_error(ctx, GL_INVALID_OPERATION,
289
                     "%s(out of bounds access: bufSize (%d) is too small)",
290
                     where, clientMemSize);
291
      }
292
      return NULL;
293
   }
294
 
295
   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
296
      /* non-PBO access: no further validation to be done */
297
      return ptr;
298
   }
299
 
300
   if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
301
      /* buffer is already mapped - that's an error */
302
      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
303
      return NULL;
304
   }
305
 
306
   ptr = _mesa_map_pbo_dest(ctx, unpack, ptr);
307
   return ptr;
308
}
309
 
310
 
311
/**
312
 * Counterpart to _mesa_map_pbo_dest()
313
 */
314
void
315
_mesa_unmap_pbo_dest(struct gl_context *ctx,
316
                     const struct gl_pixelstore_attrib *pack)
317
{
318
   ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */
319
   if (_mesa_is_bufferobj(pack->BufferObj)) {
320
      ctx->Driver.UnmapBuffer(ctx, pack->BufferObj);
321
   }
322
}
323
 
324
 
325
/**
326
 * Check if an unpack PBO is active prior to fetching a texture image.
327
 * If so, do bounds checking and map the buffer into main memory.
328
 * Any errors detected will be recorded.
329
 * The caller _must_ call _mesa_unmap_teximage_pbo() too!
330
 */
331
const GLvoid *
332
_mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions,
333
			    GLsizei width, GLsizei height, GLsizei depth,
334
			    GLenum format, GLenum type, const GLvoid *pixels,
335
			    const struct gl_pixelstore_attrib *unpack,
336
			    const char *funcName)
337
{
338
   GLubyte *buf;
339
 
340
   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
341
      /* no PBO */
342
      return pixels;
343
   }
344
   if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
345
                                  format, type, INT_MAX, pixels)) {
346
      _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(invalid PBO access)",
347
                  funcName, dimensions);
348
      return NULL;
349
   }
350
 
351
   buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0,
352
                                                unpack->BufferObj->Size,
353
						GL_MAP_READ_BIT,
354
						unpack->BufferObj);
355
   if (!buf) {
356
      _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(PBO is mapped)", funcName,
357
                  dimensions);
358
      return NULL;
359
   }
360
 
361
   return ADD_POINTERS(buf, pixels);
362
}
363
 
364
 
365
/**
366
 * Check if an unpack PBO is active prior to fetching a compressed texture
367
 * image.
368
 * If so, do bounds checking and map the buffer into main memory.
369
 * Any errors detected will be recorded.
370
 * The caller _must_ call _mesa_unmap_teximage_pbo() too!
371
 */
372
const GLvoid *
373
_mesa_validate_pbo_compressed_teximage(struct gl_context *ctx,
374
                                 GLuint dimensions, GLsizei imageSize,
375
                                 const GLvoid *pixels,
376
                                 const struct gl_pixelstore_attrib *packing,
377
                                 const char *funcName)
378
{
379
   GLubyte *buf;
380
 
381
   if (!_mesa_is_bufferobj(packing->BufferObj)) {
382
      /* not using a PBO - return pointer unchanged */
383
      return pixels;
384
   }
385
   if ((const GLubyte *) pixels + imageSize >
386
       ((const GLubyte *) 0) + packing->BufferObj->Size) {
387
      /* out of bounds read! */
388
      _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(invalid PBO access)",
389
                  funcName, dimensions);
390
      return NULL;
391
   }
392
 
393
   buf = (GLubyte*) ctx->Driver.MapBufferRange(ctx, 0,
394
					       packing->BufferObj->Size,
395
					       GL_MAP_READ_BIT,
396
					       packing->BufferObj);
397
   if (!buf) {
398
      _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(PBO is mapped)", funcName,
399
                  dimensions);
400
      return NULL;
401
   }
402
 
403
   return ADD_POINTERS(buf, pixels);
404
}
405
 
406
 
407
/**
408
 * This function must be called after either of the validate_pbo_*_teximage()
409
 * functions.  It unmaps the PBO buffer if it was mapped earlier.
410
 */
411
void
412
_mesa_unmap_teximage_pbo(struct gl_context *ctx,
413
                         const struct gl_pixelstore_attrib *unpack)
414
{
415
   if (_mesa_is_bufferobj(unpack->BufferObj)) {
416
      ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj);
417
   }
418
}