1c1f859d4Smrg/*
2c1f859d4Smrg * Mesa 3-D graphics library
3c1f859d4Smrg *
4c1f859d4Smrg * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5c1f859d4Smrg *
6c1f859d4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7c1f859d4Smrg * copy of this software and associated documentation files (the "Software"),
8c1f859d4Smrg * to deal in the Software without restriction, including without limitation
9c1f859d4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10c1f859d4Smrg * and/or sell copies of the Software, and to permit persons to whom the
11c1f859d4Smrg * Software is furnished to do so, subject to the following conditions:
12c1f859d4Smrg *
13c1f859d4Smrg * The above copyright notice and this permission notice shall be included
14c1f859d4Smrg * in all copies or substantial portions of the Software.
15c1f859d4Smrg *
16c1f859d4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17c1f859d4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18c1f859d4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
23c1f859d4Smrg */
24c1f859d4Smrg
25c1f859d4Smrg/**
26c1f859d4Smrg * \file pixelstore.c
27c1f859d4Smrg * glPixelStore functions.
28c1f859d4Smrg */
29c1f859d4Smrg
30c1f859d4Smrg
31c1f859d4Smrg#include "glheader.h"
32c1f859d4Smrg#include "bufferobj.h"
33c1f859d4Smrg#include "context.h"
34c1f859d4Smrg#include "pixelstore.h"
35c1f859d4Smrg#include "mtypes.h"
367ec681f3Smrg#include "util/rounding.h"
37c1f859d4Smrg
38c1f859d4Smrg
3901e04c3fSmrgstatic ALWAYS_INLINE void
4001e04c3fSmrgpixel_storei(GLenum pname, GLint param, bool no_error)
41c1f859d4Smrg{
42c1f859d4Smrg   /* NOTE: this call can't be compiled into the display list */
43c1f859d4Smrg   GET_CURRENT_CONTEXT(ctx);
44c1f859d4Smrg
45c1f859d4Smrg   switch (pname) {
46c1f859d4Smrg      case GL_PACK_SWAP_BYTES:
4701e04c3fSmrg         if (!no_error && !_mesa_is_desktop_gl(ctx))
48af69d88dSmrg            goto invalid_enum_error;
49c1f859d4Smrg         ctx->Pack.SwapBytes = param ? GL_TRUE : GL_FALSE;
50af69d88dSmrg         break;
51c1f859d4Smrg      case GL_PACK_LSB_FIRST:
5201e04c3fSmrg         if (!no_error && !_mesa_is_desktop_gl(ctx))
53af69d88dSmrg            goto invalid_enum_error;
54c1f859d4Smrg         ctx->Pack.LsbFirst = param ? GL_TRUE : GL_FALSE;
55af69d88dSmrg         break;
56c1f859d4Smrg      case GL_PACK_ROW_LENGTH:
5701e04c3fSmrg         if (!no_error && !_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
58af69d88dSmrg            goto invalid_enum_error;
5901e04c3fSmrg         if (!no_error && param<0)
60af69d88dSmrg            goto invalid_value_error;
61af69d88dSmrg         ctx->Pack.RowLength = param;
62af69d88dSmrg         break;
63c1f859d4Smrg      case GL_PACK_IMAGE_HEIGHT:
6401e04c3fSmrg         if (!no_error && !_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
65af69d88dSmrg            goto invalid_enum_error;
6601e04c3fSmrg         if (!no_error && param<0)
67af69d88dSmrg            goto invalid_value_error;
68af69d88dSmrg         ctx->Pack.ImageHeight = param;
69c1f859d4Smrg         break;
70c1f859d4Smrg      case GL_PACK_SKIP_PIXELS:
7101e04c3fSmrg         if (!no_error && !_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
72af69d88dSmrg            goto invalid_enum_error;
7301e04c3fSmrg         if (!no_error && param<0)
74af69d88dSmrg            goto invalid_value_error;
75af69d88dSmrg         ctx->Pack.SkipPixels = param;
76af69d88dSmrg         break;
77c1f859d4Smrg      case GL_PACK_SKIP_ROWS:
7801e04c3fSmrg         if (!no_error && !_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
79af69d88dSmrg            goto invalid_enum_error;
8001e04c3fSmrg         if (!no_error && param<0)
81af69d88dSmrg            goto invalid_value_error;
82af69d88dSmrg         ctx->Pack.SkipRows = param;
83af69d88dSmrg         break;
84c1f859d4Smrg      case GL_PACK_SKIP_IMAGES:
8501e04c3fSmrg         if (!no_error && !_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
86af69d88dSmrg            goto invalid_enum_error;
8701e04c3fSmrg         if (!no_error && param<0)
88af69d88dSmrg            goto invalid_value_error;
89af69d88dSmrg         ctx->Pack.SkipImages = param;
90af69d88dSmrg         break;
91c1f859d4Smrg      case GL_PACK_ALIGNMENT:
9201e04c3fSmrg         if (!no_error && param!=1 && param!=2 && param!=4 && param!=8)
93af69d88dSmrg            goto invalid_value_error;
94af69d88dSmrg         ctx->Pack.Alignment = param;
95af69d88dSmrg         break;
96c1f859d4Smrg      case GL_PACK_INVERT_MESA:
977ec681f3Smrg         if (!no_error && !_mesa_has_MESA_pack_invert(ctx))
987ec681f3Smrg            goto invalid_enum_error;
997ec681f3Smrg         ctx->Pack.Invert = param;
1007ec681f3Smrg         break;
1017ec681f3Smrg      case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
1027ec681f3Smrg         if (!no_error && !_mesa_has_ANGLE_pack_reverse_row_order(ctx))
103af69d88dSmrg            goto invalid_enum_error;
104c1f859d4Smrg         ctx->Pack.Invert = param;
105c1f859d4Smrg         break;
106af69d88dSmrg      case GL_PACK_COMPRESSED_BLOCK_WIDTH:
10701e04c3fSmrg         if (!no_error && !_mesa_is_desktop_gl(ctx))
108af69d88dSmrg            goto invalid_enum_error;
10901e04c3fSmrg         if (!no_error && param<0)
110af69d88dSmrg            goto invalid_value_error;
111af69d88dSmrg         ctx->Pack.CompressedBlockWidth = param;
112af69d88dSmrg         break;
113af69d88dSmrg      case GL_PACK_COMPRESSED_BLOCK_HEIGHT:
11401e04c3fSmrg         if (!no_error && !_mesa_is_desktop_gl(ctx))
115af69d88dSmrg            goto invalid_enum_error;
11601e04c3fSmrg         if (!no_error && param<0)
117af69d88dSmrg            goto invalid_value_error;
118af69d88dSmrg         ctx->Pack.CompressedBlockHeight = param;
119af69d88dSmrg         break;
120af69d88dSmrg      case GL_PACK_COMPRESSED_BLOCK_DEPTH:
12101e04c3fSmrg         if (!no_error && !_mesa_is_desktop_gl(ctx))
122af69d88dSmrg            goto invalid_enum_error;
12301e04c3fSmrg         if (!no_error && param<0)
124af69d88dSmrg            goto invalid_value_error;
125af69d88dSmrg         ctx->Pack.CompressedBlockDepth = param;
126af69d88dSmrg         break;
127af69d88dSmrg      case GL_PACK_COMPRESSED_BLOCK_SIZE:
12801e04c3fSmrg         if (!no_error && !_mesa_is_desktop_gl(ctx))
129af69d88dSmrg            goto invalid_enum_error;
13001e04c3fSmrg         if (!no_error && param<0)
131af69d88dSmrg            goto invalid_value_error;
132af69d88dSmrg         ctx->Pack.CompressedBlockSize = param;
133af69d88dSmrg         break;
134c1f859d4Smrg
135c1f859d4Smrg      case GL_UNPACK_SWAP_BYTES:
13601e04c3fSmrg         if (!no_error && !_mesa_is_desktop_gl(ctx))
137af69d88dSmrg            goto invalid_enum_error;
138af69d88dSmrg         ctx->Unpack.SwapBytes = param ? GL_TRUE : GL_FALSE;
139c1f859d4Smrg         break;
140c1f859d4Smrg      case GL_UNPACK_LSB_FIRST:
14101e04c3fSmrg         if (!no_error && !_mesa_is_desktop_gl(ctx))
142af69d88dSmrg            goto invalid_enum_error;
143af69d88dSmrg         ctx->Unpack.LsbFirst = param ? GL_TRUE : GL_FALSE;
144af69d88dSmrg         break;
145c1f859d4Smrg      case GL_UNPACK_ROW_LENGTH:
14601e04c3fSmrg         if (!no_error && ctx->API == API_OPENGLES)
147af69d88dSmrg            goto invalid_enum_error;
14801e04c3fSmrg         if (!no_error && param<0)
149af69d88dSmrg            goto invalid_value_error;
150af69d88dSmrg         ctx->Unpack.RowLength = param;
151af69d88dSmrg         break;
152c1f859d4Smrg      case GL_UNPACK_IMAGE_HEIGHT:
15301e04c3fSmrg         if (!no_error && !_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
154af69d88dSmrg            goto invalid_enum_error;
15501e04c3fSmrg         if (!no_error && param<0)
156af69d88dSmrg            goto invalid_value_error;
157af69d88dSmrg         ctx->Unpack.ImageHeight = param;
158c1f859d4Smrg         break;
159c1f859d4Smrg      case GL_UNPACK_SKIP_PIXELS:
16001e04c3fSmrg         if (!no_error && ctx->API == API_OPENGLES)
161af69d88dSmrg            goto invalid_enum_error;
16201e04c3fSmrg         if (!no_error && param<0)
163af69d88dSmrg            goto invalid_value_error;
164af69d88dSmrg         ctx->Unpack.SkipPixels = param;
165af69d88dSmrg         break;
166c1f859d4Smrg      case GL_UNPACK_SKIP_ROWS:
16701e04c3fSmrg         if (!no_error && ctx->API == API_OPENGLES)
168af69d88dSmrg            goto invalid_enum_error;
16901e04c3fSmrg         if (!no_error && param<0)
170af69d88dSmrg            goto invalid_value_error;
171af69d88dSmrg         ctx->Unpack.SkipRows = param;
172af69d88dSmrg         break;
173c1f859d4Smrg      case GL_UNPACK_SKIP_IMAGES:
17401e04c3fSmrg         if (!no_error && !_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
175af69d88dSmrg            goto invalid_enum_error;
17601e04c3fSmrg         if (!no_error && param < 0)
177af69d88dSmrg            goto invalid_value_error;
178af69d88dSmrg         ctx->Unpack.SkipImages = param;
179af69d88dSmrg         break;
180c1f859d4Smrg      case GL_UNPACK_ALIGNMENT:
18101e04c3fSmrg         if (!no_error && param!=1 && param!=2 && param!=4 && param!=8)
182af69d88dSmrg            goto invalid_value_error;
183af69d88dSmrg         ctx->Unpack.Alignment = param;
184af69d88dSmrg         break;
185af69d88dSmrg      case GL_UNPACK_COMPRESSED_BLOCK_WIDTH:
18601e04c3fSmrg         if (!no_error && !_mesa_is_desktop_gl(ctx))
187af69d88dSmrg            goto invalid_enum_error;
18801e04c3fSmrg         if (!no_error && param<0)
189af69d88dSmrg            goto invalid_value_error;
190af69d88dSmrg         ctx->Unpack.CompressedBlockWidth = param;
191af69d88dSmrg         break;
192af69d88dSmrg      case GL_UNPACK_COMPRESSED_BLOCK_HEIGHT:
19301e04c3fSmrg         if (!no_error && !_mesa_is_desktop_gl(ctx))
194af69d88dSmrg            goto invalid_enum_error;
19501e04c3fSmrg         if (!no_error && param<0)
196af69d88dSmrg            goto invalid_value_error;
197af69d88dSmrg         ctx->Unpack.CompressedBlockHeight = param;
198af69d88dSmrg         break;
199af69d88dSmrg      case GL_UNPACK_COMPRESSED_BLOCK_DEPTH:
20001e04c3fSmrg         if (!no_error && !_mesa_is_desktop_gl(ctx))
201af69d88dSmrg            goto invalid_enum_error;
20201e04c3fSmrg         if (!no_error && param<0)
203af69d88dSmrg            goto invalid_value_error;
204af69d88dSmrg         ctx->Unpack.CompressedBlockDepth = param;
205af69d88dSmrg         break;
206af69d88dSmrg      case GL_UNPACK_COMPRESSED_BLOCK_SIZE:
20701e04c3fSmrg         if (!no_error && !_mesa_is_desktop_gl(ctx))
208af69d88dSmrg            goto invalid_enum_error;
20901e04c3fSmrg         if (!no_error && param<0)
210af69d88dSmrg            goto invalid_value_error;
211af69d88dSmrg         ctx->Unpack.CompressedBlockSize = param;
212c1f859d4Smrg         break;
213c1f859d4Smrg      default:
21401e04c3fSmrg         if (!no_error)
21501e04c3fSmrg            goto invalid_enum_error;
21601e04c3fSmrg         else
21701e04c3fSmrg            unreachable("invalid pixel store enum");
218c1f859d4Smrg   }
219af69d88dSmrg
220af69d88dSmrg   return;
221af69d88dSmrg
222af69d88dSmrginvalid_enum_error:
22301e04c3fSmrg   _mesa_error(ctx, GL_INVALID_ENUM, "glPixelStore");
224af69d88dSmrg   return;
225af69d88dSmrg
226af69d88dSmrginvalid_value_error:
22701e04c3fSmrg   _mesa_error(ctx, GL_INVALID_VALUE, "glPixelStore(param)");
228af69d88dSmrg   return;
229c1f859d4Smrg}
230c1f859d4Smrg
231c1f859d4Smrg
232c1f859d4Smrgvoid GLAPIENTRY
23301e04c3fSmrg_mesa_PixelStorei(GLenum pname, GLint param)
23401e04c3fSmrg{
23501e04c3fSmrg   pixel_storei(pname, param, false);
23601e04c3fSmrg}
23701e04c3fSmrg
23801e04c3fSmrg
23901e04c3fSmrgvoid GLAPIENTRY
24001e04c3fSmrg_mesa_PixelStoref(GLenum pname, GLfloat param)
24101e04c3fSmrg{
2427ec681f3Smrg   _mesa_PixelStorei(pname, lroundf(param));
24301e04c3fSmrg}
24401e04c3fSmrg
24501e04c3fSmrg
24601e04c3fSmrgvoid GLAPIENTRY
24701e04c3fSmrg_mesa_PixelStorei_no_error(GLenum pname, GLint param)
248c1f859d4Smrg{
24901e04c3fSmrg   pixel_storei(pname, param, true);
250c1f859d4Smrg}
251c1f859d4Smrg
252c1f859d4Smrg
25301e04c3fSmrgvoid GLAPIENTRY
25401e04c3fSmrg_mesa_PixelStoref_no_error(GLenum pname, GLfloat param)
25501e04c3fSmrg{
2567ec681f3Smrg   _mesa_PixelStorei_no_error(pname, lroundf(param));
25701e04c3fSmrg}
25801e04c3fSmrg
259c1f859d4Smrg
260c1f859d4Smrg/**
261c1f859d4Smrg * Initialize the context's pixel store state.
262c1f859d4Smrg */
263c1f859d4Smrgvoid
26401e04c3fSmrg_mesa_init_pixelstore(struct gl_context *ctx)
265c1f859d4Smrg{
266c1f859d4Smrg   /* Pixel transfer */
267c1f859d4Smrg   ctx->Pack.Alignment = 4;
268c1f859d4Smrg   ctx->Pack.RowLength = 0;
269c1f859d4Smrg   ctx->Pack.ImageHeight = 0;
270c1f859d4Smrg   ctx->Pack.SkipPixels = 0;
271c1f859d4Smrg   ctx->Pack.SkipRows = 0;
272c1f859d4Smrg   ctx->Pack.SkipImages = 0;
273c1f859d4Smrg   ctx->Pack.SwapBytes = GL_FALSE;
274c1f859d4Smrg   ctx->Pack.LsbFirst = GL_FALSE;
275c1f859d4Smrg   ctx->Pack.Invert = GL_FALSE;
276af69d88dSmrg   ctx->Pack.CompressedBlockWidth = 0;
277af69d88dSmrg   ctx->Pack.CompressedBlockHeight = 0;
278af69d88dSmrg   ctx->Pack.CompressedBlockDepth = 0;
279af69d88dSmrg   ctx->Pack.CompressedBlockSize = 0;
2807ec681f3Smrg   _mesa_reference_buffer_object(ctx, &ctx->Pack.BufferObj, NULL);
281c1f859d4Smrg   ctx->Unpack.Alignment = 4;
282c1f859d4Smrg   ctx->Unpack.RowLength = 0;
283c1f859d4Smrg   ctx->Unpack.ImageHeight = 0;
284c1f859d4Smrg   ctx->Unpack.SkipPixels = 0;
285c1f859d4Smrg   ctx->Unpack.SkipRows = 0;
286c1f859d4Smrg   ctx->Unpack.SkipImages = 0;
287c1f859d4Smrg   ctx->Unpack.SwapBytes = GL_FALSE;
288c1f859d4Smrg   ctx->Unpack.LsbFirst = GL_FALSE;
289c1f859d4Smrg   ctx->Unpack.Invert = GL_FALSE;
290af69d88dSmrg   ctx->Unpack.CompressedBlockWidth = 0;
291af69d88dSmrg   ctx->Unpack.CompressedBlockHeight = 0;
292af69d88dSmrg   ctx->Unpack.CompressedBlockDepth = 0;
293af69d88dSmrg   ctx->Unpack.CompressedBlockSize = 0;
2947ec681f3Smrg   _mesa_reference_buffer_object(ctx, &ctx->Unpack.BufferObj, NULL);
295c1f859d4Smrg
296c1f859d4Smrg   /*
297c1f859d4Smrg    * _mesa_unpack_image() returns image data in this format.  When we
298c1f859d4Smrg    * execute image commands (glDrawPixels(), glTexImage(), etc) from
299c1f859d4Smrg    * within display lists we have to be sure to set the current
300c1f859d4Smrg    * unpacking parameters to these values!
301c1f859d4Smrg    */
302c1f859d4Smrg   ctx->DefaultPacking.Alignment = 1;
303c1f859d4Smrg   ctx->DefaultPacking.RowLength = 0;
304c1f859d4Smrg   ctx->DefaultPacking.SkipPixels = 0;
305c1f859d4Smrg   ctx->DefaultPacking.SkipRows = 0;
306c1f859d4Smrg   ctx->DefaultPacking.ImageHeight = 0;
307c1f859d4Smrg   ctx->DefaultPacking.SkipImages = 0;
308c1f859d4Smrg   ctx->DefaultPacking.SwapBytes = GL_FALSE;
309c1f859d4Smrg   ctx->DefaultPacking.LsbFirst = GL_FALSE;
310c1f859d4Smrg   ctx->DefaultPacking.Invert = GL_FALSE;
3117ec681f3Smrg   _mesa_reference_buffer_object(ctx, &ctx->DefaultPacking.BufferObj, NULL);
312af69d88dSmrg}
313af69d88dSmrg
314af69d88dSmrg
315af69d88dSmrg/**
316af69d88dSmrg * Check if the given compressed pixel storage parameters are legal.
317af69d88dSmrg * Record a GL error if illegal.
318af69d88dSmrg * \return  true if legal, false if illegal
319af69d88dSmrg */
320af69d88dSmrgbool
321af69d88dSmrg_mesa_compressed_pixel_storage_error_check(
322af69d88dSmrg   struct gl_context *ctx,
323af69d88dSmrg   GLint dimensions,
324af69d88dSmrg   const struct gl_pixelstore_attrib *packing,
325af69d88dSmrg   const char *caller)
326af69d88dSmrg{
327af69d88dSmrg   if (!_mesa_is_desktop_gl(ctx) || !packing->CompressedBlockSize)
328af69d88dSmrg      return true;
329af69d88dSmrg
330af69d88dSmrg   if (packing->CompressedBlockWidth &&
331af69d88dSmrg       packing->SkipPixels % packing->CompressedBlockWidth) {
332af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
333af69d88dSmrg                  "%s(skip-pixels %% block-width)", caller);
334af69d88dSmrg      return false;
335af69d88dSmrg   }
336af69d88dSmrg
337af69d88dSmrg   if (dimensions > 1 &&
338af69d88dSmrg       packing->CompressedBlockHeight &&
339af69d88dSmrg       packing->SkipRows % packing->CompressedBlockHeight) {
340af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
341af69d88dSmrg                  "%s(skip-rows %% block-height)", caller);
342af69d88dSmrg      return false;
343af69d88dSmrg   }
344af69d88dSmrg
345af69d88dSmrg   if (dimensions > 2 &&
346af69d88dSmrg       packing->CompressedBlockDepth &&
347af69d88dSmrg       packing->SkipImages % packing->CompressedBlockDepth) {
348af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
349af69d88dSmrg                  "%s(skip-images %% block-depth)", caller);
350af69d88dSmrg      return false;
351af69d88dSmrg   }
352af69d88dSmrg
353af69d88dSmrg   return true;
354c1f859d4Smrg}
355