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