1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Mesa 3-D graphics library
3*61046927SAndroid Build Coastguard Worker *
4*61046927SAndroid Build Coastguard Worker * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
5*61046927SAndroid Build Coastguard Worker * Copyright (C) 2009-2011 VMware, Inc. All Rights Reserved.
6*61046927SAndroid Build Coastguard Worker *
7*61046927SAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining a
8*61046927SAndroid Build Coastguard Worker * copy of this software and associated documentation files (the "Software"),
9*61046927SAndroid Build Coastguard Worker * to deal in the Software without restriction, including without limitation
10*61046927SAndroid Build Coastguard Worker * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11*61046927SAndroid Build Coastguard Worker * and/or sell copies of the Software, and to permit persons to whom the
12*61046927SAndroid Build Coastguard Worker * Software is furnished to do so, subject to the following conditions:
13*61046927SAndroid Build Coastguard Worker *
14*61046927SAndroid Build Coastguard Worker * The above copyright notice and this permission notice shall be included
15*61046927SAndroid Build Coastguard Worker * in all copies or substantial portions of the Software.
16*61046927SAndroid Build Coastguard Worker *
17*61046927SAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18*61046927SAndroid Build Coastguard Worker * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19*61046927SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20*61046927SAndroid Build Coastguard Worker * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21*61046927SAndroid Build Coastguard Worker * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22*61046927SAndroid Build Coastguard Worker * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23*61046927SAndroid Build Coastguard Worker * OTHER DEALINGS IN THE SOFTWARE.
24*61046927SAndroid Build Coastguard Worker */
25*61046927SAndroid Build Coastguard Worker
26*61046927SAndroid Build Coastguard Worker
27*61046927SAndroid Build Coastguard Worker /**
28*61046927SAndroid Build Coastguard Worker * \file pbo.c
29*61046927SAndroid Build Coastguard Worker * \brief Functions related to Pixel Buffer Objects.
30*61046927SAndroid Build Coastguard Worker */
31*61046927SAndroid Build Coastguard Worker
32*61046927SAndroid Build Coastguard Worker
33*61046927SAndroid Build Coastguard Worker
34*61046927SAndroid Build Coastguard Worker #include "errors.h"
35*61046927SAndroid Build Coastguard Worker #include "util/glheader.h"
36*61046927SAndroid Build Coastguard Worker #include "bufferobj.h"
37*61046927SAndroid Build Coastguard Worker #include "glformats.h"
38*61046927SAndroid Build Coastguard Worker #include "image.h"
39*61046927SAndroid Build Coastguard Worker #include "mtypes.h"
40*61046927SAndroid Build Coastguard Worker #include "macros.h"
41*61046927SAndroid Build Coastguard Worker #include "pbo.h"
42*61046927SAndroid Build Coastguard Worker
43*61046927SAndroid Build Coastguard Worker /**
44*61046927SAndroid Build Coastguard Worker * When we're about to read pixel data out of a PBO (via glDrawPixels,
45*61046927SAndroid Build Coastguard Worker * glTexImage, etc) or write data into a PBO (via glReadPixels,
46*61046927SAndroid Build Coastguard Worker * glGetTexImage, etc) we call this function to check that we're not
47*61046927SAndroid Build Coastguard Worker * going to read/write out of bounds.
48*61046927SAndroid Build Coastguard Worker *
49*61046927SAndroid Build Coastguard Worker * XXX This would also be a convenient time to check that the PBO isn't
50*61046927SAndroid Build Coastguard Worker * currently mapped. Whoever calls this function should check for that.
51*61046927SAndroid Build Coastguard Worker * Remember, we can't use a PBO when it's mapped!
52*61046927SAndroid Build Coastguard Worker *
53*61046927SAndroid Build Coastguard Worker * If we're not using a PBO, this is a no-op.
54*61046927SAndroid Build Coastguard Worker *
55*61046927SAndroid Build Coastguard Worker * \param width width of image to read/write
56*61046927SAndroid Build Coastguard Worker * \param height height of image to read/write
57*61046927SAndroid Build Coastguard Worker * \param depth depth of image to read/write
58*61046927SAndroid Build Coastguard Worker * \param format format of image to read/write
59*61046927SAndroid Build Coastguard Worker * \param type datatype of image to read/write
60*61046927SAndroid Build Coastguard Worker * \param clientMemSize the maximum number of bytes to read/write
61*61046927SAndroid Build Coastguard Worker * \param ptr the user-provided pointer/offset
62*61046927SAndroid Build Coastguard Worker * \return GL_TRUE if the buffer access is OK, GL_FALSE if the access would
63*61046927SAndroid Build Coastguard Worker * go out of bounds.
64*61046927SAndroid Build Coastguard Worker */
65*61046927SAndroid Build Coastguard Worker GLboolean
_mesa_validate_pbo_access(GLuint dimensions,const struct gl_pixelstore_attrib * pack,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,GLsizei clientMemSize,const GLvoid * ptr)66*61046927SAndroid Build Coastguard Worker _mesa_validate_pbo_access(GLuint dimensions,
67*61046927SAndroid Build Coastguard Worker const struct gl_pixelstore_attrib *pack,
68*61046927SAndroid Build Coastguard Worker GLsizei width, GLsizei height, GLsizei depth,
69*61046927SAndroid Build Coastguard Worker GLenum format, GLenum type, GLsizei clientMemSize,
70*61046927SAndroid Build Coastguard Worker const GLvoid *ptr)
71*61046927SAndroid Build Coastguard Worker {
72*61046927SAndroid Build Coastguard Worker /* unsigned, to detect overflow/wrap-around */
73*61046927SAndroid Build Coastguard Worker uintptr_t start, end, offset, size;
74*61046927SAndroid Build Coastguard Worker
75*61046927SAndroid Build Coastguard Worker /* If no PBO is bound, 'ptr' is a pointer to client memory containing
76*61046927SAndroid Build Coastguard Worker 'clientMemSize' bytes.
77*61046927SAndroid Build Coastguard Worker If a PBO is bound, 'ptr' is an offset into the bound PBO.
78*61046927SAndroid Build Coastguard Worker In that case 'clientMemSize' is ignored: we just use the PBO's size.
79*61046927SAndroid Build Coastguard Worker */
80*61046927SAndroid Build Coastguard Worker if (!pack->BufferObj) {
81*61046927SAndroid Build Coastguard Worker offset = 0;
82*61046927SAndroid Build Coastguard Worker size = (clientMemSize == INT_MAX) ? UINTPTR_MAX : clientMemSize;
83*61046927SAndroid Build Coastguard Worker } else {
84*61046927SAndroid Build Coastguard Worker offset = (uintptr_t)ptr;
85*61046927SAndroid Build Coastguard Worker size = pack->BufferObj->Size;
86*61046927SAndroid Build Coastguard Worker /* The ARB_pixel_buffer_object spec says:
87*61046927SAndroid Build Coastguard Worker * "INVALID_OPERATION is generated by ColorTable, ColorSubTable,
88*61046927SAndroid Build Coastguard Worker * ConvolutionFilter2D, ConvolutionFilter1D, SeparableFilter2D,
89*61046927SAndroid Build Coastguard Worker * TexImage1D, TexImage2D, TexImage3D, TexSubImage1D,
90*61046927SAndroid Build Coastguard Worker * TexSubImage2D, TexSubImage3D, and DrawPixels if the current
91*61046927SAndroid Build Coastguard Worker * PIXEL_UNPACK_BUFFER_BINDING_ARB value is non-zero and the data
92*61046927SAndroid Build Coastguard Worker * parameter is not evenly divisible into the number of basic machine
93*61046927SAndroid Build Coastguard Worker * units needed to store in memory a datum indicated by the type
94*61046927SAndroid Build Coastguard Worker * parameter."
95*61046927SAndroid Build Coastguard Worker */
96*61046927SAndroid Build Coastguard Worker if (type != GL_BITMAP &&
97*61046927SAndroid Build Coastguard Worker (offset % _mesa_sizeof_packed_type(type)))
98*61046927SAndroid Build Coastguard Worker return GL_FALSE;
99*61046927SAndroid Build Coastguard Worker }
100*61046927SAndroid Build Coastguard Worker
101*61046927SAndroid Build Coastguard Worker if (size == 0)
102*61046927SAndroid Build Coastguard Worker /* no buffer! */
103*61046927SAndroid Build Coastguard Worker return GL_FALSE;
104*61046927SAndroid Build Coastguard Worker
105*61046927SAndroid Build Coastguard Worker /* If the size of the image is zero then no pixels are accessed so we
106*61046927SAndroid Build Coastguard Worker * don't need to check anything else.
107*61046927SAndroid Build Coastguard Worker */
108*61046927SAndroid Build Coastguard Worker if (width == 0 || height == 0 || depth == 0)
109*61046927SAndroid Build Coastguard Worker return GL_TRUE;
110*61046927SAndroid Build Coastguard Worker
111*61046927SAndroid Build Coastguard Worker /* get the offset to the first pixel we'll read/write */
112*61046927SAndroid Build Coastguard Worker start = _mesa_image_offset(dimensions, pack, width, height,
113*61046927SAndroid Build Coastguard Worker format, type, 0, 0, 0);
114*61046927SAndroid Build Coastguard Worker
115*61046927SAndroid Build Coastguard Worker /* get the offset to just past the last pixel we'll read/write */
116*61046927SAndroid Build Coastguard Worker end = _mesa_image_offset(dimensions, pack, width, height,
117*61046927SAndroid Build Coastguard Worker format, type, depth-1, height-1, width);
118*61046927SAndroid Build Coastguard Worker
119*61046927SAndroid Build Coastguard Worker start += offset;
120*61046927SAndroid Build Coastguard Worker end += offset;
121*61046927SAndroid Build Coastguard Worker
122*61046927SAndroid Build Coastguard Worker if (start > size) {
123*61046927SAndroid Build Coastguard Worker /* This will catch negative values / wrap-around */
124*61046927SAndroid Build Coastguard Worker return GL_FALSE;
125*61046927SAndroid Build Coastguard Worker }
126*61046927SAndroid Build Coastguard Worker if (end > size) {
127*61046927SAndroid Build Coastguard Worker /* Image read/write goes beyond end of buffer */
128*61046927SAndroid Build Coastguard Worker return GL_FALSE;
129*61046927SAndroid Build Coastguard Worker }
130*61046927SAndroid Build Coastguard Worker
131*61046927SAndroid Build Coastguard Worker /* OK! */
132*61046927SAndroid Build Coastguard Worker return GL_TRUE;
133*61046927SAndroid Build Coastguard Worker }
134*61046927SAndroid Build Coastguard Worker
135*61046927SAndroid Build Coastguard Worker
136*61046927SAndroid Build Coastguard Worker /**
137*61046927SAndroid Build Coastguard Worker * For commands that read from a PBO (glDrawPixels, glTexImage,
138*61046927SAndroid Build Coastguard Worker * glPolygonStipple, etc), if we're reading from a PBO, map it read-only
139*61046927SAndroid Build Coastguard Worker * and return the pointer into the PBO. If we're not reading from a
140*61046927SAndroid Build Coastguard Worker * PBO, return \p src as-is.
141*61046927SAndroid Build Coastguard Worker * If non-null return, must call _mesa_unmap_pbo_source() when done.
142*61046927SAndroid Build Coastguard Worker *
143*61046927SAndroid Build Coastguard Worker * \return NULL if error, else pointer to start of data
144*61046927SAndroid Build Coastguard Worker */
145*61046927SAndroid Build Coastguard Worker const GLvoid *
_mesa_map_pbo_source(struct gl_context * ctx,const struct gl_pixelstore_attrib * unpack,const GLvoid * src)146*61046927SAndroid Build Coastguard Worker _mesa_map_pbo_source(struct gl_context *ctx,
147*61046927SAndroid Build Coastguard Worker const struct gl_pixelstore_attrib *unpack,
148*61046927SAndroid Build Coastguard Worker const GLvoid *src)
149*61046927SAndroid Build Coastguard Worker {
150*61046927SAndroid Build Coastguard Worker const GLubyte *buf;
151*61046927SAndroid Build Coastguard Worker
152*61046927SAndroid Build Coastguard Worker if (unpack->BufferObj) {
153*61046927SAndroid Build Coastguard Worker /* unpack from PBO */
154*61046927SAndroid Build Coastguard Worker buf = (GLubyte *) _mesa_bufferobj_map_range(ctx, 0,
155*61046927SAndroid Build Coastguard Worker unpack->BufferObj->Size,
156*61046927SAndroid Build Coastguard Worker GL_MAP_READ_BIT,
157*61046927SAndroid Build Coastguard Worker unpack->BufferObj,
158*61046927SAndroid Build Coastguard Worker MAP_INTERNAL);
159*61046927SAndroid Build Coastguard Worker if (!buf)
160*61046927SAndroid Build Coastguard Worker return NULL;
161*61046927SAndroid Build Coastguard Worker
162*61046927SAndroid Build Coastguard Worker buf = ADD_POINTERS(buf, src);
163*61046927SAndroid Build Coastguard Worker }
164*61046927SAndroid Build Coastguard Worker else {
165*61046927SAndroid Build Coastguard Worker /* unpack from normal memory */
166*61046927SAndroid Build Coastguard Worker buf = src;
167*61046927SAndroid Build Coastguard Worker }
168*61046927SAndroid Build Coastguard Worker
169*61046927SAndroid Build Coastguard Worker return buf;
170*61046927SAndroid Build Coastguard Worker }
171*61046927SAndroid Build Coastguard Worker
172*61046927SAndroid Build Coastguard Worker /**
173*61046927SAndroid Build Coastguard Worker * Perform PBO validation for read operations with uncompressed textures.
174*61046927SAndroid Build Coastguard Worker * If any GL errors are detected, false is returned, otherwise returns true.
175*61046927SAndroid Build Coastguard Worker * \sa _mesa_validate_pbo_access
176*61046927SAndroid Build Coastguard Worker */
177*61046927SAndroid Build Coastguard Worker bool
_mesa_validate_pbo_source(struct gl_context * ctx,GLuint dimensions,const struct gl_pixelstore_attrib * unpack,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,GLsizei clientMemSize,const GLvoid * ptr,const char * where)178*61046927SAndroid Build Coastguard Worker _mesa_validate_pbo_source(struct gl_context *ctx, GLuint dimensions,
179*61046927SAndroid Build Coastguard Worker const struct gl_pixelstore_attrib *unpack,
180*61046927SAndroid Build Coastguard Worker GLsizei width, GLsizei height, GLsizei depth,
181*61046927SAndroid Build Coastguard Worker GLenum format, GLenum type,
182*61046927SAndroid Build Coastguard Worker GLsizei clientMemSize,
183*61046927SAndroid Build Coastguard Worker const GLvoid *ptr, const char *where)
184*61046927SAndroid Build Coastguard Worker {
185*61046927SAndroid Build Coastguard Worker assert(dimensions == 1 || dimensions == 2 || dimensions == 3);
186*61046927SAndroid Build Coastguard Worker
187*61046927SAndroid Build Coastguard Worker if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
188*61046927SAndroid Build Coastguard Worker format, type, clientMemSize, ptr)) {
189*61046927SAndroid Build Coastguard Worker if (unpack->BufferObj) {
190*61046927SAndroid Build Coastguard Worker _mesa_error(ctx, GL_INVALID_OPERATION,
191*61046927SAndroid Build Coastguard Worker "%s(out of bounds PBO access)",
192*61046927SAndroid Build Coastguard Worker where);
193*61046927SAndroid Build Coastguard Worker } else {
194*61046927SAndroid Build Coastguard Worker _mesa_error(ctx, GL_INVALID_OPERATION,
195*61046927SAndroid Build Coastguard Worker "%s(out of bounds access: bufSize (%d) is too small)",
196*61046927SAndroid Build Coastguard Worker where, clientMemSize);
197*61046927SAndroid Build Coastguard Worker }
198*61046927SAndroid Build Coastguard Worker return false;
199*61046927SAndroid Build Coastguard Worker }
200*61046927SAndroid Build Coastguard Worker
201*61046927SAndroid Build Coastguard Worker if (!unpack->BufferObj) {
202*61046927SAndroid Build Coastguard Worker /* non-PBO access: no further validation to be done */
203*61046927SAndroid Build Coastguard Worker return true;
204*61046927SAndroid Build Coastguard Worker }
205*61046927SAndroid Build Coastguard Worker
206*61046927SAndroid Build Coastguard Worker if (_mesa_check_disallowed_mapping(unpack->BufferObj)) {
207*61046927SAndroid Build Coastguard Worker /* buffer is already mapped - that's an error */
208*61046927SAndroid Build Coastguard Worker _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)",
209*61046927SAndroid Build Coastguard Worker where);
210*61046927SAndroid Build Coastguard Worker return false;
211*61046927SAndroid Build Coastguard Worker }
212*61046927SAndroid Build Coastguard Worker
213*61046927SAndroid Build Coastguard Worker return true;
214*61046927SAndroid Build Coastguard Worker }
215*61046927SAndroid Build Coastguard Worker
216*61046927SAndroid Build Coastguard Worker /**
217*61046927SAndroid Build Coastguard Worker * Perform PBO validation for read operations with compressed textures.
218*61046927SAndroid Build Coastguard Worker * If any GL errors are detected, false is returned, otherwise returns true.
219*61046927SAndroid Build Coastguard Worker */
220*61046927SAndroid Build Coastguard Worker bool
_mesa_validate_pbo_source_compressed(struct gl_context * ctx,GLuint dimensions,const struct gl_pixelstore_attrib * unpack,GLsizei imageSize,const GLvoid * pixels,const char * where)221*61046927SAndroid Build Coastguard Worker _mesa_validate_pbo_source_compressed(struct gl_context *ctx, GLuint dimensions,
222*61046927SAndroid Build Coastguard Worker const struct gl_pixelstore_attrib *unpack,
223*61046927SAndroid Build Coastguard Worker GLsizei imageSize, const GLvoid *pixels,
224*61046927SAndroid Build Coastguard Worker const char *where)
225*61046927SAndroid Build Coastguard Worker {
226*61046927SAndroid Build Coastguard Worker if (!unpack->BufferObj) {
227*61046927SAndroid Build Coastguard Worker /* not using a PBO */
228*61046927SAndroid Build Coastguard Worker return true;
229*61046927SAndroid Build Coastguard Worker }
230*61046927SAndroid Build Coastguard Worker
231*61046927SAndroid Build Coastguard Worker if ((const GLubyte *) pixels + imageSize >
232*61046927SAndroid Build Coastguard Worker ((const GLubyte *) 0) + unpack->BufferObj->Size) {
233*61046927SAndroid Build Coastguard Worker /* out of bounds read! */
234*61046927SAndroid Build Coastguard Worker _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid PBO access)",
235*61046927SAndroid Build Coastguard Worker where);
236*61046927SAndroid Build Coastguard Worker return false;
237*61046927SAndroid Build Coastguard Worker }
238*61046927SAndroid Build Coastguard Worker
239*61046927SAndroid Build Coastguard Worker if (_mesa_check_disallowed_mapping(unpack->BufferObj)) {
240*61046927SAndroid Build Coastguard Worker /* buffer is already mapped - that's an error */
241*61046927SAndroid Build Coastguard Worker _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)",
242*61046927SAndroid Build Coastguard Worker where);
243*61046927SAndroid Build Coastguard Worker return false;
244*61046927SAndroid Build Coastguard Worker }
245*61046927SAndroid Build Coastguard Worker
246*61046927SAndroid Build Coastguard Worker return true;
247*61046927SAndroid Build Coastguard Worker }
248*61046927SAndroid Build Coastguard Worker
249*61046927SAndroid Build Coastguard Worker /**
250*61046927SAndroid Build Coastguard Worker * Perform PBO-read mapping.
251*61046927SAndroid Build Coastguard Worker * If any GL errors are detected, they'll be recorded and NULL returned.
252*61046927SAndroid Build Coastguard Worker * \sa _mesa_validate_pbo_source
253*61046927SAndroid Build Coastguard Worker * \sa _mesa_map_pbo_source
254*61046927SAndroid Build Coastguard Worker * A call to this function should have a matching call to
255*61046927SAndroid Build Coastguard Worker * _mesa_unmap_pbo_source().
256*61046927SAndroid Build Coastguard Worker */
257*61046927SAndroid Build Coastguard Worker const GLvoid *
_mesa_map_validate_pbo_source(struct gl_context * ctx,GLuint dimensions,const struct gl_pixelstore_attrib * unpack,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,GLsizei clientMemSize,const GLvoid * ptr,const char * where)258*61046927SAndroid Build Coastguard Worker _mesa_map_validate_pbo_source(struct gl_context *ctx,
259*61046927SAndroid Build Coastguard Worker GLuint dimensions,
260*61046927SAndroid Build Coastguard Worker const struct gl_pixelstore_attrib *unpack,
261*61046927SAndroid Build Coastguard Worker GLsizei width, GLsizei height, GLsizei depth,
262*61046927SAndroid Build Coastguard Worker GLenum format, GLenum type,
263*61046927SAndroid Build Coastguard Worker GLsizei clientMemSize,
264*61046927SAndroid Build Coastguard Worker const GLvoid *ptr, const char *where)
265*61046927SAndroid Build Coastguard Worker {
266*61046927SAndroid Build Coastguard Worker if (!_mesa_validate_pbo_source(ctx, dimensions, unpack,
267*61046927SAndroid Build Coastguard Worker width, height, depth, format, type,
268*61046927SAndroid Build Coastguard Worker clientMemSize, ptr, where)) {
269*61046927SAndroid Build Coastguard Worker return NULL;
270*61046927SAndroid Build Coastguard Worker }
271*61046927SAndroid Build Coastguard Worker
272*61046927SAndroid Build Coastguard Worker ptr = _mesa_map_pbo_source(ctx, unpack, ptr);
273*61046927SAndroid Build Coastguard Worker return ptr;
274*61046927SAndroid Build Coastguard Worker }
275*61046927SAndroid Build Coastguard Worker
276*61046927SAndroid Build Coastguard Worker
277*61046927SAndroid Build Coastguard Worker /**
278*61046927SAndroid Build Coastguard Worker * Counterpart to _mesa_map_pbo_source()
279*61046927SAndroid Build Coastguard Worker */
280*61046927SAndroid Build Coastguard Worker void
_mesa_unmap_pbo_source(struct gl_context * ctx,const struct gl_pixelstore_attrib * unpack)281*61046927SAndroid Build Coastguard Worker _mesa_unmap_pbo_source(struct gl_context *ctx,
282*61046927SAndroid Build Coastguard Worker const struct gl_pixelstore_attrib *unpack)
283*61046927SAndroid Build Coastguard Worker {
284*61046927SAndroid Build Coastguard Worker assert(unpack != &ctx->Pack); /* catch pack/unpack mismatch */
285*61046927SAndroid Build Coastguard Worker if (unpack->BufferObj) {
286*61046927SAndroid Build Coastguard Worker _mesa_bufferobj_unmap(ctx, unpack->BufferObj, MAP_INTERNAL);
287*61046927SAndroid Build Coastguard Worker }
288*61046927SAndroid Build Coastguard Worker }
289*61046927SAndroid Build Coastguard Worker
290*61046927SAndroid Build Coastguard Worker
291*61046927SAndroid Build Coastguard Worker /**
292*61046927SAndroid Build Coastguard Worker * For commands that write to a PBO (glReadPixels, glGetColorTable, etc),
293*61046927SAndroid Build Coastguard Worker * if we're writing to a PBO, map it write-only and return the pointer
294*61046927SAndroid Build Coastguard Worker * into the PBO. If we're not writing to a PBO, return \p dst as-is.
295*61046927SAndroid Build Coastguard Worker * If non-null return, must call _mesa_unmap_pbo_dest() when done.
296*61046927SAndroid Build Coastguard Worker *
297*61046927SAndroid Build Coastguard Worker * \return NULL if error, else pointer to start of data
298*61046927SAndroid Build Coastguard Worker */
299*61046927SAndroid Build Coastguard Worker void *
_mesa_map_pbo_dest(struct gl_context * ctx,const struct gl_pixelstore_attrib * pack,GLvoid * dest)300*61046927SAndroid Build Coastguard Worker _mesa_map_pbo_dest(struct gl_context *ctx,
301*61046927SAndroid Build Coastguard Worker const struct gl_pixelstore_attrib *pack,
302*61046927SAndroid Build Coastguard Worker GLvoid *dest)
303*61046927SAndroid Build Coastguard Worker {
304*61046927SAndroid Build Coastguard Worker void *buf;
305*61046927SAndroid Build Coastguard Worker
306*61046927SAndroid Build Coastguard Worker if (pack->BufferObj) {
307*61046927SAndroid Build Coastguard Worker /* pack into PBO */
308*61046927SAndroid Build Coastguard Worker buf = (GLubyte *) _mesa_bufferobj_map_range(ctx, 0,
309*61046927SAndroid Build Coastguard Worker pack->BufferObj->Size,
310*61046927SAndroid Build Coastguard Worker GL_MAP_WRITE_BIT,
311*61046927SAndroid Build Coastguard Worker pack->BufferObj,
312*61046927SAndroid Build Coastguard Worker MAP_INTERNAL);
313*61046927SAndroid Build Coastguard Worker if (!buf)
314*61046927SAndroid Build Coastguard Worker return NULL;
315*61046927SAndroid Build Coastguard Worker
316*61046927SAndroid Build Coastguard Worker buf = ADD_POINTERS(buf, dest);
317*61046927SAndroid Build Coastguard Worker }
318*61046927SAndroid Build Coastguard Worker else {
319*61046927SAndroid Build Coastguard Worker /* pack to normal memory */
320*61046927SAndroid Build Coastguard Worker buf = dest;
321*61046927SAndroid Build Coastguard Worker }
322*61046927SAndroid Build Coastguard Worker
323*61046927SAndroid Build Coastguard Worker return buf;
324*61046927SAndroid Build Coastguard Worker }
325*61046927SAndroid Build Coastguard Worker
326*61046927SAndroid Build Coastguard Worker
327*61046927SAndroid Build Coastguard Worker /**
328*61046927SAndroid Build Coastguard Worker * Combine PBO-write validation and mapping.
329*61046927SAndroid Build Coastguard Worker * If any GL errors are detected, they'll be recorded and NULL returned.
330*61046927SAndroid Build Coastguard Worker * \sa _mesa_validate_pbo_access
331*61046927SAndroid Build Coastguard Worker * \sa _mesa_map_pbo_dest
332*61046927SAndroid Build Coastguard Worker * A call to this function should have a matching call to
333*61046927SAndroid Build Coastguard Worker * _mesa_unmap_pbo_dest().
334*61046927SAndroid Build Coastguard Worker */
335*61046927SAndroid Build Coastguard Worker GLvoid *
_mesa_map_validate_pbo_dest(struct gl_context * ctx,GLuint dimensions,const struct gl_pixelstore_attrib * unpack,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,GLsizei clientMemSize,GLvoid * ptr,const char * where)336*61046927SAndroid Build Coastguard Worker _mesa_map_validate_pbo_dest(struct gl_context *ctx,
337*61046927SAndroid Build Coastguard Worker GLuint dimensions,
338*61046927SAndroid Build Coastguard Worker const struct gl_pixelstore_attrib *unpack,
339*61046927SAndroid Build Coastguard Worker GLsizei width, GLsizei height, GLsizei depth,
340*61046927SAndroid Build Coastguard Worker GLenum format, GLenum type, GLsizei clientMemSize,
341*61046927SAndroid Build Coastguard Worker GLvoid *ptr, const char *where)
342*61046927SAndroid Build Coastguard Worker {
343*61046927SAndroid Build Coastguard Worker assert(dimensions == 1 || dimensions == 2 || dimensions == 3);
344*61046927SAndroid Build Coastguard Worker
345*61046927SAndroid Build Coastguard Worker if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
346*61046927SAndroid Build Coastguard Worker format, type, clientMemSize, ptr)) {
347*61046927SAndroid Build Coastguard Worker if (unpack->BufferObj) {
348*61046927SAndroid Build Coastguard Worker _mesa_error(ctx, GL_INVALID_OPERATION,
349*61046927SAndroid Build Coastguard Worker "%s(out of bounds PBO access)", where);
350*61046927SAndroid Build Coastguard Worker } else {
351*61046927SAndroid Build Coastguard Worker _mesa_error(ctx, GL_INVALID_OPERATION,
352*61046927SAndroid Build Coastguard Worker "%s(out of bounds access: bufSize (%d) is too small)",
353*61046927SAndroid Build Coastguard Worker where, clientMemSize);
354*61046927SAndroid Build Coastguard Worker }
355*61046927SAndroid Build Coastguard Worker return NULL;
356*61046927SAndroid Build Coastguard Worker }
357*61046927SAndroid Build Coastguard Worker
358*61046927SAndroid Build Coastguard Worker if (!unpack->BufferObj) {
359*61046927SAndroid Build Coastguard Worker /* non-PBO access: no further validation to be done */
360*61046927SAndroid Build Coastguard Worker return ptr;
361*61046927SAndroid Build Coastguard Worker }
362*61046927SAndroid Build Coastguard Worker
363*61046927SAndroid Build Coastguard Worker if (_mesa_check_disallowed_mapping(unpack->BufferObj)) {
364*61046927SAndroid Build Coastguard Worker /* buffer is already mapped - that's an error */
365*61046927SAndroid Build Coastguard Worker _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
366*61046927SAndroid Build Coastguard Worker return NULL;
367*61046927SAndroid Build Coastguard Worker }
368*61046927SAndroid Build Coastguard Worker
369*61046927SAndroid Build Coastguard Worker ptr = _mesa_map_pbo_dest(ctx, unpack, ptr);
370*61046927SAndroid Build Coastguard Worker return ptr;
371*61046927SAndroid Build Coastguard Worker }
372*61046927SAndroid Build Coastguard Worker
373*61046927SAndroid Build Coastguard Worker
374*61046927SAndroid Build Coastguard Worker /**
375*61046927SAndroid Build Coastguard Worker * Counterpart to _mesa_map_pbo_dest()
376*61046927SAndroid Build Coastguard Worker */
377*61046927SAndroid Build Coastguard Worker void
_mesa_unmap_pbo_dest(struct gl_context * ctx,const struct gl_pixelstore_attrib * pack)378*61046927SAndroid Build Coastguard Worker _mesa_unmap_pbo_dest(struct gl_context *ctx,
379*61046927SAndroid Build Coastguard Worker const struct gl_pixelstore_attrib *pack)
380*61046927SAndroid Build Coastguard Worker {
381*61046927SAndroid Build Coastguard Worker assert(pack != &ctx->Unpack); /* catch pack/unpack mismatch */
382*61046927SAndroid Build Coastguard Worker if (pack->BufferObj) {
383*61046927SAndroid Build Coastguard Worker _mesa_bufferobj_unmap(ctx, pack->BufferObj, MAP_INTERNAL);
384*61046927SAndroid Build Coastguard Worker }
385*61046927SAndroid Build Coastguard Worker }
386*61046927SAndroid Build Coastguard Worker
387*61046927SAndroid Build Coastguard Worker
388*61046927SAndroid Build Coastguard Worker /**
389*61046927SAndroid Build Coastguard Worker * Check if an unpack PBO is active prior to fetching a texture image.
390*61046927SAndroid Build Coastguard Worker * If so, do bounds checking and map the buffer into main memory.
391*61046927SAndroid Build Coastguard Worker * Any errors detected will be recorded.
392*61046927SAndroid Build Coastguard Worker * The caller _must_ call _mesa_unmap_teximage_pbo() too!
393*61046927SAndroid Build Coastguard Worker */
394*61046927SAndroid Build Coastguard Worker const GLvoid *
_mesa_validate_pbo_teximage(struct gl_context * ctx,GLuint dimensions,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,const GLvoid * pixels,const struct gl_pixelstore_attrib * unpack,const char * funcName)395*61046927SAndroid Build Coastguard Worker _mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions,
396*61046927SAndroid Build Coastguard Worker GLsizei width, GLsizei height, GLsizei depth,
397*61046927SAndroid Build Coastguard Worker GLenum format, GLenum type, const GLvoid *pixels,
398*61046927SAndroid Build Coastguard Worker const struct gl_pixelstore_attrib *unpack,
399*61046927SAndroid Build Coastguard Worker const char *funcName)
400*61046927SAndroid Build Coastguard Worker {
401*61046927SAndroid Build Coastguard Worker GLubyte *buf;
402*61046927SAndroid Build Coastguard Worker
403*61046927SAndroid Build Coastguard Worker if (!unpack->BufferObj) {
404*61046927SAndroid Build Coastguard Worker /* no PBO */
405*61046927SAndroid Build Coastguard Worker return pixels;
406*61046927SAndroid Build Coastguard Worker }
407*61046927SAndroid Build Coastguard Worker if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
408*61046927SAndroid Build Coastguard Worker format, type, INT_MAX, pixels)) {
409*61046927SAndroid Build Coastguard Worker _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(invalid PBO access)",
410*61046927SAndroid Build Coastguard Worker funcName, dimensions);
411*61046927SAndroid Build Coastguard Worker return NULL;
412*61046927SAndroid Build Coastguard Worker }
413*61046927SAndroid Build Coastguard Worker
414*61046927SAndroid Build Coastguard Worker buf = (GLubyte *) _mesa_bufferobj_map_range(ctx, 0,
415*61046927SAndroid Build Coastguard Worker unpack->BufferObj->Size,
416*61046927SAndroid Build Coastguard Worker GL_MAP_READ_BIT,
417*61046927SAndroid Build Coastguard Worker unpack->BufferObj,
418*61046927SAndroid Build Coastguard Worker MAP_INTERNAL);
419*61046927SAndroid Build Coastguard Worker if (!buf) {
420*61046927SAndroid Build Coastguard Worker _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(PBO is mapped)", funcName,
421*61046927SAndroid Build Coastguard Worker dimensions);
422*61046927SAndroid Build Coastguard Worker return NULL;
423*61046927SAndroid Build Coastguard Worker }
424*61046927SAndroid Build Coastguard Worker
425*61046927SAndroid Build Coastguard Worker return ADD_POINTERS(buf, pixels);
426*61046927SAndroid Build Coastguard Worker }
427*61046927SAndroid Build Coastguard Worker
428*61046927SAndroid Build Coastguard Worker
429*61046927SAndroid Build Coastguard Worker /**
430*61046927SAndroid Build Coastguard Worker * Check if an unpack PBO is active prior to fetching a compressed texture
431*61046927SAndroid Build Coastguard Worker * image.
432*61046927SAndroid Build Coastguard Worker * If so, do bounds checking and map the buffer into main memory.
433*61046927SAndroid Build Coastguard Worker * Any errors detected will be recorded.
434*61046927SAndroid Build Coastguard Worker * The caller _must_ call _mesa_unmap_teximage_pbo() too!
435*61046927SAndroid Build Coastguard Worker */
436*61046927SAndroid Build Coastguard Worker const GLvoid *
_mesa_validate_pbo_compressed_teximage(struct gl_context * ctx,GLuint dimensions,GLsizei imageSize,const GLvoid * pixels,const struct gl_pixelstore_attrib * packing,const char * funcName)437*61046927SAndroid Build Coastguard Worker _mesa_validate_pbo_compressed_teximage(struct gl_context *ctx,
438*61046927SAndroid Build Coastguard Worker GLuint dimensions, GLsizei imageSize,
439*61046927SAndroid Build Coastguard Worker const GLvoid *pixels,
440*61046927SAndroid Build Coastguard Worker const struct gl_pixelstore_attrib *packing,
441*61046927SAndroid Build Coastguard Worker const char *funcName)
442*61046927SAndroid Build Coastguard Worker {
443*61046927SAndroid Build Coastguard Worker GLubyte *buf;
444*61046927SAndroid Build Coastguard Worker
445*61046927SAndroid Build Coastguard Worker if (!_mesa_validate_pbo_source_compressed(ctx, dimensions, packing,
446*61046927SAndroid Build Coastguard Worker imageSize, pixels, funcName)) {
447*61046927SAndroid Build Coastguard Worker /* error is already set during validation */
448*61046927SAndroid Build Coastguard Worker return NULL;
449*61046927SAndroid Build Coastguard Worker }
450*61046927SAndroid Build Coastguard Worker
451*61046927SAndroid Build Coastguard Worker if (!packing->BufferObj) {
452*61046927SAndroid Build Coastguard Worker /* not using a PBO - return pointer unchanged */
453*61046927SAndroid Build Coastguard Worker return pixels;
454*61046927SAndroid Build Coastguard Worker }
455*61046927SAndroid Build Coastguard Worker
456*61046927SAndroid Build Coastguard Worker buf = (GLubyte*) _mesa_bufferobj_map_range(ctx, 0,
457*61046927SAndroid Build Coastguard Worker packing->BufferObj->Size,
458*61046927SAndroid Build Coastguard Worker GL_MAP_READ_BIT,
459*61046927SAndroid Build Coastguard Worker packing->BufferObj,
460*61046927SAndroid Build Coastguard Worker MAP_INTERNAL);
461*61046927SAndroid Build Coastguard Worker
462*61046927SAndroid Build Coastguard Worker /* Validation above already checked that PBO is not mapped, so buffer
463*61046927SAndroid Build Coastguard Worker * should not be null.
464*61046927SAndroid Build Coastguard Worker */
465*61046927SAndroid Build Coastguard Worker assert(buf);
466*61046927SAndroid Build Coastguard Worker
467*61046927SAndroid Build Coastguard Worker return ADD_POINTERS(buf, pixels);
468*61046927SAndroid Build Coastguard Worker }
469*61046927SAndroid Build Coastguard Worker
470*61046927SAndroid Build Coastguard Worker
471*61046927SAndroid Build Coastguard Worker /**
472*61046927SAndroid Build Coastguard Worker * This function must be called after either of the validate_pbo_*_teximage()
473*61046927SAndroid Build Coastguard Worker * functions. It unmaps the PBO buffer if it was mapped earlier.
474*61046927SAndroid Build Coastguard Worker */
475*61046927SAndroid Build Coastguard Worker void
_mesa_unmap_teximage_pbo(struct gl_context * ctx,const struct gl_pixelstore_attrib * unpack)476*61046927SAndroid Build Coastguard Worker _mesa_unmap_teximage_pbo(struct gl_context *ctx,
477*61046927SAndroid Build Coastguard Worker const struct gl_pixelstore_attrib *unpack)
478*61046927SAndroid Build Coastguard Worker {
479*61046927SAndroid Build Coastguard Worker if (unpack->BufferObj) {
480*61046927SAndroid Build Coastguard Worker _mesa_bufferobj_unmap(ctx, unpack->BufferObj, MAP_INTERNAL);
481*61046927SAndroid Build Coastguard Worker }
482*61046927SAndroid Build Coastguard Worker }
483