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