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