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