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