glthread: track instance divisor changes
[mesa.git] / src / mesa / main / pixelstore.c
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
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 &&
98 (!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.MESA_pack_invert))
99 goto invalid_enum_error;
100 ctx->Pack.Invert = param;
101 break;
102 case GL_PACK_COMPRESSED_BLOCK_WIDTH:
103 if (!no_error && !_mesa_is_desktop_gl(ctx))
104 goto invalid_enum_error;
105 if (!no_error && param<0)
106 goto invalid_value_error;
107 ctx->Pack.CompressedBlockWidth = param;
108 break;
109 case GL_PACK_COMPRESSED_BLOCK_HEIGHT:
110 if (!no_error && !_mesa_is_desktop_gl(ctx))
111 goto invalid_enum_error;
112 if (!no_error && param<0)
113 goto invalid_value_error;
114 ctx->Pack.CompressedBlockHeight = param;
115 break;
116 case GL_PACK_COMPRESSED_BLOCK_DEPTH:
117 if (!no_error && !_mesa_is_desktop_gl(ctx))
118 goto invalid_enum_error;
119 if (!no_error && param<0)
120 goto invalid_value_error;
121 ctx->Pack.CompressedBlockDepth = param;
122 break;
123 case GL_PACK_COMPRESSED_BLOCK_SIZE:
124 if (!no_error && !_mesa_is_desktop_gl(ctx))
125 goto invalid_enum_error;
126 if (!no_error && param<0)
127 goto invalid_value_error;
128 ctx->Pack.CompressedBlockSize = param;
129 break;
130
131 case GL_UNPACK_SWAP_BYTES:
132 if (!no_error && !_mesa_is_desktop_gl(ctx))
133 goto invalid_enum_error;
134 ctx->Unpack.SwapBytes = param ? GL_TRUE : GL_FALSE;
135 break;
136 case GL_UNPACK_LSB_FIRST:
137 if (!no_error && !_mesa_is_desktop_gl(ctx))
138 goto invalid_enum_error;
139 ctx->Unpack.LsbFirst = param ? GL_TRUE : GL_FALSE;
140 break;
141 case GL_UNPACK_ROW_LENGTH:
142 if (!no_error && ctx->API == API_OPENGLES)
143 goto invalid_enum_error;
144 if (!no_error && param<0)
145 goto invalid_value_error;
146 ctx->Unpack.RowLength = param;
147 break;
148 case GL_UNPACK_IMAGE_HEIGHT:
149 if (!no_error && !_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
150 goto invalid_enum_error;
151 if (!no_error && param<0)
152 goto invalid_value_error;
153 ctx->Unpack.ImageHeight = param;
154 break;
155 case GL_UNPACK_SKIP_PIXELS:
156 if (!no_error && ctx->API == API_OPENGLES)
157 goto invalid_enum_error;
158 if (!no_error && param<0)
159 goto invalid_value_error;
160 ctx->Unpack.SkipPixels = param;
161 break;
162 case GL_UNPACK_SKIP_ROWS:
163 if (!no_error && ctx->API == API_OPENGLES)
164 goto invalid_enum_error;
165 if (!no_error && param<0)
166 goto invalid_value_error;
167 ctx->Unpack.SkipRows = param;
168 break;
169 case GL_UNPACK_SKIP_IMAGES:
170 if (!no_error && !_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
171 goto invalid_enum_error;
172 if (!no_error && param < 0)
173 goto invalid_value_error;
174 ctx->Unpack.SkipImages = param;
175 break;
176 case GL_UNPACK_ALIGNMENT:
177 if (!no_error && param!=1 && param!=2 && param!=4 && param!=8)
178 goto invalid_value_error;
179 ctx->Unpack.Alignment = param;
180 break;
181 case GL_UNPACK_COMPRESSED_BLOCK_WIDTH:
182 if (!no_error && !_mesa_is_desktop_gl(ctx))
183 goto invalid_enum_error;
184 if (!no_error && param<0)
185 goto invalid_value_error;
186 ctx->Unpack.CompressedBlockWidth = param;
187 break;
188 case GL_UNPACK_COMPRESSED_BLOCK_HEIGHT:
189 if (!no_error && !_mesa_is_desktop_gl(ctx))
190 goto invalid_enum_error;
191 if (!no_error && param<0)
192 goto invalid_value_error;
193 ctx->Unpack.CompressedBlockHeight = param;
194 break;
195 case GL_UNPACK_COMPRESSED_BLOCK_DEPTH:
196 if (!no_error && !_mesa_is_desktop_gl(ctx))
197 goto invalid_enum_error;
198 if (!no_error && param<0)
199 goto invalid_value_error;
200 ctx->Unpack.CompressedBlockDepth = param;
201 break;
202 case GL_UNPACK_COMPRESSED_BLOCK_SIZE:
203 if (!no_error && !_mesa_is_desktop_gl(ctx))
204 goto invalid_enum_error;
205 if (!no_error && param<0)
206 goto invalid_value_error;
207 ctx->Unpack.CompressedBlockSize = param;
208 break;
209 default:
210 if (!no_error)
211 goto invalid_enum_error;
212 else
213 unreachable("invalid pixel store enum");
214 }
215
216 return;
217
218 invalid_enum_error:
219 _mesa_error(ctx, GL_INVALID_ENUM, "glPixelStore");
220 return;
221
222 invalid_value_error:
223 _mesa_error(ctx, GL_INVALID_VALUE, "glPixelStore(param)");
224 return;
225 }
226
227
228 void GLAPIENTRY
229 _mesa_PixelStorei(GLenum pname, GLint param)
230 {
231 pixel_storei(pname, param, false);
232 }
233
234
235 void GLAPIENTRY
236 _mesa_PixelStoref(GLenum pname, GLfloat param)
237 {
238 _mesa_PixelStorei(pname, lroundf(param));
239 }
240
241
242 void GLAPIENTRY
243 _mesa_PixelStorei_no_error(GLenum pname, GLint param)
244 {
245 pixel_storei(pname, param, true);
246 }
247
248
249 void GLAPIENTRY
250 _mesa_PixelStoref_no_error(GLenum pname, GLfloat param)
251 {
252 _mesa_PixelStorei_no_error(pname, lroundf(param));
253 }
254
255
256 /**
257 * Initialize the context's pixel store state.
258 */
259 void
260 _mesa_init_pixelstore(struct gl_context *ctx)
261 {
262 /* Pixel transfer */
263 ctx->Pack.Alignment = 4;
264 ctx->Pack.RowLength = 0;
265 ctx->Pack.ImageHeight = 0;
266 ctx->Pack.SkipPixels = 0;
267 ctx->Pack.SkipRows = 0;
268 ctx->Pack.SkipImages = 0;
269 ctx->Pack.SwapBytes = GL_FALSE;
270 ctx->Pack.LsbFirst = GL_FALSE;
271 ctx->Pack.Invert = GL_FALSE;
272 ctx->Pack.CompressedBlockWidth = 0;
273 ctx->Pack.CompressedBlockHeight = 0;
274 ctx->Pack.CompressedBlockDepth = 0;
275 ctx->Pack.CompressedBlockSize = 0;
276 _mesa_reference_buffer_object(ctx, &ctx->Pack.BufferObj, NULL);
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, NULL);
291
292 /*
293 * _mesa_unpack_image() returns image data in this format. When we
294 * execute image commands (glDrawPixels(), glTexImage(), etc) from
295 * within display lists we have to be sure to set the current
296 * unpacking parameters to these values!
297 */
298 ctx->DefaultPacking.Alignment = 1;
299 ctx->DefaultPacking.RowLength = 0;
300 ctx->DefaultPacking.SkipPixels = 0;
301 ctx->DefaultPacking.SkipRows = 0;
302 ctx->DefaultPacking.ImageHeight = 0;
303 ctx->DefaultPacking.SkipImages = 0;
304 ctx->DefaultPacking.SwapBytes = GL_FALSE;
305 ctx->DefaultPacking.LsbFirst = GL_FALSE;
306 ctx->DefaultPacking.Invert = GL_FALSE;
307 _mesa_reference_buffer_object(ctx, &ctx->DefaultPacking.BufferObj, NULL);
308 }
309
310
311 /**
312 * Check if the given compressed pixel storage parameters are legal.
313 * Record a GL error if illegal.
314 * \return true if legal, false if illegal
315 */
316 bool
317 _mesa_compressed_pixel_storage_error_check(
318 struct gl_context *ctx,
319 GLint dimensions,
320 const struct gl_pixelstore_attrib *packing,
321 const char *caller)
322 {
323 if (!_mesa_is_desktop_gl(ctx) || !packing->CompressedBlockSize)
324 return true;
325
326 if (packing->CompressedBlockWidth &&
327 packing->SkipPixels % packing->CompressedBlockWidth) {
328 _mesa_error(ctx, GL_INVALID_OPERATION,
329 "%s(skip-pixels %% block-width)", caller);
330 return false;
331 }
332
333 if (dimensions > 1 &&
334 packing->CompressedBlockHeight &&
335 packing->SkipRows % packing->CompressedBlockHeight) {
336 _mesa_error(ctx, GL_INVALID_OPERATION,
337 "%s(skip-rows %% block-height)", caller);
338 return false;
339 }
340
341 if (dimensions > 2 &&
342 packing->CompressedBlockDepth &&
343 packing->SkipImages % packing->CompressedBlockDepth) {
344 _mesa_error(ctx, GL_INVALID_OPERATION,
345 "%s(skip-images %% block-depth)", caller);
346 return false;
347 }
348
349 return true;
350 }