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