33e7bc001611f0c64010dec4770e66707d04b828
1 /* $Id: buffers.c,v 1.16 2000/10/30 13:31:59 keithw Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
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:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
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.
49 _mesa_ClearIndex( GLfloat c
)
51 GET_CURRENT_CONTEXT(ctx
);
52 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glClearIndex");
53 ctx
->Color
.ClearIndex
= (GLuint
) c
;
54 ctx
->NewState
|= _NEW_COLOR
;
56 if (!ctx
->Visual
.RGBAflag
) {
57 /* it's OK to call glClearIndex in RGBA mode but it should be a NOP */
58 (*ctx
->Driver
.ClearIndex
)( ctx
, ctx
->Color
.ClearIndex
);
65 _mesa_ClearColor( GLclampf red
, GLclampf green
,
66 GLclampf blue
, GLclampf alpha
)
68 GET_CURRENT_CONTEXT(ctx
);
69 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glClearColor");
71 ctx
->Color
.ClearColor
[0] = CLAMP( red
, 0.0F
, 1.0F
);
72 ctx
->Color
.ClearColor
[1] = CLAMP( green
, 0.0F
, 1.0F
);
73 ctx
->Color
.ClearColor
[2] = CLAMP( blue
, 0.0F
, 1.0F
);
74 ctx
->Color
.ClearColor
[3] = CLAMP( alpha
, 0.0F
, 1.0F
);
75 ctx
->NewState
|= _NEW_COLOR
;
77 if (ctx
->Visual
.RGBAflag
) {
78 GLchan r
= (GLint
) (ctx
->Color
.ClearColor
[0] * CHAN_MAXF
);
79 GLchan g
= (GLint
) (ctx
->Color
.ClearColor
[1] * CHAN_MAXF
);
80 GLchan b
= (GLint
) (ctx
->Color
.ClearColor
[2] * CHAN_MAXF
);
81 GLchan a
= (GLint
) (ctx
->Color
.ClearColor
[3] * CHAN_MAXF
);
82 (*ctx
->Driver
.ClearColor
)( ctx
, r
, g
, b
, a
);
90 * Clear the color buffer when glColorMask or glIndexMask is in effect.
93 clear_color_buffer_with_masking( GLcontext
*ctx
)
95 const GLint x
= ctx
->DrawBuffer
->Xmin
;
96 const GLint y
= ctx
->DrawBuffer
->Ymin
;
97 const GLint height
= ctx
->DrawBuffer
->Ymax
- ctx
->DrawBuffer
->Ymin
;
98 const GLint width
= ctx
->DrawBuffer
->Xmax
- ctx
->DrawBuffer
->Xmin
;
100 if (ctx
->Visual
.RGBAflag
) {
102 const GLchan r
= (GLint
) (ctx
->Color
.ClearColor
[0] * CHAN_MAXF
);
103 const GLchan g
= (GLint
) (ctx
->Color
.ClearColor
[1] * CHAN_MAXF
);
104 const GLchan b
= (GLint
) (ctx
->Color
.ClearColor
[2] * CHAN_MAXF
);
105 const GLchan a
= (GLint
) (ctx
->Color
.ClearColor
[3] * CHAN_MAXF
);
107 for (i
= 0; i
< height
; i
++) {
108 GLchan rgba
[MAX_WIDTH
][4];
110 for (j
=0; j
<width
; j
++) {
116 _mesa_mask_rgba_span( ctx
, width
, x
, y
+ i
, rgba
);
117 (*ctx
->Driver
.WriteRGBASpan
)( ctx
, width
, x
, y
+ i
,
118 (CONST
GLchan (*)[4]) rgba
, NULL
);
122 /* Color index mode */
123 GLuint span
[MAX_WIDTH
];
124 GLubyte mask
[MAX_WIDTH
];
126 MEMSET( mask
, 1, width
);
127 for (i
=0;i
<height
;i
++) {
128 for (j
=0;j
<width
;j
++) {
129 span
[j
] = ctx
->Color
.ClearIndex
;
131 _mesa_mask_index_span( ctx
, width
, x
, y
+ i
, span
);
132 (*ctx
->Driver
.WriteCI32Span
)( ctx
, width
, x
, y
+ i
, span
, mask
);
140 * Clear a color buffer without index/channel masking.
143 clear_color_buffer(GLcontext
*ctx
)
145 const GLint x
= ctx
->DrawBuffer
->Xmin
;
146 const GLint y
= ctx
->DrawBuffer
->Ymin
;
147 const GLint height
= ctx
->DrawBuffer
->Ymax
- ctx
->DrawBuffer
->Ymin
;
148 const GLint width
= ctx
->DrawBuffer
->Xmax
- ctx
->DrawBuffer
->Xmin
;
149 const GLuint colorMask
= *((GLuint
*) &ctx
->Color
.ColorMask
);
151 if (ctx
->Visual
.RGBAflag
) {
153 const GLchan r
= (GLint
) (ctx
->Color
.ClearColor
[0] * CHAN_MAXF
);
154 const GLchan g
= (GLint
) (ctx
->Color
.ClearColor
[1] * CHAN_MAXF
);
155 const GLchan b
= (GLint
) (ctx
->Color
.ClearColor
[2] * CHAN_MAXF
);
156 const GLchan a
= (GLint
) (ctx
->Color
.ClearColor
[3] * CHAN_MAXF
);
157 GLchan span
[MAX_WIDTH
][4];
160 ASSERT(colorMask
== 0xffffffff);
162 for (i
= 0; i
< width
; i
++) {
168 for (i
= 0; i
< height
; i
++) {
169 (*ctx
->Driver
.WriteRGBASpan
)( ctx
, width
, x
, y
+ i
,
170 (CONST
GLchan (*)[4]) span
, NULL
);
174 /* Color index mode */
175 ASSERT(ctx
->Color
.IndexMask
== ~0);
176 if (ctx
->Visual
.IndexBits
== 8) {
178 GLchan span
[MAX_WIDTH
];
180 MEMSET(span
, ctx
->Color
.ClearIndex
, width
);
181 for (i
= 0; i
< height
; i
++) {
182 (*ctx
->Driver
.WriteCI8Span
)( ctx
, width
, x
, y
+ i
, span
, NULL
);
186 /* non 8-bit clear */
187 GLuint span
[MAX_WIDTH
];
189 for (i
= 0; i
< width
; i
++) {
190 span
[i
] = ctx
->Color
.ClearIndex
;
192 for (i
= 0; i
< height
; i
++) {
193 (*ctx
->Driver
.WriteCI32Span
)( ctx
, width
, x
, y
+ i
, span
, NULL
);
202 * Clear the front/back/left/right color buffers.
203 * This function is usually only called if we need to clear the
204 * buffers with masking.
207 clear_color_buffers(GLcontext
*ctx
)
209 const GLuint colorMask
= *((GLuint
*) &ctx
->Color
.ColorMask
);
212 /* loop over four possible dest color buffers */
213 for (bufferBit
= 1; bufferBit
<= 8; bufferBit
= bufferBit
<< 1) {
214 if (bufferBit
& ctx
->Color
.DrawDestMask
) {
215 if (bufferBit
== FRONT_LEFT_BIT
) {
216 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_FRONT_LEFT
);
217 (void) (*ctx
->Driver
.SetReadBuffer
)( ctx
, ctx
->DrawBuffer
, GL_FRONT_LEFT
);
219 else if (bufferBit
== FRONT_RIGHT_BIT
) {
220 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_FRONT_RIGHT
);
221 (void) (*ctx
->Driver
.SetReadBuffer
)( ctx
, ctx
->DrawBuffer
, GL_FRONT_RIGHT
);
223 else if (bufferBit
== BACK_LEFT_BIT
) {
224 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_BACK_LEFT
);
225 (void) (*ctx
->Driver
.SetReadBuffer
)( ctx
, ctx
->DrawBuffer
, GL_BACK_LEFT
);
228 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, GL_BACK_RIGHT
);
229 (void) (*ctx
->Driver
.SetReadBuffer
)( ctx
, ctx
->DrawBuffer
, GL_BACK_RIGHT
);
232 if (colorMask
!= 0xffffffff) {
233 clear_color_buffer_with_masking(ctx
);
236 clear_color_buffer(ctx
);
241 /* restore default read/draw buffers */
242 (void) (*ctx
->Driver
.SetDrawBuffer
)( ctx
, ctx
->Color
.DriverDrawBuffer
);
243 (void) (*ctx
->Driver
.SetReadBuffer
)( ctx
, ctx
->ReadBuffer
, ctx
->Pixel
.DriverReadBuffer
);
249 _mesa_Clear( GLbitfield mask
)
251 GET_CURRENT_CONTEXT(ctx
);
253 GLdouble t0
= gl_time();
255 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glClear");
257 if (MESA_VERBOSE
& VERBOSE_API
)
258 fprintf(stderr
, "glClear 0x%x\n", mask
);
261 gl_update_state( ctx
);
264 if (ctx
->RenderMode
==GL_RENDER
) {
265 const GLint x
= ctx
->DrawBuffer
->Xmin
;
266 const GLint y
= ctx
->DrawBuffer
->Ymin
;
267 const GLint height
= ctx
->DrawBuffer
->Ymax
- ctx
->DrawBuffer
->Ymin
;
268 const GLint width
= ctx
->DrawBuffer
->Xmax
- ctx
->DrawBuffer
->Xmin
;
272 /* don't clear depth buffer if depth writing disabled */
273 if (!ctx
->Depth
.Mask
)
274 CLEAR_BITS(mask
, GL_DEPTH_BUFFER_BIT
);
276 /* Build bitmask to send to driver Clear function */
277 ddMask
= mask
& (GL_DEPTH_BUFFER_BIT
|
278 GL_STENCIL_BUFFER_BIT
|
279 GL_ACCUM_BUFFER_BIT
);
280 if (mask
& GL_COLOR_BUFFER_BIT
) {
281 ddMask
|= ctx
->Color
.DrawDestMask
;
284 ASSERT(ctx
->Driver
.Clear
);
285 newMask
= (*ctx
->Driver
.Clear
)( ctx
, ddMask
, !ctx
->Scissor
.Enabled
,
286 x
, y
, width
, height
);
290 GLbitfield legalBits
= DD_FRONT_LEFT_BIT
|
297 assert((newMask
& (~legalBits
)) == 0);
303 /* do software clearing here */
305 if (newMask
& ctx
->Color
.DrawDestMask
) clear_color_buffers(ctx
);
306 if (newMask
& GL_DEPTH_BUFFER_BIT
) _mesa_clear_depth_buffer(ctx
);
307 if (newMask
& GL_ACCUM_BUFFER_BIT
) _mesa_clear_accum_buffer(ctx
);
308 if (newMask
& GL_STENCIL_BUFFER_BIT
) _mesa_clear_stencil_buffer(ctx
);
311 /* clear software-based alpha buffer(s) */
312 if ( (mask
& GL_COLOR_BUFFER_BIT
)
313 && ctx
->DrawBuffer
->UseSoftwareAlphaBuffers
314 && ctx
->Color
.ColorMask
[ACOMP
]) {
315 _mesa_clear_alpha_buffers( ctx
);
321 ctx
->ClearTime
+= gl_time() - t0
;
329 _mesa_DrawBuffer( GLenum mode
)
331 GET_CURRENT_CONTEXT(ctx
);
332 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glDrawBuffer");
334 if (MESA_VERBOSE
& VERBOSE_API
)
335 fprintf(stderr
, "glDrawBuffer %s\n", gl_lookup_enum_by_nr(mode
));
342 /* AUX buffers not implemented in Mesa at this time */
343 gl_error( ctx
, GL_INVALID_OPERATION
, "glDrawBuffer" );
346 if (!ctx
->Visual
.StereoFlag
) {
347 gl_error( ctx
, GL_INVALID_OPERATION
, "glDrawBuffer" );
349 if (ctx
->Visual
.DBflag
)
350 ctx
->Color
.DrawDestMask
= FRONT_RIGHT_BIT
| BACK_RIGHT_BIT
;
352 ctx
->Color
.DrawDestMask
= FRONT_RIGHT_BIT
;
355 if (!ctx
->Visual
.StereoFlag
) {
356 gl_error( ctx
, GL_INVALID_OPERATION
, "glDrawBuffer" );
359 ctx
->Color
.DrawDestMask
= FRONT_RIGHT_BIT
;
362 if (!ctx
->Visual
.StereoFlag
) {
363 gl_error( ctx
, GL_INVALID_OPERATION
, "glDrawBuffer" );
366 if (!ctx
->Visual
.DBflag
) {
367 gl_error( ctx
, GL_INVALID_OPERATION
, "glDrawBuffer" );
370 ctx
->Color
.DrawDestMask
= BACK_RIGHT_BIT
;
373 if (!ctx
->Visual
.DBflag
) {
374 gl_error( ctx
, GL_INVALID_OPERATION
, "glDrawBuffer" );
377 ctx
->Color
.DrawDestMask
= BACK_LEFT_BIT
;
379 case GL_FRONT_AND_BACK
:
380 if (!ctx
->Visual
.DBflag
) {
381 gl_error( ctx
, GL_INVALID_OPERATION
, "glDrawBuffer" );
384 if (ctx
->Visual
.StereoFlag
)
385 ctx
->Color
.DrawDestMask
= FRONT_LEFT_BIT
| BACK_LEFT_BIT
386 | FRONT_RIGHT_BIT
| BACK_RIGHT_BIT
;
388 ctx
->Color
.DrawDestMask
= FRONT_LEFT_BIT
| BACK_LEFT_BIT
;
391 if (!ctx
->Visual
.DBflag
) {
392 gl_error( ctx
, GL_INVALID_OPERATION
, "glDrawBuffer" );
395 if (ctx
->Visual
.StereoFlag
)
396 ctx
->Color
.DrawDestMask
= BACK_LEFT_BIT
| BACK_RIGHT_BIT
;
398 ctx
->Color
.DrawDestMask
= BACK_LEFT_BIT
;
402 if (ctx
->Visual
.DBflag
)
403 ctx
->Color
.DrawDestMask
= FRONT_LEFT_BIT
| BACK_LEFT_BIT
;
405 ctx
->Color
.DrawDestMask
= FRONT_LEFT_BIT
;
409 ctx
->Color
.DrawDestMask
= FRONT_LEFT_BIT
;
413 if (ctx
->Visual
.StereoFlag
)
414 ctx
->Color
.DrawDestMask
= FRONT_LEFT_BIT
| FRONT_RIGHT_BIT
;
416 ctx
->Color
.DrawDestMask
= FRONT_LEFT_BIT
;
420 ctx
->Color
.DrawDestMask
= 0;
423 gl_error( ctx
, GL_INVALID_ENUM
, "glDrawBuffer" );
428 * Make the dest buffer mode more precise if possible
430 if (mode
== GL_LEFT
&& !ctx
->Visual
.DBflag
)
431 ctx
->Color
.DriverDrawBuffer
= GL_FRONT_LEFT
;
432 else if (mode
== GL_RIGHT
&& !ctx
->Visual
.DBflag
)
433 ctx
->Color
.DriverDrawBuffer
= GL_FRONT_RIGHT
;
434 else if (mode
== GL_FRONT
&& !ctx
->Visual
.StereoFlag
)
435 ctx
->Color
.DriverDrawBuffer
= GL_FRONT_LEFT
;
436 else if (mode
== GL_BACK
&& !ctx
->Visual
.StereoFlag
)
437 ctx
->Color
.DriverDrawBuffer
= GL_BACK_LEFT
;
439 ctx
->Color
.DriverDrawBuffer
= mode
;
442 * Set current alpha buffer pointer
444 if (ctx
->DrawBuffer
->UseSoftwareAlphaBuffers
) {
445 if (ctx
->Color
.DriverDrawBuffer
== GL_FRONT_LEFT
)
446 ctx
->DrawBuffer
->Alpha
= ctx
->DrawBuffer
->FrontLeftAlpha
;
447 else if (ctx
->Color
.DriverDrawBuffer
== GL_BACK_LEFT
)
448 ctx
->DrawBuffer
->Alpha
= ctx
->DrawBuffer
->BackLeftAlpha
;
449 else if (ctx
->Color
.DriverDrawBuffer
== GL_FRONT_RIGHT
)
450 ctx
->DrawBuffer
->Alpha
= ctx
->DrawBuffer
->FrontRightAlpha
;
451 else if (ctx
->Color
.DriverDrawBuffer
== GL_BACK_RIGHT
)
452 ctx
->DrawBuffer
->Alpha
= ctx
->DrawBuffer
->BackRightAlpha
;
456 * If we get here there can't have been an error.
457 * Now see if device driver can implement the drawing to the target
458 * buffer(s). The driver may not be able to do GL_FRONT_AND_BACK mode
459 * for example. We'll take care of that in the core code by looping
460 * over the individual buffers.
462 ASSERT(ctx
->Driver
.SetDrawBuffer
);
463 if ( (*ctx
->Driver
.SetDrawBuffer
)(ctx
, ctx
->Color
.DriverDrawBuffer
) ) {
464 /* All OK, the driver will do all buffer writes */
465 ctx
->Color
.MultiDrawBuffer
= GL_FALSE
;
468 /* We'll have to loop over the multiple draw buffer targets */
469 ctx
->Color
.MultiDrawBuffer
= GL_TRUE
;
470 /* Set drawing buffer to front for now */
471 (void) (*ctx
->Driver
.SetDrawBuffer
)(ctx
, GL_FRONT_LEFT
);
474 ctx
->Color
.DrawBuffer
= mode
;
475 ctx
->NewState
|= _NEW_COLOR
;
481 _mesa_ReadBuffer( GLenum mode
)
483 GET_CURRENT_CONTEXT(ctx
);
484 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glReadBuffer");
486 if (MESA_VERBOSE
& VERBOSE_API
)
487 fprintf(stderr
, "glReadBuffer %s\n", gl_lookup_enum_by_nr(mode
));
494 /* AUX buffers not implemented in Mesa at this time */
495 gl_error( ctx
, GL_INVALID_OPERATION
, "glReadBuffer" );
500 /* Front-Left buffer, always exists */
501 ctx
->Pixel
.DriverReadBuffer
= GL_FRONT_LEFT
;
505 /* Back-Left buffer, requires double buffering */
506 if (!ctx
->Visual
.DBflag
) {
507 gl_error( ctx
, GL_INVALID_OPERATION
, "glReadBuffer" );
510 ctx
->Pixel
.DriverReadBuffer
= GL_BACK_LEFT
;
514 if (!ctx
->Visual
.StereoFlag
) {
515 gl_error( ctx
, GL_INVALID_OPERATION
, "glReadBuffer" );
518 ctx
->Pixel
.DriverReadBuffer
= GL_FRONT_RIGHT
;
521 if (!ctx
->Visual
.StereoFlag
|| !ctx
->Visual
.DBflag
) {
522 gl_error( ctx
, GL_INVALID_OPERATION
, "glReadBuffer" );
525 ctx
->Pixel
.DriverReadBuffer
= GL_BACK_RIGHT
;
528 gl_error( ctx
, GL_INVALID_ENUM
, "glReadBuffer" );
532 ctx
->Pixel
.ReadBuffer
= mode
;
533 ctx
->NewState
|= _NEW_PIXEL
;
538 * GL_MESA_resize_buffers extension
541 _mesa_ResizeBuffersMESA( void )
543 GLcontext
*ctx
= _mesa_get_current_context();
545 GLuint buf_width
, buf_height
;
547 if (MESA_VERBOSE
& VERBOSE_API
)
548 fprintf(stderr
, "glResizeBuffersMESA\n");
550 /* ask device driver for size of output buffer */
551 (*ctx
->Driver
.GetBufferSize
)( ctx
, &buf_width
, &buf_height
);
553 /* see if size of device driver's color buffer (window) has changed */
554 if (ctx
->DrawBuffer
->Width
== (GLint
) buf_width
&&
555 ctx
->DrawBuffer
->Height
== (GLint
) buf_height
)
558 ctx
->NewState
|= _NEW_BUFFERS
; /* to update scissor / window bounds */
560 /* save buffer size */
561 ctx
->DrawBuffer
->Width
= buf_width
;
562 ctx
->DrawBuffer
->Height
= buf_height
;
564 /* Reallocate other buffers if needed. */
565 if (ctx
->DrawBuffer
->UseSoftwareDepthBuffer
) {
566 _mesa_alloc_depth_buffer( ctx
);
568 if (ctx
->DrawBuffer
->UseSoftwareStencilBuffer
) {
569 _mesa_alloc_stencil_buffer( ctx
);
571 if (ctx
->DrawBuffer
->UseSoftwareAccumBuffer
) {
572 _mesa_alloc_accum_buffer( ctx
);
574 if (ctx
->DrawBuffer
->UseSoftwareAlphaBuffers
) {
575 _mesa_alloc_alpha_buffers( ctx
);