pixelstore.c revision b8e80941
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
37
38static ALWAYS_INLINE void
39pixel_storei(GLenum pname, GLint param, bool no_error)
40{
41   /* NOTE: this call can't be compiled into the display list */
42   GET_CURRENT_CONTEXT(ctx);
43
44   switch (pname) {
45      case GL_PACK_SWAP_BYTES:
46         if (!no_error && !_mesa_is_desktop_gl(ctx))
47            goto invalid_enum_error;
48         ctx->Pack.SwapBytes = param ? GL_TRUE : GL_FALSE;
49         break;
50      case GL_PACK_LSB_FIRST:
51         if (!no_error && !_mesa_is_desktop_gl(ctx))
52            goto invalid_enum_error;
53         ctx->Pack.LsbFirst = param ? GL_TRUE : GL_FALSE;
54         break;
55      case GL_PACK_ROW_LENGTH:
56         if (!no_error && !_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
57            goto invalid_enum_error;
58         if (!no_error && param<0)
59            goto invalid_value_error;
60         ctx->Pack.RowLength = param;
61         break;
62      case GL_PACK_IMAGE_HEIGHT:
63         if (!no_error && !_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
64            goto invalid_enum_error;
65         if (!no_error && param<0)
66            goto invalid_value_error;
67         ctx->Pack.ImageHeight = param;
68         break;
69      case GL_PACK_SKIP_PIXELS:
70         if (!no_error && !_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
71            goto invalid_enum_error;
72         if (!no_error && param<0)
73            goto invalid_value_error;
74         ctx->Pack.SkipPixels = param;
75         break;
76      case GL_PACK_SKIP_ROWS:
77         if (!no_error && !_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
78            goto invalid_enum_error;
79         if (!no_error && param<0)
80            goto invalid_value_error;
81         ctx->Pack.SkipRows = param;
82         break;
83      case GL_PACK_SKIP_IMAGES:
84         if (!no_error && !_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
85            goto invalid_enum_error;
86         if (!no_error && param<0)
87            goto invalid_value_error;
88         ctx->Pack.SkipImages = param;
89         break;
90      case GL_PACK_ALIGNMENT:
91         if (!no_error && param!=1 && param!=2 && param!=4 && param!=8)
92            goto invalid_value_error;
93         ctx->Pack.Alignment = param;
94         break;
95      case GL_PACK_INVERT_MESA:
96         if (!no_error &&
97             (!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.MESA_pack_invert))
98            goto invalid_enum_error;
99         ctx->Pack.Invert = param;
100         break;
101      case GL_PACK_COMPRESSED_BLOCK_WIDTH:
102         if (!no_error && !_mesa_is_desktop_gl(ctx))
103            goto invalid_enum_error;
104         if (!no_error && param<0)
105            goto invalid_value_error;
106         ctx->Pack.CompressedBlockWidth = param;
107         break;
108      case GL_PACK_COMPRESSED_BLOCK_HEIGHT:
109         if (!no_error && !_mesa_is_desktop_gl(ctx))
110            goto invalid_enum_error;
111         if (!no_error && param<0)
112            goto invalid_value_error;
113         ctx->Pack.CompressedBlockHeight = param;
114         break;
115      case GL_PACK_COMPRESSED_BLOCK_DEPTH:
116         if (!no_error && !_mesa_is_desktop_gl(ctx))
117            goto invalid_enum_error;
118         if (!no_error && param<0)
119            goto invalid_value_error;
120         ctx->Pack.CompressedBlockDepth = param;
121         break;
122      case GL_PACK_COMPRESSED_BLOCK_SIZE:
123         if (!no_error && !_mesa_is_desktop_gl(ctx))
124            goto invalid_enum_error;
125         if (!no_error && param<0)
126            goto invalid_value_error;
127         ctx->Pack.CompressedBlockSize = param;
128         break;
129
130      case GL_UNPACK_SWAP_BYTES:
131         if (!no_error && !_mesa_is_desktop_gl(ctx))
132            goto invalid_enum_error;
133         ctx->Unpack.SwapBytes = param ? GL_TRUE : GL_FALSE;
134         break;
135      case GL_UNPACK_LSB_FIRST:
136         if (!no_error && !_mesa_is_desktop_gl(ctx))
137            goto invalid_enum_error;
138         ctx->Unpack.LsbFirst = param ? GL_TRUE : GL_FALSE;
139         break;
140      case GL_UNPACK_ROW_LENGTH:
141         if (!no_error && ctx->API == API_OPENGLES)
142            goto invalid_enum_error;
143         if (!no_error && param<0)
144            goto invalid_value_error;
145         ctx->Unpack.RowLength = param;
146         break;
147      case GL_UNPACK_IMAGE_HEIGHT:
148         if (!no_error && !_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
149            goto invalid_enum_error;
150         if (!no_error && param<0)
151            goto invalid_value_error;
152         ctx->Unpack.ImageHeight = param;
153         break;
154      case GL_UNPACK_SKIP_PIXELS:
155         if (!no_error && ctx->API == API_OPENGLES)
156            goto invalid_enum_error;
157         if (!no_error && param<0)
158            goto invalid_value_error;
159         ctx->Unpack.SkipPixels = param;
160         break;
161      case GL_UNPACK_SKIP_ROWS:
162         if (!no_error && ctx->API == API_OPENGLES)
163            goto invalid_enum_error;
164         if (!no_error && param<0)
165            goto invalid_value_error;
166         ctx->Unpack.SkipRows = param;
167         break;
168      case GL_UNPACK_SKIP_IMAGES:
169         if (!no_error && !_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
170            goto invalid_enum_error;
171         if (!no_error && param < 0)
172            goto invalid_value_error;
173         ctx->Unpack.SkipImages = param;
174         break;
175      case GL_UNPACK_ALIGNMENT:
176         if (!no_error && param!=1 && param!=2 && param!=4 && param!=8)
177            goto invalid_value_error;
178         ctx->Unpack.Alignment = param;
179         break;
180      case GL_UNPACK_COMPRESSED_BLOCK_WIDTH:
181         if (!no_error && !_mesa_is_desktop_gl(ctx))
182            goto invalid_enum_error;
183         if (!no_error && param<0)
184            goto invalid_value_error;
185         ctx->Unpack.CompressedBlockWidth = param;
186         break;
187      case GL_UNPACK_COMPRESSED_BLOCK_HEIGHT:
188         if (!no_error && !_mesa_is_desktop_gl(ctx))
189            goto invalid_enum_error;
190         if (!no_error && param<0)
191            goto invalid_value_error;
192         ctx->Unpack.CompressedBlockHeight = param;
193         break;
194      case GL_UNPACK_COMPRESSED_BLOCK_DEPTH:
195         if (!no_error && !_mesa_is_desktop_gl(ctx))
196            goto invalid_enum_error;
197         if (!no_error && param<0)
198            goto invalid_value_error;
199         ctx->Unpack.CompressedBlockDepth = param;
200         break;
201      case GL_UNPACK_COMPRESSED_BLOCK_SIZE:
202         if (!no_error && !_mesa_is_desktop_gl(ctx))
203            goto invalid_enum_error;
204         if (!no_error && param<0)
205            goto invalid_value_error;
206         ctx->Unpack.CompressedBlockSize = param;
207         break;
208      default:
209         if (!no_error)
210            goto invalid_enum_error;
211         else
212            unreachable("invalid pixel store enum");
213   }
214
215   return;
216
217invalid_enum_error:
218   _mesa_error(ctx, GL_INVALID_ENUM, "glPixelStore");
219   return;
220
221invalid_value_error:
222   _mesa_error(ctx, GL_INVALID_VALUE, "glPixelStore(param)");
223   return;
224}
225
226
227void GLAPIENTRY
228_mesa_PixelStorei(GLenum pname, GLint param)
229{
230   pixel_storei(pname, param, false);
231}
232
233
234void GLAPIENTRY
235_mesa_PixelStoref(GLenum pname, GLfloat param)
236{
237   _mesa_PixelStorei(pname, IROUND(param));
238}
239
240
241void GLAPIENTRY
242_mesa_PixelStorei_no_error(GLenum pname, GLint param)
243{
244   pixel_storei(pname, param, true);
245}
246
247
248void GLAPIENTRY
249_mesa_PixelStoref_no_error(GLenum pname, GLfloat param)
250{
251   _mesa_PixelStorei_no_error(pname, IROUND(param));
252}
253
254
255/**
256 * Initialize the context's pixel store state.
257 */
258void
259_mesa_init_pixelstore(struct gl_context *ctx)
260{
261   /* Pixel transfer */
262   ctx->Pack.Alignment = 4;
263   ctx->Pack.RowLength = 0;
264   ctx->Pack.ImageHeight = 0;
265   ctx->Pack.SkipPixels = 0;
266   ctx->Pack.SkipRows = 0;
267   ctx->Pack.SkipImages = 0;
268   ctx->Pack.SwapBytes = GL_FALSE;
269   ctx->Pack.LsbFirst = GL_FALSE;
270   ctx->Pack.Invert = GL_FALSE;
271   ctx->Pack.CompressedBlockWidth = 0;
272   ctx->Pack.CompressedBlockHeight = 0;
273   ctx->Pack.CompressedBlockDepth = 0;
274   ctx->Pack.CompressedBlockSize = 0;
275   _mesa_reference_buffer_object(ctx, &ctx->Pack.BufferObj,
276                                 ctx->Shared->NullBufferObj);
277   ctx->Unpack.Alignment = 4;
278   ctx->Unpack.RowLength = 0;
279   ctx->Unpack.ImageHeight = 0;
280   ctx->Unpack.SkipPixels = 0;
281   ctx->Unpack.SkipRows = 0;
282   ctx->Unpack.SkipImages = 0;
283   ctx->Unpack.SwapBytes = GL_FALSE;
284   ctx->Unpack.LsbFirst = GL_FALSE;
285   ctx->Unpack.Invert = GL_FALSE;
286   ctx->Unpack.CompressedBlockWidth = 0;
287   ctx->Unpack.CompressedBlockHeight = 0;
288   ctx->Unpack.CompressedBlockDepth = 0;
289   ctx->Unpack.CompressedBlockSize = 0;
290   _mesa_reference_buffer_object(ctx, &ctx->Unpack.BufferObj,
291                                 ctx->Shared->NullBufferObj);
292
293   /*
294    * _mesa_unpack_image() returns image data in this format.  When we
295    * execute image commands (glDrawPixels(), glTexImage(), etc) from
296    * within display lists we have to be sure to set the current
297    * unpacking parameters to these values!
298    */
299   ctx->DefaultPacking.Alignment = 1;
300   ctx->DefaultPacking.RowLength = 0;
301   ctx->DefaultPacking.SkipPixels = 0;
302   ctx->DefaultPacking.SkipRows = 0;
303   ctx->DefaultPacking.ImageHeight = 0;
304   ctx->DefaultPacking.SkipImages = 0;
305   ctx->DefaultPacking.SwapBytes = GL_FALSE;
306   ctx->DefaultPacking.LsbFirst = GL_FALSE;
307   ctx->DefaultPacking.Invert = GL_FALSE;
308   _mesa_reference_buffer_object(ctx, &ctx->DefaultPacking.BufferObj,
309                                 ctx->Shared->NullBufferObj);
310}
311
312
313/**
314 * Check if the given compressed pixel storage parameters are legal.
315 * Record a GL error if illegal.
316 * \return  true if legal, false if illegal
317 */
318bool
319_mesa_compressed_pixel_storage_error_check(
320   struct gl_context *ctx,
321   GLint dimensions,
322   const struct gl_pixelstore_attrib *packing,
323   const char *caller)
324{
325   if (!_mesa_is_desktop_gl(ctx) || !packing->CompressedBlockSize)
326      return true;
327
328   if (packing->CompressedBlockWidth &&
329       packing->SkipPixels % packing->CompressedBlockWidth) {
330      _mesa_error(ctx, GL_INVALID_OPERATION,
331                  "%s(skip-pixels %% block-width)", caller);
332      return false;
333   }
334
335   if (dimensions > 1 &&
336       packing->CompressedBlockHeight &&
337       packing->SkipRows % packing->CompressedBlockHeight) {
338      _mesa_error(ctx, GL_INVALID_OPERATION,
339                  "%s(skip-rows %% block-height)", caller);
340      return false;
341   }
342
343   if (dimensions > 2 &&
344       packing->CompressedBlockDepth &&
345       packing->SkipImages % packing->CompressedBlockDepth) {
346      _mesa_error(ctx, GL_INVALID_OPERATION,
347                  "%s(skip-images %% block-depth)", caller);
348      return false;
349   }
350
351   return true;
352}
353