drawpix.c revision 19b05d5009f4b0e83118b351b7261bb914e33f2b
1/* 2 * Mesa 3-D graphics library 3 * Version: 6.5 4 * 5 * Copyright (C) 1999-2006 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 struct gl_framebuffer *fb = drawing ? ctx->DrawBuffer : ctx->ReadBuffer; 47 48 if (ctx->Extensions.EXT_packed_depth_stencil 49 && type == GL_UNSIGNED_INT_24_8_EXT 50 && format != GL_DEPTH_STENCIL_EXT) { 51 _mesa_error(ctx, GL_INVALID_OPERATION, 52 "gl%sPixels(format is not GL_DEPTH_STENCIL_EXT)", readDraw); 53 return GL_TRUE; 54 } 55 56 /* basic combinations test */ 57 if (!_mesa_is_legal_format_and_type(ctx, format, type)) { 58 _mesa_error(ctx, GL_INVALID_ENUM, 59 "gl%sPixels(format or type)", readDraw); 60 return GL_TRUE; 61 } 62 63 /* additional checks */ 64 switch (format) { 65 case GL_RED: 66 case GL_GREEN: 67 case GL_BLUE: 68 case GL_ALPHA: 69 case GL_LUMINANCE: 70 case GL_LUMINANCE_ALPHA: 71 case GL_RGB: 72 case GL_BGR: 73 case GL_RGBA: 74 case GL_BGRA: 75 case GL_ABGR_EXT: 76 if (drawing && !ctx->Visual.rgbMode) { 77 _mesa_error(ctx, GL_INVALID_OPERATION, 78 "glDrawPixels(drawing RGB pixels into color index buffer)"); 79 return GL_TRUE; 80 } 81 break; 82 case GL_COLOR_INDEX: 83 if (!drawing && ctx->Visual.rgbMode) { 84 _mesa_error(ctx, GL_INVALID_OPERATION, 85 "glReadPixels(reading color index format from RGB buffer"); 86 return GL_TRUE; 87 } 88 break; 89 case GL_STENCIL_INDEX: 90 if (fb->Visual.stencilBits == 0) { 91 _mesa_error(ctx, GL_INVALID_OPERATION, 92 "gl%sPixels(no stencil buffer)", readDraw); 93 return GL_TRUE; 94 } 95 break; 96 case GL_DEPTH_COMPONENT: 97 if (fb->Visual.depthBits == 0) { 98 _mesa_error(ctx, GL_INVALID_OPERATION, 99 "gl%sPixels(no depth buffer)", readDraw); 100 return GL_TRUE; 101 } 102 break; 103 case GL_DEPTH_STENCIL_EXT: 104 if (!ctx->Extensions.EXT_packed_depth_stencil || 105 type != GL_UNSIGNED_INT_24_8_EXT) { 106 _mesa_error(ctx, GL_INVALID_ENUM, "gl%sPixels(type)", readDraw); 107 return GL_TRUE; 108 } 109 if (fb->Visual.depthBits == 0 || fb->Visual.stencilBits == 0) { 110 _mesa_error(ctx, GL_INVALID_OPERATION, 111 "gl%sPixels(no depth or stencil buffer)", readDraw); 112 return GL_TRUE; 113 } 114 ASSERT(fb->Attachment[BUFFER_DEPTH].Renderbuffer); 115 ASSERT(fb->Attachment[BUFFER_STENCIL].Renderbuffer); 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 (ctx->NewState) { 153 _mesa_update_state(ctx); 154 } 155 156 if (error_check_format_type(ctx, format, type, GL_TRUE)) { 157 /* found an error */ 158 return; 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->NewState) { 203 _mesa_update_state(ctx); 204 } 205 206 if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { 207 _mesa_error(ctx, GL_INVALID_OPERATION, 208 "glCopyPixels (invalid fragment program)"); 209 return; 210 } 211 212 if (width < 0 || height < 0) { 213 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)"); 214 return; 215 } 216 217 switch (type) { 218 case GL_COLOR: 219 /* OK */ 220 break; 221 case GL_DEPTH: 222 if (ctx->DrawBuffer->Visual.depthBits == 0 || 223 ctx->ReadBuffer->Visual.depthBits == 0) { 224 _mesa_error(ctx, GL_INVALID_OPERATION, 225 "glCopyPixels(no depth buffer)"); 226 return; 227 } 228 break; 229 case GL_STENCIL: 230 if (ctx->DrawBuffer->Visual.stencilBits == 0 || 231 ctx->ReadBuffer->Visual.stencilBits == 0) { 232 _mesa_error(ctx, GL_INVALID_OPERATION, 233 "glCopyPixels(no stencil buffer)"); 234 return; 235 } 236 break; 237 case GL_DEPTH_STENCIL_EXT: 238 if (!ctx->Extensions.EXT_packed_depth_stencil) { 239 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels"); 240 return; 241 } 242 if (ctx->DrawBuffer->Visual.depthBits == 0 || 243 ctx->ReadBuffer->Visual.depthBits == 0 || 244 ctx->DrawBuffer->Visual.stencilBits == 0 || 245 ctx->ReadBuffer->Visual.stencilBits == 0) { 246 _mesa_error(ctx, GL_INVALID_OPERATION, 247 "glCopyPixels(no depth or stencil buffer)"); 248 return; 249 } 250 break; 251 default: 252 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels"); 253 return; 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 (ctx->NewState) 308 _mesa_update_state(ctx); 309 310 if (error_check_format_type(ctx, format, type, GL_FALSE)) { 311 /* found an error */ 312 return; 313 } 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 if (bitmap) { 367 /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */ 368 GLint x = IFLOOR(ctx->Current.RasterPos[0] - xorig); 369 GLint y = IFLOOR(ctx->Current.RasterPos[1] - yorig); 370 ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap ); 371 } 372 } 373#if _HAVE_FULL_GL 374 else if (ctx->RenderMode == GL_FEEDBACK) { 375 FLUSH_CURRENT(ctx, 0); 376 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN ); 377 _mesa_feedback_vertex( ctx, 378 ctx->Current.RasterPos, 379 ctx->Current.RasterColor, 380 ctx->Current.RasterIndex, 381 ctx->Current.RasterTexCoords[0] ); 382 } 383 else { 384 ASSERT(ctx->RenderMode == GL_SELECT); 385 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 386 } 387#endif 388 389 /* update raster position */ 390 ctx->Current.RasterPos[0] += xmove; 391 ctx->Current.RasterPos[1] += ymove; 392} 393 394 395 396#if 0 /* experimental */ 397/* 398 * Execute glDrawDepthPixelsMESA(). This function accepts both a color 399 * image and depth (Z) image. Rasterization produces fragments with 400 * color and Z taken from these images. This function is intended for 401 * Z-compositing. Normally, this operation requires two glDrawPixels 402 * calls with stencil testing. 403 */ 404void GLAPIENTRY 405_mesa_DrawDepthPixelsMESA( GLsizei width, GLsizei height, 406 GLenum colorFormat, GLenum colorType, 407 const GLvoid *colors, 408 GLenum depthType, const GLvoid *depths ) 409{ 410 GET_CURRENT_CONTEXT(ctx); 411 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 412 413 if (width < 0 || height < 0) { 414 _mesa_error( ctx, GL_INVALID_VALUE, 415 "glDrawDepthPixelsMESA(width or height < 0" ); 416 return; 417 } 418 419 if (!ctx->Current.RasterPosValid) { 420 return; 421 } 422 423 if (ctx->NewState) { 424 _mesa_update_state(ctx); 425 } 426 427 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 428 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 429 "glDrawDepthPixelsMESA(incomplete framebuffer)"); 430 return; 431 } 432 433 if (ctx->RenderMode == GL_RENDER) { 434 /* Round, to satisfy conformance tests (matches SGI's OpenGL) */ 435 GLint x = IROUND(ctx->Current.RasterPos[0]); 436 GLint y = IROUND(ctx->Current.RasterPos[1]); 437 ctx->Driver.DrawDepthPixelsMESA(ctx, x, y, width, height, 438 colorFormat, colorType, colors, 439 depthType, depths, &ctx->Unpack); 440 } 441 else if (ctx->RenderMode == GL_FEEDBACK) { 442 /* Feedback the current raster pos info */ 443 FLUSH_CURRENT( ctx, 0 ); 444 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); 445 _mesa_feedback_vertex( ctx, 446 ctx->Current.RasterPos, 447 ctx->Current.RasterColor, 448 ctx->Current.RasterIndex, 449 ctx->Current.RasterTexCoords[0] ); 450 } 451 else { 452 ASSERT(ctx->RenderMode == GL_SELECT); 453 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 454 } 455} 456 457#endif 458