drawpix.c revision 7bf6efe78066b33c4ddd278d78ea44cfd12154cc
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 "readpix.h" 35#include "state.h" 36 37 38 39/** 40 * If a fragment program is enabled, check that it's valid. 41 * \return GL_TRUE if valid, GL_FALSE otherwise 42 */ 43static GLboolean 44valid_fragment_program(GLcontext *ctx) 45{ 46 return !(ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled); 47} 48 49 50#if _HAVE_FULL_GL 51 52/* 53 * Execute glDrawPixels 54 */ 55void GLAPIENTRY 56_mesa_DrawPixels( GLsizei width, GLsizei height, 57 GLenum format, GLenum type, const GLvoid *pixels ) 58{ 59 GET_CURRENT_CONTEXT(ctx); 60 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 61 62 if (width < 0 || height < 0) { 63 _mesa_error( ctx, GL_INVALID_VALUE, "glDrawPixels(width or height < 0" ); 64 return; 65 } 66 67 if (ctx->NewState) { 68 _mesa_update_state(ctx); 69 } 70 71 if (!valid_fragment_program(ctx)) { 72 _mesa_error(ctx, GL_INVALID_OPERATION, 73 "glDrawPixels (invalid fragment program)"); 74 return; 75 } 76 77 if (_mesa_error_check_format_type(ctx, format, type, GL_TRUE)) { 78 /* the error was already recorded */ 79 return; 80 } 81 82 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 83 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 84 "glDrawPixels(incomplete framebuffer)" ); 85 return; 86 } 87 88 if (!ctx->Current.RasterPosValid) { 89 return; /* no-op, not an error */ 90 } 91 92 if (ctx->RenderMode == GL_RENDER) { 93 if (width > 0 && height > 0) { 94 /* Round, to satisfy conformance tests (matches SGI's OpenGL) */ 95 GLint x = IROUND(ctx->Current.RasterPos[0]); 96 GLint y = IROUND(ctx->Current.RasterPos[1]); 97 98 if (ctx->Unpack.BufferObj->Name) { 99 /* unpack from PBO */ 100 if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 1, 101 format, type, pixels)) { 102 _mesa_error(ctx, GL_INVALID_OPERATION, 103 "glDrawPixels(invalid PBO access)"); 104 return; 105 } 106 if (_mesa_bufferobj_mapped(ctx->Unpack.BufferObj)) { 107 /* buffer is mapped - that's an error */ 108 _mesa_error(ctx, GL_INVALID_OPERATION, 109 "glDrawPixels(PBO is mapped)"); 110 return; 111 } 112 } 113 114 ctx->Driver.DrawPixels(ctx, x, y, width, height, format, type, 115 &ctx->Unpack, pixels); 116 } 117 } 118 else if (ctx->RenderMode == GL_FEEDBACK) { 119 /* Feedback the current raster pos info */ 120 FLUSH_CURRENT( ctx, 0 ); 121 _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); 122 _mesa_feedback_vertex( ctx, 123 ctx->Current.RasterPos, 124 ctx->Current.RasterColor, 125 ctx->Current.RasterIndex, 126 ctx->Current.RasterTexCoords[0] ); 127 } 128 else { 129 ASSERT(ctx->RenderMode == GL_SELECT); 130 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 131 } 132} 133 134 135void GLAPIENTRY 136_mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height, 137 GLenum type ) 138{ 139 GET_CURRENT_CONTEXT(ctx); 140 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 141 142 if (width < 0 || height < 0) { 143 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)"); 144 return; 145 } 146 147 if (type != GL_COLOR && type != GL_DEPTH && type != GL_STENCIL) { 148 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels(type=%s)", 149 _mesa_lookup_enum_by_nr(type)); 150 return; 151 } 152 153 if (ctx->NewState) { 154 _mesa_update_state(ctx); 155 } 156 157 if (!valid_fragment_program(ctx)) { 158 _mesa_error(ctx, GL_INVALID_OPERATION, 159 "glCopyPixels (invalid fragment program)"); 160 return; 161 } 162 163 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT || 164 ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 165 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 166 "glCopyPixels(incomplete framebuffer)" ); 167 return; 168 } 169 170 if (!_mesa_source_buffer_exists(ctx, type) || 171 !_mesa_dest_buffer_exists(ctx, type)) { 172 _mesa_error(ctx, GL_INVALID_OPERATION, 173 "glCopyPixels(missing source or dest buffer)"); 174 return; 175 } 176 177 if (!ctx->Current.RasterPosValid || width ==0 || height == 0) { 178 return; /* no-op, not an error */ 179 } 180 181 if (ctx->RenderMode == GL_RENDER) { 182 /* Round to satisfy conformance tests (matches SGI's OpenGL) */ 183 if (width > 0 && height > 0) { 184 GLint destx = IROUND(ctx->Current.RasterPos[0]); 185 GLint desty = IROUND(ctx->Current.RasterPos[1]); 186 ctx->Driver.CopyPixels( ctx, srcx, srcy, width, height, destx, desty, 187 type ); 188 } 189 } 190 else if (ctx->RenderMode == GL_FEEDBACK) { 191 FLUSH_CURRENT( ctx, 0 ); 192 _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_COPY_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#endif /* _HAVE_FULL_GL */ 206 207 208 209void GLAPIENTRY 210_mesa_Bitmap( GLsizei width, GLsizei height, 211 GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, 212 const GLubyte *bitmap ) 213{ 214 GET_CURRENT_CONTEXT(ctx); 215 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 216 217 if (width < 0 || height < 0) { 218 _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" ); 219 return; 220 } 221 222 if (!ctx->Current.RasterPosValid) { 223 return; /* do nothing */ 224 } 225 226 if (ctx->NewState) { 227 _mesa_update_state(ctx); 228 } 229 230 if (!valid_fragment_program(ctx)) { 231 _mesa_error(ctx, GL_INVALID_OPERATION, 232 "glBitmap (invalid fragment program)"); 233 return; 234 } 235 236 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 237 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 238 "glBitmap(incomplete framebuffer)"); 239 return; 240 } 241 242 if (ctx->RenderMode == GL_RENDER) { 243 /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */ 244 const GLfloat epsilon = 0.0001F; 245 GLint x = IFLOOR(ctx->Current.RasterPos[0] + epsilon - xorig); 246 GLint y = IFLOOR(ctx->Current.RasterPos[1] + epsilon - yorig); 247 248 if (ctx->Unpack.BufferObj->Name) { 249 /* unpack from PBO */ 250 if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 1, 251 GL_COLOR_INDEX, GL_BITMAP, 252 (GLvoid *) bitmap)) { 253 _mesa_error(ctx, GL_INVALID_OPERATION, 254 "glBitmap(invalid PBO access)"); 255 return; 256 } 257 if (_mesa_bufferobj_mapped(ctx->Unpack.BufferObj)) { 258 /* buffer is mapped - that's an error */ 259 _mesa_error(ctx, GL_INVALID_OPERATION, "glBitmap(PBO is mapped)"); 260 return; 261 } 262 } 263 264 ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap ); 265 } 266#if _HAVE_FULL_GL 267 else if (ctx->RenderMode == GL_FEEDBACK) { 268 FLUSH_CURRENT(ctx, 0); 269 _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN ); 270 _mesa_feedback_vertex( ctx, 271 ctx->Current.RasterPos, 272 ctx->Current.RasterColor, 273 ctx->Current.RasterIndex, 274 ctx->Current.RasterTexCoords[0] ); 275 } 276 else { 277 ASSERT(ctx->RenderMode == GL_SELECT); 278 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 279 } 280#endif 281 282 /* update raster position */ 283 ctx->Current.RasterPos[0] += xmove; 284 ctx->Current.RasterPos[1] += ymove; 285} 286 287 288 289#if 0 /* experimental */ 290/* 291 * Execute glDrawDepthPixelsMESA(). This function accepts both a color 292 * image and depth (Z) image. Rasterization produces fragments with 293 * color and Z taken from these images. This function is intended for 294 * Z-compositing. Normally, this operation requires two glDrawPixels 295 * calls with stencil testing. 296 */ 297void GLAPIENTRY 298_mesa_DrawDepthPixelsMESA( GLsizei width, GLsizei height, 299 GLenum colorFormat, GLenum colorType, 300 const GLvoid *colors, 301 GLenum depthType, const GLvoid *depths ) 302{ 303 GET_CURRENT_CONTEXT(ctx); 304 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 305 306 if (width < 0 || height < 0) { 307 _mesa_error( ctx, GL_INVALID_VALUE, 308 "glDrawDepthPixelsMESA(width or height < 0" ); 309 return; 310 } 311 312 if (!ctx->Current.RasterPosValid) { 313 return; 314 } 315 316 if (ctx->NewState) { 317 _mesa_update_state(ctx); 318 } 319 320 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 321 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 322 "glDrawDepthPixelsMESA(incomplete framebuffer)"); 323 return; 324 } 325 326 if (ctx->RenderMode == GL_RENDER) { 327 /* Round, to satisfy conformance tests (matches SGI's OpenGL) */ 328 GLint x = IROUND(ctx->Current.RasterPos[0]); 329 GLint y = IROUND(ctx->Current.RasterPos[1]); 330 ctx->Driver.DrawDepthPixelsMESA(ctx, x, y, width, height, 331 colorFormat, colorType, colors, 332 depthType, depths, &ctx->Unpack); 333 } 334 else if (ctx->RenderMode == GL_FEEDBACK) { 335 /* Feedback the current raster pos info */ 336 FLUSH_CURRENT( ctx, 0 ); 337 _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); 338 _mesa_feedback_vertex( ctx, 339 ctx->Current.RasterPos, 340 ctx->Current.RasterColor, 341 ctx->Current.RasterIndex, 342 ctx->Current.RasterTexCoords[0] ); 343 } 344 else { 345 ASSERT(ctx->RenderMode == GL_SELECT); 346 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 347 } 348} 349 350#endif 351