clear.c revision cdc920a0
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.1 4 * 5 * Copyright (C) 1999-2007 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 26/** 27 * \file clear.c 28 * glClearColor, glClearIndex, glClear() functions. 29 */ 30 31 32 33#include "glheader.h" 34#include "clear.h" 35#include "context.h" 36#include "colormac.h" 37#include "enums.h" 38#include "state.h" 39 40 41 42#if _HAVE_FULL_GL 43void GLAPIENTRY 44_mesa_ClearIndex( GLfloat c ) 45{ 46 GET_CURRENT_CONTEXT(ctx); 47 ASSERT_OUTSIDE_BEGIN_END(ctx); 48 49 if (ctx->Color.ClearIndex == (GLuint) c) 50 return; 51 52 FLUSH_VERTICES(ctx, _NEW_COLOR); 53 ctx->Color.ClearIndex = (GLuint) c; 54} 55#endif 56 57 58/** 59 * Specify the clear values for the color buffers. 60 * 61 * \param red red color component. 62 * \param green green color component. 63 * \param blue blue color component. 64 * \param alpha alpha component. 65 * 66 * \sa glClearColor(). 67 * 68 * Clamps the parameters and updates gl_colorbuffer_attrib::ClearColor. On a 69 * change, flushes the vertices and notifies the driver via the 70 * dd_function_table::ClearColor callback. 71 */ 72void GLAPIENTRY 73_mesa_ClearColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) 74{ 75 GLfloat tmp[4]; 76 GET_CURRENT_CONTEXT(ctx); 77 ASSERT_OUTSIDE_BEGIN_END(ctx); 78 79 tmp[0] = CLAMP(red, 0.0F, 1.0F); 80 tmp[1] = CLAMP(green, 0.0F, 1.0F); 81 tmp[2] = CLAMP(blue, 0.0F, 1.0F); 82 tmp[3] = CLAMP(alpha, 0.0F, 1.0F); 83 84 if (TEST_EQ_4V(tmp, ctx->Color.ClearColor)) 85 return; /* no change */ 86 87 FLUSH_VERTICES(ctx, _NEW_COLOR); 88 COPY_4V(ctx->Color.ClearColor, tmp); 89 90 if (ctx->Driver.ClearColor) { 91 /* it's OK to call glClearColor in CI mode but it should be a NOP */ 92 (*ctx->Driver.ClearColor)(ctx, ctx->Color.ClearColor); 93 } 94} 95 96 97/** 98 * Clear buffers. 99 * 100 * \param mask bit-mask indicating the buffers to be cleared. 101 * 102 * Flushes the vertices and verifies the parameter. If __GLcontextRec::NewState 103 * is set then calls _mesa_update_state() to update gl_frame_buffer::_Xmin, 104 * etc. If the rasterization mode is set to GL_RENDER then requests the driver 105 * to clear the buffers, via the dd_function_table::Clear callback. 106 */ 107void GLAPIENTRY 108_mesa_Clear( GLbitfield mask ) 109{ 110 GET_CURRENT_CONTEXT(ctx); 111 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 112 113 FLUSH_CURRENT(ctx, 0); 114 115 if (MESA_VERBOSE & VERBOSE_API) 116 _mesa_debug(ctx, "glClear 0x%x\n", mask); 117 118 if (mask & ~(GL_COLOR_BUFFER_BIT | 119 GL_DEPTH_BUFFER_BIT | 120 GL_STENCIL_BUFFER_BIT | 121 GL_ACCUM_BUFFER_BIT)) { 122 /* invalid bit set */ 123 _mesa_error( ctx, GL_INVALID_VALUE, "glClear(0x%x)", mask); 124 return; 125 } 126 127 if (ctx->NewState) { 128 _mesa_update_state( ctx ); /* update _Xmin, etc */ 129 } 130 131 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 132 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 133 "glClear(incomplete framebuffer)"); 134 return; 135 } 136 137 if (ctx->DrawBuffer->Width == 0 || ctx->DrawBuffer->Height == 0 || 138 ctx->DrawBuffer->_Xmin >= ctx->DrawBuffer->_Xmax || 139 ctx->DrawBuffer->_Ymin >= ctx->DrawBuffer->_Ymax) 140 return; 141 142 if (ctx->RenderMode == GL_RENDER) { 143 GLbitfield bufferMask; 144 145 /* don't clear depth buffer if depth writing disabled */ 146 if (!ctx->Depth.Mask) 147 mask &= ~GL_DEPTH_BUFFER_BIT; 148 149 /* Build the bitmask to send to device driver's Clear function. 150 * Note that the GL_COLOR_BUFFER_BIT flag will expand to 0, 1, 2 or 4 151 * of the BUFFER_BIT_FRONT/BACK_LEFT/RIGHT flags, or one of the 152 * BUFFER_BIT_COLORn flags. 153 */ 154 bufferMask = 0; 155 if (mask & GL_COLOR_BUFFER_BIT) { 156 GLuint i; 157 for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) { 158 bufferMask |= (1 << ctx->DrawBuffer->_ColorDrawBufferIndexes[i]); 159 } 160 } 161 162 if ((mask & GL_DEPTH_BUFFER_BIT) 163 && ctx->DrawBuffer->Visual.haveDepthBuffer) { 164 bufferMask |= BUFFER_BIT_DEPTH; 165 } 166 167 if ((mask & GL_STENCIL_BUFFER_BIT) 168 && ctx->DrawBuffer->Visual.haveStencilBuffer) { 169 bufferMask |= BUFFER_BIT_STENCIL; 170 } 171 172 if ((mask & GL_ACCUM_BUFFER_BIT) 173 && ctx->DrawBuffer->Visual.haveAccumBuffer) { 174 bufferMask |= BUFFER_BIT_ACCUM; 175 } 176 177 ASSERT(ctx->Driver.Clear); 178 ctx->Driver.Clear(ctx, bufferMask); 179 } 180} 181 182 183/** Returned by make_color_buffer_mask() for errors */ 184#define INVALID_MASK ~0x0 185 186 187/** 188 * Convert the glClearBuffer 'drawbuffer' parameter into a bitmask of 189 * BUFFER_BIT_x values. 190 * Return INVALID_MASK if the drawbuffer value is invalid. 191 */ 192static GLbitfield 193make_color_buffer_mask(GLcontext *ctx, GLint drawbuffer) 194{ 195 const struct gl_renderbuffer_attachment *att = ctx->DrawBuffer->Attachment; 196 GLbitfield mask = 0x0; 197 198 switch (drawbuffer) { 199 case GL_FRONT: 200 if (att[BUFFER_FRONT_LEFT].Renderbuffer) 201 mask |= BUFFER_BIT_FRONT_LEFT; 202 if (att[BUFFER_FRONT_RIGHT].Renderbuffer) 203 mask |= BUFFER_BIT_FRONT_RIGHT; 204 break; 205 case GL_BACK: 206 if (att[BUFFER_BACK_LEFT].Renderbuffer) 207 mask |= BUFFER_BIT_BACK_LEFT; 208 if (att[BUFFER_BACK_RIGHT].Renderbuffer) 209 mask |= BUFFER_BIT_BACK_RIGHT; 210 break; 211 case GL_LEFT: 212 if (att[BUFFER_FRONT_LEFT].Renderbuffer) 213 mask |= BUFFER_BIT_FRONT_LEFT; 214 if (att[BUFFER_BACK_LEFT].Renderbuffer) 215 mask |= BUFFER_BIT_BACK_LEFT; 216 break; 217 case GL_RIGHT: 218 if (att[BUFFER_FRONT_RIGHT].Renderbuffer) 219 mask |= BUFFER_BIT_FRONT_RIGHT; 220 if (att[BUFFER_BACK_RIGHT].Renderbuffer) 221 mask |= BUFFER_BIT_BACK_RIGHT; 222 break; 223 case GL_FRONT_AND_BACK: 224 if (att[BUFFER_FRONT_LEFT].Renderbuffer) 225 mask |= BUFFER_BIT_FRONT_LEFT; 226 if (att[BUFFER_BACK_LEFT].Renderbuffer) 227 mask |= BUFFER_BIT_BACK_LEFT; 228 if (att[BUFFER_FRONT_RIGHT].Renderbuffer) 229 mask |= BUFFER_BIT_FRONT_RIGHT; 230 if (att[BUFFER_BACK_RIGHT].Renderbuffer) 231 mask |= BUFFER_BIT_BACK_RIGHT; 232 break; 233 default: 234 if (drawbuffer < 0 || drawbuffer >= (GLint)ctx->Const.MaxDrawBuffers) { 235 mask = INVALID_MASK; 236 } 237 else if (att[BUFFER_COLOR0 + drawbuffer].Renderbuffer) { 238 mask |= (BUFFER_BIT_COLOR0 << drawbuffer); 239 } 240 } 241 242 return mask; 243} 244 245 246 247/** 248 * New in GL 3.0 249 * Clear signed integer color buffer or stencil buffer (not depth). 250 */ 251void GLAPIENTRY 252_mesa_ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *value) 253{ 254 GET_CURRENT_CONTEXT(ctx); 255 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 256 257 FLUSH_CURRENT(ctx, 0); 258 259 if (ctx->NewState) { 260 _mesa_update_state( ctx ); 261 } 262 263 switch (buffer) { 264 case GL_STENCIL: 265 if (drawbuffer != 0) { 266 _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferiv(drawbuffer=%d)", 267 drawbuffer); 268 return; 269 } 270 else { 271 /* Save current stencil clear value, set to 'value', do the 272 * stencil clear and restore the clear value. 273 * XXX in the future we may have a new ctx->Driver.ClearBuffer() 274 * hook instead. 275 */ 276 const GLuint clearSave = ctx->Stencil.Clear; 277 ctx->Stencil.Clear = *value; 278 if (ctx->Driver.ClearStencil) 279 ctx->Driver.ClearStencil(ctx, *value); 280 ctx->Driver.Clear(ctx, BUFFER_BIT_STENCIL); 281 ctx->Stencil.Clear = clearSave; 282 if (ctx->Driver.ClearStencil) 283 ctx->Driver.ClearStencil(ctx, clearSave); 284 } 285 break; 286 case GL_COLOR: 287 { 288 const GLbitfield mask = make_color_buffer_mask(ctx, drawbuffer); 289 if (mask == INVALID_MASK) { 290 _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferiv(drawbuffer=%d)", 291 drawbuffer); 292 return; 293 } 294 else if (mask) { 295 /* XXX note: we're putting the integer clear values into the 296 * floating point state var. This will not always work. We'll 297 * need a new ctx->Driver.ClearBuffer() hook.... 298 */ 299 GLclampf clearSave[4]; 300 /* save color */ 301 COPY_4V(clearSave, ctx->Color.ClearColor); 302 /* set color */ 303 COPY_4V_CAST(ctx->Color.ClearColor, value, GLclampf); 304 if (ctx->Driver.ClearColor) 305 ctx->Driver.ClearColor(ctx, ctx->Color.ClearColor); 306 /* clear buffer(s) */ 307 ctx->Driver.Clear(ctx, mask); 308 /* restore color */ 309 COPY_4V(ctx->Color.ClearColor, clearSave); 310 if (ctx->Driver.ClearColor) 311 ctx->Driver.ClearColor(ctx, clearSave); 312 } 313 } 314 break; 315 default: 316 _mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferiv(buffer=%s)", 317 _mesa_lookup_enum_by_nr(buffer)); 318 return; 319 } 320} 321 322 323/** 324 * New in GL 3.0 325 * Clear unsigned integer color buffer (not depth, not stencil). 326 */ 327void GLAPIENTRY 328_mesa_ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *value) 329{ 330 GET_CURRENT_CONTEXT(ctx); 331 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 332 333 FLUSH_CURRENT(ctx, 0); 334 335 if (ctx->NewState) { 336 _mesa_update_state( ctx ); 337 } 338 339 switch (buffer) { 340 case GL_COLOR: 341 { 342 const GLbitfield mask = make_color_buffer_mask(ctx, drawbuffer); 343 if (mask == INVALID_MASK) { 344 _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferiv(drawbuffer=%d)", 345 drawbuffer); 346 return; 347 } 348 else if (mask) { 349 /* XXX note: we're putting the uint clear values into the 350 * floating point state var. This will not always work. We'll 351 * need a new ctx->Driver.ClearBuffer() hook.... 352 */ 353 GLclampf clearSave[4]; 354 /* save color */ 355 COPY_4V(clearSave, ctx->Color.ClearColor); 356 /* set color */ 357 COPY_4V_CAST(ctx->Color.ClearColor, value, GLclampf); 358 if (ctx->Driver.ClearColor) 359 ctx->Driver.ClearColor(ctx, ctx->Color.ClearColor); 360 /* clear buffer(s) */ 361 ctx->Driver.Clear(ctx, mask); 362 /* restore color */ 363 COPY_4V(ctx->Color.ClearColor, clearSave); 364 if (ctx->Driver.ClearColor) 365 ctx->Driver.ClearColor(ctx, clearSave); 366 } 367 } 368 break; 369 default: 370 _mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferuiv(buffer=%s)", 371 _mesa_lookup_enum_by_nr(buffer)); 372 return; 373 } 374} 375 376 377/** 378 * New in GL 3.0 379 * Clear fixed-pt or float color buffer or depth buffer (not stencil). 380 */ 381void GLAPIENTRY 382_mesa_ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value) 383{ 384 GET_CURRENT_CONTEXT(ctx); 385 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 386 387 FLUSH_CURRENT(ctx, 0); 388 389 if (ctx->NewState) { 390 _mesa_update_state( ctx ); 391 } 392 393 switch (buffer) { 394 case GL_DEPTH: 395 if (drawbuffer != 0) { 396 _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfv(drawbuffer=%d)", 397 drawbuffer); 398 return; 399 } 400 else { 401 /* Save current depth clear value, set to 'value', do the 402 * depth clear and restore the clear value. 403 * XXX in the future we may have a new ctx->Driver.ClearBuffer() 404 * hook instead. 405 */ 406 const GLclampd clearSave = ctx->Depth.Clear; 407 ctx->Depth.Clear = *value; 408 if (ctx->Driver.ClearDepth) 409 ctx->Driver.ClearDepth(ctx, *value); 410 ctx->Driver.Clear(ctx, BUFFER_BIT_DEPTH); 411 ctx->Depth.Clear = clearSave; 412 if (ctx->Driver.ClearDepth) 413 ctx->Driver.ClearDepth(ctx, clearSave); 414 } 415 /* clear depth buffer to value */ 416 break; 417 case GL_COLOR: 418 { 419 const GLbitfield mask = make_color_buffer_mask(ctx, drawbuffer); 420 if (mask == INVALID_MASK) { 421 _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfv(drawbuffer=%d)", 422 drawbuffer); 423 return; 424 } 425 else if (mask) { 426 GLclampf clearSave[4]; 427 /* save color */ 428 COPY_4V(clearSave, ctx->Color.ClearColor); 429 /* set color */ 430 COPY_4V_CAST(ctx->Color.ClearColor, value, GLclampf); 431 if (ctx->Driver.ClearColor) 432 ctx->Driver.ClearColor(ctx, ctx->Color.ClearColor); 433 /* clear buffer(s) */ 434 ctx->Driver.Clear(ctx, mask); 435 /* restore color */ 436 COPY_4V(ctx->Color.ClearColor, clearSave); 437 if (ctx->Driver.ClearColor) 438 ctx->Driver.ClearColor(ctx, clearSave); 439 } 440 } 441 break; 442 default: 443 _mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferfv(buffer=%s)", 444 _mesa_lookup_enum_by_nr(buffer)); 445 return; 446 } 447} 448 449 450/** 451 * New in GL 3.0 452 * Clear depth/stencil buffer only. 453 */ 454void GLAPIENTRY 455_mesa_ClearBufferfi(GLenum buffer, GLint drawbuffer, 456 GLfloat depth, GLint stencil) 457{ 458 GET_CURRENT_CONTEXT(ctx); 459 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 460 461 FLUSH_CURRENT(ctx, 0); 462 463 if (buffer != GL_DEPTH_STENCIL) { 464 _mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferfi(buffer=%s)", 465 _mesa_lookup_enum_by_nr(buffer)); 466 return; 467 } 468 469 if (drawbuffer != 0) { 470 _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfi(drawbuffer=%d)", 471 drawbuffer); 472 return; 473 } 474 475 if (ctx->NewState) { 476 _mesa_update_state( ctx ); 477 } 478 479 { 480 /* save current clear values */ 481 const GLclampd clearDepthSave = ctx->Depth.Clear; 482 const GLuint clearStencilSave = ctx->Stencil.Clear; 483 484 /* set new clear values */ 485 ctx->Depth.Clear = depth; 486 ctx->Stencil.Clear = stencil; 487 if (ctx->Driver.ClearDepth) 488 ctx->Driver.ClearDepth(ctx, depth); 489 if (ctx->Driver.ClearStencil) 490 ctx->Driver.ClearStencil(ctx, stencil); 491 492 /* clear buffers */ 493 ctx->Driver.Clear(ctx, BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL); 494 495 /* restore */ 496 ctx->Depth.Clear = clearDepthSave; 497 ctx->Stencil.Clear = clearStencilSave; 498 if (ctx->Driver.ClearDepth) 499 ctx->Driver.ClearDepth(ctx, clearDepthSave); 500 if (ctx->Driver.ClearStencil) 501 ctx->Driver.ClearStencil(ctx, clearStencilSave); 502 } 503} 504