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