drawpix.c revision 4e0e02ae684c0286599309ae166cfc716db940d7
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.1 4 * 5 * Copyright (C) 1999-2008 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 "bufferobj.h" 28#include "context.h" 29#include "drawpix.h" 30#include "feedback.h" 31#include "framebuffer.h" 32#include "image.h" 33#include "state.h" 34 35 36/** 37 * Do error checking of the format/type parameters to glReadPixels and 38 * glDrawPixels. 39 * \param drawing if GL_TRUE do checking for DrawPixels, else do checking 40 * for ReadPixels. 41 * \return GL_TRUE if error detected, GL_FALSE if no errors 42 */ 43static GLboolean 44error_check_format_type(GLcontext *ctx, GLenum format, GLenum type, 45 GLboolean drawing) 46{ 47 const char *readDraw = drawing ? "Draw" : "Read"; 48 49 if (ctx->Extensions.EXT_packed_depth_stencil 50 && type == GL_UNSIGNED_INT_24_8_EXT 51 && format != GL_DEPTH_STENCIL_EXT) { 52 _mesa_error(ctx, GL_INVALID_OPERATION, 53 "gl%sPixels(format is not GL_DEPTH_STENCIL_EXT)", readDraw); 54 return GL_TRUE; 55 } 56 57 /* basic combinations test */ 58 if (!_mesa_is_legal_format_and_type(ctx, format, type)) { 59 _mesa_error(ctx, GL_INVALID_ENUM, 60 "gl%sPixels(format or type)", readDraw); 61 return GL_TRUE; 62 } 63 64 /* additional checks */ 65 switch (format) { 66 case GL_RED: 67 case GL_GREEN: 68 case GL_BLUE: 69 case GL_ALPHA: 70 case GL_LUMINANCE: 71 case GL_LUMINANCE_ALPHA: 72 case GL_RGB: 73 case GL_BGR: 74 case GL_RGBA: 75 case GL_BGRA: 76 case GL_ABGR_EXT: 77 if (drawing && !ctx->Visual.rgbMode) { 78 _mesa_error(ctx, GL_INVALID_OPERATION, 79 "glDrawPixels(drawing RGB pixels into color index buffer)"); 80 return GL_TRUE; 81 } 82 if (!drawing && !_mesa_dest_buffer_exists(ctx, GL_COLOR)) { 83 _mesa_error(ctx, GL_INVALID_OPERATION, 84 "glReadPixels(no color buffer)"); 85 return GL_TRUE; 86 } 87 break; 88 case GL_COLOR_INDEX: 89 if (!drawing && ctx->Visual.rgbMode) { 90 _mesa_error(ctx, GL_INVALID_OPERATION, 91 "glReadPixels(reading color index format from RGB buffer)"); 92 return GL_TRUE; 93 } 94 if (!drawing && !_mesa_dest_buffer_exists(ctx, GL_COLOR)) { 95 _mesa_error(ctx, GL_INVALID_OPERATION, 96 "glReadPixels(no color buffer)"); 97 return GL_TRUE; 98 } 99 break; 100 case GL_STENCIL_INDEX: 101 if ((drawing && !_mesa_dest_buffer_exists(ctx, format)) || 102 (!drawing && !_mesa_source_buffer_exists(ctx, format))) { 103 _mesa_error(ctx, GL_INVALID_OPERATION, 104 "gl%sPixels(no stencil buffer)", readDraw); 105 return GL_TRUE; 106 } 107 break; 108 case GL_DEPTH_COMPONENT: 109 if (!drawing && !_mesa_source_buffer_exists(ctx, format)) { 110 _mesa_error(ctx, GL_INVALID_OPERATION, 111 "gl%sPixels(no depth buffer)", readDraw); 112 return GL_TRUE; 113 } 114 break; 115 case GL_DEPTH_STENCIL_EXT: 116 if (!ctx->Extensions.EXT_packed_depth_stencil || 117 type != GL_UNSIGNED_INT_24_8_EXT) { 118 _mesa_error(ctx, GL_INVALID_ENUM, "gl%sPixels(type)", readDraw); 119 return GL_TRUE; 120 } 121 if ((drawing && !_mesa_dest_buffer_exists(ctx, format)) || 122 (!drawing && !_mesa_source_buffer_exists(ctx, format))) { 123 _mesa_error(ctx, GL_INVALID_OPERATION, 124 "gl%sPixels(no depth or stencil buffer)", readDraw); 125 return GL_TRUE; 126 } 127 break; 128 default: 129 /* this should have been caught in _mesa_is_legal_format_type() */ 130 _mesa_problem(ctx, "unexpected format in _mesa_%sPixels", readDraw); 131 return GL_TRUE; 132 } 133 134 /* no errors */ 135 return GL_FALSE; 136} 137 138 139 140#if _HAVE_FULL_GL 141 142/* 143 * Execute glDrawPixels 144 */ 145void GLAPIENTRY 146_mesa_DrawPixels( GLsizei width, GLsizei height, 147 GLenum format, GLenum type, const GLvoid *pixels ) 148{ 149 GET_CURRENT_CONTEXT(ctx); 150 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 151 152 if (width < 0 || height < 0) { 153 _mesa_error( ctx, GL_INVALID_VALUE, "glDrawPixels(width or height < 0" ); 154 return; 155 } 156 157 if (ctx->NewState) { 158 _mesa_update_state(ctx); 159 } 160 161 if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { 162 _mesa_error(ctx, GL_INVALID_OPERATION, 163 "glDrawPixels (invalid fragment program)"); 164 return; 165 } 166 167 if (error_check_format_type(ctx, format, type, GL_TRUE)) { 168 /* found an error */ 169 return; 170 } 171 172 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 173 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 174 "glDrawPixels(incomplete framebuffer)" ); 175 return; 176 } 177 178 if (!ctx->Current.RasterPosValid) { 179 return; 180 } 181 182 if (ctx->RenderMode == GL_RENDER) { 183 /* Round, to satisfy conformance tests (matches SGI's OpenGL) */ 184 GLint x = IROUND(ctx->Current.RasterPos[0]); 185 GLint y = IROUND(ctx->Current.RasterPos[1]); 186 187 if (ctx->Unpack.BufferObj->Name) { 188 /* unpack from PBO */ 189 if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 1, 190 format, type, pixels)) { 191 _mesa_error(ctx, GL_INVALID_OPERATION, 192 "glDrawPixels(invalid PBO access)"); 193 return; 194 } 195 if (ctx->Unpack.BufferObj->Pointer) { 196 /* buffer is mapped - that's an error */ 197 _mesa_error(ctx, GL_INVALID_OPERATION, 198 "glDrawPixels(PBO is mapped)"); 199 return; 200 } 201 } 202 203 ctx->Driver.DrawPixels(ctx, x, y, width, height, format, type, 204 &ctx->Unpack, pixels); 205 } 206 else if (ctx->RenderMode == GL_FEEDBACK) { 207 /* Feedback the current raster pos info */ 208 FLUSH_CURRENT( ctx, 0 ); 209 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); 210 _mesa_feedback_vertex( ctx, 211 ctx->Current.RasterPos, 212 ctx->Current.RasterColor, 213 ctx->Current.RasterIndex, 214 ctx->Current.RasterTexCoords[0] ); 215 } 216 else { 217 ASSERT(ctx->RenderMode == GL_SELECT); 218 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 219 } 220} 221 222 223void GLAPIENTRY 224_mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height, 225 GLenum type ) 226{ 227 GET_CURRENT_CONTEXT(ctx); 228 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 229 230 if (ctx->NewState) { 231 _mesa_update_state(ctx); 232 } 233 234 if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { 235 _mesa_error(ctx, GL_INVALID_OPERATION, 236 "glCopyPixels (invalid fragment program)"); 237 return; 238 } 239 240 if (width < 0 || height < 0) { 241 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)"); 242 return; 243 } 244 245 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT || 246 ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 247 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 248 "glCopyPixels(incomplete framebuffer)" ); 249 return; 250 } 251 252 if (!_mesa_source_buffer_exists(ctx, type) || 253 !_mesa_dest_buffer_exists(ctx, type)) { 254 _mesa_error(ctx, GL_INVALID_OPERATION, 255 "glCopyPixels(missing source or dest buffer)"); 256 return; 257 } 258 259 if (!ctx->Current.RasterPosValid) { 260 return; 261 } 262 263 if (ctx->RenderMode == GL_RENDER) { 264 /* Round to satisfy conformance tests (matches SGI's OpenGL) */ 265 GLint destx = IROUND(ctx->Current.RasterPos[0]); 266 GLint desty = IROUND(ctx->Current.RasterPos[1]); 267 ctx->Driver.CopyPixels( ctx, srcx, srcy, width, height, destx, desty, 268 type ); 269 } 270 else if (ctx->RenderMode == GL_FEEDBACK) { 271 FLUSH_CURRENT( ctx, 0 ); 272 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN ); 273 _mesa_feedback_vertex( ctx, 274 ctx->Current.RasterPos, 275 ctx->Current.RasterColor, 276 ctx->Current.RasterIndex, 277 ctx->Current.RasterTexCoords[0] ); 278 } 279 else { 280 ASSERT(ctx->RenderMode == GL_SELECT); 281 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 282 } 283} 284 285#endif /* _HAVE_FULL_GL */ 286 287 288 289void GLAPIENTRY 290_mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height, 291 GLenum format, GLenum type, GLvoid *pixels ) 292{ 293 GET_CURRENT_CONTEXT(ctx); 294 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 295 296 if (width < 0 || height < 0) { 297 _mesa_error( ctx, GL_INVALID_VALUE, 298 "glReadPixels(width=%d height=%d)", width, height ); 299 return; 300 } 301 302 if (ctx->NewState) 303 _mesa_update_state(ctx); 304 305 if (error_check_format_type(ctx, format, type, GL_FALSE)) { 306 /* found an error */ 307 return; 308 } 309 310 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 311 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 312 "glReadPixels(incomplete framebuffer)" ); 313 return; 314 } 315 316 if (!_mesa_source_buffer_exists(ctx, format)) { 317 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)"); 318 return; 319 } 320 321 if (ctx->Pack.BufferObj->Name) { 322 if (!_mesa_validate_pbo_access(2, &ctx->Pack, width, height, 1, 323 format, type, pixels)) { 324 _mesa_error(ctx, GL_INVALID_OPERATION, 325 "glReadPixels(invalid PBO access)"); 326 return; 327 } 328 329 if (ctx->Pack.BufferObj->Pointer) { 330 /* buffer is mapped - that's an error */ 331 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(PBO is mapped)"); 332 return; 333 } 334 } 335 336 ctx->Driver.ReadPixels(ctx, x, y, width, height, 337 format, type, &ctx->Pack, pixels); 338} 339 340 341 342void GLAPIENTRY 343_mesa_Bitmap( GLsizei width, GLsizei height, 344 GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, 345 const GLubyte *bitmap ) 346{ 347 GET_CURRENT_CONTEXT(ctx); 348 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 349 350 if (width < 0 || height < 0) { 351 _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" ); 352 return; 353 } 354 355 if (!ctx->Current.RasterPosValid) { 356 return; /* do nothing */ 357 } 358 359 if (ctx->NewState) { 360 _mesa_update_state(ctx); 361 } 362 363 if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { 364 _mesa_error(ctx, GL_INVALID_OPERATION, 365 "glBitmap (invalid fragment program)"); 366 return; 367 } 368 369 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 370 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 371 "glBitmap(incomplete framebuffer)"); 372 return; 373 } 374 375 if (ctx->RenderMode == GL_RENDER) { 376 /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */ 377 const GLfloat epsilon = 0.0001; 378 GLint x = IFLOOR(ctx->Current.RasterPos[0] + epsilon - xorig); 379 GLint y = IFLOOR(ctx->Current.RasterPos[1] + epsilon - yorig); 380 381 if (ctx->Unpack.BufferObj->Name) { 382 /* unpack from PBO */ 383 if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 1, 384 GL_COLOR_INDEX, GL_BITMAP, 385 (GLvoid *) bitmap)) { 386 _mesa_error(ctx, GL_INVALID_OPERATION, 387 "glBitmap(invalid PBO access)"); 388 return; 389 } 390 if (ctx->Unpack.BufferObj->Pointer) { 391 /* buffer is mapped - that's an error */ 392 _mesa_error(ctx, GL_INVALID_OPERATION, "glBitmap(PBO is mapped)"); 393 return; 394 } 395 } 396 397 ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap ); 398 } 399#if _HAVE_FULL_GL 400 else if (ctx->RenderMode == GL_FEEDBACK) { 401 FLUSH_CURRENT(ctx, 0); 402 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN ); 403 _mesa_feedback_vertex( ctx, 404 ctx->Current.RasterPos, 405 ctx->Current.RasterColor, 406 ctx->Current.RasterIndex, 407 ctx->Current.RasterTexCoords[0] ); 408 } 409 else { 410 ASSERT(ctx->RenderMode == GL_SELECT); 411 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 412 } 413#endif 414 415 /* update raster position */ 416 ctx->Current.RasterPos[0] += xmove; 417 ctx->Current.RasterPos[1] += ymove; 418} 419 420 421 422#if 0 /* experimental */ 423/* 424 * Execute glDrawDepthPixelsMESA(). This function accepts both a color 425 * image and depth (Z) image. Rasterization produces fragments with 426 * color and Z taken from these images. This function is intended for 427 * Z-compositing. Normally, this operation requires two glDrawPixels 428 * calls with stencil testing. 429 */ 430void GLAPIENTRY 431_mesa_DrawDepthPixelsMESA( GLsizei width, GLsizei height, 432 GLenum colorFormat, GLenum colorType, 433 const GLvoid *colors, 434 GLenum depthType, const GLvoid *depths ) 435{ 436 GET_CURRENT_CONTEXT(ctx); 437 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 438 439 if (width < 0 || height < 0) { 440 _mesa_error( ctx, GL_INVALID_VALUE, 441 "glDrawDepthPixelsMESA(width or height < 0" ); 442 return; 443 } 444 445 if (!ctx->Current.RasterPosValid) { 446 return; 447 } 448 449 if (ctx->NewState) { 450 _mesa_update_state(ctx); 451 } 452 453 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 454 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 455 "glDrawDepthPixelsMESA(incomplete framebuffer)"); 456 return; 457 } 458 459 if (ctx->RenderMode == GL_RENDER) { 460 /* Round, to satisfy conformance tests (matches SGI's OpenGL) */ 461 GLint x = IROUND(ctx->Current.RasterPos[0]); 462 GLint y = IROUND(ctx->Current.RasterPos[1]); 463 ctx->Driver.DrawDepthPixelsMESA(ctx, x, y, width, height, 464 colorFormat, colorType, colors, 465 depthType, depths, &ctx->Unpack); 466 } 467 else if (ctx->RenderMode == GL_FEEDBACK) { 468 /* Feedback the current raster pos info */ 469 FLUSH_CURRENT( ctx, 0 ); 470 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); 471 _mesa_feedback_vertex( ctx, 472 ctx->Current.RasterPos, 473 ctx->Current.RasterColor, 474 ctx->Current.RasterIndex, 475 ctx->Current.RasterTexCoords[0] ); 476 } 477 else { 478 ASSERT(ctx->RenderMode == GL_SELECT); 479 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 480 } 481} 482 483#endif 484