da1e6125c98077a5f679838f412b56b31e410f62
[mesa.git] / src / mesa / main / buffers.c
1 /* $Id: buffers.c,v 1.21 2000/12/26 05:09:27 keithw Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
7 * Copyright (C) 1999-2000 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 "context.h"
35 #include "depth.h"
36 #include "enums.h"
37 #include "macros.h"
38 #include "masking.h"
39 #include "mem.h"
40 #include "stencil.h"
41 #include "state.h"
42 #include "mtypes.h"
43 #include "swrast/swrast.h"
44 #endif
45
46
47
48 void
49 _mesa_ClearIndex( GLfloat c )
50 {
51 GET_CURRENT_CONTEXT(ctx);
52 ASSERT_OUTSIDE_BEGIN_END(ctx);
53
54 if (ctx->Color.ClearIndex == (GLuint)c)
55 return;
56
57
58 FLUSH_VERTICES(ctx, _NEW_COLOR);
59 ctx->Color.ClearIndex = (GLuint) c;
60
61 if (!ctx->Visual.RGBAflag) {
62 /* it's OK to call glClearIndex in RGBA mode but it should be a NOP */
63 (*ctx->Driver.ClearIndex)( ctx, ctx->Color.ClearIndex );
64 }
65 }
66
67
68
69 void
70 _mesa_ClearColor( GLclampf red, GLclampf green,
71 GLclampf blue, GLclampf alpha )
72 {
73 GLfloat tmp[4];
74 GET_CURRENT_CONTEXT(ctx);
75 ASSERT_OUTSIDE_BEGIN_END(ctx);
76
77 tmp[0] = CLAMP( red, 0.0, 1.0 );
78 tmp[1] = CLAMP( green, 0.0, 1.0 );
79 tmp[2] = CLAMP( blue, 0.0, 1.0 );
80 tmp[3] = CLAMP( alpha, 0.0, 1.0 );
81
82 if (TEST_EQ_4V(tmp, ctx->Color.ClearColor))
83 return;
84
85 FLUSH_VERTICES(ctx, _NEW_COLOR);
86 COPY_4FV( ctx->Color.ClearColor, tmp );
87
88 if (ctx->Visual.RGBAflag) {
89 GLchan r = (GLint) (ctx->Color.ClearColor[0] * CHAN_MAXF);
90 GLchan g = (GLint) (ctx->Color.ClearColor[1] * CHAN_MAXF);
91 GLchan b = (GLint) (ctx->Color.ClearColor[2] * CHAN_MAXF);
92 GLchan a = (GLint) (ctx->Color.ClearColor[3] * CHAN_MAXF);
93 (*ctx->Driver.ClearColor)( ctx, r, g, b, a );
94 }
95 }
96
97
98
99
100
101
102 void
103 _mesa_Clear( GLbitfield mask )
104 {
105 GET_CURRENT_CONTEXT(ctx);
106 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
107
108 if (MESA_VERBOSE & VERBOSE_API)
109 fprintf(stderr, "glClear 0x%x\n", mask);
110
111 if (ctx->NewState) {
112 gl_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 GLbitfield newMask;
122
123 /* don't clear depth buffer if depth writing disabled */
124 if (!ctx->Depth.Mask)
125 CLEAR_BITS(mask, GL_DEPTH_BUFFER_BIT);
126
127 /* Build bitmask to send to driver Clear function */
128 ddMask = mask & (GL_DEPTH_BUFFER_BIT |
129 GL_STENCIL_BUFFER_BIT |
130 GL_ACCUM_BUFFER_BIT);
131 if (mask & GL_COLOR_BUFFER_BIT) {
132 ddMask |= ctx->Color.DrawDestMask;
133 }
134
135 ASSERT(ctx->Driver.Clear);
136 newMask = (*ctx->Driver.Clear)( ctx, ddMask, !ctx->Scissor.Enabled,
137 x, y, width, height );
138
139 #ifdef DEBUG
140 {
141 GLbitfield legalBits = DD_FRONT_LEFT_BIT |
142 DD_FRONT_RIGHT_BIT |
143 DD_BACK_LEFT_BIT |
144 DD_BACK_RIGHT_BIT |
145 DD_DEPTH_BIT |
146 DD_STENCIL_BIT |
147 DD_ACCUM_BIT;
148 assert((newMask & (~legalBits)) == 0);
149 }
150 #endif
151
152 if (newMask)
153 _swrast_Clear( ctx, newMask, !ctx->Scissor.Enabled,
154 x, y, width, height );
155 }
156 }
157
158
159 void
160 _mesa_DrawBuffer( GLenum mode )
161 {
162 GET_CURRENT_CONTEXT(ctx);
163 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex... */
164
165
166 if (MESA_VERBOSE & VERBOSE_API)
167 fprintf(stderr, "glDrawBuffer %s\n", gl_lookup_enum_by_nr(mode));
168
169 switch (mode) {
170 case GL_AUX0:
171 case GL_AUX1:
172 case GL_AUX2:
173 case GL_AUX3:
174 /* AUX buffers not implemented in Mesa at this time */
175 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
176 return;
177 case GL_RIGHT:
178 if (!ctx->Visual.StereoFlag) {
179 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
180 return;}
181 if (ctx->Visual.DBflag)
182 ctx->Color.DrawDestMask = FRONT_RIGHT_BIT | BACK_RIGHT_BIT;
183 else
184 ctx->Color.DrawDestMask = FRONT_RIGHT_BIT;
185 break;
186 case GL_FRONT_RIGHT:
187 if (!ctx->Visual.StereoFlag) {
188 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
189 return;
190 }
191 ctx->Color.DrawDestMask = FRONT_RIGHT_BIT;
192 break;
193 case GL_BACK_RIGHT:
194 if (!ctx->Visual.StereoFlag) {
195 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
196 return;
197 }
198 if (!ctx->Visual.DBflag) {
199 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
200 return;
201 }
202 ctx->Color.DrawDestMask = BACK_RIGHT_BIT;
203 break;
204 case GL_BACK_LEFT:
205 if (!ctx->Visual.DBflag) {
206 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
207 return;
208 }
209 ctx->Color.DrawDestMask = BACK_LEFT_BIT;
210 break;
211 case GL_FRONT_AND_BACK:
212 if (!ctx->Visual.DBflag) {
213 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
214 return;
215 }
216 if (ctx->Visual.StereoFlag)
217 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT
218 | FRONT_RIGHT_BIT | BACK_RIGHT_BIT;
219 else
220 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT;
221 break;
222 case GL_BACK:
223 if (!ctx->Visual.DBflag) {
224 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
225 return;
226 }
227 if (ctx->Visual.StereoFlag)
228 ctx->Color.DrawDestMask = BACK_LEFT_BIT | BACK_RIGHT_BIT;
229 else
230 ctx->Color.DrawDestMask = BACK_LEFT_BIT;
231 break;
232 case GL_LEFT:
233 /* never an error */
234 if (ctx->Visual.DBflag)
235 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT;
236 else
237 ctx->Color.DrawDestMask = FRONT_LEFT_BIT;
238 break;
239 case GL_FRONT_LEFT:
240 /* never an error */
241 ctx->Color.DrawDestMask = FRONT_LEFT_BIT;
242 break;
243 case GL_FRONT:
244 /* never an error */
245 if (ctx->Visual.StereoFlag)
246 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | FRONT_RIGHT_BIT;
247 else
248 ctx->Color.DrawDestMask = FRONT_LEFT_BIT;
249 break;
250 case GL_NONE:
251 /* never an error */
252 ctx->Color.DrawDestMask = 0;
253 break;
254 default:
255 gl_error( ctx, GL_INVALID_ENUM, "glDrawBuffer" );
256 return;
257 }
258
259 /*
260 * Make the dest buffer mode more precise if possible
261 */
262 if (mode == GL_LEFT && !ctx->Visual.DBflag)
263 ctx->Color.DriverDrawBuffer = GL_FRONT_LEFT;
264 else if (mode == GL_RIGHT && !ctx->Visual.DBflag)
265 ctx->Color.DriverDrawBuffer = GL_FRONT_RIGHT;
266 else if (mode == GL_FRONT && !ctx->Visual.StereoFlag)
267 ctx->Color.DriverDrawBuffer = GL_FRONT_LEFT;
268 else if (mode == GL_BACK && !ctx->Visual.StereoFlag)
269 ctx->Color.DriverDrawBuffer = GL_BACK_LEFT;
270 else
271 ctx->Color.DriverDrawBuffer = mode;
272
273 /*
274 * Set current alpha buffer pointer
275 */
276 if (ctx->DrawBuffer->UseSoftwareAlphaBuffers) {
277 if (ctx->Color.DriverDrawBuffer == GL_FRONT_LEFT)
278 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontLeftAlpha;
279 else if (ctx->Color.DriverDrawBuffer == GL_BACK_LEFT)
280 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackLeftAlpha;
281 else if (ctx->Color.DriverDrawBuffer == GL_FRONT_RIGHT)
282 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontRightAlpha;
283 else if (ctx->Color.DriverDrawBuffer == GL_BACK_RIGHT)
284 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackRightAlpha;
285 }
286
287 /*
288 * If we get here there can't have been an error.
289 * Now see if device driver can implement the drawing to the target
290 * buffer(s). The driver may not be able to do GL_FRONT_AND_BACK mode
291 * for example. We'll take care of that in the core code by looping
292 * over the individual buffers.
293 */
294 ASSERT(ctx->Driver.SetDrawBuffer);
295 if ( (*ctx->Driver.SetDrawBuffer)(ctx, ctx->Color.DriverDrawBuffer) ) {
296 /* All OK, the driver will do all buffer writes */
297 ctx->Color.MultiDrawBuffer = GL_FALSE;
298 }
299 else {
300 /* We'll have to loop over the multiple draw buffer targets */
301 ctx->Color.MultiDrawBuffer = GL_TRUE;
302 /* Set drawing buffer to front for now */
303 (void) (*ctx->Driver.SetDrawBuffer)(ctx, GL_FRONT_LEFT);
304 }
305
306 ctx->Color.DrawBuffer = mode;
307 ctx->NewState |= _NEW_COLOR;
308 }
309
310
311
312 void
313 _mesa_ReadBuffer( GLenum mode )
314 {
315 GET_CURRENT_CONTEXT(ctx);
316 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
317
318 if (MESA_VERBOSE & VERBOSE_API)
319 fprintf(stderr, "glReadBuffer %s\n", gl_lookup_enum_by_nr(mode));
320
321 switch (mode) {
322 case GL_AUX0:
323 case GL_AUX1:
324 case GL_AUX2:
325 case GL_AUX3:
326 /* AUX buffers not implemented in Mesa at this time */
327 gl_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
328 return;
329 case GL_LEFT:
330 case GL_FRONT:
331 case GL_FRONT_LEFT:
332 /* Front-Left buffer, always exists */
333 ctx->Pixel.DriverReadBuffer = GL_FRONT_LEFT;
334 break;
335 case GL_BACK:
336 case GL_BACK_LEFT:
337 /* Back-Left buffer, requires double buffering */
338 if (!ctx->Visual.DBflag) {
339 gl_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
340 return;
341 }
342 ctx->Pixel.DriverReadBuffer = GL_BACK_LEFT;
343 break;
344 case GL_FRONT_RIGHT:
345 case GL_RIGHT:
346 if (!ctx->Visual.StereoFlag) {
347 gl_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
348 return;
349 }
350 ctx->Pixel.DriverReadBuffer = GL_FRONT_RIGHT;
351 break;
352 case GL_BACK_RIGHT:
353 if (!ctx->Visual.StereoFlag || !ctx->Visual.DBflag) {
354 gl_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
355 return;
356 }
357 ctx->Pixel.DriverReadBuffer = GL_BACK_RIGHT;
358 break;
359 default:
360 gl_error( ctx, GL_INVALID_ENUM, "glReadBuffer" );
361 return;
362 }
363
364 ctx->Pixel.ReadBuffer = mode;
365 ctx->NewState |= _NEW_PIXEL;
366 }
367
368
369 /*
370 * GL_MESA_resize_buffers extension
371 */
372 void
373 _mesa_ResizeBuffersMESA( void )
374 {
375 GLcontext *ctx = _mesa_get_current_context();
376
377 GLuint buf_width, buf_height;
378
379 if (MESA_VERBOSE & VERBOSE_API)
380 fprintf(stderr, "glResizeBuffersMESA\n");
381
382 /* ask device driver for size of output buffer */
383 (*ctx->Driver.GetBufferSize)( ctx, &buf_width, &buf_height );
384
385 /* see if size of device driver's color buffer (window) has changed */
386 if (ctx->DrawBuffer->Width == (GLint) buf_width &&
387 ctx->DrawBuffer->Height == (GLint) buf_height)
388 return;
389
390 ctx->NewState |= _NEW_BUFFERS; /* to update scissor / window bounds */
391
392 /* save buffer size */
393 ctx->DrawBuffer->Width = buf_width;
394 ctx->DrawBuffer->Height = buf_height;
395
396 _swrast_alloc_buffers( ctx );
397 }