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 40static ALWAYS_INLINE void 41pixel_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 223invalid_enum_error: 224 _mesa_error(ctx, GL_INVALID_ENUM, "glPixelStore"); 225 return; 226 227invalid_value_error: 228 _mesa_error(ctx, GL_INVALID_VALUE, "glPixelStore(param)"); 229 return; 230} 231 232 233void GLAPIENTRY 234_mesa_PixelStorei(GLenum pname, GLint param) 235{ 236 pixel_storei(pname, param, false); 237} 238 239 240void GLAPIENTRY 241_mesa_PixelStoref(GLenum pname, GLfloat param) 242{ 243 _mesa_PixelStorei(pname, lroundf(param)); 244} 245 246 247void GLAPIENTRY 248_mesa_PixelStorei_no_error(GLenum pname, GLint param) 249{ 250 pixel_storei(pname, param, true); 251} 252 253 254void GLAPIENTRY 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 */ 264void 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 */ 321bool 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