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