drawpix.c revision c80a380ebb58c15db87309d466ef57fb006b40ae
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 "context.h" 28#include "drawpix.h" 29#include "feedback.h" 30#include "framebuffer.h" 31#include "image.h" 32#include "state.h" 33 34 35/** 36 * Do error checking of the format/type parameters to glReadPixels and 37 * glDrawPixels. 38 * \param drawing if GL_TRUE do checking for DrawPixels, else do checking 39 * for ReadPixels. 40 * \return GL_TRUE if error detected, GL_FALSE if no errors 41 */ 42static GLboolean 43error_check_format_type(GLcontext *ctx, GLenum format, GLenum type, 44 GLboolean drawing) 45{ 46 const char *readDraw = drawing ? "Draw" : "Read"; 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 if (!drawing && !_mesa_dest_buffer_exists(ctx, GL_COLOR)) { 82 _mesa_error(ctx, GL_INVALID_OPERATION, 83 "glReadPixels(no color buffer)"); 84 return GL_TRUE; 85 } 86 break; 87 case GL_COLOR_INDEX: 88 if (!drawing && ctx->Visual.rgbMode) { 89 _mesa_error(ctx, GL_INVALID_OPERATION, 90 "glReadPixels(reading color index format from RGB buffer)"); 91 return GL_TRUE; 92 } 93 if (!drawing && !_mesa_dest_buffer_exists(ctx, GL_COLOR)) { 94 _mesa_error(ctx, GL_INVALID_OPERATION, 95 "glReadPixels(no color buffer)"); 96 return GL_TRUE; 97 } 98 break; 99 case GL_STENCIL_INDEX: 100 if ((drawing && !_mesa_dest_buffer_exists(ctx, format)) || 101 (!drawing && !_mesa_source_buffer_exists(ctx, format))) { 102 _mesa_error(ctx, GL_INVALID_OPERATION, 103 "gl%sPixels(no stencil buffer)", readDraw); 104 return GL_TRUE; 105 } 106 break; 107 case GL_DEPTH_COMPONENT: 108 if ((drawing && !_mesa_dest_buffer_exists(ctx, format)) || 109 (!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 ctx->Driver.DrawPixels(ctx, x, y, width, height, format, type, 187 &ctx->Unpack, pixels); 188 } 189 else if (ctx->RenderMode == GL_FEEDBACK) { 190 /* Feedback the current raster pos info */ 191 FLUSH_CURRENT( ctx, 0 ); 192 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); 193 _mesa_feedback_vertex( ctx, 194 ctx->Current.RasterPos, 195 ctx->Current.RasterColor, 196 ctx->Current.RasterIndex, 197 ctx->Current.RasterTexCoords[0] ); 198 } 199 else { 200 ASSERT(ctx->RenderMode == GL_SELECT); 201 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 202 } 203} 204 205 206void GLAPIENTRY 207_mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height, 208 GLenum type ) 209{ 210 GET_CURRENT_CONTEXT(ctx); 211 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 212 213 if (ctx->NewState) { 214 _mesa_update_state(ctx); 215 } 216 217 if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { 218 _mesa_error(ctx, GL_INVALID_OPERATION, 219 "glCopyPixels (invalid fragment program)"); 220 return; 221 } 222 223 if (width < 0 || height < 0) { 224 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)"); 225 return; 226 } 227 228 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT || 229 ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 230 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 231 "glCopyPixels(incomplete framebuffer)" ); 232 return; 233 } 234 235 if (!_mesa_source_buffer_exists(ctx, type) || 236 !_mesa_dest_buffer_exists(ctx, type)) { 237 _mesa_error(ctx, GL_INVALID_OPERATION, 238 "glCopyPixels(missing source or dest buffer)"); 239 return; 240 } 241 242 if (!ctx->Current.RasterPosValid || width ==0 || height == 0) { 243 return; 244 } 245 246 if (ctx->RenderMode == GL_RENDER) { 247 /* Round to satisfy conformance tests (matches SGI's OpenGL) */ 248 GLint destx = IROUND(ctx->Current.RasterPos[0]); 249 GLint desty = IROUND(ctx->Current.RasterPos[1]); 250 ctx->Driver.CopyPixels( ctx, srcx, srcy, width, height, destx, desty, 251 type ); 252 } 253 else if (ctx->RenderMode == GL_FEEDBACK) { 254 FLUSH_CURRENT( ctx, 0 ); 255 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN ); 256 _mesa_feedback_vertex( ctx, 257 ctx->Current.RasterPos, 258 ctx->Current.RasterColor, 259 ctx->Current.RasterIndex, 260 ctx->Current.RasterTexCoords[0] ); 261 } 262 else { 263 ASSERT(ctx->RenderMode == GL_SELECT); 264 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 265 } 266} 267 268#endif /* _HAVE_FULL_GL */ 269 270 271 272void GLAPIENTRY 273_mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height, 274 GLenum format, GLenum type, GLvoid *pixels ) 275{ 276 GET_CURRENT_CONTEXT(ctx); 277 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 278 279 FLUSH_CURRENT(ctx, 0); 280 281 if (width < 0 || height < 0) { 282 _mesa_error( ctx, GL_INVALID_VALUE, 283 "glReadPixels(width=%d height=%d)", width, height ); 284 return; 285 } 286 287 if (ctx->NewState) 288 _mesa_update_state(ctx); 289 290 if (error_check_format_type(ctx, format, type, GL_FALSE)) { 291 /* found an error */ 292 return; 293 } 294 295 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 296 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 297 "glReadPixels(incomplete framebuffer)" ); 298 return; 299 } 300 301 if (!_mesa_source_buffer_exists(ctx, format)) { 302 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)"); 303 return; 304 } 305 306 ctx->Driver.ReadPixels(ctx, x, y, width, height, 307 format, type, &ctx->Pack, pixels); 308} 309 310 311 312void GLAPIENTRY 313_mesa_Bitmap( GLsizei width, GLsizei height, 314 GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, 315 const GLubyte *bitmap ) 316{ 317 GET_CURRENT_CONTEXT(ctx); 318 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 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->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { 334 _mesa_error(ctx, GL_INVALID_OPERATION, 335 "glBitmap (invalid fragment program)"); 336 return; 337 } 338 339 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 340 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 341 "glBitmap(incomplete framebuffer)"); 342 return; 343 } 344 345 if (ctx->RenderMode == GL_RENDER) { 346 /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */ 347 GLint x = IFLOOR(ctx->Current.RasterPos[0] - xorig); 348 GLint y = IFLOOR(ctx->Current.RasterPos[1] - yorig); 349 ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap ); 350 } 351#if _HAVE_FULL_GL 352 else if (ctx->RenderMode == GL_FEEDBACK) { 353 FLUSH_CURRENT(ctx, 0); 354 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN ); 355 _mesa_feedback_vertex( ctx, 356 ctx->Current.RasterPos, 357 ctx->Current.RasterColor, 358 ctx->Current.RasterIndex, 359 ctx->Current.RasterTexCoords[0] ); 360 } 361 else { 362 ASSERT(ctx->RenderMode == GL_SELECT); 363 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 364 } 365#endif 366 367 /* update raster position */ 368 ctx->Current.RasterPos[0] += xmove; 369 ctx->Current.RasterPos[1] += ymove; 370} 371 372 373 374#if 0 /* experimental */ 375/* 376 * Execute glDrawDepthPixelsMESA(). This function accepts both a color 377 * image and depth (Z) image. Rasterization produces fragments with 378 * color and Z taken from these images. This function is intended for 379 * Z-compositing. Normally, this operation requires two glDrawPixels 380 * calls with stencil testing. 381 */ 382void GLAPIENTRY 383_mesa_DrawDepthPixelsMESA( GLsizei width, GLsizei height, 384 GLenum colorFormat, GLenum colorType, 385 const GLvoid *colors, 386 GLenum depthType, const GLvoid *depths ) 387{ 388 GET_CURRENT_CONTEXT(ctx); 389 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 390 391 if (width < 0 || height < 0) { 392 _mesa_error( ctx, GL_INVALID_VALUE, 393 "glDrawDepthPixelsMESA(width or height < 0" ); 394 return; 395 } 396 397 if (!ctx->Current.RasterPosValid) { 398 return; 399 } 400 401 if (ctx->NewState) { 402 _mesa_update_state(ctx); 403 } 404 405 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 406 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 407 "glDrawDepthPixelsMESA(incomplete framebuffer)"); 408 return; 409 } 410 411 if (ctx->RenderMode == GL_RENDER) { 412 /* Round, to satisfy conformance tests (matches SGI's OpenGL) */ 413 GLint x = IROUND(ctx->Current.RasterPos[0]); 414 GLint y = IROUND(ctx->Current.RasterPos[1]); 415 ctx->Driver.DrawDepthPixelsMESA(ctx, x, y, width, height, 416 colorFormat, colorType, colors, 417 depthType, depths, &ctx->Unpack); 418 } 419 else if (ctx->RenderMode == GL_FEEDBACK) { 420 /* Feedback the current raster pos info */ 421 FLUSH_CURRENT( ctx, 0 ); 422 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); 423 _mesa_feedback_vertex( ctx, 424 ctx->Current.RasterPos, 425 ctx->Current.RasterColor, 426 ctx->Current.RasterIndex, 427 ctx->Current.RasterTexCoords[0] ); 428 } 429 else { 430 ASSERT(ctx->RenderMode == GL_SELECT); 431 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 432 } 433} 434 435#endif 436