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 "imports.h" 27#include "draw_validate.h" 28#include "bufferobj.h" 29#include "context.h" 30#include "drawpix.h" 31#include "enums.h" 32#include "feedback.h" 33#include "framebuffer.h" 34#include "image.h" 35#include "pbo.h" 36#include "state.h" 37#include "glformats.h" 38#include "fbobject.h" 39 40 41/* 42 * Execute glDrawPixels 43 */ 44void GLAPIENTRY 45_mesa_DrawPixels( GLsizei width, GLsizei height, 46 GLenum format, GLenum type, const GLvoid *pixels ) 47{ 48 GLenum err; 49 GET_CURRENT_CONTEXT(ctx); 50 51 FLUSH_VERTICES(ctx, 0); 52 53 if (MESA_VERBOSE & VERBOSE_API) 54 _mesa_debug(ctx, "glDrawPixels(%d, %d, %s, %s, %p) // to %s at %d, %d\n", 55 width, height, 56 _mesa_enum_to_string(format), 57 _mesa_enum_to_string(type), 58 pixels, 59 _mesa_enum_to_string(ctx->DrawBuffer->ColorDrawBuffer[0]), 60 IROUND(ctx->Current.RasterPos[0]), 61 IROUND(ctx->Current.RasterPos[1])); 62 63 64 if (width < 0 || height < 0) { 65 _mesa_error( ctx, GL_INVALID_VALUE, "glDrawPixels(width or height < 0)" ); 66 return; 67 } 68 69 /* We're not using the current vertex program, and the driver may install 70 * its own. Note: this may dirty some state. 71 */ 72 _mesa_set_vp_override(ctx, GL_TRUE); 73 74 /* Note: this call does state validation */ 75 if (!_mesa_valid_to_render(ctx, "glDrawPixels")) { 76 goto end; /* the error code was recorded */ 77 } 78 79 /* GL 3.0 introduced a new restriction on glDrawPixels() over what was in 80 * GL_EXT_texture_integer. From section 3.7.4 ("Rasterization of Pixel 81 * Rectangles) on page 151 of the GL 3.0 specification: 82 * 83 * "If format contains integer components, as shown in table 3.6, an 84 * INVALID OPERATION error is generated." 85 * 86 * Since DrawPixels rendering would be merely undefined if not an error (due 87 * to a lack of defined mapping from integer data to gl_Color fragment shader 88 * input), NVIDIA's implementation also just returns this error despite 89 * exposing GL_EXT_texture_integer, just return an error regardless. 90 */ 91 if (_mesa_is_enum_format_integer(format)) { 92 _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels(integer format)"); 93 goto end; 94 } 95 96 err = _mesa_error_check_format_and_type(ctx, format, type); 97 if (err != GL_NO_ERROR) { 98 _mesa_error(ctx, err, "glDrawPixels(invalid format %s and/or type %s)", 99 _mesa_enum_to_string(format), 100 _mesa_enum_to_string(type)); 101 goto end; 102 } 103 104 /* do special format-related checks */ 105 switch (format) { 106 case GL_STENCIL_INDEX: 107 case GL_DEPTH_COMPONENT: 108 case GL_DEPTH_STENCIL_EXT: 109 /* these buffers must exist */ 110 if (!_mesa_dest_buffer_exists(ctx, format)) { 111 _mesa_error(ctx, GL_INVALID_OPERATION, 112 "glDrawPixels(missing dest buffer)"); 113 goto end; 114 } 115 break; 116 case GL_COLOR_INDEX: 117 if (ctx->PixelMaps.ItoR.Size == 0 || 118 ctx->PixelMaps.ItoG.Size == 0 || 119 ctx->PixelMaps.ItoB.Size == 0) { 120 _mesa_error(ctx, GL_INVALID_OPERATION, 121 "glDrawPixels(drawing color index pixels into RGB buffer)"); 122 goto end; 123 } 124 break; 125 default: 126 /* for color formats it's not an error if the destination color 127 * buffer doesn't exist. 128 */ 129 break; 130 } 131 132 if (ctx->RasterDiscard) { 133 goto end; 134 } 135 136 if (!ctx->Current.RasterPosValid) { 137 goto end; /* no-op, not an error */ 138 } 139 140 if (ctx->RenderMode == GL_RENDER) { 141 if (width > 0 && height > 0) { 142 /* Round, to satisfy conformance tests (matches SGI's OpenGL) */ 143 GLint x = IROUND(ctx->Current.RasterPos[0]); 144 GLint y = IROUND(ctx->Current.RasterPos[1]); 145 146 if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) { 147 /* unpack from PBO */ 148 if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 149 1, format, type, INT_MAX, pixels)) { 150 _mesa_error(ctx, GL_INVALID_OPERATION, 151 "glDrawPixels(invalid PBO access)"); 152 goto end; 153 } 154 if (_mesa_check_disallowed_mapping(ctx->Unpack.BufferObj)) { 155 /* buffer is mapped - that's an error */ 156 _mesa_error(ctx, GL_INVALID_OPERATION, 157 "glDrawPixels(PBO is mapped)"); 158 goto end; 159 } 160 } 161 162 ctx->Driver.DrawPixels(ctx, x, y, width, height, format, type, 163 &ctx->Unpack, pixels); 164 } 165 } 166 else if (ctx->RenderMode == GL_FEEDBACK) { 167 /* Feedback the current raster pos info */ 168 FLUSH_CURRENT( ctx, 0 ); 169 _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); 170 _mesa_feedback_vertex( ctx, 171 ctx->Current.RasterPos, 172 ctx->Current.RasterColor, 173 ctx->Current.RasterTexCoords[0] ); 174 } 175 else { 176 assert(ctx->RenderMode == GL_SELECT); 177 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 178 } 179 180end: 181 _mesa_set_vp_override(ctx, GL_FALSE); 182 183 if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { 184 _mesa_flush(ctx); 185 } 186} 187 188 189void GLAPIENTRY 190_mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height, 191 GLenum type ) 192{ 193 GET_CURRENT_CONTEXT(ctx); 194 195 FLUSH_VERTICES(ctx, 0); 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_enum_to_string(type), 202 _mesa_enum_to_string(ctx->ReadBuffer->ColorReadBuffer), 203 _mesa_enum_to_string(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_enum_to_string(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 (_mesa_is_user_fbo(ctx->ReadBuffer) && 243 ctx->ReadBuffer->Visual.samples > 0) { 244 _mesa_error(ctx, GL_INVALID_OPERATION, 245 "glCopyPixels(multisample FBO)"); 246 goto end; 247 } 248 249 if (!_mesa_source_buffer_exists(ctx, type) || 250 !_mesa_dest_buffer_exists(ctx, type)) { 251 _mesa_error(ctx, GL_INVALID_OPERATION, 252 "glCopyPixels(missing source or dest buffer)"); 253 goto end; 254 } 255 256 if (ctx->RasterDiscard) { 257 goto end; 258 } 259 260 if (!ctx->Current.RasterPosValid || width == 0 || height == 0) { 261 goto end; /* no-op, not an error */ 262 } 263 264 if (ctx->RenderMode == GL_RENDER) { 265 /* Round to satisfy conformance tests (matches SGI's OpenGL) */ 266 if (width > 0 && height > 0) { 267 GLint destx = IROUND(ctx->Current.RasterPos[0]); 268 GLint desty = IROUND(ctx->Current.RasterPos[1]); 269 ctx->Driver.CopyPixels( ctx, srcx, srcy, width, height, destx, desty, 270 type ); 271 } 272 } 273 else if (ctx->RenderMode == GL_FEEDBACK) { 274 FLUSH_CURRENT( ctx, 0 ); 275 _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN ); 276 _mesa_feedback_vertex( ctx, 277 ctx->Current.RasterPos, 278 ctx->Current.RasterColor, 279 ctx->Current.RasterTexCoords[0] ); 280 } 281 else { 282 assert(ctx->RenderMode == GL_SELECT); 283 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 284 } 285 286end: 287 _mesa_set_vp_override(ctx, GL_FALSE); 288 289 if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { 290 _mesa_flush(ctx); 291 } 292} 293 294 295void GLAPIENTRY 296_mesa_Bitmap( GLsizei width, GLsizei height, 297 GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, 298 const GLubyte *bitmap ) 299{ 300 GET_CURRENT_CONTEXT(ctx); 301 302 FLUSH_VERTICES(ctx, 0); 303 304 if (width < 0 || height < 0) { 305 _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" ); 306 return; 307 } 308 309 if (!ctx->Current.RasterPosValid) { 310 return; /* do nothing */ 311 } 312 313 /* Note: this call does state validation */ 314 if (!_mesa_valid_to_render(ctx, "glBitmap")) { 315 /* the error code was recorded */ 316 return; 317 } 318 319 if (ctx->RasterDiscard) 320 return; 321 322 if (ctx->RenderMode == GL_RENDER) { 323 /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */ 324 if (width > 0 && height > 0) { 325 const GLfloat epsilon = 0.0001F; 326 GLint x = IFLOOR(ctx->Current.RasterPos[0] + epsilon - xorig); 327 GLint y = IFLOOR(ctx->Current.RasterPos[1] + epsilon - yorig); 328 329 if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) { 330 /* unpack from PBO */ 331 if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 332 1, GL_COLOR_INDEX, GL_BITMAP, 333 INT_MAX, (const GLvoid *) bitmap)) { 334 _mesa_error(ctx, GL_INVALID_OPERATION, 335 "glBitmap(invalid PBO access)"); 336 return; 337 } 338 if (_mesa_check_disallowed_mapping(ctx->Unpack.BufferObj)) { 339 /* buffer is mapped - that's an error */ 340 _mesa_error(ctx, GL_INVALID_OPERATION, 341 "glBitmap(PBO is mapped)"); 342 return; 343 } 344 } 345 346 ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap ); 347 } 348 } 349 else if (ctx->RenderMode == GL_FEEDBACK) { 350 FLUSH_CURRENT(ctx, 0); 351 _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN ); 352 _mesa_feedback_vertex( ctx, 353 ctx->Current.RasterPos, 354 ctx->Current.RasterColor, 355 ctx->Current.RasterTexCoords[0] ); 356 } 357 else { 358 assert(ctx->RenderMode == GL_SELECT); 359 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 360 } 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