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