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 "enums.h" 31 #include "feedback.h" 32 #include "framebuffer.h" 33 #include "image.h" 34 #include "mfeatures.h" 35 #include "pbo.h" 36 #include "state.h" 37 #include "dispatch.h" 38 #include "glformats.h" 39 #include "fbobject.h" 40 41 42 #if FEATURE_drawpix 43 44 45 /* 46 * Execute glDrawPixels 47 */ 48 static void GLAPIENTRY 49 _mesa_DrawPixels( GLsizei width, GLsizei height, 50 GLenum format, GLenum type, const GLvoid *pixels ) 51 { 52 GLenum err; 53 GET_CURRENT_CONTEXT(ctx); 54 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 55 56 if (MESA_VERBOSE & VERBOSE_API) 57 _mesa_debug(ctx, "glDrawPixels(%d, %d, %s, %s, %p) // to %s at %d, %d\n", 58 width, height, 59 _mesa_lookup_enum_by_nr(format), 60 _mesa_lookup_enum_by_nr(type), 61 pixels, 62 _mesa_lookup_enum_by_nr(ctx->DrawBuffer->ColorDrawBuffer[0]), 63 IROUND(ctx->Current.RasterPos[0]), 64 IROUND(ctx->Current.RasterPos[1])); 65 66 67 if (width < 0 || height < 0) { 68 _mesa_error( ctx, GL_INVALID_VALUE, "glDrawPixels(width or height < 0)" ); 69 return; 70 } 71 72 /* We're not using the current vertex program, and the driver may install 73 * its own. Note: this may dirty some state. 74 */ 75 _mesa_set_vp_override(ctx, GL_TRUE); 76 77 /* Note: this call does state validation */ 78 if (!_mesa_valid_to_render(ctx, "glDrawPixels")) { 79 goto end; /* the error code was recorded */ 80 } 81 82 /* GL 3.0 introduced a new restriction on glDrawPixels() over what was in 83 * GL_EXT_texture_integer. From section 3.7.4 ("Rasterization of Pixel 84 * Rectangles) on page 151 of the GL 3.0 specification: 85 * 86 * "If format contains integer components, as shown in table 3.6, an 87 * INVALID OPERATION error is generated." 88 * 89 * Since DrawPixels rendering would be merely undefined if not an error (due 90 * to a lack of defined mapping from integer data to gl_Color fragment shader 91 * input), NVIDIA's implementation also just returns this error despite 92 * exposing GL_EXT_texture_integer, just return an error regardless. 93 */ 94 if (_mesa_is_enum_format_integer(format)) { 95 _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels(integer format)"); 96 goto end; 97 } 98 99 err = _mesa_error_check_format_and_type(ctx, format, type); 100 if (err != GL_NO_ERROR) { 101 _mesa_error(ctx, err, "glDrawPixels(invalid format %s and/or type %s)", 102 _mesa_lookup_enum_by_nr(format), 103 _mesa_lookup_enum_by_nr(type)); 104 goto end; 105 } 106 107 /* do special format-related checks */ 108 switch (format) { 109 case GL_STENCIL_INDEX: 110 case GL_DEPTH_COMPONENT: 111 case GL_DEPTH_STENCIL_EXT: 112 /* these buffers must exist */ 113 if (!_mesa_dest_buffer_exists(ctx, format)) { 114 _mesa_error(ctx, GL_INVALID_OPERATION, 115 "glDrawPixels(missing deest buffer)"); 116 goto end; 117 } 118 break; 119 case GL_COLOR_INDEX: 120 if (ctx->PixelMaps.ItoR.Size == 0 || 121 ctx->PixelMaps.ItoG.Size == 0 || 122 ctx->PixelMaps.ItoB.Size == 0) { 123 _mesa_error(ctx, GL_INVALID_OPERATION, 124 "glDrawPixels(drawing color index pixels into RGB buffer)"); 125 goto end; 126 } 127 break; 128 default: 129 /* for color formats it's not an error if the destination color 130 * buffer doesn't exist. 131 */ 132 break; 133 } 134 135 if (ctx->RasterDiscard) { 136 goto end; 137 } 138 139 if (!ctx->Current.RasterPosValid) { 140 goto end; /* no-op, not an error */ 141 } 142 143 if (ctx->RenderMode == GL_RENDER) { 144 if (width > 0 && height > 0) { 145 /* Round, to satisfy conformance tests (matches SGI's OpenGL) */ 146 GLint x = IROUND(ctx->Current.RasterPos[0]); 147 GLint y = IROUND(ctx->Current.RasterPos[1]); 148 149 if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) { 150 /* unpack from PBO */ 151 if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 152 1, format, type, INT_MAX, pixels)) { 153 _mesa_error(ctx, GL_INVALID_OPERATION, 154 "glDrawPixels(invalid PBO access)"); 155 goto end; 156 } 157 if (_mesa_bufferobj_mapped(ctx->Unpack.BufferObj)) { 158 /* buffer is mapped - that's an error */ 159 _mesa_error(ctx, GL_INVALID_OPERATION, 160 "glDrawPixels(PBO is mapped)"); 161 goto end; 162 } 163 } 164 165 ctx->Driver.DrawPixels(ctx, x, y, width, height, format, type, 166 &ctx->Unpack, pixels); 167 } 168 } 169 else if (ctx->RenderMode == GL_FEEDBACK) { 170 /* Feedback the current raster pos info */ 171 FLUSH_CURRENT( ctx, 0 ); 172 _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); 173 _mesa_feedback_vertex( ctx, 174 ctx->Current.RasterPos, 175 ctx->Current.RasterColor, 176 ctx->Current.RasterTexCoords[0] ); 177 } 178 else { 179 ASSERT(ctx->RenderMode == GL_SELECT); 180 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 181 } 182 183 end: 184 _mesa_set_vp_override(ctx, GL_FALSE); 185 186 if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { 187 _mesa_flush(ctx); 188 } 189 } 190 191 192 static void GLAPIENTRY 193 _mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height, 194 GLenum type ) 195 { 196 GET_CURRENT_CONTEXT(ctx); 197 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 198 199 if (MESA_VERBOSE & VERBOSE_API) 200 _mesa_debug(ctx, 201 "glCopyPixels(%d, %d, %d, %d, %s) // from %s to %s at %d, %d\n", 202 srcx, srcy, width, height, 203 _mesa_lookup_enum_by_nr(type), 204 _mesa_lookup_enum_by_nr(ctx->ReadBuffer->ColorReadBuffer), 205 _mesa_lookup_enum_by_nr(ctx->DrawBuffer->ColorDrawBuffer[0]), 206 IROUND(ctx->Current.RasterPos[0]), 207 IROUND(ctx->Current.RasterPos[1])); 208 209 if (width < 0 || height < 0) { 210 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)"); 211 return; 212 } 213 214 /* Note: more detailed 'type' checking is done by the 215 * _mesa_source/dest_buffer_exists() calls below. That's where we 216 * check if the stencil buffer exists, etc. 217 */ 218 if (type != GL_COLOR && 219 type != GL_DEPTH && 220 type != GL_STENCIL && 221 type != GL_DEPTH_STENCIL) { 222 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels(type=%s)", 223 _mesa_lookup_enum_by_nr(type)); 224 return; 225 } 226 227 /* We're not using the current vertex program, and the driver may install 228 * it's own. Note: this may dirty some state. 229 */ 230 _mesa_set_vp_override(ctx, GL_TRUE); 231 232 /* Note: this call does state validation */ 233 if (!_mesa_valid_to_render(ctx, "glCopyPixels")) { 234 goto end; /* the error code was recorded */ 235 } 236 237 /* Check read buffer's status (draw buffer was already checked) */ 238 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 239 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 240 "glCopyPixels(incomplete framebuffer)" ); 241 goto end; 242 } 243 244 if (_mesa_is_user_fbo(ctx->ReadBuffer) && 245 ctx->ReadBuffer->Visual.samples > 0) { 246 _mesa_error(ctx, GL_INVALID_OPERATION, 247 "glCopyPixels(multisample FBO)"); 248 goto end; 249 } 250 251 if (!_mesa_source_buffer_exists(ctx, type) || 252 !_mesa_dest_buffer_exists(ctx, type)) { 253 _mesa_error(ctx, GL_INVALID_OPERATION, 254 "glCopyPixels(missing source or dest buffer)"); 255 goto end; 256 } 257 258 if (ctx->RasterDiscard) { 259 goto end; 260 } 261 262 if (!ctx->Current.RasterPosValid || width == 0 || height == 0) { 263 goto end; /* no-op, not an error */ 264 } 265 266 if (ctx->RenderMode == GL_RENDER) { 267 /* Round to satisfy conformance tests (matches SGI's OpenGL) */ 268 if (width > 0 && height > 0) { 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 } 275 else if (ctx->RenderMode == GL_FEEDBACK) { 276 FLUSH_CURRENT( ctx, 0 ); 277 _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN ); 278 _mesa_feedback_vertex( ctx, 279 ctx->Current.RasterPos, 280 ctx->Current.RasterColor, 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 end: 289 _mesa_set_vp_override(ctx, GL_FALSE); 290 291 if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { 292 _mesa_flush(ctx); 293 } 294 } 295 296 297 static void GLAPIENTRY 298 _mesa_Bitmap( GLsizei width, GLsizei height, 299 GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, 300 const GLubyte *bitmap ) 301 { 302 GET_CURRENT_CONTEXT(ctx); 303 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 304 305 if (width < 0 || height < 0) { 306 _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" ); 307 return; 308 } 309 310 if (!ctx->Current.RasterPosValid) { 311 return; /* do nothing */ 312 } 313 314 /* Note: this call does state validation */ 315 if (!_mesa_valid_to_render(ctx, "glBitmap")) { 316 /* the error code was recorded */ 317 return; 318 } 319 320 if (ctx->RasterDiscard) 321 return; 322 323 if (ctx->RenderMode == GL_RENDER) { 324 /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */ 325 if (width > 0 && height > 0) { 326 const GLfloat epsilon = 0.0001F; 327 GLint x = IFLOOR(ctx->Current.RasterPos[0] + epsilon - xorig); 328 GLint y = IFLOOR(ctx->Current.RasterPos[1] + epsilon - yorig); 329 330 if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) { 331 /* unpack from PBO */ 332 if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 333 1, GL_COLOR_INDEX, GL_BITMAP, 334 INT_MAX, (const GLvoid *) bitmap)) { 335 _mesa_error(ctx, GL_INVALID_OPERATION, 336 "glBitmap(invalid PBO access)"); 337 return; 338 } 339 if (_mesa_bufferobj_mapped(ctx->Unpack.BufferObj)) { 340 /* buffer is mapped - that's an error */ 341 _mesa_error(ctx, GL_INVALID_OPERATION, 342 "glBitmap(PBO is mapped)"); 343 return; 344 } 345 } 346 347 ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap ); 348 } 349 } 350 #if _HAVE_FULL_GL 351 else if (ctx->RenderMode == GL_FEEDBACK) { 352 FLUSH_CURRENT(ctx, 0); 353 _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN ); 354 _mesa_feedback_vertex( ctx, 355 ctx->Current.RasterPos, 356 ctx->Current.RasterColor, 357 ctx->Current.RasterTexCoords[0] ); 358 } 359 else { 360 ASSERT(ctx->RenderMode == GL_SELECT); 361 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 362 } 363 #endif 364 365 /* update raster position */ 366 ctx->Current.RasterPos[0] += xmove; 367 ctx->Current.RasterPos[1] += ymove; 368 369 if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { 370 _mesa_flush(ctx); 371 } 372 } 373 374 375 void 376 _mesa_init_drawpix_dispatch(struct _glapi_table *disp) 377 { 378 SET_Bitmap(disp, _mesa_Bitmap); 379 SET_CopyPixels(disp, _mesa_CopyPixels); 380 SET_DrawPixels(disp, _mesa_DrawPixels); 381 } 382 383 384 #endif /* FEATURE_drawpix */ 385