1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  */
24 
25 /**
26  * \file pixelstore.c
27  * glPixelStore functions.
28  */
29 
30 
31 #include "glheader.h"
32 #include "bufferobj.h"
33 #include "context.h"
34 #include "pixelstore.h"
35 #include "mtypes.h"
36 #include "util/rounding.h"
37 #include "api_exec_decl.h"
38 
39 
40 static ALWAYS_INLINE void
pixel_storei(GLenum pname,GLint param,bool no_error)41 pixel_storei(GLenum pname, GLint param, bool no_error)
42 {
43    /* NOTE: this call can't be compiled into the display list */
44    GET_CURRENT_CONTEXT(ctx);
45 
46    switch (pname) {
47       case GL_PACK_SWAP_BYTES:
48          if (!no_error && !_mesa_is_desktop_gl(ctx))
49             goto invalid_enum_error;
50          ctx->Pack.SwapBytes = param ? GL_TRUE : GL_FALSE;
51          break;
52       case GL_PACK_LSB_FIRST:
53          if (!no_error && !_mesa_is_desktop_gl(ctx))
54             goto invalid_enum_error;
55          ctx->Pack.LsbFirst = param ? GL_TRUE : GL_FALSE;
56          break;
57       case GL_PACK_ROW_LENGTH:
58          if (!no_error && ctx->API == API_OPENGLES)
59             goto invalid_enum_error;
60          if (!no_error && param<0)
61             goto invalid_value_error;
62          ctx->Pack.RowLength = param;
63          break;
64       case GL_PACK_IMAGE_HEIGHT:
65          if (!no_error && !_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
66             goto invalid_enum_error;
67          if (!no_error && param<0)
68             goto invalid_value_error;
69          ctx->Pack.ImageHeight = param;
70          break;
71       case GL_PACK_SKIP_PIXELS:
72          if (!no_error && ctx->API == API_OPENGLES)
73             goto invalid_enum_error;
74          if (!no_error && param<0)
75             goto invalid_value_error;
76          ctx->Pack.SkipPixels = param;
77          break;
78       case GL_PACK_SKIP_ROWS:
79          if (!no_error && ctx->API == API_OPENGLES)
80             goto invalid_enum_error;
81          if (!no_error && param<0)
82             goto invalid_value_error;
83          ctx->Pack.SkipRows = param;
84          break;
85       case GL_PACK_SKIP_IMAGES:
86          if (!no_error && !_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
87             goto invalid_enum_error;
88          if (!no_error && param<0)
89             goto invalid_value_error;
90          ctx->Pack.SkipImages = param;
91          break;
92       case GL_PACK_ALIGNMENT:
93          if (!no_error && param!=1 && param!=2 && param!=4 && param!=8)
94             goto invalid_value_error;
95          ctx->Pack.Alignment = param;
96          break;
97       case GL_PACK_INVERT_MESA:
98          if (!no_error && !_mesa_has_MESA_pack_invert(ctx))
99             goto invalid_enum_error;
100          ctx->Pack.Invert = param;
101          break;
102       case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
103          if (!no_error && !_mesa_has_ANGLE_pack_reverse_row_order(ctx))
104             goto invalid_enum_error;
105          ctx->Pack.Invert = param;
106          break;
107       case GL_PACK_COMPRESSED_BLOCK_WIDTH:
108          if (!no_error && !_mesa_is_desktop_gl(ctx))
109             goto invalid_enum_error;
110          if (!no_error && param<0)
111             goto invalid_value_error;
112          ctx->Pack.CompressedBlockWidth = param;
113          break;
114       case GL_PACK_COMPRESSED_BLOCK_HEIGHT:
115          if (!no_error && !_mesa_is_desktop_gl(ctx))
116             goto invalid_enum_error;
117          if (!no_error && param<0)
118             goto invalid_value_error;
119          ctx->Pack.CompressedBlockHeight = param;
120          break;
121       case GL_PACK_COMPRESSED_BLOCK_DEPTH:
122          if (!no_error && !_mesa_is_desktop_gl(ctx))
123             goto invalid_enum_error;
124          if (!no_error && param<0)
125             goto invalid_value_error;
126          ctx->Pack.CompressedBlockDepth = param;
127          break;
128       case GL_PACK_COMPRESSED_BLOCK_SIZE:
129          if (!no_error && !_mesa_is_desktop_gl(ctx))
130             goto invalid_enum_error;
131          if (!no_error && param<0)
132             goto invalid_value_error;
133          ctx->Pack.CompressedBlockSize = param;
134          break;
135 
136       case GL_UNPACK_SWAP_BYTES:
137          if (!no_error && !_mesa_is_desktop_gl(ctx))
138             goto invalid_enum_error;
139          ctx->Unpack.SwapBytes = param ? GL_TRUE : GL_FALSE;
140          break;
141       case GL_UNPACK_LSB_FIRST:
142          if (!no_error && !_mesa_is_desktop_gl(ctx))
143             goto invalid_enum_error;
144          ctx->Unpack.LsbFirst = param ? GL_TRUE : GL_FALSE;
145          break;
146       case GL_UNPACK_ROW_LENGTH:
147          if (!no_error && ctx->API == API_OPENGLES)
148             goto invalid_enum_error;
149          if (!no_error && param<0)
150             goto invalid_value_error;
151          ctx->Unpack.RowLength = param;
152          break;
153       case GL_UNPACK_IMAGE_HEIGHT:
154          if (!no_error && !_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
155             goto invalid_enum_error;
156          if (!no_error && param<0)
157             goto invalid_value_error;
158          ctx->Unpack.ImageHeight = param;
159          break;
160       case GL_UNPACK_SKIP_PIXELS:
161          if (!no_error && ctx->API == API_OPENGLES)
162             goto invalid_enum_error;
163          if (!no_error && param<0)
164             goto invalid_value_error;
165          ctx->Unpack.SkipPixels = param;
166          break;
167       case GL_UNPACK_SKIP_ROWS:
168          if (!no_error && ctx->API == API_OPENGLES)
169             goto invalid_enum_error;
170          if (!no_error && param<0)
171             goto invalid_value_error;
172          ctx->Unpack.SkipRows = param;
173          break;
174       case GL_UNPACK_SKIP_IMAGES:
175          if (!no_error && !_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
176             goto invalid_enum_error;
177          if (!no_error && param < 0)
178             goto invalid_value_error;
179          ctx->Unpack.SkipImages = param;
180          break;
181       case GL_UNPACK_ALIGNMENT:
182          if (!no_error && param!=1 && param!=2 && param!=4 && param!=8)
183             goto invalid_value_error;
184          ctx->Unpack.Alignment = param;
185          break;
186       case GL_UNPACK_COMPRESSED_BLOCK_WIDTH:
187          if (!no_error && !_mesa_is_desktop_gl(ctx))
188             goto invalid_enum_error;
189          if (!no_error && param<0)
190             goto invalid_value_error;
191          ctx->Unpack.CompressedBlockWidth = param;
192          break;
193       case GL_UNPACK_COMPRESSED_BLOCK_HEIGHT:
194          if (!no_error && !_mesa_is_desktop_gl(ctx))
195             goto invalid_enum_error;
196          if (!no_error && param<0)
197             goto invalid_value_error;
198          ctx->Unpack.CompressedBlockHeight = param;
199          break;
200       case GL_UNPACK_COMPRESSED_BLOCK_DEPTH:
201          if (!no_error && !_mesa_is_desktop_gl(ctx))
202             goto invalid_enum_error;
203          if (!no_error && param<0)
204             goto invalid_value_error;
205          ctx->Unpack.CompressedBlockDepth = param;
206          break;
207       case GL_UNPACK_COMPRESSED_BLOCK_SIZE:
208          if (!no_error && !_mesa_is_desktop_gl(ctx))
209             goto invalid_enum_error;
210          if (!no_error && param<0)
211             goto invalid_value_error;
212          ctx->Unpack.CompressedBlockSize = param;
213          break;
214       default:
215          if (!no_error)
216             goto invalid_enum_error;
217          else
218             unreachable("invalid pixel store enum");
219    }
220 
221    return;
222 
223 invalid_enum_error:
224    _mesa_error(ctx, GL_INVALID_ENUM, "glPixelStore");
225    return;
226 
227 invalid_value_error:
228    _mesa_error(ctx, GL_INVALID_VALUE, "glPixelStore(param)");
229    return;
230 }
231 
232 
233 void GLAPIENTRY
_mesa_PixelStorei(GLenum pname,GLint param)234 _mesa_PixelStorei(GLenum pname, GLint param)
235 {
236    pixel_storei(pname, param, false);
237 }
238 
239 
240 void GLAPIENTRY
_mesa_PixelStoref(GLenum pname,GLfloat param)241 _mesa_PixelStoref(GLenum pname, GLfloat param)
242 {
243    _mesa_PixelStorei(pname, lroundf(param));
244 }
245 
246 
247 void GLAPIENTRY
_mesa_PixelStorei_no_error(GLenum pname,GLint param)248 _mesa_PixelStorei_no_error(GLenum pname, GLint param)
249 {
250    pixel_storei(pname, param, true);
251 }
252 
253 
254 void GLAPIENTRY
_mesa_PixelStoref_no_error(GLenum pname,GLfloat param)255 _mesa_PixelStoref_no_error(GLenum pname, GLfloat param)
256 {
257    _mesa_PixelStorei_no_error(pname, lroundf(param));
258 }
259 
260 
261 /**
262  * Initialize the context's pixel store state.
263  */
264 void
_mesa_init_pixelstore(struct gl_context * ctx)265 _mesa_init_pixelstore(struct gl_context *ctx)
266 {
267    /* Pixel transfer */
268    ctx->Pack.Alignment = 4;
269    ctx->Pack.RowLength = 0;
270    ctx->Pack.ImageHeight = 0;
271    ctx->Pack.SkipPixels = 0;
272    ctx->Pack.SkipRows = 0;
273    ctx->Pack.SkipImages = 0;
274    ctx->Pack.SwapBytes = GL_FALSE;
275    ctx->Pack.LsbFirst = GL_FALSE;
276    ctx->Pack.Invert = GL_FALSE;
277    ctx->Pack.CompressedBlockWidth = 0;
278    ctx->Pack.CompressedBlockHeight = 0;
279    ctx->Pack.CompressedBlockDepth = 0;
280    ctx->Pack.CompressedBlockSize = 0;
281    _mesa_reference_buffer_object(ctx, &ctx->Pack.BufferObj, NULL);
282    ctx->Unpack.Alignment = 4;
283    ctx->Unpack.RowLength = 0;
284    ctx->Unpack.ImageHeight = 0;
285    ctx->Unpack.SkipPixels = 0;
286    ctx->Unpack.SkipRows = 0;
287    ctx->Unpack.SkipImages = 0;
288    ctx->Unpack.SwapBytes = GL_FALSE;
289    ctx->Unpack.LsbFirst = GL_FALSE;
290    ctx->Unpack.Invert = GL_FALSE;
291    ctx->Unpack.CompressedBlockWidth = 0;
292    ctx->Unpack.CompressedBlockHeight = 0;
293    ctx->Unpack.CompressedBlockDepth = 0;
294    ctx->Unpack.CompressedBlockSize = 0;
295    _mesa_reference_buffer_object(ctx, &ctx->Unpack.BufferObj, NULL);
296 
297    /*
298     * _mesa_unpack_image() returns image data in this format.  When we
299     * execute image commands (glDrawPixels(), glTexImage(), etc) from
300     * within display lists we have to be sure to set the current
301     * unpacking parameters to these values!
302     */
303    ctx->DefaultPacking.Alignment = 1;
304    ctx->DefaultPacking.RowLength = 0;
305    ctx->DefaultPacking.SkipPixels = 0;
306    ctx->DefaultPacking.SkipRows = 0;
307    ctx->DefaultPacking.ImageHeight = 0;
308    ctx->DefaultPacking.SkipImages = 0;
309    ctx->DefaultPacking.SwapBytes = GL_FALSE;
310    ctx->DefaultPacking.LsbFirst = GL_FALSE;
311    ctx->DefaultPacking.Invert = GL_FALSE;
312    _mesa_reference_buffer_object(ctx, &ctx->DefaultPacking.BufferObj, NULL);
313 }
314 
315 
316 /**
317  * Check if the given compressed pixel storage parameters are legal.
318  * Record a GL error if illegal.
319  * \return  true if legal, false if illegal
320  */
321 bool
_mesa_compressed_pixel_storage_error_check(struct gl_context * ctx,GLint dimensions,const struct gl_pixelstore_attrib * packing,const char * caller)322 _mesa_compressed_pixel_storage_error_check(
323    struct gl_context *ctx,
324    GLint dimensions,
325    const struct gl_pixelstore_attrib *packing,
326    const char *caller)
327 {
328    if (!_mesa_is_desktop_gl(ctx) || !packing->CompressedBlockSize)
329       return true;
330 
331    if (packing->CompressedBlockWidth &&
332        packing->SkipPixels % packing->CompressedBlockWidth) {
333       _mesa_error(ctx, GL_INVALID_OPERATION,
334                   "%s(skip-pixels %% block-width)", caller);
335       return false;
336    }
337 
338    if (dimensions > 1 &&
339        packing->CompressedBlockHeight &&
340        packing->SkipRows % packing->CompressedBlockHeight) {
341       _mesa_error(ctx, GL_INVALID_OPERATION,
342                   "%s(skip-rows %% block-height)", caller);
343       return false;
344    }
345 
346    if (dimensions > 2 &&
347        packing->CompressedBlockDepth &&
348        packing->SkipImages % packing->CompressedBlockDepth) {
349       _mesa_error(ctx, GL_INVALID_OPERATION,
350                   "%s(skip-images %% block-depth)", caller);
351       return false;
352    }
353 
354    return true;
355 }
356