35e03d7eb5cca9229d4fa5f849f3fcbed11e0ad7
[mesa.git] / src / mesa / main / buffers.c
1 /**
2 * \file buffers.c
3 * Frame buffer management.
4 */
5
6 /*
7 * Mesa 3-D graphics library
8 * Version: 6.1
9 *
10 * Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
11 *
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:
18 *
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
21 *
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.
28 */
29
30
31 #include "glheader.h"
32 #include "imports.h"
33 #include "buffers.h"
34 #include "colormac.h"
35 #include "context.h"
36 #include "depth.h"
37 #include "enums.h"
38 #include "stencil.h"
39 #include "state.h"
40 #include "mtypes.h"
41
42
43 #if _HAVE_FULL_GL
44 void 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 if (!ctx->Visual.rgbMode && ctx->Driver.ClearIndex) {
57 /* it's OK to call glClearIndex in RGBA mode but it should be a NOP */
58 (*ctx->Driver.ClearIndex)( ctx, ctx->Color.ClearIndex );
59 }
60 }
61 #endif
62
63
64 /**
65 * Specify the clear values for the color buffers.
66 *
67 * \param red red color component.
68 * \param green green color component.
69 * \param blue blue color component.
70 * \param alpha alpha component.
71 *
72 * \sa glClearColor().
73 *
74 * Clamps the parameters and updates gl_colorbuffer_attrib::ClearColor. On a
75 * change, flushes the vertices and notifies the driver via the
76 * dd_function_table::ClearColor callback.
77 */
78 void GLAPIENTRY
79 _mesa_ClearColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )
80 {
81 GLfloat tmp[4];
82 GET_CURRENT_CONTEXT(ctx);
83 ASSERT_OUTSIDE_BEGIN_END(ctx);
84
85 tmp[0] = CLAMP(red, 0.0F, 1.0F);
86 tmp[1] = CLAMP(green, 0.0F, 1.0F);
87 tmp[2] = CLAMP(blue, 0.0F, 1.0F);
88 tmp[3] = CLAMP(alpha, 0.0F, 1.0F);
89
90 if (TEST_EQ_4V(tmp, ctx->Color.ClearColor))
91 return; /* no change */
92
93 FLUSH_VERTICES(ctx, _NEW_COLOR);
94 COPY_4V(ctx->Color.ClearColor, tmp);
95
96 if (ctx->Visual.rgbMode && ctx->Driver.ClearColor) {
97 /* it's OK to call glClearColor in CI mode but it should be a NOP */
98 (*ctx->Driver.ClearColor)(ctx, ctx->Color.ClearColor);
99 }
100 }
101
102
103 /**
104 * Clear buffers.
105 *
106 * \param mask bit-mask indicating the buffers to be cleared.
107 *
108 * Flushes the vertices and verifies the parameter. If __GLcontextRec::NewState
109 * is set then calls _mesa_update_state() to update gl_frame_buffer::_Xmin,
110 * etc. If the rasterization mode is set to GL_RENDER then requests the driver
111 * to clear the buffers, via the dd_function_table::Clear callback.
112 */
113 void GLAPIENTRY
114 _mesa_Clear( GLbitfield mask )
115 {
116 GET_CURRENT_CONTEXT(ctx);
117 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
118
119 if (MESA_VERBOSE & VERBOSE_API)
120 _mesa_debug(ctx, "glClear 0x%x\n", mask);
121
122 if (mask & ~(GL_COLOR_BUFFER_BIT |
123 GL_DEPTH_BUFFER_BIT |
124 GL_STENCIL_BUFFER_BIT |
125 GL_ACCUM_BUFFER_BIT)) {
126 /* invalid bit set */
127 _mesa_error( ctx, GL_INVALID_VALUE, "glClear(0x%x)", mask);
128 return;
129 }
130
131 if (ctx->NewState) {
132 _mesa_update_state( ctx ); /* update _Xmin, etc */
133 }
134
135 if (ctx->RenderMode==GL_RENDER) {
136 const GLint x = ctx->DrawBuffer->_Xmin;
137 const GLint y = ctx->DrawBuffer->_Ymin;
138 const GLint height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
139 const GLint width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
140 GLbitfield ddMask;
141
142 /* don't clear depth buffer if depth writing disabled */
143 if (!ctx->Depth.Mask)
144 mask &= ~GL_DEPTH_BUFFER_BIT;
145
146 /* Build the bitmask to send to device driver's Clear function.
147 * Note that the GL_COLOR_BUFFER_BIT flag will expand to 0, 1, 2 or 4
148 * of the FRONT/BACK_LEFT/RIGHT_BIT flags.
149 */
150 ddMask = 0;
151 if (mask & GL_COLOR_BUFFER_BIT)
152 ddMask |= ctx->Color._DrawDestMask[0];
153 if ((mask & GL_DEPTH_BUFFER_BIT) && ctx->Visual.depthBits > 0)
154 ddMask |= GL_DEPTH_BUFFER_BIT;
155 if ((mask & GL_STENCIL_BUFFER_BIT) && ctx->Visual.stencilBits > 0)
156 ddMask |= GL_STENCIL_BUFFER_BIT;
157 if ((mask & GL_ACCUM_BUFFER_BIT) && ctx->Visual.accumRedBits > 0)
158 ddMask |= GL_ACCUM_BUFFER_BIT;
159
160 ASSERT(ctx->Driver.Clear);
161 ctx->Driver.Clear( ctx, ddMask, (GLboolean) !ctx->Scissor.Enabled,
162 x, y, width, height );
163 }
164 }
165
166
167
168 /**
169 * Return bitmask of DD_* flags indicating which color buffers are
170 * available to the rendering context;
171 */
172 static GLuint
173 supported_buffer_bitmask(const GLcontext *ctx)
174 {
175 GLuint mask = DD_FRONT_LEFT_BIT; /* always have this */
176 GLuint i;
177
178 if (ctx->Visual.stereoMode) {
179 mask |= DD_FRONT_RIGHT_BIT;
180 if (ctx->Visual.doubleBufferMode) {
181 mask |= DD_BACK_LEFT_BIT | DD_BACK_RIGHT_BIT;
182 }
183 }
184 else if (ctx->Visual.doubleBufferMode) {
185 mask |= DD_BACK_LEFT_BIT;
186 }
187
188 for (i = 0; i < ctx->Visual.numAuxBuffers; i++) {
189 mask |= (DD_AUX0_BIT << i);
190 }
191
192 return mask;
193 }
194
195
196 /**
197 * Helper routine used by glDrawBuffer and glDrawBuffersARB.
198 * Given a GLenum naming (a) color buffer(s), return the corresponding
199 * bitmask of DD_* flags.
200 */
201 static GLuint
202 draw_buffer_enum_to_bitmask(GLenum buffer)
203 {
204 switch (buffer) {
205 case GL_FRONT:
206 return DD_FRONT_LEFT_BIT | DD_FRONT_RIGHT_BIT;
207 case GL_BACK:
208 return DD_BACK_LEFT_BIT | DD_BACK_RIGHT_BIT;
209 case GL_NONE:
210 return 0;
211 case GL_RIGHT:
212 return DD_FRONT_RIGHT_BIT | DD_BACK_RIGHT_BIT;
213 case GL_FRONT_RIGHT:
214 return DD_FRONT_RIGHT_BIT;
215 case GL_BACK_RIGHT:
216 return DD_BACK_RIGHT_BIT;
217 case GL_BACK_LEFT:
218 return DD_BACK_LEFT_BIT;
219 case GL_FRONT_AND_BACK:
220 return DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT
221 | DD_FRONT_RIGHT_BIT | DD_BACK_RIGHT_BIT;
222 case GL_LEFT:
223 return DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT;
224 case GL_FRONT_LEFT:
225 return DD_FRONT_LEFT_BIT;
226 case GL_AUX0:
227 return DD_AUX0_BIT;
228 case GL_AUX1:
229 return DD_AUX1_BIT;
230 case GL_AUX2:
231 return DD_AUX2_BIT;
232 case GL_AUX3:
233 return DD_AUX3_BIT;
234 default:
235 /* error */
236 return ~0;
237 }
238 }
239
240
241 /**
242 * Helper routine used by glReadBuffer.
243 * Given a GLenum naming (a) color buffer(s), return the corresponding
244 * bitmask of DD_* flags.
245 */
246 static GLuint
247 read_buffer_enum_to_bitmask(GLenum buffer)
248 {
249 switch (buffer) {
250 case GL_FRONT:
251 return DD_FRONT_LEFT_BIT;
252 case GL_BACK:
253 return DD_BACK_LEFT_BIT;
254 case GL_RIGHT:
255 return DD_FRONT_RIGHT_BIT;
256 case GL_FRONT_RIGHT:
257 return DD_FRONT_RIGHT_BIT;
258 case GL_BACK_RIGHT:
259 return DD_BACK_RIGHT_BIT;
260 case GL_BACK_LEFT:
261 return DD_BACK_LEFT_BIT;
262 case GL_LEFT:
263 return DD_FRONT_LEFT_BIT;
264 case GL_FRONT_LEFT:
265 return DD_FRONT_LEFT_BIT;
266 case GL_AUX0:
267 return DD_AUX0_BIT;
268 case GL_AUX1:
269 return DD_AUX1_BIT;
270 case GL_AUX2:
271 return DD_AUX2_BIT;
272 case GL_AUX3:
273 return DD_AUX3_BIT;
274 default:
275 /* error */
276 return ~0;
277 }
278 }
279
280
281
282 /**
283 * Specify which color buffers to draw into.
284 *
285 * \param mode color buffer combination.
286 *
287 * \sa glDrawBuffer().
288 *
289 * Flushes the vertices and verifies the parameter and updates the
290 * gl_colorbuffer_attrib::_DrawDestMask bitfield. Marks new color state in
291 * __GLcontextRec::NewState and notifies the driver via the
292 * dd_function_table::DrawBuffer callback.
293 */
294 void GLAPIENTRY
295 _mesa_DrawBuffer( GLenum mode )
296 {
297 GLenum destMask, supportedMask;
298 GET_CURRENT_CONTEXT(ctx);
299 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex... */
300
301 if (MESA_VERBOSE & VERBOSE_API)
302 _mesa_debug(ctx, "glDrawBuffer %s\n", _mesa_lookup_enum_by_nr(mode));
303
304 /*
305 * Do error checking and compute the _DrawDestMask bitfield.
306 */
307 destMask = draw_buffer_enum_to_bitmask(mode);
308 if (destMask == ~0) {
309 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawBuffer(mode)");
310 return;
311 }
312
313 supportedMask = supported_buffer_bitmask(ctx);
314 destMask &= supportedMask;
315
316 if (destMask == 0) {
317 _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawBuffer(mode)");
318 return;
319 }
320
321 ctx->Color.DrawBuffer[0] = mode;
322 ctx->Color._DrawDestMask[0] = destMask;
323 ctx->NewState |= _NEW_COLOR;
324
325 /*
326 * Call device driver function.
327 */
328 if (ctx->Driver.DrawBuffer)
329 (*ctx->Driver.DrawBuffer)(ctx, mode);
330 }
331
332
333 /**
334 * Called by glDrawBuffersARB; specifies the destination color buffers
335 * for N fragment program color outputs.
336 */
337 void GLAPIENTRY
338 _mesa_DrawBuffersARB(GLsizei n, const GLenum *buffers)
339 {
340 GLint i;
341 GLuint usedBufferMask, supportedMask;
342 GET_CURRENT_CONTEXT(ctx);
343 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
344
345 if (n < 1 || n > ctx->Const.MaxDrawBuffers) {
346 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawBuffersARB(n)" );
347 return;
348 }
349
350 supportedMask = supported_buffer_bitmask(ctx);
351 usedBufferMask = 0;
352 for (i = 0; i < n; i++) {
353 GLuint destMask = draw_buffer_enum_to_bitmask(buffers[i]);
354 if (destMask == ~0) {
355 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawBuffersARB(buffer)");
356 return;
357 }
358 destMask &= supportedMask;
359 if (destMask == 0) {
360 _mesa_error(ctx, GL_INVALID_OPERATION,
361 "glDrawBuffersARB(unsupported buffer)");
362 return;
363 }
364 if (destMask & usedBufferMask) {
365 /* can't use a dest buffer more than once! */
366 _mesa_error(ctx, GL_INVALID_OPERATION,
367 "glDrawBuffersARB(duplicated buffer)");
368 return;
369 }
370 /* update bitmask */
371 usedBufferMask |= destMask;
372 /* save state */
373 ctx->Color.DrawBuffer[i] = buffers[i];
374 ctx->Color._DrawDestMask[i] = destMask;
375 }
376
377 ctx->NewState |= _NEW_COLOR;
378
379 /*
380 * Call device driver function.
381 */
382 if (ctx->Driver.DrawBuffers)
383 (*ctx->Driver.DrawBuffers)(ctx, n, buffers);
384 }
385
386
387 /**
388 * Set the color buffer source for reading pixels.
389 *
390 * \param mode color buffer.
391 *
392 * \sa glReadBuffer().
393 *
394 * Verifies the parameter and updates gl_pixel_attrib::_ReadSrcMask. Marks
395 * new pixel state in __GLcontextRec::NewState and notifies the driver via
396 * dd_function_table::ReadBuffer.
397 */
398 void GLAPIENTRY
399 _mesa_ReadBuffer( GLenum mode )
400 {
401 GLuint srcMask, supportedMask;
402 GET_CURRENT_CONTEXT(ctx);
403 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
404
405 if (MESA_VERBOSE & VERBOSE_API)
406 _mesa_debug(ctx, "glReadBuffer %s\n", _mesa_lookup_enum_by_nr(mode));
407
408 srcMask = read_buffer_enum_to_bitmask(mode);
409 if (srcMask == ~0) {
410 _mesa_error(ctx, GL_INVALID_ENUM, "glReadBuffer(mode)");
411 return;
412 }
413 supportedMask = supported_buffer_bitmask(ctx);
414 if ((srcMask & supportedMask) == 0) {
415 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadBuffer(mode)");
416 return;
417 }
418 ctx->Pixel._ReadSrcMask = srcMask;
419 ctx->Pixel.ReadBuffer = mode;
420 ctx->NewState |= _NEW_PIXEL;
421
422 /*
423 * Call device driver function.
424 */
425 if (ctx->Driver.ReadBuffer)
426 (*ctx->Driver.ReadBuffer)(ctx, mode);
427 }
428
429
430 #if _HAVE_FULL_GL
431
432 /**
433 * GL_MESA_resize_buffers extension.
434 *
435 * When this function is called, we'll ask the window system how large
436 * the current window is. If it's a new size, we'll call the driver's
437 * ResizeBuffers function. The driver will then resize its color buffers
438 * as needed, and maybe call the swrast's routine for reallocating
439 * swrast-managed depth/stencil/accum/etc buffers.
440 * \note This function may be called from within Mesa or called by the
441 * user directly (see the GL_MESA_resize_buffers extension).
442 */
443 void GLAPIENTRY
444 _mesa_ResizeBuffersMESA( void )
445 {
446 GET_CURRENT_CONTEXT(ctx);
447
448 if (MESA_VERBOSE & VERBOSE_API)
449 _mesa_debug(ctx, "glResizeBuffersMESA\n");
450
451 if (ctx) {
452 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH( ctx );
453
454 if (ctx->DrawBuffer) {
455 GLuint buf_width, buf_height;
456 GLframebuffer *buffer = ctx->DrawBuffer;
457
458 /* ask device driver for size of output buffer */
459 (*ctx->Driver.GetBufferSize)( buffer, &buf_width, &buf_height );
460
461 /* see if size of device driver's color buffer (window) has changed */
462 if (buffer->Width == buf_width && buffer->Height == buf_height)
463 return; /* size is as expected */
464
465 buffer->Width = buf_width;
466 buffer->Height = buf_height;
467
468 ctx->Driver.ResizeBuffers( buffer );
469 }
470
471 if (ctx->ReadBuffer && ctx->ReadBuffer != ctx->DrawBuffer) {
472 GLuint buf_width, buf_height;
473 GLframebuffer *buffer = ctx->ReadBuffer;
474
475 /* ask device driver for size of read buffer */
476 (*ctx->Driver.GetBufferSize)( buffer, &buf_width, &buf_height );
477
478 /* see if size of device driver's color buffer (window) has changed */
479 if (buffer->Width == buf_width && buffer->Height == buf_height)
480 return; /* size is as expected */
481
482 buffer->Width = buf_width;
483 buffer->Height = buf_height;
484
485 ctx->Driver.ResizeBuffers( buffer );
486 }
487
488 ctx->NewState |= _NEW_BUFFERS; /* to update scissor / window bounds */
489 }
490 }
491
492
493 /*
494 * XXX move somewhere else someday?
495 */
496 void GLAPIENTRY
497 _mesa_SampleCoverageARB(GLclampf value, GLboolean invert)
498 {
499 GET_CURRENT_CONTEXT(ctx);
500
501 if (!ctx->Extensions.ARB_multisample) {
502 _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleCoverageARB");
503 return;
504 }
505
506 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH( ctx );
507 ctx->Multisample.SampleCoverageValue = (GLfloat) CLAMP(value, 0.0, 1.0);
508 ctx->Multisample.SampleCoverageInvert = invert;
509 ctx->NewState |= _NEW_MULTISAMPLE;
510 }
511
512 #endif
513
514
515 /**
516 * Define the scissor box.
517 *
518 * \param x, y coordinates of the scissor box lower-left corner.
519 * \param width width of the scissor box.
520 * \param height height of the scissor box.
521 *
522 * \sa glScissor().
523 *
524 * Verifies the parameters and updates __GLcontextRec::Scissor. On a
525 * change flushes the vertices and notifies the driver via
526 * the dd_function_table::Scissor callback.
527 */
528 void GLAPIENTRY
529 _mesa_Scissor( GLint x, GLint y, GLsizei width, GLsizei height )
530 {
531 GET_CURRENT_CONTEXT(ctx);
532 ASSERT_OUTSIDE_BEGIN_END(ctx);
533
534 if (width < 0 || height < 0) {
535 _mesa_error( ctx, GL_INVALID_VALUE, "glScissor" );
536 return;
537 }
538
539 if (MESA_VERBOSE & VERBOSE_API)
540 _mesa_debug(ctx, "glScissor %d %d %d %d\n", x, y, width, height);
541
542 if (x == ctx->Scissor.X &&
543 y == ctx->Scissor.Y &&
544 width == ctx->Scissor.Width &&
545 height == ctx->Scissor.Height)
546 return;
547
548 FLUSH_VERTICES(ctx, _NEW_SCISSOR);
549 ctx->Scissor.X = x;
550 ctx->Scissor.Y = y;
551 ctx->Scissor.Width = width;
552 ctx->Scissor.Height = height;
553
554 if (ctx->Driver.Scissor)
555 ctx->Driver.Scissor( ctx, x, y, width, height );
556 }
557
558
559
560 /**********************************************************************/
561 /** \name State management */
562 /*@{*/
563
564 /**
565 * Update screen bounds.
566 *
567 * \param ctx GL context.
568 *
569 * Update gl_frame_buffer::_Xmin, and etc.
570 */
571 void _mesa_update_buffers( GLcontext *ctx )
572 {
573 ctx->DrawBuffer->_Xmin = 0;
574 ctx->DrawBuffer->_Ymin = 0;
575 ctx->DrawBuffer->_Xmax = ctx->DrawBuffer->Width;
576 ctx->DrawBuffer->_Ymax = ctx->DrawBuffer->Height;
577 if (ctx->Scissor.Enabled) {
578 if (ctx->Scissor.X > ctx->DrawBuffer->_Xmin) {
579 ctx->DrawBuffer->_Xmin = ctx->Scissor.X;
580 }
581 if (ctx->Scissor.Y > ctx->DrawBuffer->_Ymin) {
582 ctx->DrawBuffer->_Ymin = ctx->Scissor.Y;
583 }
584 if (ctx->Scissor.X + ctx->Scissor.Width < ctx->DrawBuffer->_Xmax) {
585 ctx->DrawBuffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width;
586 }
587 if (ctx->Scissor.Y + ctx->Scissor.Height < ctx->DrawBuffer->_Ymax) {
588 ctx->DrawBuffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height;
589 }
590 }
591 }
592
593 /*@}*/
594
595
596 /**********************************************************************/
597 /** \name Initialization */
598 /*@{*/
599
600 /**
601 * Initialize the context scissor data.
602 *
603 * \param ctx GL context.
604 *
605 * Initializes the __GLcontextRec::Scissor and __GLcontextRec::Multisample
606 * attribute groups, and related constants in __GLcontextRec::Const.
607 */
608 void _mesa_init_buffers( GLcontext * ctx )
609 {
610 /* Scissor group */
611 ctx->Scissor.Enabled = GL_FALSE;
612 ctx->Scissor.X = 0;
613 ctx->Scissor.Y = 0;
614 ctx->Scissor.Width = 0;
615 ctx->Scissor.Height = 0;
616
617 /* Multisample */
618 ctx->Multisample.Enabled = GL_FALSE;
619 ctx->Multisample.SampleAlphaToCoverage = GL_FALSE;
620 ctx->Multisample.SampleAlphaToOne = GL_FALSE;
621 ctx->Multisample.SampleCoverage = GL_FALSE;
622 ctx->Multisample.SampleCoverageValue = 1.0;
623 ctx->Multisample.SampleCoverageInvert = GL_FALSE;
624
625 }
626
627 /*@}*/