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