2fa540250abf40cc290e313a90a0fe30948d0030
[mesa.git] / src / mesa / main / buffers.c
1 /* $Id: buffers.c,v 1.31 2001/09/14 21:36:43 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
7 * Copyright (C) 1999-2001 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 GLchan tmp[4];
71 GET_CURRENT_CONTEXT(ctx);
72 ASSERT_OUTSIDE_BEGIN_END(ctx);
73
74 UNCLAMPED_FLOAT_TO_CHAN(tmp[0], red);
75 UNCLAMPED_FLOAT_TO_CHAN(tmp[1], green);
76 UNCLAMPED_FLOAT_TO_CHAN(tmp[2], blue);
77 UNCLAMPED_FLOAT_TO_CHAN(tmp[3], alpha);
78
79 if (TEST_EQ_4V(tmp, ctx->Color.ClearColor))
80 return;
81
82 FLUSH_VERTICES(ctx, _NEW_COLOR);
83 COPY_CHAN4(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 fprintf(stderr, "glClear 0x%x\n", mask);
101
102 if (ctx->NewState) {
103 _mesa_update_state( ctx ); /* update _Xmin, etc */
104 }
105
106 if (ctx->RenderMode==GL_RENDER) {
107 const GLint x = ctx->DrawBuffer->_Xmin;
108 const GLint y = ctx->DrawBuffer->_Ymin;
109 const GLint height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
110 const GLint width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
111 GLbitfield ddMask;
112
113 /* don't clear depth buffer if depth writing disabled */
114 if (!ctx->Depth.Mask)
115 CLEAR_BITS(mask, GL_DEPTH_BUFFER_BIT);
116
117 /* Build bitmask to send to driver Clear function */
118 ddMask = mask & (GL_DEPTH_BUFFER_BIT |
119 GL_STENCIL_BUFFER_BIT |
120 GL_ACCUM_BUFFER_BIT);
121 if (mask & GL_COLOR_BUFFER_BIT) {
122 ddMask |= ctx->Color.DrawDestMask;
123 }
124
125 ASSERT(ctx->Driver.Clear);
126 ctx->Driver.Clear( ctx, ddMask, (GLboolean) !ctx->Scissor.Enabled,
127 x, y, width, height );
128 }
129 }
130
131
132 void
133 _mesa_DrawBuffer( GLenum mode )
134 {
135 GET_CURRENT_CONTEXT(ctx);
136 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex... */
137
138
139 if (MESA_VERBOSE & VERBOSE_API)
140 fprintf(stderr, "glDrawBuffer %s\n", _mesa_lookup_enum_by_nr(mode));
141
142 switch (mode) {
143 case GL_AUX0:
144 case GL_AUX1:
145 case GL_AUX2:
146 case GL_AUX3:
147 /* AUX buffers not implemented in Mesa at this time */
148 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
149 return;
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) {
168 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
169 return;
170 }
171 if (!ctx->Visual.doubleBufferMode) {
172 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
173 return;
174 }
175 ctx->Color.DrawDestMask = BACK_RIGHT_BIT;
176 break;
177 case GL_BACK_LEFT:
178 if (!ctx->Visual.doubleBufferMode) {
179 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
180 return;
181 }
182 ctx->Color.DrawDestMask = BACK_LEFT_BIT;
183 break;
184 case GL_FRONT_AND_BACK:
185 if (!ctx->Visual.doubleBufferMode) {
186 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
187 return;
188 }
189 if (ctx->Visual.stereoMode)
190 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT
191 | FRONT_RIGHT_BIT | BACK_RIGHT_BIT;
192 else
193 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT;
194 break;
195 case GL_BACK:
196 if (!ctx->Visual.doubleBufferMode) {
197 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
198 return;
199 }
200 if (ctx->Visual.stereoMode)
201 ctx->Color.DrawDestMask = BACK_LEFT_BIT | BACK_RIGHT_BIT;
202 else
203 ctx->Color.DrawDestMask = BACK_LEFT_BIT;
204 break;
205 case GL_LEFT:
206 /* never an error */
207 if (ctx->Visual.doubleBufferMode)
208 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT;
209 else
210 ctx->Color.DrawDestMask = FRONT_LEFT_BIT;
211 break;
212 case GL_FRONT_LEFT:
213 /* never an error */
214 ctx->Color.DrawDestMask = FRONT_LEFT_BIT;
215 break;
216 case GL_FRONT:
217 /* never an error */
218 if (ctx->Visual.stereoMode)
219 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | FRONT_RIGHT_BIT;
220 else
221 ctx->Color.DrawDestMask = FRONT_LEFT_BIT;
222 break;
223 case GL_NONE:
224 /* never an error */
225 ctx->Color.DrawDestMask = 0;
226 break;
227 default:
228 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawBuffer" );
229 return;
230 }
231
232 /*
233 * Make the dest buffer mode more precise if possible
234 */
235 if (mode == GL_LEFT && !ctx->Visual.doubleBufferMode)
236 ctx->Color.DriverDrawBuffer = GL_FRONT_LEFT;
237 else if (mode == GL_RIGHT && !ctx->Visual.doubleBufferMode)
238 ctx->Color.DriverDrawBuffer = GL_FRONT_RIGHT;
239 else if (mode == GL_FRONT && !ctx->Visual.stereoMode)
240 ctx->Color.DriverDrawBuffer = GL_FRONT_LEFT;
241 else if (mode == GL_BACK && !ctx->Visual.stereoMode)
242 ctx->Color.DriverDrawBuffer = GL_BACK_LEFT;
243 else
244 ctx->Color.DriverDrawBuffer = mode;
245
246 /*
247 * Set current alpha buffer pointer
248 */
249 if (ctx->DrawBuffer->UseSoftwareAlphaBuffers) {
250 if (ctx->Color.DriverDrawBuffer == GL_FRONT_LEFT)
251 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontLeftAlpha;
252 else if (ctx->Color.DriverDrawBuffer == GL_BACK_LEFT)
253 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackLeftAlpha;
254 else if (ctx->Color.DriverDrawBuffer == GL_FRONT_RIGHT)
255 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontRightAlpha;
256 else if (ctx->Color.DriverDrawBuffer == GL_BACK_RIGHT)
257 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackRightAlpha;
258 }
259
260 /*
261 * If we get here there can't have been an error.
262 * Now see if device driver can implement the drawing to the target
263 * buffer(s). The driver may not be able to do GL_FRONT_AND_BACK mode
264 * for example. We'll take care of that in the core code by looping
265 * over the individual buffers.
266 */
267 ASSERT(ctx->Driver.SetDrawBuffer);
268 if ( (*ctx->Driver.SetDrawBuffer)(ctx, ctx->Color.DriverDrawBuffer) ) {
269 /* All OK, the driver will do all buffer writes */
270 ctx->Color.MultiDrawBuffer = GL_FALSE;
271 }
272 else {
273 /* We'll have to loop over the multiple draw buffer targets */
274 ctx->Color.MultiDrawBuffer = GL_TRUE;
275 /* Set drawing buffer to front for now */
276 (void) (*ctx->Driver.SetDrawBuffer)(ctx, GL_FRONT_LEFT);
277 }
278
279 ctx->Color.DrawBuffer = mode;
280 ctx->NewState |= _NEW_COLOR;
281 }
282
283
284
285 void
286 _mesa_ReadBuffer( GLenum mode )
287 {
288 GET_CURRENT_CONTEXT(ctx);
289 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
290
291 if (MESA_VERBOSE & VERBOSE_API)
292 fprintf(stderr, "glReadBuffer %s\n", _mesa_lookup_enum_by_nr(mode));
293
294 switch (mode) {
295 case GL_AUX0:
296 case GL_AUX1:
297 case GL_AUX2:
298 case GL_AUX3:
299 /* AUX buffers not implemented in Mesa at this time */
300 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
301 return;
302 case GL_LEFT:
303 case GL_FRONT:
304 case GL_FRONT_LEFT:
305 /* Front-Left buffer, always exists */
306 ctx->Pixel.DriverReadBuffer = GL_FRONT_LEFT;
307 break;
308 case GL_BACK:
309 case GL_BACK_LEFT:
310 /* Back-Left buffer, requires double buffering */
311 if (!ctx->Visual.doubleBufferMode) {
312 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
313 return;
314 }
315 ctx->Pixel.DriverReadBuffer = GL_BACK_LEFT;
316 break;
317 case GL_FRONT_RIGHT:
318 case GL_RIGHT:
319 if (!ctx->Visual.stereoMode) {
320 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
321 return;
322 }
323 ctx->Pixel.DriverReadBuffer = GL_FRONT_RIGHT;
324 break;
325 case GL_BACK_RIGHT:
326 if (!ctx->Visual.stereoMode || !ctx->Visual.doubleBufferMode) {
327 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
328 return;
329 }
330 ctx->Pixel.DriverReadBuffer = GL_BACK_RIGHT;
331 break;
332 default:
333 _mesa_error( ctx, GL_INVALID_ENUM, "glReadBuffer" );
334 return;
335 }
336
337 ctx->Pixel.ReadBuffer = mode;
338 ctx->NewState |= _NEW_PIXEL;
339 }
340
341
342 /*
343 * GL_MESA_resize_buffers extension
344 */
345 void
346 _mesa_ResizeBuffersMESA( void )
347 {
348 GLcontext *ctx = _mesa_get_current_context();
349 GLuint buf_width, buf_height;
350 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH( ctx );
351
352
353 if (MESA_VERBOSE & VERBOSE_API)
354 fprintf(stderr, "glResizeBuffersMESA\n");
355
356 /* ask device driver for size of output buffer */
357 (*ctx->Driver.GetBufferSize)( ctx, &buf_width, &buf_height );
358
359 /* see if size of device driver's color buffer (window) has changed */
360 if (ctx->DrawBuffer->Width == (GLint) buf_width &&
361 ctx->DrawBuffer->Height == (GLint) buf_height)
362 return;
363
364 ctx->NewState |= _NEW_BUFFERS; /* to update scissor / window bounds */
365
366 /* save buffer size */
367 ctx->DrawBuffer->Width = buf_width;
368 ctx->DrawBuffer->Height = buf_height;
369
370 ctx->Driver.ResizeBuffersMESA( ctx );
371 }
372
373
374 void
375 _mesa_Scissor( GLint x, GLint y, GLsizei width, GLsizei height )
376 {
377 GET_CURRENT_CONTEXT(ctx);
378 ASSERT_OUTSIDE_BEGIN_END(ctx);
379
380 if (width < 0 || height < 0) {
381 _mesa_error( ctx, GL_INVALID_VALUE, "glScissor" );
382 return;
383 }
384
385 if (MESA_VERBOSE & VERBOSE_API)
386 fprintf(stderr, "glScissor %d %d %d %d\n", x, y, width, height);
387
388 if (x == ctx->Scissor.X &&
389 y == ctx->Scissor.Y &&
390 width == ctx->Scissor.Width &&
391 height == ctx->Scissor.Height)
392 return;
393
394 FLUSH_VERTICES(ctx, _NEW_SCISSOR);
395 ctx->Scissor.X = x;
396 ctx->Scissor.Y = y;
397 ctx->Scissor.Width = width;
398 ctx->Scissor.Height = height;
399
400 if (ctx->Driver.Scissor)
401 ctx->Driver.Scissor( ctx, x, y, width, height );
402 }
403
404
405 /*
406 * XXX move somewhere else someday?
407 */
408 void
409 _mesa_SampleCoverageARB(GLclampf value, GLboolean invert)
410 {
411 GLcontext *ctx = _mesa_get_current_context();
412
413 if (!ctx->Extensions.ARB_multisample) {
414 _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleCoverageARB");
415 return;
416 }
417
418 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH( ctx );
419 ctx->Multisample.SampleCoverageValue = (GLfloat) CLAMP(value, 0.0, 1.0);
420 ctx->Multisample.SampleCoverageInvert = invert;
421 ctx->NewState |= _NEW_MULTISAMPLE;
422 }
423