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