drawpix.c revision 5208867f12abd4b13c517e8cd006afde6fadbed8
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->NewState) { 157 _mesa_update_state(ctx); 158 } 159 160 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 161 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 162 "glDrawPixels(incomplete framebuffer)" ); 163 return; 164 } 165 166 if (!ctx->Current.RasterPosValid) { 167 return; 168 } 169 170 if (ctx->RenderMode == GL_RENDER) { 171 /* Round, to satisfy conformance tests (matches SGI's OpenGL) */ 172 GLint x = IROUND(ctx->Current.RasterPos[0]); 173 GLint y = IROUND(ctx->Current.RasterPos[1]); 174 ctx->Driver.DrawPixels(ctx, x, y, width, height, format, type, 175 &ctx->Unpack, pixels); 176 } 177 else if (ctx->RenderMode == GL_FEEDBACK) { 178 /* Feedback the current raster pos info */ 179 FLUSH_CURRENT( ctx, 0 ); 180 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); 181 _mesa_feedback_vertex( ctx, 182 ctx->Current.RasterPos, 183 ctx->Current.RasterColor, 184 ctx->Current.RasterIndex, 185 ctx->Current.RasterTexCoords[0] ); 186 } 187 else { 188 ASSERT(ctx->RenderMode == GL_SELECT); 189 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 190 } 191} 192 193 194void GLAPIENTRY 195_mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height, 196 GLenum type ) 197{ 198 GET_CURRENT_CONTEXT(ctx); 199 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 200 201 if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { 202 _mesa_error(ctx, GL_INVALID_OPERATION, 203 "glCopyPixels (invalid fragment program)"); 204 return; 205 } 206 207 if (width < 0 || height < 0) { 208 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)"); 209 return; 210 } 211 212 switch (type) { 213 case GL_COLOR: 214 /* OK */ 215 break; 216 case GL_DEPTH: 217 if (ctx->DrawBuffer->Visual.depthBits == 0 || 218 ctx->ReadBuffer->Visual.depthBits == 0) { 219 _mesa_error(ctx, GL_INVALID_OPERATION, 220 "glCopyPixels(no depth buffer)"); 221 return; 222 } 223 break; 224 case GL_STENCIL: 225 if (ctx->DrawBuffer->Visual.stencilBits == 0 || 226 ctx->ReadBuffer->Visual.stencilBits == 0) { 227 _mesa_error(ctx, GL_INVALID_OPERATION, 228 "glCopyPixels(no stencil buffer)"); 229 return; 230 } 231 break; 232 case GL_DEPTH_STENCIL_EXT: 233 if (!ctx->Extensions.EXT_packed_depth_stencil) { 234 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels"); 235 return; 236 } 237 if (ctx->DrawBuffer->Visual.depthBits == 0 || 238 ctx->ReadBuffer->Visual.depthBits == 0 || 239 ctx->DrawBuffer->Visual.stencilBits == 0 || 240 ctx->ReadBuffer->Visual.stencilBits == 0) { 241 _mesa_error(ctx, GL_INVALID_OPERATION, 242 "glCopyPixels(no depth or stencil buffer)"); 243 return; 244 } 245 break; 246 default: 247 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels"); 248 return; 249 } 250 251 if (ctx->NewState) { 252 _mesa_update_state(ctx); 253 } 254 255 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT || 256 ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 257 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 258 "glCopyPixels(incomplete framebuffer)" ); 259 return; 260 } 261 262 if (!ctx->Current.RasterPosValid) { 263 return; 264 } 265 266 if (ctx->RenderMode == GL_RENDER) { 267 /* Round to satisfy conformance tests (matches SGI's OpenGL) */ 268 GLint destx = IROUND(ctx->Current.RasterPos[0]); 269 GLint desty = IROUND(ctx->Current.RasterPos[1]); 270 ctx->Driver.CopyPixels( ctx, srcx, srcy, width, height, destx, desty, 271 type ); 272 } 273 else if (ctx->RenderMode == GL_FEEDBACK) { 274 FLUSH_CURRENT( ctx, 0 ); 275 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN ); 276 _mesa_feedback_vertex( ctx, 277 ctx->Current.RasterPos, 278 ctx->Current.RasterColor, 279 ctx->Current.RasterIndex, 280 ctx->Current.RasterTexCoords[0] ); 281 } 282 else { 283 ASSERT(ctx->RenderMode == GL_SELECT); 284 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 285 } 286} 287 288#endif /* _HAVE_FULL_GL */ 289 290 291 292void GLAPIENTRY 293_mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height, 294 GLenum format, GLenum type, GLvoid *pixels ) 295{ 296 GET_CURRENT_CONTEXT(ctx); 297 const struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; 298 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 299 300 if (width < 0 || height < 0) { 301 _mesa_error( ctx, GL_INVALID_VALUE, 302 "glReadPixels(width=%d height=%d)", width, height ); 303 return; 304 } 305 306 if (error_check_format_type(ctx, format, type, GL_FALSE)) { 307 /* found an error */ 308 return; 309 } 310 311 if (ctx->NewState) 312 _mesa_update_state(ctx); 313 314 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 315 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 316 "glReadPixels(incomplete framebuffer)" ); 317 return; 318 } 319 320 if (!rb) { 321 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)"); 322 return; 323 } 324 325 ctx->Driver.ReadPixels(ctx, x, y, width, height, 326 format, type, &ctx->Pack, pixels); 327} 328 329 330 331void GLAPIENTRY 332_mesa_Bitmap( GLsizei width, GLsizei height, 333 GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, 334 const GLubyte *bitmap ) 335{ 336 GET_CURRENT_CONTEXT(ctx); 337 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 338 339 if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { 340 _mesa_error(ctx, GL_INVALID_OPERATION, 341 "glBitmap (invalid fragment program)"); 342 return; 343 } 344 345 if (width < 0 || height < 0) { 346 _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" ); 347 return; 348 } 349 350 if (!ctx->Current.RasterPosValid) { 351 return; /* do nothing */ 352 } 353 354 if (ctx->NewState) { 355 _mesa_update_state(ctx); 356 } 357 358 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 359 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 360 "glBitmap(incomplete framebuffer)"); 361 return; 362 } 363 364 if (ctx->RenderMode == GL_RENDER) { 365 /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */ 366 GLint x = IFLOOR(ctx->Current.RasterPos[0] - xorig); 367 GLint y = IFLOOR(ctx->Current.RasterPos[1] - yorig); 368 ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap ); 369 } 370#if _HAVE_FULL_GL 371 else if (ctx->RenderMode == GL_FEEDBACK) { 372 FLUSH_CURRENT(ctx, 0); 373 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN ); 374 _mesa_feedback_vertex( ctx, 375 ctx->Current.RasterPos, 376 ctx->Current.RasterColor, 377 ctx->Current.RasterIndex, 378 ctx->Current.RasterTexCoords[0] ); 379 } 380 else { 381 ASSERT(ctx->RenderMode == GL_SELECT); 382 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 383 } 384#endif 385 386 /* update raster position */ 387 ctx->Current.RasterPos[0] += xmove; 388 ctx->Current.RasterPos[1] += ymove; 389} 390 391 392 393#if 0 /* experimental */ 394/* 395 * Execute glDrawDepthPixelsMESA(). This function accepts both a color 396 * image and depth (Z) image. Rasterization produces fragments with 397 * color and Z taken from these images. This function is intended for 398 * Z-compositing. Normally, this operation requires two glDrawPixels 399 * calls with stencil testing. 400 */ 401void GLAPIENTRY 402_mesa_DrawDepthPixelsMESA( GLsizei width, GLsizei height, 403 GLenum colorFormat, GLenum colorType, 404 const GLvoid *colors, 405 GLenum depthType, const GLvoid *depths ) 406{ 407 GET_CURRENT_CONTEXT(ctx); 408 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 409 410 if (width < 0 || height < 0) { 411 _mesa_error( ctx, GL_INVALID_VALUE, 412 "glDrawDepthPixelsMESA(width or height < 0" ); 413 return; 414 } 415 416 if (!ctx->Current.RasterPosValid) { 417 return; 418 } 419 420 if (ctx->NewState) { 421 _mesa_update_state(ctx); 422 } 423 424 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 425 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 426 "glDrawDepthPixelsMESA(incomplete framebuffer)"); 427 return; 428 } 429 430 if (ctx->RenderMode == GL_RENDER) { 431 /* Round, to satisfy conformance tests (matches SGI's OpenGL) */ 432 GLint x = IROUND(ctx->Current.RasterPos[0]); 433 GLint y = IROUND(ctx->Current.RasterPos[1]); 434 ctx->Driver.DrawDepthPixelsMESA(ctx, x, y, width, height, 435 colorFormat, colorType, colors, 436 depthType, depths, &ctx->Unpack); 437 } 438 else if (ctx->RenderMode == GL_FEEDBACK) { 439 /* Feedback the current raster pos info */ 440 FLUSH_CURRENT( ctx, 0 ); 441 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); 442 _mesa_feedback_vertex( ctx, 443 ctx->Current.RasterPos, 444 ctx->Current.RasterColor, 445 ctx->Current.RasterIndex, 446 ctx->Current.RasterTexCoords[0] ); 447 } 448 else { 449 ASSERT(ctx->RenderMode == GL_SELECT); 450 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 451 } 452} 453 454#endif 455