buffers.c revision 9c4f016d2171319ad8cde2366d76fd7f70520621
1/* $Id: buffers.c,v 1.4 2000/04/05 14:40:04 brianp Exp $ */ 2 3/* 4 * Mesa 3-D graphics library 5 * Version: 3.3 6 * 7 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26 27 28#ifdef PC_HEADER 29#include "all.h" 30#else 31#include "glheader.h" 32#include "accum.h" 33#include "alphabuf.h" 34#include "buffers.h" 35#include "context.h" 36#include "depth.h" 37#include "enums.h" 38#include "macros.h" 39#include "masking.h" 40#include "mem.h" 41#include "stencil.h" 42#include "state.h" 43#include "types.h" 44#endif 45 46 47 48void 49_mesa_ClearIndex( GLfloat c ) 50{ 51 GET_CURRENT_CONTEXT(ctx); 52 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glClearIndex"); 53 ctx->Color.ClearIndex = (GLuint) c; 54 if (!ctx->Visual->RGBAflag) { 55 /* it's OK to call glClearIndex in RGBA mode but it should be a NOP */ 56 (*ctx->Driver.ClearIndex)( ctx, ctx->Color.ClearIndex ); 57 } 58} 59 60 61 62void 63_mesa_ClearColor( GLclampf red, GLclampf green, 64 GLclampf blue, GLclampf alpha ) 65{ 66 GET_CURRENT_CONTEXT(ctx); 67 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glClearColor"); 68 69 ctx->Color.ClearColor[0] = CLAMP( red, 0.0F, 1.0F ); 70 ctx->Color.ClearColor[1] = CLAMP( green, 0.0F, 1.0F ); 71 ctx->Color.ClearColor[2] = CLAMP( blue, 0.0F, 1.0F ); 72 ctx->Color.ClearColor[3] = CLAMP( alpha, 0.0F, 1.0F ); 73 74 if (ctx->Visual->RGBAflag) { 75 GLubyte r = (GLint) (ctx->Color.ClearColor[0] * 255.0F); 76 GLubyte g = (GLint) (ctx->Color.ClearColor[1] * 255.0F); 77 GLubyte b = (GLint) (ctx->Color.ClearColor[2] * 255.0F); 78 GLubyte a = (GLint) (ctx->Color.ClearColor[3] * 255.0F); 79 (*ctx->Driver.ClearColor)( ctx, r, g, b, a ); 80 } 81} 82 83 84 85 86/* 87 * Clear the color buffer when glColorMask or glIndexMask is in effect. 88 */ 89static void 90clear_color_buffer_with_masking( GLcontext *ctx ) 91{ 92 const GLint x = ctx->DrawBuffer->Xmin; 93 const GLint y = ctx->DrawBuffer->Ymin; 94 const GLint height = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin + 1; 95 const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin + 1; 96 97 if (ctx->Visual->RGBAflag) { 98 /* RGBA mode */ 99 const GLubyte r = (GLint) (ctx->Color.ClearColor[0] * 255.0F); 100 const GLubyte g = (GLint) (ctx->Color.ClearColor[1] * 255.0F); 101 const GLubyte b = (GLint) (ctx->Color.ClearColor[2] * 255.0F); 102 const GLubyte a = (GLint) (ctx->Color.ClearColor[3] * 255.0F); 103 GLint i; 104 for (i = 0; i < height; i++) { 105 GLubyte rgba[MAX_WIDTH][4]; 106 GLint j; 107 for (j=0; j<width; j++) { 108 rgba[j][RCOMP] = r; 109 rgba[j][GCOMP] = g; 110 rgba[j][BCOMP] = b; 111 rgba[j][ACOMP] = a; 112 } 113 _mesa_mask_rgba_span( ctx, width, x, y + i, rgba ); 114 (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y + i, 115 (CONST GLubyte (*)[4])rgba, NULL ); 116 } 117 } 118 else { 119 /* Color index mode */ 120 GLuint span[MAX_WIDTH]; 121 GLubyte mask[MAX_WIDTH]; 122 GLint i, j; 123 MEMSET( mask, 1, width ); 124 for (i=0;i<height;i++) { 125 for (j=0;j<width;j++) { 126 span[j] = ctx->Color.ClearIndex; 127 } 128 _mesa_mask_index_span( ctx, width, x, y + i, span ); 129 (*ctx->Driver.WriteCI32Span)( ctx, width, x, y + i, span, mask ); 130 } 131 } 132} 133 134 135 136/* 137 * Clear a color buffer without index/channel masking. 138 */ 139static void 140clear_color_buffer(GLcontext *ctx) 141{ 142 const GLint x = ctx->DrawBuffer->Xmin; 143 const GLint y = ctx->DrawBuffer->Ymin; 144 const GLint height = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin + 1; 145 const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin + 1; 146 147 if (ctx->Visual->RGBAflag) { 148 /* RGBA mode */ 149 const GLubyte r = (GLint) (ctx->Color.ClearColor[0] * 255.0F); 150 const GLubyte g = (GLint) (ctx->Color.ClearColor[1] * 255.0F); 151 const GLubyte b = (GLint) (ctx->Color.ClearColor[2] * 255.0F); 152 const GLubyte a = (GLint) (ctx->Color.ClearColor[3] * 255.0F); 153 GLubyte span[MAX_WIDTH][4]; 154 GLint i; 155 ASSERT(ctx->Color.ColorMask[0] && 156 ctx->Color.ColorMask[1] && 157 ctx->Color.ColorMask[2] && 158 ctx->Color.ColorMask[3]); 159 for (i = 0; i < width; i++) { 160 span[i][RCOMP] = r; 161 span[i][GCOMP] = g; 162 span[i][BCOMP] = b; 163 span[i][ACOMP] = a; 164 } 165 for (i = 0; i < height; i++) { 166 (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y + i, 167 (CONST GLubyte (*)[4]) span, NULL ); 168 } 169 } 170 else { 171 /* Color index mode */ 172 ASSERT(ctx->Color.IndexMask == ~0); 173 if (ctx->Visual->IndexBits == 8) { 174 /* 8-bit clear */ 175 GLubyte span[MAX_WIDTH]; 176 GLint i; 177 MEMSET(span, ctx->Color.ClearIndex, width); 178 for (i = 0; i < height; i++) { 179 (*ctx->Driver.WriteCI8Span)( ctx, width, x, y + i, span, NULL ); 180 } 181 } 182 else { 183 /* non 8-bit clear */ 184 GLuint span[MAX_WIDTH]; 185 GLint i; 186 for (i = 0; i < width; i++) { 187 span[i] = ctx->Color.ClearIndex; 188 } 189 for (i = 0; i < height; i++) { 190 (*ctx->Driver.WriteCI32Span)( ctx, width, x, y + i, span, NULL ); 191 } 192 } 193 } 194} 195 196 197 198/* 199 * Clear the front/back/left/right color buffers. 200 * This function is usually only called if we need to clear the 201 * buffers with masking. 202 */ 203static void 204clear_color_buffers(GLcontext *ctx) 205{ 206 GLuint bufferBit; 207 208 /* loop over four possible dest color buffers */ 209 for (bufferBit = 1; bufferBit <= 8; bufferBit = bufferBit << 1) { 210 if (bufferBit & ctx->Color.DrawDestMask) { 211 if (bufferBit == FRONT_LEFT_BIT) { 212 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_LEFT); 213 } 214 else if (bufferBit == FRONT_RIGHT_BIT) { 215 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_RIGHT); 216 } 217 else if (bufferBit == BACK_LEFT_BIT) { 218 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_LEFT); 219 } 220 else { 221 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT); 222 } 223 224 if (ctx->Color.SWmasking) { 225 clear_color_buffer_with_masking(ctx); 226 } 227 else { 228 clear_color_buffer(ctx); 229 } 230 } 231 } 232 233 /* restore default dest buffer */ 234 (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer ); 235} 236 237 238 239void 240_mesa_Clear( GLbitfield mask ) 241{ 242 GET_CURRENT_CONTEXT(ctx); 243#ifdef PROFILE 244 GLdouble t0 = gl_time(); 245#endif 246 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glClear"); 247 248 if (MESA_VERBOSE & VERBOSE_API) 249 fprintf(stderr, "glClear 0x%x\n", mask); 250 251 if (ctx->NewState) { 252 gl_update_state( ctx ); 253 } 254 255 if (ctx->RenderMode==GL_RENDER) { 256 const GLint x = ctx->DrawBuffer->Xmin; 257 const GLint y = ctx->DrawBuffer->Ymin; 258 const GLint height = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin + 1; 259 const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin + 1; 260 GLbitfield ddMask; 261 GLbitfield newMask; 262 263 /* don't clear depth buffer if depth writing disabled */ 264 if (!ctx->Depth.Mask) 265 CLEAR_BITS(mask, GL_DEPTH_BUFFER_BIT); 266 267 /* Build bitmask to send to driver Clear function */ 268 ddMask = mask & (GL_DEPTH_BUFFER_BIT | 269 GL_STENCIL_BUFFER_BIT | 270 GL_ACCUM_BUFFER_BIT); 271 if (mask & GL_COLOR_BUFFER_BIT) { 272 ddMask |= ctx->Color.DrawDestMask; 273 } 274 275 ASSERT(ctx->Driver.Clear); 276 newMask = (*ctx->Driver.Clear)( ctx, ddMask, !ctx->Scissor.Enabled, 277 x, y, width, height ); 278 279#ifdef DEBUG 280 { 281 GLbitfield legalBits = DD_FRONT_LEFT_BIT | 282 DD_FRONT_RIGHT_BIT | 283 DD_BACK_LEFT_BIT | 284 DD_BACK_RIGHT_BIT | 285 DD_DEPTH_BIT | 286 DD_STENCIL_BIT | 287 DD_ACCUM_BIT; 288 assert((newMask & (~legalBits)) == 0); 289 } 290#endif 291 292 /* do software clearing here */ 293 if (newMask) { 294 if (newMask & ctx->Color.DrawDestMask) clear_color_buffers( ctx ); 295 if (newMask & GL_DEPTH_BUFFER_BIT) _mesa_clear_depth_buffer( ctx ); 296 if (newMask & GL_ACCUM_BUFFER_BIT) _mesa_clear_accum_buffer( ctx ); 297 if (newMask & GL_STENCIL_BUFFER_BIT) gl_clear_stencil_buffer( ctx ); 298 } 299 300 /* clear software-based alpha buffer(s) */ 301 if ( (mask & GL_COLOR_BUFFER_BIT) && ctx->Visual->SoftwareAlpha 302 && ctx->Color.ColorMask[RCOMP]) { 303 gl_clear_alpha_buffers( ctx ); 304 } 305 306#ifdef PROFILE 307 ctx->ClearTime += gl_time() - t0; 308 ctx->ClearCount++; 309#endif 310 } 311} 312 313 314void 315_mesa_DrawBuffer( GLenum mode ) 316{ 317 GET_CURRENT_CONTEXT(ctx); 318 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDrawBuffer"); 319 320 if (MESA_VERBOSE & VERBOSE_API) 321 fprintf(stderr, "glDrawBuffer %s\n", gl_lookup_enum_by_nr(mode)); 322 323 switch (mode) { 324 case GL_AUX0: 325 case GL_AUX1: 326 case GL_AUX2: 327 case GL_AUX3: 328 /* AUX buffers not implemented in Mesa at this time */ 329 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" ); 330 return; 331 case GL_RIGHT: 332 if (!ctx->Visual->StereoFlag) { 333 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" ); 334 return; 335 } 336 if (ctx->Visual->DBflag) 337 ctx->Color.DrawDestMask = FRONT_RIGHT_BIT | BACK_RIGHT_BIT; 338 else 339 ctx->Color.DrawDestMask = FRONT_RIGHT_BIT; 340 break; 341 case GL_FRONT_RIGHT: 342 if (!ctx->Visual->StereoFlag) { 343 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" ); 344 return; 345 } 346 ctx->Color.DrawDestMask = FRONT_RIGHT_BIT; 347 break; 348 case GL_BACK_RIGHT: 349 if (!ctx->Visual->StereoFlag) { 350 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" ); 351 return; 352 } 353 if (!ctx->Visual->DBflag) { 354 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" ); 355 return; 356 } 357 ctx->Color.DrawDestMask = BACK_RIGHT_BIT; 358 break; 359 case GL_BACK_LEFT: 360 if (!ctx->Visual->DBflag) { 361 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" ); 362 return; 363 } 364 ctx->Color.DrawDestMask = BACK_LEFT_BIT; 365 break; 366 case GL_FRONT_AND_BACK: 367 if (!ctx->Visual->DBflag) { 368 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" ); 369 return; 370 } 371 if (ctx->Visual->StereoFlag) 372 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT 373 | FRONT_RIGHT_BIT | BACK_RIGHT_BIT; 374 else 375 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT; 376 break; 377 case GL_BACK: 378 if (!ctx->Visual->DBflag) { 379 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" ); 380 return; 381 } 382 if (ctx->Visual->StereoFlag) 383 ctx->Color.DrawDestMask = BACK_LEFT_BIT | BACK_RIGHT_BIT; 384 else 385 ctx->Color.DrawDestMask = BACK_LEFT_BIT; 386 break; 387 case GL_LEFT: 388 /* never an error */ 389 if (ctx->Visual->DBflag) 390 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT; 391 else 392 ctx->Color.DrawDestMask = FRONT_LEFT_BIT; 393 break; 394 case GL_FRONT_LEFT: 395 /* never an error */ 396 ctx->Color.DrawDestMask = FRONT_LEFT_BIT; 397 break; 398 case GL_FRONT: 399 /* never an error */ 400 if (ctx->Visual->StereoFlag) 401 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | FRONT_RIGHT_BIT; 402 else 403 ctx->Color.DrawDestMask = FRONT_LEFT_BIT; 404 break; 405 case GL_NONE: 406 /* never an error */ 407 ctx->Color.DrawDestMask = 0; 408 break; 409 default: 410 gl_error( ctx, GL_INVALID_ENUM, "glDrawBuffer" ); 411 return; 412 } 413 414 /* 415 * Make the dest buffer mode more precise if possible 416 */ 417 if (mode == GL_LEFT && !ctx->Visual->DBflag) 418 ctx->Color.DriverDrawBuffer = GL_FRONT_LEFT; 419 else if (mode == GL_RIGHT && !ctx->Visual->DBflag) 420 ctx->Color.DriverDrawBuffer = GL_FRONT_RIGHT; 421 else if (mode == GL_FRONT && !ctx->Visual->StereoFlag) 422 ctx->Color.DriverDrawBuffer = GL_FRONT_LEFT; 423 else if (mode == GL_BACK && !ctx->Visual->StereoFlag) 424 ctx->Color.DriverDrawBuffer = GL_BACK_LEFT; 425 else 426 ctx->Color.DriverDrawBuffer = mode; 427 428 /* 429 * Set current alpha buffer pointer 430 */ 431 if (ctx->Visual->SoftwareAlpha) { 432 if (ctx->Color.DriverDrawBuffer == GL_FRONT_LEFT) 433 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontLeftAlpha; 434 else if (ctx->Color.DriverDrawBuffer == GL_BACK_LEFT) 435 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackLeftAlpha; 436 else if (ctx->Color.DriverDrawBuffer == GL_FRONT_RIGHT) 437 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontRightAlpha; 438 else if (ctx->Color.DriverDrawBuffer == GL_BACK_RIGHT) 439 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackRightAlpha; 440 } 441 442 /* 443 * If we get here there can't have been an error. 444 * Now see if device driver can implement the drawing to the target 445 * buffer(s). The driver may not be able to do GL_FRONT_AND_BACK mode 446 * for example. We'll take care of that in the core code by looping 447 * over the individual buffers. 448 */ 449 ASSERT(ctx->Driver.SetDrawBuffer); 450 if ( (*ctx->Driver.SetDrawBuffer)(ctx, ctx->Color.DriverDrawBuffer) ) { 451 /* All OK, the driver will do all buffer writes */ 452 ctx->Color.MultiDrawBuffer = GL_FALSE; 453 } 454 else { 455 /* We'll have to loop over the multiple draw buffer targets */ 456 ctx->Color.MultiDrawBuffer = GL_TRUE; 457 /* Set drawing buffer to front for now */ 458 (void) (*ctx->Driver.SetDrawBuffer)(ctx, GL_FRONT_LEFT); 459 } 460 461 ctx->Color.DrawBuffer = mode; 462 ctx->NewState |= NEW_RASTER_OPS; 463} 464 465 466 467void 468_mesa_ReadBuffer( GLenum mode ) 469{ 470 GET_CURRENT_CONTEXT(ctx); 471 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glReadBuffer"); 472 473 if (MESA_VERBOSE & VERBOSE_API) 474 fprintf(stderr, "glReadBuffer %s\n", gl_lookup_enum_by_nr(mode)); 475 476 switch (mode) { 477 case GL_AUX0: 478 case GL_AUX1: 479 case GL_AUX2: 480 case GL_AUX3: 481 /* AUX buffers not implemented in Mesa at this time */ 482 gl_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" ); 483 return; 484 case GL_LEFT: 485 case GL_FRONT: 486 case GL_FRONT_LEFT: 487 /* Front-Left buffer, always exists */ 488 ctx->Pixel.DriverReadBuffer = GL_FRONT_LEFT; 489 break; 490 case GL_BACK: 491 case GL_BACK_LEFT: 492 /* Back-Left buffer, requires double buffering */ 493 if (!ctx->Visual->DBflag) { 494 gl_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" ); 495 return; 496 } 497 ctx->Pixel.DriverReadBuffer = GL_BACK_LEFT; 498 break; 499 case GL_FRONT_RIGHT: 500 case GL_RIGHT: 501 if (!ctx->Visual->StereoFlag) { 502 gl_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" ); 503 return; 504 } 505 ctx->Pixel.DriverReadBuffer = GL_FRONT_RIGHT; 506 break; 507 case GL_BACK_RIGHT: 508 if (!ctx->Visual->StereoFlag || !ctx->Visual->DBflag) { 509 gl_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" ); 510 return; 511 } 512 ctx->Pixel.DriverReadBuffer = GL_BACK_RIGHT; 513 break; 514 default: 515 gl_error( ctx, GL_INVALID_ENUM, "glReadBuffer" ); 516 return; 517 } 518 519 ctx->Pixel.ReadBuffer = mode; 520 ctx->NewState |= NEW_RASTER_OPS; 521} 522 523 524/* 525 * GL_MESA_resize_buffers extension 526 */ 527void 528_mesa_ResizeBuffersMESA( void ) 529{ 530 GLcontext *ctx = gl_get_current_context(); 531 532 GLuint buf_width, buf_height; 533 534 if (MESA_VERBOSE & VERBOSE_API) 535 fprintf(stderr, "glResizeBuffersMESA\n"); 536 537 /* ask device driver for size of output buffer */ 538 (*ctx->Driver.GetBufferSize)( ctx, &buf_width, &buf_height ); 539 540 /* see if size of device driver's color buffer (window) has changed */ 541 if (ctx->DrawBuffer->Width == (GLint) buf_width && 542 ctx->DrawBuffer->Height == (GLint) buf_height) 543 return; 544 545 ctx->NewState |= NEW_RASTER_OPS; /* to update scissor / window bounds */ 546 547 /* save buffer size */ 548 ctx->DrawBuffer->Width = buf_width; 549 ctx->DrawBuffer->Height = buf_height; 550 551 /* Reallocate other buffers if needed. */ 552 if (ctx->DrawBuffer->UseSoftwareDepthBuffer) { 553 _mesa_alloc_depth_buffer( ctx ); 554 } 555 if (ctx->DrawBuffer->UseSoftwareStencilBuffer) { 556 gl_alloc_stencil_buffer( ctx ); 557 } 558 if (ctx->DrawBuffer->UseSoftwareAccumBuffer) { 559 _mesa_alloc_accum_buffer( ctx ); 560 } 561 if (ctx->Visual->SoftwareAlpha) { 562 gl_alloc_alpha_buffers( ctx ); 563 } 564} 565