1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25#include "glheader.h" 26#include "draw_validate.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 "pbo.h" 35#include "pixel.h" 36#include "state.h" 37#include "glformats.h" 38#include "fbobject.h" 39#include "util/u_math.h" 40#include "util/rounding.h" 41 42 43/* 44 * Execute glDrawPixels 45 */ 46void GLAPIENTRY 47_mesa_DrawPixels( GLsizei width, GLsizei height, 48 GLenum format, GLenum type, const GLvoid *pixels ) 49{ 50 GLenum err; 51 GET_CURRENT_CONTEXT(ctx); 52 53 FLUSH_VERTICES(ctx, 0, 0); 54 55 if (MESA_VERBOSE & VERBOSE_API) 56 _mesa_debug(ctx, "glDrawPixels(%d, %d, %s, %s, %p) // to %s at %ld, %ld\n", 57 width, height, 58 _mesa_enum_to_string(format), 59 _mesa_enum_to_string(type), 60 pixels, 61 _mesa_enum_to_string(ctx->DrawBuffer->ColorDrawBuffer[0]), 62 lroundf(ctx->Current.RasterPos[0]), 63 lroundf(ctx->Current.RasterPos[1])); 64 65 66 if (width < 0 || height < 0) { 67 _mesa_error( ctx, GL_INVALID_VALUE, "glDrawPixels(width or height < 0)" ); 68 return; 69 } 70 71 /* We're not using the current vertex program, and the driver may install 72 * its own. Note: this may dirty some state. 73 */ 74 _mesa_set_vp_override(ctx, GL_TRUE); 75 76 _mesa_update_pixel(ctx); 77 78 if (ctx->NewState) 79 _mesa_update_state(ctx); 80 81 if (!ctx->DrawPixValid) { 82 _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels"); 83 goto end; 84 } 85 86 /* GL 3.0 introduced a new restriction on glDrawPixels() over what was in 87 * GL_EXT_texture_integer. From section 3.7.4 ("Rasterization of Pixel 88 * Rectangles) on page 151 of the GL 3.0 specification: 89 * 90 * "If format contains integer components, as shown in table 3.6, an 91 * INVALID OPERATION error is generated." 92 * 93 * Since DrawPixels rendering would be merely undefined if not an error (due 94 * to a lack of defined mapping from integer data to gl_Color fragment shader 95 * input), NVIDIA's implementation also just returns this error despite 96 * exposing GL_EXT_texture_integer, just return an error regardless. 97 */ 98 if (_mesa_is_enum_format_integer(format)) { 99 _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels(integer format)"); 100 goto end; 101 } 102 103 err = _mesa_error_check_format_and_type(ctx, format, type); 104 if (err != GL_NO_ERROR) { 105 _mesa_error(ctx, err, "glDrawPixels(invalid format %s and/or type %s)", 106 _mesa_enum_to_string(format), 107 _mesa_enum_to_string(type)); 108 goto end; 109 } 110 111 /* do special format-related checks */ 112 switch (format) { 113 case GL_STENCIL_INDEX: 114 case GL_DEPTH_COMPONENT: 115 case GL_DEPTH_STENCIL_EXT: 116 /* these buffers must exist */ 117 if (!_mesa_dest_buffer_exists(ctx, format)) { 118 _mesa_error(ctx, GL_INVALID_OPERATION, 119 "glDrawPixels(missing dest buffer)"); 120 goto end; 121 } 122 break; 123 case GL_COLOR_INDEX: 124 if (ctx->PixelMaps.ItoR.Size == 0 || 125 ctx->PixelMaps.ItoG.Size == 0 || 126 ctx->PixelMaps.ItoB.Size == 0) { 127 _mesa_error(ctx, GL_INVALID_OPERATION, 128 "glDrawPixels(drawing color index pixels into RGB buffer)"); 129 goto end; 130 } 131 break; 132 default: 133 /* for color formats it's not an error if the destination color 134 * buffer doesn't exist. 135 */ 136 break; 137 } 138 139 if (ctx->RasterDiscard) { 140 goto end; 141 } 142 143 if (!ctx->Current.RasterPosValid) { 144 goto end; /* no-op, not an error */ 145 } 146 147 if (ctx->RenderMode == GL_RENDER) { 148 if (width > 0 && height > 0) { 149 /* Round, to satisfy conformance tests (matches SGI's OpenGL) */ 150 GLint x = lroundf(ctx->Current.RasterPos[0]); 151 GLint y = lroundf(ctx->Current.RasterPos[1]); 152 153 if (ctx->Unpack.BufferObj) { 154 /* unpack from PBO */ 155 if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 156 1, format, type, INT_MAX, pixels)) { 157 _mesa_error(ctx, GL_INVALID_OPERATION, 158 "glDrawPixels(invalid PBO access)"); 159 goto end; 160 } 161 if (_mesa_check_disallowed_mapping(ctx->Unpack.BufferObj)) { 162 /* buffer is mapped - that's an error */ 163 _mesa_error(ctx, GL_INVALID_OPERATION, 164 "glDrawPixels(PBO is mapped)"); 165 goto end; 166 } 167 } 168 169 ctx->Driver.DrawPixels(ctx, x, y, width, height, format, type, 170 &ctx->Unpack, pixels); 171 } 172 } 173 else if (ctx->RenderMode == GL_FEEDBACK) { 174 /* Feedback the current raster pos info */ 175 FLUSH_CURRENT( ctx, 0 ); 176 _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); 177 _mesa_feedback_vertex( ctx, 178 ctx->Current.RasterPos, 179 ctx->Current.RasterColor, 180 ctx->Current.RasterTexCoords[0] ); 181 } 182 else { 183 assert(ctx->RenderMode == GL_SELECT); 184 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 185 } 186 187end: 188 _mesa_set_vp_override(ctx, GL_FALSE); 189 190 if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { 191 _mesa_flush(ctx); 192 } 193} 194 195 196void GLAPIENTRY 197_mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height, 198 GLenum type ) 199{ 200 GET_CURRENT_CONTEXT(ctx); 201 202 FLUSH_VERTICES(ctx, 0, 0); 203 204 if (MESA_VERBOSE & VERBOSE_API) 205 _mesa_debug(ctx, 206 "glCopyPixels(%d, %d, %d, %d, %s) // from %s to %s at %ld, %ld\n", 207 srcx, srcy, width, height, 208 _mesa_enum_to_string(type), 209 _mesa_enum_to_string(ctx->ReadBuffer->ColorReadBuffer), 210 _mesa_enum_to_string(ctx->DrawBuffer->ColorDrawBuffer[0]), 211 lroundf(ctx->Current.RasterPos[0]), 212 lroundf(ctx->Current.RasterPos[1])); 213 214 if (width < 0 || height < 0) { 215 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)"); 216 return; 217 } 218 219 /* Note: more detailed 'type' checking is done by the 220 * _mesa_source/dest_buffer_exists() calls below. That's where we 221 * check if the stencil buffer exists, etc. 222 */ 223 if (type != GL_COLOR && 224 type != GL_DEPTH && 225 type != GL_STENCIL && 226 type != GL_DEPTH_STENCIL && 227 type != GL_DEPTH_STENCIL_TO_RGBA_NV && 228 type != GL_DEPTH_STENCIL_TO_BGRA_NV) { 229 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels(type=%s)", 230 _mesa_enum_to_string(type)); 231 return; 232 } 233 234 /* Return GL_INVALID_ENUM if the relevant extension is not enabled */ 235 if ((type == GL_DEPTH_STENCIL_TO_RGBA_NV || type == GL_DEPTH_STENCIL_TO_BGRA_NV) && 236 !ctx->Extensions.NV_copy_depth_to_color) { 237 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels(type=%s)", 238 _mesa_enum_to_string(type)); 239 return; 240 } 241 242 /* We're not using the current vertex program, and the driver may install 243 * it's own. Note: this may dirty some state. 244 */ 245 _mesa_set_vp_override(ctx, GL_TRUE); 246 247 _mesa_update_pixel(ctx); 248 249 if (ctx->NewState) 250 _mesa_update_state(ctx); 251 252 if (!ctx->DrawPixValid) { 253 _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyPixels"); 254 goto end; 255 } 256 257 /* Check read buffer's status (draw buffer was already checked) */ 258 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 259 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 260 "glCopyPixels(incomplete framebuffer)" ); 261 goto end; 262 } 263 264 if (_mesa_is_user_fbo(ctx->ReadBuffer) && 265 ctx->ReadBuffer->Visual.samples > 0) { 266 _mesa_error(ctx, GL_INVALID_OPERATION, 267 "glCopyPixels(multisample FBO)"); 268 goto end; 269 } 270 271 if (!_mesa_source_buffer_exists(ctx, type) || 272 !_mesa_dest_buffer_exists(ctx, type)) { 273 _mesa_error(ctx, GL_INVALID_OPERATION, 274 "glCopyPixels(missing source or dest buffer)"); 275 goto end; 276 } 277 278 if (ctx->RasterDiscard) { 279 goto end; 280 } 281 282 if (!ctx->Current.RasterPosValid || width == 0 || height == 0) { 283 goto end; /* no-op, not an error */ 284 } 285 286 if (ctx->RenderMode == GL_RENDER) { 287 /* Round to satisfy conformance tests (matches SGI's OpenGL) */ 288 if (width > 0 && height > 0) { 289 GLint destx = lroundf(ctx->Current.RasterPos[0]); 290 GLint desty = lroundf(ctx->Current.RasterPos[1]); 291 ctx->Driver.CopyPixels( ctx, srcx, srcy, width, height, destx, desty, 292 type ); 293 } 294 } 295 else if (ctx->RenderMode == GL_FEEDBACK) { 296 FLUSH_CURRENT( ctx, 0 ); 297 _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN ); 298 _mesa_feedback_vertex( ctx, 299 ctx->Current.RasterPos, 300 ctx->Current.RasterColor, 301 ctx->Current.RasterTexCoords[0] ); 302 } 303 else { 304 assert(ctx->RenderMode == GL_SELECT); 305 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 306 } 307 308end: 309 _mesa_set_vp_override(ctx, GL_FALSE); 310 311 if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { 312 _mesa_flush(ctx); 313 } 314} 315 316 317void GLAPIENTRY 318_mesa_Bitmap( GLsizei width, GLsizei height, 319 GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, 320 const GLubyte *bitmap ) 321{ 322 GET_CURRENT_CONTEXT(ctx); 323 324 FLUSH_VERTICES(ctx, 0, 0); 325 326 if (width < 0 || height < 0) { 327 _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" ); 328 return; 329 } 330 331 if (!ctx->Current.RasterPosValid) { 332 return; /* do nothing */ 333 } 334 335 _mesa_update_pixel(ctx); 336 337 if (ctx->NewState) 338 _mesa_update_state(ctx); 339 340 if (!ctx->DrawPixValid) { 341 _mesa_error(ctx, GL_INVALID_OPERATION, "glBitmap"); 342 return; 343 } 344 345 if (ctx->RasterDiscard) 346 return; 347 348 if (ctx->RenderMode == GL_RENDER) { 349 /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */ 350 if (width > 0 && height > 0) { 351 const GLfloat epsilon = 0.0001F; 352 GLint x = util_ifloor(ctx->Current.RasterPos[0] + epsilon - xorig); 353 GLint y = util_ifloor(ctx->Current.RasterPos[1] + epsilon - yorig); 354 355 if (ctx->Unpack.BufferObj) { 356 /* unpack from PBO */ 357 if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 358 1, GL_COLOR_INDEX, GL_BITMAP, 359 INT_MAX, (const GLvoid *) bitmap)) { 360 _mesa_error(ctx, GL_INVALID_OPERATION, 361 "glBitmap(invalid PBO access)"); 362 return; 363 } 364 if (_mesa_check_disallowed_mapping(ctx->Unpack.BufferObj)) { 365 /* buffer is mapped - that's an error */ 366 _mesa_error(ctx, GL_INVALID_OPERATION, 367 "glBitmap(PBO is mapped)"); 368 return; 369 } 370 } 371 372 ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap ); 373 } 374 } 375 else if (ctx->RenderMode == GL_FEEDBACK) { 376 FLUSH_CURRENT(ctx, 0); 377 _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN ); 378 _mesa_feedback_vertex( ctx, 379 ctx->Current.RasterPos, 380 ctx->Current.RasterColor, 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 388 /* update raster position */ 389 ctx->Current.RasterPos[0] += xmove; 390 ctx->Current.RasterPos[1] += ymove; 391 ctx->PopAttribState |= GL_CURRENT_BIT; 392 393 if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { 394 _mesa_flush(ctx); 395 } 396} 397