drawpix.c revision 2cf44390d1e819f23e1d7ceb3199276c9148c647
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 "readpix.h" 34#include "state.h" 35#include "main/dispatch.h" 36 37 38#if FEATURE_drawpix 39 40 41/** 42 * If a fragment program is enabled, check that it's valid. 43 * \return GL_TRUE if valid, GL_FALSE otherwise 44 */ 45static GLboolean 46valid_fragment_program(GLcontext *ctx) 47{ 48 return !(ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled); 49} 50 51 52/* 53 * Execute glDrawPixels 54 */ 55static void 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 /* We're not using the current vertex program, and the driver may install 68 * it's own. 69 */ 70 _mesa_set_vp_override(ctx, GL_TRUE); 71 72 if (ctx->NewState) { 73 _mesa_update_state(ctx); 74 } 75 76 if (!valid_fragment_program(ctx)) { 77 _mesa_error(ctx, GL_INVALID_OPERATION, 78 "glDrawPixels (invalid fragment program)"); 79 goto end; 80 } 81 82 if (_mesa_error_check_format_type(ctx, format, type, GL_TRUE)) { 83 /* the error was already recorded */ 84 goto end; 85 } 86 87 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 88 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 89 "glDrawPixels(incomplete framebuffer)" ); 90 goto end; 91 } 92 93 if (!ctx->Current.RasterPosValid) { 94 goto end; /* no-op, not an error */ 95 } 96 97 if (ctx->RenderMode == GL_RENDER) { 98 if (width > 0 && height > 0) { 99 /* Round, to satisfy conformance tests (matches SGI's OpenGL) */ 100 GLint x = IROUND(ctx->Current.RasterPos[0]); 101 GLint y = IROUND(ctx->Current.RasterPos[1]); 102 103 if (ctx->Unpack.BufferObj->Name) { 104 /* unpack from PBO */ 105 if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 1, 106 format, type, pixels)) { 107 _mesa_error(ctx, GL_INVALID_OPERATION, 108 "glDrawPixels(invalid PBO access)"); 109 goto end; 110 } 111 if (_mesa_bufferobj_mapped(ctx->Unpack.BufferObj)) { 112 /* buffer is mapped - that's an error */ 113 _mesa_error(ctx, GL_INVALID_OPERATION, 114 "glDrawPixels(PBO is mapped)"); 115 goto end; 116 } 117 } 118 119 ctx->Driver.DrawPixels(ctx, x, y, width, height, format, type, 120 &ctx->Unpack, pixels); 121 } 122 } 123 else if (ctx->RenderMode == GL_FEEDBACK) { 124 /* Feedback the current raster pos info */ 125 FLUSH_CURRENT( ctx, 0 ); 126 _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); 127 _mesa_feedback_vertex( ctx, 128 ctx->Current.RasterPos, 129 ctx->Current.RasterColor, 130 ctx->Current.RasterIndex, 131 ctx->Current.RasterTexCoords[0] ); 132 } 133 else { 134 ASSERT(ctx->RenderMode == GL_SELECT); 135 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 136 } 137 138end: 139 _mesa_set_vp_override(ctx, GL_FALSE); 140} 141 142 143static void GLAPIENTRY 144_mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height, 145 GLenum type ) 146{ 147 GET_CURRENT_CONTEXT(ctx); 148 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 149 150 if (width < 0 || height < 0) { 151 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)"); 152 return; 153 } 154 155 /* Note: more detailed 'type' checking is done by the 156 * _mesa_source/dest_buffer_exists() calls below. That's where we 157 * check if the stencil buffer exists, etc. 158 */ 159 if (type != GL_COLOR && 160 type != GL_DEPTH && 161 type != GL_STENCIL && 162 type != GL_DEPTH_STENCIL) { 163 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels(type=%s)", 164 _mesa_lookup_enum_by_nr(type)); 165 return; 166 } 167 168 /* We're not using the current vertex program, and the driver may install 169 * it's own. 170 */ 171 _mesa_set_vp_override(ctx, GL_TRUE); 172 173 if (ctx->NewState) { 174 _mesa_update_state(ctx); 175 } 176 177 if (!valid_fragment_program(ctx)) { 178 _mesa_error(ctx, GL_INVALID_OPERATION, 179 "glCopyPixels (invalid fragment program)"); 180 goto end; 181 } 182 183 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT || 184 ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 185 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 186 "glCopyPixels(incomplete framebuffer)" ); 187 goto end; 188 } 189 190 if (!_mesa_source_buffer_exists(ctx, type) || 191 !_mesa_dest_buffer_exists(ctx, type)) { 192 _mesa_error(ctx, GL_INVALID_OPERATION, 193 "glCopyPixels(missing source or dest buffer)"); 194 goto end; 195 } 196 197 if (!ctx->Current.RasterPosValid || width ==0 || height == 0) { 198 goto end; /* no-op, not an error */ 199 } 200 201 if (ctx->RenderMode == GL_RENDER) { 202 /* Round to satisfy conformance tests (matches SGI's OpenGL) */ 203 if (width > 0 && height > 0) { 204 GLint destx = IROUND(ctx->Current.RasterPos[0]); 205 GLint desty = IROUND(ctx->Current.RasterPos[1]); 206 ctx->Driver.CopyPixels( ctx, srcx, srcy, width, height, destx, desty, 207 type ); 208 } 209 } 210 else if (ctx->RenderMode == GL_FEEDBACK) { 211 FLUSH_CURRENT( ctx, 0 ); 212 _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN ); 213 _mesa_feedback_vertex( ctx, 214 ctx->Current.RasterPos, 215 ctx->Current.RasterColor, 216 ctx->Current.RasterIndex, 217 ctx->Current.RasterTexCoords[0] ); 218 } 219 else { 220 ASSERT(ctx->RenderMode == GL_SELECT); 221 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 222 } 223 224end: 225 _mesa_set_vp_override(ctx, GL_FALSE); 226} 227 228 229static void GLAPIENTRY 230_mesa_Bitmap( GLsizei width, GLsizei height, 231 GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, 232 const GLubyte *bitmap ) 233{ 234 GET_CURRENT_CONTEXT(ctx); 235 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 236 237 if (width < 0 || height < 0) { 238 _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" ); 239 return; 240 } 241 242 if (!ctx->Current.RasterPosValid) { 243 return; /* do nothing */ 244 } 245 246 if (ctx->NewState) { 247 _mesa_update_state(ctx); 248 } 249 250 if (!valid_fragment_program(ctx)) { 251 _mesa_error(ctx, GL_INVALID_OPERATION, 252 "glBitmap (invalid fragment program)"); 253 return; 254 } 255 256 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 257 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 258 "glBitmap(incomplete framebuffer)"); 259 return; 260 } 261 262 if (ctx->RenderMode == GL_RENDER) { 263 /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */ 264 if (width > 0 && height > 0) { 265 const GLfloat epsilon = 0.0001F; 266 GLint x = IFLOOR(ctx->Current.RasterPos[0] + epsilon - xorig); 267 GLint y = IFLOOR(ctx->Current.RasterPos[1] + epsilon - yorig); 268 269 if (ctx->Unpack.BufferObj->Name) { 270 /* unpack from PBO */ 271 if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 1, 272 GL_COLOR_INDEX, GL_BITMAP, 273 (GLvoid *) bitmap)) { 274 _mesa_error(ctx, GL_INVALID_OPERATION, 275 "glBitmap(invalid PBO access)"); 276 return; 277 } 278 if (_mesa_bufferobj_mapped(ctx->Unpack.BufferObj)) { 279 /* buffer is mapped - that's an error */ 280 _mesa_error(ctx, GL_INVALID_OPERATION, 281 "glBitmap(PBO is mapped)"); 282 return; 283 } 284 } 285 286 ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap ); 287 } 288 } 289#if _HAVE_FULL_GL 290 else if (ctx->RenderMode == GL_FEEDBACK) { 291 FLUSH_CURRENT(ctx, 0); 292 _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN ); 293 _mesa_feedback_vertex( ctx, 294 ctx->Current.RasterPos, 295 ctx->Current.RasterColor, 296 ctx->Current.RasterIndex, 297 ctx->Current.RasterTexCoords[0] ); 298 } 299 else { 300 ASSERT(ctx->RenderMode == GL_SELECT); 301 /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ 302 } 303#endif 304 305 /* update raster position */ 306 ctx->Current.RasterPos[0] += xmove; 307 ctx->Current.RasterPos[1] += ymove; 308} 309 310 311void 312_mesa_init_drawpix_dispatch(struct _glapi_table *disp) 313{ 314 SET_Bitmap(disp, _mesa_Bitmap); 315 SET_CopyPixels(disp, _mesa_CopyPixels); 316 SET_DrawPixels(disp, _mesa_DrawPixels); 317} 318 319 320#endif /* FEATURE_drawpix */ 321