f7e922e2a22f8c91980b04c248cb5081f111fffe
[mesa.git] / src / mesa / main / buffers.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 5.1
4 *
5 * Copyright (C) 1999-2003 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 #include "glheader.h"
27 #include "imports.h"
28 #include "accum.h"
29 #include "buffers.h"
30 #include "colormac.h"
31 #include "context.h"
32 #include "depth.h"
33 #include "enums.h"
34 #include "stencil.h"
35 #include "state.h"
36 #include "mtypes.h"
37
38
39
40 void
41 _mesa_ClearIndex( GLfloat c )
42 {
43 GET_CURRENT_CONTEXT(ctx);
44 ASSERT_OUTSIDE_BEGIN_END(ctx);
45
46 if (ctx->Color.ClearIndex == (GLuint) c)
47 return;
48
49 FLUSH_VERTICES(ctx, _NEW_COLOR);
50 ctx->Color.ClearIndex = (GLuint) c;
51
52 if (!ctx->Visual.rgbMode && ctx->Driver.ClearIndex) {
53 /* it's OK to call glClearIndex in RGBA mode but it should be a NOP */
54 (*ctx->Driver.ClearIndex)( ctx, ctx->Color.ClearIndex );
55 }
56 }
57
58
59
60 void
61 _mesa_ClearColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )
62 {
63 GLfloat tmp[4];
64 GET_CURRENT_CONTEXT(ctx);
65 ASSERT_OUTSIDE_BEGIN_END(ctx);
66
67 tmp[0] = CLAMP(red, 0.0F, 1.0F);
68 tmp[1] = CLAMP(green, 0.0F, 1.0F);
69 tmp[2] = CLAMP(blue, 0.0F, 1.0F);
70 tmp[3] = CLAMP(alpha, 0.0F, 1.0F);
71
72 if (TEST_EQ_4V(tmp, ctx->Color.ClearColor))
73 return; /* no change */
74
75 FLUSH_VERTICES(ctx, _NEW_COLOR);
76 COPY_4V(ctx->Color.ClearColor, tmp);
77
78 if (ctx->Visual.rgbMode && ctx->Driver.ClearColor) {
79 /* it's OK to call glClearColor in CI mode but it should be a NOP */
80 (*ctx->Driver.ClearColor)(ctx, ctx->Color.ClearColor);
81 }
82 }
83
84
85
86 void
87 _mesa_Clear( GLbitfield mask )
88 {
89 GET_CURRENT_CONTEXT(ctx);
90 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
91
92 if (MESA_VERBOSE & VERBOSE_API)
93 _mesa_debug(ctx, "glClear 0x%x\n", mask);
94
95 if (mask & ~(GL_COLOR_BUFFER_BIT |
96 GL_DEPTH_BUFFER_BIT |
97 GL_STENCIL_BUFFER_BIT |
98 GL_ACCUM_BUFFER_BIT)) {
99 /* invalid bit set */
100 _mesa_error( ctx, GL_INVALID_VALUE, "glClear(mask)");
101 return;
102 }
103
104 if (ctx->NewState) {
105 _mesa_update_state( ctx ); /* update _Xmin, etc */
106 }
107
108 if (ctx->RenderMode==GL_RENDER) {
109 const GLint x = ctx->DrawBuffer->_Xmin;
110 const GLint y = ctx->DrawBuffer->_Ymin;
111 const GLint height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
112 const GLint width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
113 GLbitfield ddMask;
114
115 /* don't clear depth buffer if depth writing disabled */
116 if (!ctx->Depth.Mask)
117 mask &= ~GL_DEPTH_BUFFER_BIT;
118
119 /* Build the bitmask to send to device driver's Clear function.
120 * Note that the GL_COLOR_BUFFER_BIT flag will expand to 0, 1, 2 or 4
121 * of the FRONT/BACK_LEFT/RIGHT_BIT flags.
122 */
123 ddMask = 0;
124 if (mask & GL_COLOR_BUFFER_BIT)
125 ddMask |= ctx->Color._DrawDestMask;
126 if ((mask & GL_DEPTH_BUFFER_BIT) && ctx->Visual.depthBits > 0)
127 ddMask |= GL_DEPTH_BUFFER_BIT;
128 if ((mask & GL_STENCIL_BUFFER_BIT) && ctx->Visual.stencilBits > 0)
129 ddMask |= GL_STENCIL_BUFFER_BIT;
130 if ((mask & GL_ACCUM_BUFFER_BIT) && ctx->Visual.accumRedBits > 0)
131 ddMask |= GL_ACCUM_BUFFER_BIT;
132
133 ASSERT(ctx->Driver.Clear);
134 ctx->Driver.Clear( ctx, ddMask, (GLboolean) !ctx->Scissor.Enabled,
135 x, y, width, height );
136 }
137 }
138
139
140 void
141 _mesa_DrawBuffer( GLenum mode )
142 {
143 GET_CURRENT_CONTEXT(ctx);
144 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex... */
145
146 if (MESA_VERBOSE & VERBOSE_API)
147 _mesa_debug(ctx, "glDrawBuffer %s\n", _mesa_lookup_enum_by_nr(mode));
148
149 /*
150 * Do error checking and compute the _DrawDestMask bitfield.
151 */
152 switch (mode) {
153 case GL_RIGHT:
154 if (!ctx->Visual.stereoMode) {
155 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
156 return;}
157 if (ctx->Visual.doubleBufferMode)
158 ctx->Color._DrawDestMask = FRONT_RIGHT_BIT | BACK_RIGHT_BIT;
159 else
160 ctx->Color._DrawDestMask = FRONT_RIGHT_BIT;
161 break;
162 case GL_FRONT_RIGHT:
163 if (!ctx->Visual.stereoMode) {
164 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
165 return;
166 }
167 ctx->Color._DrawDestMask = FRONT_RIGHT_BIT;
168 break;
169 case GL_BACK_RIGHT:
170 if (!ctx->Visual.stereoMode || !ctx->Visual.doubleBufferMode) {
171 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
172 return;
173 }
174 ctx->Color._DrawDestMask = BACK_RIGHT_BIT;
175 break;
176 case GL_BACK_LEFT:
177 if (!ctx->Visual.doubleBufferMode) {
178 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
179 return;
180 }
181 ctx->Color._DrawDestMask = BACK_LEFT_BIT;
182 break;
183 case GL_FRONT_AND_BACK:
184 if (!ctx->Visual.doubleBufferMode) {
185 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
186 return;
187 }
188 if (ctx->Visual.stereoMode)
189 ctx->Color._DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT
190 | FRONT_RIGHT_BIT | BACK_RIGHT_BIT;
191 else
192 ctx->Color._DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT;
193 break;
194 case GL_BACK:
195 if (!ctx->Visual.doubleBufferMode) {
196 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
197 return;
198 }
199 if (ctx->Visual.stereoMode)
200 ctx->Color._DrawDestMask = BACK_LEFT_BIT | BACK_RIGHT_BIT;
201 else
202 ctx->Color._DrawDestMask = BACK_LEFT_BIT;
203 break;
204 case GL_LEFT:
205 /* never an error */
206 if (ctx->Visual.doubleBufferMode)
207 ctx->Color._DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT;
208 else
209 ctx->Color._DrawDestMask = FRONT_LEFT_BIT;
210 break;
211 case GL_FRONT_LEFT:
212 /* never an error */
213 ctx->Color._DrawDestMask = FRONT_LEFT_BIT;
214 break;
215 case GL_FRONT:
216 /* never an error */
217 if (ctx->Visual.stereoMode)
218 ctx->Color._DrawDestMask = FRONT_LEFT_BIT | FRONT_RIGHT_BIT;
219 else
220 ctx->Color._DrawDestMask = FRONT_LEFT_BIT;
221 break;
222 case GL_NONE:
223 /* never an error */
224 ctx->Color._DrawDestMask = 0;
225 break;
226 case GL_AUX0:
227 if (ctx->Const.NumAuxBuffers >= 1) {
228 ctx->Color._DrawDestMask = AUX0_BIT;
229 }
230 else {
231 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer(GL_AUX0)" );
232 return;
233 }
234 break;
235 case GL_AUX1:
236 if (ctx->Const.NumAuxBuffers >= 2) {
237 ctx->Color._DrawDestMask = AUX1_BIT;
238 }
239 else {
240 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer(GL_AUX1)" );
241 return;
242 }
243 break;
244 case GL_AUX2:
245 if (ctx->Const.NumAuxBuffers >= 3) {
246 ctx->Color._DrawDestMask = AUX2_BIT;
247 }
248 else {
249 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer(GL_AUX2)" );
250 return;
251 }
252 break;
253 case GL_AUX3:
254 if (ctx->Const.NumAuxBuffers >= 4) {
255 ctx->Color._DrawDestMask = AUX3_BIT;
256 }
257 else {
258 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer(GL_AUX3)" );
259 return;
260 }
261 break;
262 default:
263 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawBuffer" );
264 return;
265 }
266
267 ctx->Color.DrawBuffer = mode;
268 ctx->NewState |= _NEW_COLOR;
269
270 /*
271 * Call device driver function.
272 */
273 if (ctx->Driver.DrawBuffer)
274 (*ctx->Driver.DrawBuffer)(ctx, mode);
275 }
276
277
278
279 void
280 _mesa_ReadBuffer( GLenum mode )
281 {
282 GET_CURRENT_CONTEXT(ctx);
283 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
284
285 if (MESA_VERBOSE & VERBOSE_API)
286 _mesa_debug(ctx, "glReadBuffer %s\n", _mesa_lookup_enum_by_nr(mode));
287
288 /*
289 * Do error checking and compute ctx->Pixel._ReadSrcMask.
290 */
291 switch (mode) {
292 case GL_LEFT:
293 case GL_FRONT:
294 case GL_FRONT_LEFT:
295 /* Front-Left buffer, always exists */
296 ctx->Pixel._ReadSrcMask = FRONT_LEFT_BIT;
297 break;
298 case GL_BACK:
299 case GL_BACK_LEFT:
300 /* Back-Left buffer, requires double buffering */
301 if (!ctx->Visual.doubleBufferMode) {
302 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
303 return;
304 }
305 ctx->Pixel._ReadSrcMask = BACK_LEFT_BIT;
306 break;
307 case GL_FRONT_RIGHT:
308 case GL_RIGHT:
309 if (!ctx->Visual.stereoMode) {
310 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
311 return;
312 }
313 ctx->Pixel._ReadSrcMask = FRONT_RIGHT_BIT;
314 break;
315 case GL_BACK_RIGHT:
316 if (!ctx->Visual.stereoMode || !ctx->Visual.doubleBufferMode) {
317 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
318 return;
319 }
320 ctx->Pixel._ReadSrcMask = BACK_RIGHT_BIT;
321 break;
322 case GL_AUX0:
323 if (ctx->Const.NumAuxBuffers >= 1) {
324 ctx->Pixel._ReadSrcMask = AUX0_BIT;
325 }
326 else {
327 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadBuffer(GL_AUX0)" );
328 return;
329 }
330 break;
331 case GL_AUX1:
332 if (ctx->Const.NumAuxBuffers >= 2) {
333 ctx->Pixel._ReadSrcMask = AUX1_BIT;
334 }
335 else {
336 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadBuffer(GL_AUX1)" );
337 return;
338 }
339 break;
340 case GL_AUX2:
341 if (ctx->Const.NumAuxBuffers >= 3) {
342 ctx->Pixel._ReadSrcMask = AUX2_BIT;
343 }
344 else {
345 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadBuffer(GL_AUX2)" );
346 return;
347 }
348 break;
349 case GL_AUX3:
350 if (ctx->Const.NumAuxBuffers >= 4) {
351 ctx->Pixel._ReadSrcMask = AUX3_BIT;
352 }
353 else {
354 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadBuffer(GL_AUX3)" );
355 return;
356 }
357 break;
358 default:
359 _mesa_error( ctx, GL_INVALID_ENUM, "glReadBuffer" );
360 return;
361 }
362
363 ctx->Pixel.ReadBuffer = mode;
364 ctx->NewState |= _NEW_PIXEL;
365
366 /*
367 * Call device driver function.
368 */
369 if (ctx->Driver.ReadBuffer)
370 (*ctx->Driver.ReadBuffer)(ctx, mode);
371 }
372
373
374 /*
375 * GL_MESA_resize_buffers extension
376 * When this function is called, we'll ask the window system how large
377 * the current window is. If it's not what we expect, we'll have to
378 * resize/reallocate the software accum/stencil/depth/alpha buffers.
379 */
380 void
381 _mesa_ResizeBuffersMESA( void )
382 {
383 GLcontext *ctx = _mesa_get_current_context();
384
385 if (MESA_VERBOSE & VERBOSE_API)
386 _mesa_debug(ctx, "glResizeBuffersMESA\n");
387
388 if (ctx) {
389 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH( ctx );
390
391 if (ctx->DrawBuffer) {
392 GLuint buf_width, buf_height;
393 GLframebuffer *buffer = ctx->DrawBuffer;
394
395 /* ask device driver for size of output buffer */
396 (*ctx->Driver.GetBufferSize)( buffer, &buf_width, &buf_height );
397
398 /* see if size of device driver's color buffer (window) has changed */
399 if (buffer->Width == buf_width && buffer->Height == buf_height)
400 return; /* size is as expected */
401
402 buffer->Width = buf_width;
403 buffer->Height = buf_height;
404
405 ctx->Driver.ResizeBuffers( buffer );
406 }
407
408 if (ctx->ReadBuffer && ctx->ReadBuffer != ctx->DrawBuffer) {
409 GLuint buf_width, buf_height;
410 GLframebuffer *buffer = ctx->DrawBuffer;
411
412 /* ask device driver for size of output buffer */
413 (*ctx->Driver.GetBufferSize)( buffer, &buf_width, &buf_height );
414
415 /* see if size of device driver's color buffer (window) has changed */
416 if (buffer->Width == buf_width && buffer->Height == buf_height)
417 return; /* size is as expected */
418
419 buffer->Width = buf_width;
420 buffer->Height = buf_height;
421
422 ctx->Driver.ResizeBuffers( buffer );
423 }
424
425 ctx->NewState |= _NEW_BUFFERS; /* to update scissor / window bounds */
426 }
427 }
428
429
430 void
431 _mesa_Scissor( GLint x, GLint y, GLsizei width, GLsizei height )
432 {
433 GET_CURRENT_CONTEXT(ctx);
434 ASSERT_OUTSIDE_BEGIN_END(ctx);
435
436 if (width < 0 || height < 0) {
437 _mesa_error( ctx, GL_INVALID_VALUE, "glScissor" );
438 return;
439 }
440
441 if (MESA_VERBOSE & VERBOSE_API)
442 _mesa_debug(ctx, "glScissor %d %d %d %d\n", x, y, width, height);
443
444 if (x == ctx->Scissor.X &&
445 y == ctx->Scissor.Y &&
446 width == ctx->Scissor.Width &&
447 height == ctx->Scissor.Height)
448 return;
449
450 FLUSH_VERTICES(ctx, _NEW_SCISSOR);
451 ctx->Scissor.X = x;
452 ctx->Scissor.Y = y;
453 ctx->Scissor.Width = width;
454 ctx->Scissor.Height = height;
455
456 if (ctx->Driver.Scissor)
457 ctx->Driver.Scissor( ctx, x, y, width, height );
458 }
459
460
461 /*
462 * XXX move somewhere else someday?
463 */
464 void
465 _mesa_SampleCoverageARB(GLclampf value, GLboolean invert)
466 {
467 GLcontext *ctx = _mesa_get_current_context();
468
469 if (!ctx->Extensions.ARB_multisample) {
470 _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleCoverageARB");
471 return;
472 }
473
474 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH( ctx );
475 ctx->Multisample.SampleCoverageValue = (GLfloat) CLAMP(value, 0.0, 1.0);
476 ctx->Multisample.SampleCoverageInvert = invert;
477 ctx->NewState |= _NEW_MULTISAMPLE;
478 }
479