3 * Frame buffer management.
7 * Mesa 3-D graphics library
10 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
26 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
27 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
46 _mesa_ClearIndex( GLfloat c
)
48 GET_CURRENT_CONTEXT(ctx
);
49 ASSERT_OUTSIDE_BEGIN_END(ctx
);
51 if (ctx
->Color
.ClearIndex
== (GLuint
) c
)
54 FLUSH_VERTICES(ctx
, _NEW_COLOR
);
55 ctx
->Color
.ClearIndex
= (GLuint
) c
;
57 if (!ctx
->Visual
.rgbMode
&& ctx
->Driver
.ClearIndex
) {
58 /* it's OK to call glClearIndex in RGBA mode but it should be a NOP */
59 (*ctx
->Driver
.ClearIndex
)( ctx
, ctx
->Color
.ClearIndex
);
66 * Specify the clear values for the color buffers.
68 * \param red red color component.
69 * \param green green color component.
70 * \param blue blue color component.
71 * \param alpha alpha component.
75 * Clamps the parameters and updates gl_colorbuffer_attrib::ClearColor. On a
76 * change, flushes the vertices and notifies the driver via the
77 * dd_function_table::ClearColor callback.
80 _mesa_ClearColor( GLclampf red
, GLclampf green
, GLclampf blue
, GLclampf alpha
)
83 GET_CURRENT_CONTEXT(ctx
);
84 ASSERT_OUTSIDE_BEGIN_END(ctx
);
86 tmp
[0] = CLAMP(red
, 0.0F
, 1.0F
);
87 tmp
[1] = CLAMP(green
, 0.0F
, 1.0F
);
88 tmp
[2] = CLAMP(blue
, 0.0F
, 1.0F
);
89 tmp
[3] = CLAMP(alpha
, 0.0F
, 1.0F
);
91 if (TEST_EQ_4V(tmp
, ctx
->Color
.ClearColor
))
92 return; /* no change */
94 FLUSH_VERTICES(ctx
, _NEW_COLOR
);
95 COPY_4V(ctx
->Color
.ClearColor
, tmp
);
97 if (ctx
->Visual
.rgbMode
&& ctx
->Driver
.ClearColor
) {
98 /* it's OK to call glClearColor in CI mode but it should be a NOP */
99 (*ctx
->Driver
.ClearColor
)(ctx
, ctx
->Color
.ClearColor
);
107 * \param mask bit-mask indicating the buffers to be cleared.
109 * Flushes the vertices and verifies the parameter. If __GLcontextRec::NewState
110 * is set then calls _mesa_update_state() to update gl_frame_buffer::_Xmin,
111 * etc. If the rasterization mode is set to GL_RENDER then requests the driver
112 * to clear the buffers, via the dd_function_table::Clear callback.
115 _mesa_Clear( GLbitfield mask
)
117 GET_CURRENT_CONTEXT(ctx
);
118 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
120 if (MESA_VERBOSE
& VERBOSE_API
)
121 _mesa_debug(ctx
, "glClear 0x%x\n", mask
);
123 if (mask
& ~(GL_COLOR_BUFFER_BIT
|
124 GL_DEPTH_BUFFER_BIT
|
125 GL_STENCIL_BUFFER_BIT
|
126 GL_ACCUM_BUFFER_BIT
)) {
127 /* invalid bit set */
128 _mesa_error( ctx
, GL_INVALID_VALUE
, "glClear(0x%x)", mask
);
133 _mesa_update_state( ctx
); /* update _Xmin, etc */
136 if (ctx
->RenderMode
==GL_RENDER
) {
137 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
138 const GLint y
= ctx
->DrawBuffer
->_Ymin
;
139 const GLint height
= ctx
->DrawBuffer
->_Ymax
- ctx
->DrawBuffer
->_Ymin
;
140 const GLint width
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
143 /* don't clear depth buffer if depth writing disabled */
144 if (!ctx
->Depth
.Mask
)
145 mask
&= ~GL_DEPTH_BUFFER_BIT
;
147 /* Build the bitmask to send to device driver's Clear function.
148 * Note that the GL_COLOR_BUFFER_BIT flag will expand to 0, 1, 2 or 4
149 * of the FRONT/BACK_LEFT/RIGHT_BIT flags.
152 if (mask
& GL_COLOR_BUFFER_BIT
)
153 ddMask
|= ctx
->Color
._DrawDestMask
[0];
154 if ((mask
& GL_DEPTH_BUFFER_BIT
) && ctx
->Visual
.depthBits
> 0)
155 ddMask
|= GL_DEPTH_BUFFER_BIT
;
156 if ((mask
& GL_STENCIL_BUFFER_BIT
) && ctx
->Visual
.stencilBits
> 0)
157 ddMask
|= GL_STENCIL_BUFFER_BIT
;
158 if ((mask
& GL_ACCUM_BUFFER_BIT
) && ctx
->Visual
.accumRedBits
> 0)
159 ddMask
|= GL_ACCUM_BUFFER_BIT
;
161 ASSERT(ctx
->Driver
.Clear
);
162 ctx
->Driver
.Clear( ctx
, ddMask
, (GLboolean
) !ctx
->Scissor
.Enabled
,
163 x
, y
, width
, height
);
170 * Return bitmask of DD_* flags indicating which color buffers are
171 * available to the rendering context;
174 supported_buffer_bitmask(const GLcontext
*ctx
)
176 GLuint mask
= DD_FRONT_LEFT_BIT
; /* always have this */
179 if (ctx
->Visual
.stereoMode
) {
180 mask
|= DD_FRONT_RIGHT_BIT
;
181 if (ctx
->Visual
.doubleBufferMode
) {
182 mask
|= DD_BACK_LEFT_BIT
| DD_BACK_RIGHT_BIT
;
185 else if (ctx
->Visual
.doubleBufferMode
) {
186 mask
|= DD_BACK_LEFT_BIT
;
189 for (i
= 0; i
< ctx
->Visual
.numAuxBuffers
; i
++) {
190 mask
|= (DD_AUX0_BIT
<< i
);
198 * Helper routine used by glDrawBuffer and glDrawBuffersARB.
199 * Given a GLenum naming (a) color buffer(s), return the corresponding
200 * bitmask of DD_* flags.
203 draw_buffer_enum_to_bitmask(GLenum buffer
)
207 return DD_FRONT_LEFT_BIT
| DD_FRONT_RIGHT_BIT
;
209 return DD_BACK_LEFT_BIT
| DD_BACK_RIGHT_BIT
;
213 return DD_FRONT_RIGHT_BIT
| DD_BACK_RIGHT_BIT
;
215 return DD_FRONT_RIGHT_BIT
;
217 return DD_BACK_RIGHT_BIT
;
219 return DD_BACK_LEFT_BIT
;
220 case GL_FRONT_AND_BACK
:
221 return DD_FRONT_LEFT_BIT
| DD_BACK_LEFT_BIT
222 | DD_FRONT_RIGHT_BIT
| DD_BACK_RIGHT_BIT
;
224 return DD_FRONT_LEFT_BIT
| DD_BACK_LEFT_BIT
;
226 return DD_FRONT_LEFT_BIT
;
243 * Helper routine used by glReadBuffer.
244 * Given a GLenum naming (a) color buffer(s), return the corresponding
245 * bitmask of DD_* flags.
248 read_buffer_enum_to_bitmask(GLenum buffer
)
252 return DD_FRONT_LEFT_BIT
;
254 return DD_BACK_LEFT_BIT
;
256 return DD_FRONT_RIGHT_BIT
;
258 return DD_FRONT_RIGHT_BIT
;
260 return DD_BACK_RIGHT_BIT
;
262 return DD_BACK_LEFT_BIT
;
264 return DD_FRONT_LEFT_BIT
;
266 return DD_FRONT_LEFT_BIT
;
284 * Specify which color buffers to draw into.
286 * \param mode color buffer combination.
288 * \sa glDrawBuffer().
290 * Flushes the vertices and verifies the parameter and updates the
291 * gl_colorbuffer_attrib::_DrawDestMask bitfield. Marks new color state in
292 * __GLcontextRec::NewState and notifies the driver via the
293 * dd_function_table::DrawBuffer callback.
296 _mesa_DrawBuffer( GLenum mode
)
298 GET_CURRENT_CONTEXT(ctx
);
299 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
); /* too complex... */
301 if (MESA_VERBOSE
& VERBOSE_API
)
302 _mesa_debug(ctx
, "glDrawBuffer %s\n", _mesa_lookup_enum_by_nr(mode
));
304 if (ctx
->Extensions
.EXT_framebuffer_object
&& ctx
->CurrentFramebuffer
) {
305 /* Set drawbuffer for a framebuffer object */
306 if (mode
== GL_NONE
) {
307 ctx
->CurrentFramebuffer
->DrawBuffer
[0] = mode
;
310 const GLint k
= mode
- GL_COLOR_ATTACHMENT0_EXT
;
311 if (k
>= 0 && k
< ctx
->Const
.MaxColorAttachments
) {
312 /* XXX check that the attachment point's Type != GL_NONE */
313 ctx
->CurrentFramebuffer
->DrawBuffer
[0] = mode
;
316 _mesa_error(ctx
, GL_INVALID_ENUM
, "glDrawBuffer(mode)");
322 /* conventional behaviour */
323 /* Do error checking and compute the _DrawDestMask bitfield. */
324 GLenum destMask
, supportedMask
;
326 destMask
= draw_buffer_enum_to_bitmask(mode
);
327 if (destMask
== ~0u) {
328 _mesa_error(ctx
, GL_INVALID_ENUM
, "glDrawBuffer(mode)");
332 supportedMask
= supported_buffer_bitmask(ctx
);
333 destMask
&= supportedMask
;
336 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glDrawBuffer(mode)");
340 ctx
->Color
.DrawBuffer
[0] = mode
;
341 ctx
->Color
._DrawDestMask
[0] = destMask
;
342 ctx
->NewState
|= _NEW_COLOR
;
346 * Call device driver function.
348 if (ctx
->Driver
.DrawBuffer
)
349 (*ctx
->Driver
.DrawBuffer
)(ctx
, mode
);
354 * Called by glDrawBuffersARB; specifies the destination color buffers
355 * for N fragment program color outputs.
358 _mesa_DrawBuffersARB(GLsizei n
, const GLenum
*buffers
)
360 GET_CURRENT_CONTEXT(ctx
);
361 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
363 if (n
< 1 || n
> (GLsizei
) ctx
->Const
.MaxDrawBuffers
) {
364 _mesa_error(ctx
, GL_INVALID_VALUE
, "glDrawBuffersARB(n)" );
368 if (ctx
->Extensions
.EXT_framebuffer_object
&& ctx
->CurrentFramebuffer
) {
369 /* Set drawbuffers for a framebuffer object */
371 GLuint usedAttachments
= 0x0;
372 for (i
= 0; i
< n
; i
++) {
373 if (buffers
[i
] == GL_NONE
) {
375 ctx
->CurrentFramebuffer
->DrawBuffer
[i
] = GL_NONE
;
378 const GLint k
= buffers
[i
] - GL_COLOR_ATTACHMENT0_EXT
;
379 if (k
>= 0 && k
< ctx
->Const
.MaxColorAttachments
) {
380 /* XXX check that the attachment point's Type != GL_NONE */
381 if ((1 << k
) & usedAttachments
) {
382 _mesa_error(ctx
, GL_INVALID_OPERATION
,
383 "glDrawBuffersARB(duplicated attachment)");
386 usedAttachments
|= (1 << k
);
387 ctx
->CurrentFramebuffer
->DrawBuffer
[i
] = buffers
[i
];
390 _mesa_error(ctx
, GL_INVALID_ENUM
, "glDrawBuffersARB(mode)");
396 /* set remaining color outputs to NONE */
397 for (i
= n
; i
< ctx
->Const
.MaxDrawBuffers
; i
++) {
398 ctx
->CurrentFramebuffer
->DrawBuffer
[i
] = GL_NONE
;
402 /* Conventional operation */
404 GLuint usedBufferMask
, supportedMask
;
406 supportedMask
= supported_buffer_bitmask(ctx
);
408 for (i
= 0; i
< n
; i
++) {
409 GLuint destMask
= draw_buffer_enum_to_bitmask(buffers
[i
]);
410 if (destMask
== ~0u ) {
411 _mesa_error(ctx
, GL_INVALID_ENUM
, "glDrawBuffersARB(buffer)");
414 destMask
&= supportedMask
;
416 _mesa_error(ctx
, GL_INVALID_OPERATION
,
417 "glDrawBuffersARB(unsupported buffer)");
420 if (destMask
& usedBufferMask
) {
421 /* can't specify a dest buffer more than once! */
422 _mesa_error(ctx
, GL_INVALID_OPERATION
,
423 "glDrawBuffersARB(duplicated buffer)");
427 usedBufferMask
|= destMask
;
429 ctx
->Color
.DrawBuffer
[i
] = buffers
[i
];
430 ctx
->Color
._DrawDestMask
[i
] = destMask
;
433 /* set remaining color outputs to NONE */
434 for (i
= n
; i
< ctx
->Const
.MaxDrawBuffers
; i
++) {
435 ctx
->Color
.DrawBuffer
[i
] = GL_NONE
;
436 ctx
->Color
._DrawDestMask
[i
] = 0;
439 ctx
->NewState
|= _NEW_COLOR
;
443 * Call device driver function.
445 if (ctx
->Driver
.DrawBuffers
)
446 (*ctx
->Driver
.DrawBuffers
)(ctx
, n
, buffers
);
451 * Set the color buffer source for reading pixels.
453 * \param mode color buffer.
455 * \sa glReadBuffer().
457 * Verifies the parameter and updates gl_pixel_attrib::_ReadSrcMask. Marks
458 * new pixel state in __GLcontextRec::NewState and notifies the driver via
459 * dd_function_table::ReadBuffer.
462 _mesa_ReadBuffer( GLenum mode
)
464 GET_CURRENT_CONTEXT(ctx
);
465 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
467 if (MESA_VERBOSE
& VERBOSE_API
)
468 _mesa_debug(ctx
, "glReadBuffer %s\n", _mesa_lookup_enum_by_nr(mode
));
470 if (ctx
->Extensions
.EXT_framebuffer_object
&& ctx
->CurrentFramebuffer
) {
471 /* Set readbuffer for a framebuffer object */
472 if (mode
== GL_NONE
) {
473 ctx
->CurrentFramebuffer
->ReadBuffer
= mode
;
476 const GLint k
= mode
- GL_COLOR_ATTACHMENT0_EXT
;
477 if (k
>= 0 && k
< ctx
->Const
.MaxColorAttachments
) {
478 /* XXX check that the attachment point's Type != GL_NONE */
479 ctx
->CurrentFramebuffer
->ReadBuffer
= mode
;
482 _mesa_error(ctx
, GL_INVALID_ENUM
, "glReadBuffer(mode)");
488 /* conventional operation */
489 GLuint srcMask
, supportedMask
;
491 srcMask
= read_buffer_enum_to_bitmask(mode
);
492 if (srcMask
== ~0u) {
493 _mesa_error(ctx
, GL_INVALID_ENUM
, "glReadBuffer(mode)");
496 supportedMask
= supported_buffer_bitmask(ctx
);
497 if ((srcMask
& supportedMask
) == 0) {
498 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glReadBuffer(mode)");
501 ctx
->Pixel
._ReadSrcMask
= srcMask
;
502 ctx
->Pixel
.ReadBuffer
= mode
;
503 ctx
->NewState
|= _NEW_PIXEL
;
507 * Call device driver function.
509 if (ctx
->Driver
.ReadBuffer
)
510 (*ctx
->Driver
.ReadBuffer
)(ctx
, mode
);
517 * GL_MESA_resize_buffers extension.
519 * When this function is called, we'll ask the window system how large
520 * the current window is. If it's a new size, we'll call the driver's
521 * ResizeBuffers function. The driver will then resize its color buffers
522 * as needed, and maybe call the swrast's routine for reallocating
523 * swrast-managed depth/stencil/accum/etc buffers.
524 * \note This function may be called from within Mesa or called by the
525 * user directly (see the GL_MESA_resize_buffers extension).
528 _mesa_ResizeBuffersMESA( void )
530 GET_CURRENT_CONTEXT(ctx
);
532 if (MESA_VERBOSE
& VERBOSE_API
)
533 _mesa_debug(ctx
, "glResizeBuffersMESA\n");
536 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH( ctx
);
538 if (ctx
->DrawBuffer
) {
539 GLuint buf_width
, buf_height
;
540 GLframebuffer
*buffer
= ctx
->DrawBuffer
;
542 /* ask device driver for size of output buffer */
543 (*ctx
->Driver
.GetBufferSize
)( buffer
, &buf_width
, &buf_height
);
545 /* see if size of device driver's color buffer (window) has changed */
546 if (buffer
->Width
== buf_width
&& buffer
->Height
== buf_height
)
547 return; /* size is as expected */
549 buffer
->Width
= buf_width
;
550 buffer
->Height
= buf_height
;
552 ctx
->Driver
.ResizeBuffers( buffer
);
555 if (ctx
->ReadBuffer
&& ctx
->ReadBuffer
!= ctx
->DrawBuffer
) {
556 GLuint buf_width
, buf_height
;
557 GLframebuffer
*buffer
= ctx
->ReadBuffer
;
559 /* ask device driver for size of read buffer */
560 (*ctx
->Driver
.GetBufferSize
)( buffer
, &buf_width
, &buf_height
);
562 /* see if size of device driver's color buffer (window) has changed */
563 if (buffer
->Width
== buf_width
&& buffer
->Height
== buf_height
)
564 return; /* size is as expected */
566 buffer
->Width
= buf_width
;
567 buffer
->Height
= buf_height
;
569 ctx
->Driver
.ResizeBuffers( buffer
);
572 ctx
->NewState
|= _NEW_BUFFERS
; /* to update scissor / window bounds */
578 * XXX move somewhere else someday?
581 _mesa_SampleCoverageARB(GLclampf value
, GLboolean invert
)
583 GET_CURRENT_CONTEXT(ctx
);
585 if (!ctx
->Extensions
.ARB_multisample
) {
586 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glSampleCoverageARB");
590 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH( ctx
);
591 ctx
->Multisample
.SampleCoverageValue
= (GLfloat
) CLAMP(value
, 0.0, 1.0);
592 ctx
->Multisample
.SampleCoverageInvert
= invert
;
593 ctx
->NewState
|= _NEW_MULTISAMPLE
;
600 * Define the scissor box.
602 * \param x, y coordinates of the scissor box lower-left corner.
603 * \param width width of the scissor box.
604 * \param height height of the scissor box.
608 * Verifies the parameters and updates __GLcontextRec::Scissor. On a
609 * change flushes the vertices and notifies the driver via
610 * the dd_function_table::Scissor callback.
613 _mesa_Scissor( GLint x
, GLint y
, GLsizei width
, GLsizei height
)
615 GET_CURRENT_CONTEXT(ctx
);
616 ASSERT_OUTSIDE_BEGIN_END(ctx
);
618 if (width
< 0 || height
< 0) {
619 _mesa_error( ctx
, GL_INVALID_VALUE
, "glScissor" );
623 if (MESA_VERBOSE
& VERBOSE_API
)
624 _mesa_debug(ctx
, "glScissor %d %d %d %d\n", x
, y
, width
, height
);
626 if (x
== ctx
->Scissor
.X
&&
627 y
== ctx
->Scissor
.Y
&&
628 width
== ctx
->Scissor
.Width
&&
629 height
== ctx
->Scissor
.Height
)
632 FLUSH_VERTICES(ctx
, _NEW_SCISSOR
);
635 ctx
->Scissor
.Width
= width
;
636 ctx
->Scissor
.Height
= height
;
638 if (ctx
->Driver
.Scissor
)
639 ctx
->Driver
.Scissor( ctx
, x
, y
, width
, height
);
644 /**********************************************************************/
645 /** \name State management */
650 * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields.
651 * These values are computed from the buffer's width and height and
652 * the scissor box, if it's enabled.
653 * \param ctx the GL context.
656 _mesa_update_draw_buffer_bounds(GLcontext
*ctx
)
658 GLframebuffer
*buffer
= ctx
->DrawBuffer
;
662 buffer
->_Xmax
= buffer
->Width
;
663 buffer
->_Ymax
= buffer
->Height
;
665 if (ctx
->Scissor
.Enabled
) {
666 if (ctx
->Scissor
.X
> buffer
->_Xmin
) {
667 buffer
->_Xmin
= ctx
->Scissor
.X
;
669 if (ctx
->Scissor
.Y
> buffer
->_Ymin
) {
670 buffer
->_Ymin
= ctx
->Scissor
.Y
;
672 if (ctx
->Scissor
.X
+ ctx
->Scissor
.Width
< buffer
->_Xmax
) {
673 buffer
->_Xmax
= ctx
->Scissor
.X
+ ctx
->Scissor
.Width
;
675 if (ctx
->Scissor
.Y
+ ctx
->Scissor
.Height
< buffer
->_Ymax
) {
676 buffer
->_Ymax
= ctx
->Scissor
.Y
+ ctx
->Scissor
.Height
;
678 /* finally, check for empty region */
679 if (buffer
->_Xmin
> buffer
->_Xmax
) {
680 buffer
->_Xmin
= buffer
->_Xmax
;
682 if (buffer
->_Ymin
> buffer
->_Ymax
) {
683 buffer
->_Ymin
= buffer
->_Ymax
;
687 ASSERT(buffer
->_Xmin
<= buffer
->_Xmax
);
688 ASSERT(buffer
->_Ymin
<= buffer
->_Ymax
);
694 /**********************************************************************/
695 /** \name Initialization */
699 * Initialize the context's scissor state.
700 * \param ctx the GL context.
703 _mesa_init_scissor(GLcontext
*ctx
)
706 ctx
->Scissor
.Enabled
= GL_FALSE
;
709 ctx
->Scissor
.Width
= 0;
710 ctx
->Scissor
.Height
= 0;
715 * Initialize the context's multisample state.
716 * \param ctx the GL context.
719 _mesa_init_multisample(GLcontext
*ctx
)
721 ctx
->Multisample
.Enabled
= GL_FALSE
;
722 ctx
->Multisample
.SampleAlphaToCoverage
= GL_FALSE
;
723 ctx
->Multisample
.SampleAlphaToOne
= GL_FALSE
;
724 ctx
->Multisample
.SampleCoverage
= GL_FALSE
;
725 ctx
->Multisample
.SampleCoverageValue
= 1.0;
726 ctx
->Multisample
.SampleCoverageInvert
= GL_FALSE
;