drawpix.c revision 1ad7b99925e044f82e635f746c1ef2df77f69ac9
1/* 2 * Mesa 3-D graphics library 3 * Version: 6.5 4 * 5 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25#include "glheader.h" 26#include "imports.h" 27#include "context.h" 28#include "drawpix.h" 29#include "feedback.h" 30#include "image.h" 31#include "state.h" 32 33 34/** 35 * Do error checking of the format/type parameters to glReadPixels and 36 * glDrawPixels. 37 * \param drawing if GL_TRUE do checking for DrawPixels, else do checking 38 * for ReadPixels. 39 * \return GL_TRUE if error detected, GL_FALSE if no errors 40 */ 41static GLboolean 42error_check_format_type(GLcontext *ctx, GLenum format, GLenum type, 43 GLboolean drawing) 44{ 45 const char *readDraw = drawing ? "Draw" : "Read"; 46 47 /* basic combinations test */ 48 if (!_mesa_is_legal_format_and_type(ctx, format, type)) { 49 _mesa_error(ctx, GL_INVALID_ENUM, 50 "gl%sPixels(format or type)", readDraw); 51 return GL_TRUE; 52 } 53 54 /* additional checks */ 55 switch (format) { 56 case GL_RED: 57 case GL_GREEN: 58 case GL_BLUE: 59 case GL_ALPHA: 60 case GL_LUMINANCE: 61 case GL_LUMINANCE_ALPHA: 62 case GL_RGB: 63 case GL_BGR: 64 case GL_RGBA: 65 case GL_BGRA: 66 case GL_ABGR_EXT: 67 if (drawing && !ctx->Visual.rgbMode) { 68 _mesa_error(ctx, GL_INVALID_OPERATION, 69 "glDrawPixels(drawing RGB pixels into color index buffer)"); 70 return GL_TRUE; 71 } 72 break; 73 case GL_COLOR_INDEX: 74 if (!drawing && ctx->Visual.rgbMode) { 75 _mesa_error(ctx, GL_INVALID_OPERATION, 76 "glReadPixels(reading color index format from RGB buffer"); 77 return GL_TRUE; 78 } 79 break; 80 case GL_STENCIL_INDEX: 81 if (ctx->DrawBuffer->Visual.stencilBits == 0) { 82 _mesa_error(ctx, GL_INVALID_OPERATION, 83 "gl%sPixels(no stencil buffer)", readDraw); 84 return GL_TRUE; 85 } 86 break; 87 case GL_DEPTH_COMPONENT: 88 if (ctx->DrawBuffer->Visual.depthBits == 0) { 89 _mesa_error(ctx, GL_INVALID_OPERATION, 90 "gl%sPixels(no depth buffer)", readDraw); 91 return GL_TRUE; 92 } 93 break; 94 case GL_DEPTH_STENCIL_EXT: 95 if (!ctx->Extensions.EXT_packed_depth_stencil || 96 type != GL_UNSIGNED_INT_24_8_EXT) { 97 _mesa_error(ctx, GL_INVALID_ENUM, "gl%sPixels(type)", readDraw); 98 return GL_TRUE; 99 } 100 if (ctx->DrawBuffer->Visual.depthBits == 0 || 101 ctx->ReadBuffer->Visual.depthBits == 0 || 102 ctx->DrawBuffer->Visual.stencilBits == 0 || 103 ctx->ReadBuffer->Visual.stencilBits == 0) { 104 _mesa_error(ctx, GL_INVALID_OPERATION, 105 "gl%sPixels(no depth or stencil buffer)", readDraw); 106 return GL_TRUE; 107 } 108 break; 109 default: 110 /* this should have been caught in _mesa_is_legal_format_type() */ 111 _mesa_problem(ctx, "unexpected format in _mesa_%sPixels", readDraw); 112 return GL_TRUE; 113 } 114 115 /* XXX might have to move this to the top of the function */ 116 if (type == GL_UNSIGNED_INT_24_8_EXT && format != GL_DEPTH_STENCIL_EXT) { 117 _mesa_error(ctx, GL_INVALID_OPERATION, 118 "gl%sPixels(format is not GL_DEPTH_STENCIL_EXT)", readDraw); 119 return GL_TRUE; 120 } 121 122 /* no errors */ 123 return GL_FALSE; 124} 125 126 127 128#if _HAVE_FULL_GL 129 130/* 131 * Execute glDrawPixels 132 */ 133void GLAPIENTRY 134_mesa_DrawPixels( GLsizei width, GLsizei height, 135 GLenum format, GLenum type, const GLvoid *pixels ) 136{ 137 GET_CURRENT_CONTEXT(ctx); 138 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 139 140 if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { 141 _mesa_error(ctx, GL_INVALID_OPERATION, 142 "glDrawPixels (invalid fragment program)"); 143 return; 144 } 145 146 if (width < 0 || height < 0) { 147 _mesa_error( ctx, GL_INVALID_VALUE, "glDrawPixels(width or height < 0" ); 148 return; 149 } 150 151 if (error_check_format_type(ctx, format, type, GL_TRUE)) { 152 /* found an error */ 153 return; 154 } 155 156 if (!ctx->Current.RasterPosValid) { 157 return; /* not an error */ 158 } 159 160 if (ctx->NewState) { 161 _mesa_update_state(ctx); 162 } 163 164 if (ctx->RenderMode == GL_RENDER) { 165 /* Round, to satisfy conformance tests (matches SGI's OpenGL) */ 166 GLint x = IROUND(ctx->Current.RasterPos[0]); 167 GLint y = IROUND(ctx->Current.RasterPos[1]); 168 ctx->Driver.DrawPixels(ctx, x, y, width, height, format, type, 169 &ctx->Unpack, pixels); 170 } 171 else if (ctx->RenderMode == GL_FEEDBACK) { 172 /* Feedback the current raster pos info */ 173 FLUSH_CURRENT( ctx, 0 ); 174 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); 175 _mesa_feedback_vertex( ctx, 176 ctx->Current.RasterPos, 177 ctx->Current.RasterColor, 178 ctx->Current.RasterIndex, 179 ctx->Current.RasterTexCoords[0] ); 180 } 181 else { 182 ASSERT(ctx->RenderMode == GL_SELECT); 183 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 184 } 185} 186 187 188void GLAPIENTRY 189_mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height, 190 GLenum type ) 191{ 192 GET_CURRENT_CONTEXT(ctx); 193 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 194 195 if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { 196 _mesa_error(ctx, GL_INVALID_OPERATION, 197 "glCopyPixels (invalid fragment program)"); 198 return; 199 } 200 201 if (width < 0 || height < 0) { 202 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)"); 203 return; 204 } 205 206 switch (type) { 207 case GL_COLOR: 208 /* OK */ 209 break; 210 case GL_DEPTH: 211 if (ctx->DrawBuffer->Visual.depthBits == 0 || 212 ctx->ReadBuffer->Visual.depthBits == 0) { 213 _mesa_error(ctx, GL_INVALID_OPERATION, 214 "glCopyPixels(no depth buffer)"); 215 return; 216 } 217 break; 218 case GL_STENCIL: 219 if (ctx->DrawBuffer->Visual.stencilBits == 0 || 220 ctx->ReadBuffer->Visual.stencilBits == 0) { 221 _mesa_error(ctx, GL_INVALID_OPERATION, 222 "glCopyPixels(no stencil buffer)"); 223 return; 224 } 225 break; 226 case GL_DEPTH_STENCIL_EXT: 227 if (!ctx->Extensions.EXT_packed_depth_stencil) { 228 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels"); 229 return; 230 } 231 if (ctx->DrawBuffer->Visual.depthBits == 0 || 232 ctx->ReadBuffer->Visual.depthBits == 0 || 233 ctx->DrawBuffer->Visual.stencilBits == 0 || 234 ctx->ReadBuffer->Visual.stencilBits == 0) { 235 _mesa_error(ctx, GL_INVALID_OPERATION, 236 "glCopyPixels(no depth or stencil buffer)"); 237 return; 238 } 239 break; 240 default: 241 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels"); 242 return; 243 } 244 245 if (ctx->NewState) { 246 _mesa_update_state(ctx); 247 } 248 249 if (!ctx->Current.RasterPosValid) { 250 return; 251 } 252 253 if (ctx->RenderMode == GL_RENDER) { 254 /* Round to satisfy conformance tests (matches SGI's OpenGL) */ 255 GLint destx = IROUND(ctx->Current.RasterPos[0]); 256 GLint desty = IROUND(ctx->Current.RasterPos[1]); 257 ctx->Driver.CopyPixels( ctx, srcx, srcy, width, height, destx, desty, 258 type ); 259 } 260 else if (ctx->RenderMode == GL_FEEDBACK) { 261 FLUSH_CURRENT( ctx, 0 ); 262 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN ); 263 _mesa_feedback_vertex( ctx, 264 ctx->Current.RasterPos, 265 ctx->Current.RasterColor, 266 ctx->Current.RasterIndex, 267 ctx->Current.RasterTexCoords[0] ); 268 } 269 else { 270 ASSERT(ctx->RenderMode == GL_SELECT); 271 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 272 } 273} 274 275#endif /* _HAVE_FULL_GL */ 276 277 278 279void GLAPIENTRY 280_mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height, 281 GLenum format, GLenum type, GLvoid *pixels ) 282{ 283 GET_CURRENT_CONTEXT(ctx); 284 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 285 286 if (width < 0 || height < 0) { 287 _mesa_error( ctx, GL_INVALID_VALUE, 288 "glReadPixels(width=%d height=%d)", width, height ); 289 return; 290 } 291 292 if (error_check_format_type(ctx, format, type, GL_FALSE)) { 293 /* found an error */ 294 return; 295 } 296 297 if (ctx->NewState) 298 _mesa_update_state(ctx); 299 300 ctx->Driver.ReadPixels(ctx, x, y, width, height, 301 format, type, &ctx->Pack, pixels); 302} 303 304 305 306void GLAPIENTRY 307_mesa_Bitmap( GLsizei width, GLsizei height, 308 GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, 309 const GLubyte *bitmap ) 310{ 311 GET_CURRENT_CONTEXT(ctx); 312 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 313 314 if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { 315 _mesa_error(ctx, GL_INVALID_OPERATION, 316 "glBitmap (invalid fragment program)"); 317 return; 318 } 319 320 if (width < 0 || height < 0) { 321 _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" ); 322 return; 323 } 324 325 if (!ctx->Current.RasterPosValid) { 326 return; /* do nothing */ 327 } 328 329 if (ctx->NewState) { 330 _mesa_update_state(ctx); 331 } 332 333 if (ctx->RenderMode == GL_RENDER) { 334 /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */ 335 GLint x = IFLOOR(ctx->Current.RasterPos[0] - xorig); 336 GLint y = IFLOOR(ctx->Current.RasterPos[1] - yorig); 337 ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap ); 338 } 339#if _HAVE_FULL_GL 340 else if (ctx->RenderMode == GL_FEEDBACK) { 341 FLUSH_CURRENT(ctx, 0); 342 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN ); 343 _mesa_feedback_vertex( ctx, 344 ctx->Current.RasterPos, 345 ctx->Current.RasterColor, 346 ctx->Current.RasterIndex, 347 ctx->Current.RasterTexCoords[0] ); 348 } 349 else { 350 ASSERT(ctx->RenderMode == GL_SELECT); 351 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 352 } 353#endif 354 355 /* update raster position */ 356 ctx->Current.RasterPos[0] += xmove; 357 ctx->Current.RasterPos[1] += ymove; 358} 359 360 361 362#if 0 /* experimental */ 363/* 364 * Execute glDrawDepthPixelsMESA(). This function accepts both a color 365 * image and depth (Z) image. Rasterization produces fragments with 366 * color and Z taken from these images. This function is intended for 367 * Z-compositing. Normally, this operation requires two glDrawPixels 368 * calls with stencil testing. 369 */ 370void GLAPIENTRY 371_mesa_DrawDepthPixelsMESA( GLsizei width, GLsizei height, 372 GLenum colorFormat, GLenum colorType, 373 const GLvoid *colors, 374 GLenum depthType, const GLvoid *depths ) 375{ 376 GET_CURRENT_CONTEXT(ctx); 377 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 378 379 if (width < 0 || height < 0) { 380 _mesa_error( ctx, GL_INVALID_VALUE, 381 "glDrawDepthPixelsMESA(width or height < 0" ); 382 return; 383 } 384 385 if (!ctx->Current.RasterPosValid) { 386 return; 387 } 388 389 if (ctx->NewState) { 390 _mesa_update_state(ctx); 391 } 392 393 if (ctx->RenderMode == GL_RENDER) { 394 /* Round, to satisfy conformance tests (matches SGI's OpenGL) */ 395 GLint x = IROUND(ctx->Current.RasterPos[0]); 396 GLint y = IROUND(ctx->Current.RasterPos[1]); 397 ctx->Driver.DrawDepthPixelsMESA(ctx, x, y, width, height, 398 colorFormat, colorType, colors, 399 depthType, depths, &ctx->Unpack); 400 } 401 else if (ctx->RenderMode == GL_FEEDBACK) { 402 /* Feedback the current raster pos info */ 403 FLUSH_CURRENT( ctx, 0 ); 404 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); 405 _mesa_feedback_vertex( ctx, 406 ctx->Current.RasterPos, 407 ctx->Current.RasterColor, 408 ctx->Current.RasterIndex, 409 ctx->Current.RasterTexCoords[0] ); 410 } 411 else { 412 ASSERT(ctx->RenderMode == GL_SELECT); 413 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 414 } 415} 416 417#endif 418