Lots of changes related to framebuffer/window buffer resizing. Basically,
[mesa.git] / src / mesa / main / buffers.c
1 /* $Id: buffers.c,v 1.33 2002/03/16 00:53:15 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 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 (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 CLEAR_BITS(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
148 if (MESA_VERBOSE & VERBOSE_API)
149 fprintf(stderr, "glDrawBuffer %s\n", _mesa_lookup_enum_by_nr(mode));
150
151 switch (mode) {
152 case GL_AUX0:
153 case GL_AUX1:
154 case GL_AUX2:
155 case GL_AUX3:
156 /* AUX buffers not implemented in Mesa at this time */
157 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
158 return;
159 case GL_RIGHT:
160 if (!ctx->Visual.stereoMode) {
161 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
162 return;}
163 if (ctx->Visual.doubleBufferMode)
164 ctx->Color.DrawDestMask = FRONT_RIGHT_BIT | BACK_RIGHT_BIT;
165 else
166 ctx->Color.DrawDestMask = FRONT_RIGHT_BIT;
167 break;
168 case GL_FRONT_RIGHT:
169 if (!ctx->Visual.stereoMode) {
170 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
171 return;
172 }
173 ctx->Color.DrawDestMask = FRONT_RIGHT_BIT;
174 break;
175 case GL_BACK_RIGHT:
176 if (!ctx->Visual.stereoMode) {
177 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
178 return;
179 }
180 if (!ctx->Visual.doubleBufferMode) {
181 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
182 return;
183 }
184 ctx->Color.DrawDestMask = BACK_RIGHT_BIT;
185 break;
186 case GL_BACK_LEFT:
187 if (!ctx->Visual.doubleBufferMode) {
188 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
189 return;
190 }
191 ctx->Color.DrawDestMask = BACK_LEFT_BIT;
192 break;
193 case GL_FRONT_AND_BACK:
194 if (!ctx->Visual.doubleBufferMode) {
195 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
196 return;
197 }
198 if (ctx->Visual.stereoMode)
199 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT
200 | FRONT_RIGHT_BIT | BACK_RIGHT_BIT;
201 else
202 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT;
203 break;
204 case GL_BACK:
205 if (!ctx->Visual.doubleBufferMode) {
206 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
207 return;
208 }
209 if (ctx->Visual.stereoMode)
210 ctx->Color.DrawDestMask = BACK_LEFT_BIT | BACK_RIGHT_BIT;
211 else
212 ctx->Color.DrawDestMask = BACK_LEFT_BIT;
213 break;
214 case GL_LEFT:
215 /* never an error */
216 if (ctx->Visual.doubleBufferMode)
217 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT;
218 else
219 ctx->Color.DrawDestMask = FRONT_LEFT_BIT;
220 break;
221 case GL_FRONT_LEFT:
222 /* never an error */
223 ctx->Color.DrawDestMask = FRONT_LEFT_BIT;
224 break;
225 case GL_FRONT:
226 /* never an error */
227 if (ctx->Visual.stereoMode)
228 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | FRONT_RIGHT_BIT;
229 else
230 ctx->Color.DrawDestMask = FRONT_LEFT_BIT;
231 break;
232 case GL_NONE:
233 /* never an error */
234 ctx->Color.DrawDestMask = 0;
235 break;
236 default:
237 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawBuffer" );
238 return;
239 }
240
241 /*
242 * Make the dest buffer mode more precise if possible
243 */
244 if (mode == GL_LEFT && !ctx->Visual.doubleBufferMode)
245 ctx->Color.DriverDrawBuffer = GL_FRONT_LEFT;
246 else if (mode == GL_RIGHT && !ctx->Visual.doubleBufferMode)
247 ctx->Color.DriverDrawBuffer = GL_FRONT_RIGHT;
248 else if (mode == GL_FRONT && !ctx->Visual.stereoMode)
249 ctx->Color.DriverDrawBuffer = GL_FRONT_LEFT;
250 else if (mode == GL_BACK && !ctx->Visual.stereoMode)
251 ctx->Color.DriverDrawBuffer = GL_BACK_LEFT;
252 else
253 ctx->Color.DriverDrawBuffer = mode;
254
255 /*
256 * Set current alpha buffer pointer
257 */
258 if (ctx->DrawBuffer->UseSoftwareAlphaBuffers) {
259 if (ctx->Color.DriverDrawBuffer == GL_FRONT_LEFT)
260 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontLeftAlpha;
261 else if (ctx->Color.DriverDrawBuffer == GL_BACK_LEFT)
262 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackLeftAlpha;
263 else if (ctx->Color.DriverDrawBuffer == GL_FRONT_RIGHT)
264 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontRightAlpha;
265 else if (ctx->Color.DriverDrawBuffer == GL_BACK_RIGHT)
266 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackRightAlpha;
267 }
268
269 /*
270 * If we get here there can't have been an error.
271 * Now see if device driver can implement the drawing to the target
272 * buffer(s). The driver may not be able to do GL_FRONT_AND_BACK mode
273 * for example. We'll take care of that in the core code by looping
274 * over the individual buffers.
275 */
276 ASSERT(ctx->Driver.SetDrawBuffer);
277 if ( (*ctx->Driver.SetDrawBuffer)(ctx, ctx->Color.DriverDrawBuffer) ) {
278 /* All OK, the driver will do all buffer writes */
279 ctx->Color.MultiDrawBuffer = GL_FALSE;
280 }
281 else {
282 /* We'll have to loop over the multiple draw buffer targets */
283 ctx->Color.MultiDrawBuffer = GL_TRUE;
284 /* Set drawing buffer to front for now */
285 (void) (*ctx->Driver.SetDrawBuffer)(ctx, GL_FRONT_LEFT);
286 }
287
288 ctx->Color.DrawBuffer = mode;
289 ctx->NewState |= _NEW_COLOR;
290 }
291
292
293
294 void
295 _mesa_ReadBuffer( GLenum mode )
296 {
297 GET_CURRENT_CONTEXT(ctx);
298 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
299
300 if (MESA_VERBOSE & VERBOSE_API)
301 fprintf(stderr, "glReadBuffer %s\n", _mesa_lookup_enum_by_nr(mode));
302
303 switch (mode) {
304 case GL_AUX0:
305 case GL_AUX1:
306 case GL_AUX2:
307 case GL_AUX3:
308 /* AUX buffers not implemented in Mesa at this time */
309 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
310 return;
311 case GL_LEFT:
312 case GL_FRONT:
313 case GL_FRONT_LEFT:
314 /* Front-Left buffer, always exists */
315 ctx->Pixel.DriverReadBuffer = GL_FRONT_LEFT;
316 break;
317 case GL_BACK:
318 case GL_BACK_LEFT:
319 /* Back-Left buffer, requires double buffering */
320 if (!ctx->Visual.doubleBufferMode) {
321 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
322 return;
323 }
324 ctx->Pixel.DriverReadBuffer = GL_BACK_LEFT;
325 break;
326 case GL_FRONT_RIGHT:
327 case GL_RIGHT:
328 if (!ctx->Visual.stereoMode) {
329 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
330 return;
331 }
332 ctx->Pixel.DriverReadBuffer = GL_FRONT_RIGHT;
333 break;
334 case GL_BACK_RIGHT:
335 if (!ctx->Visual.stereoMode || !ctx->Visual.doubleBufferMode) {
336 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
337 return;
338 }
339 ctx->Pixel.DriverReadBuffer = GL_BACK_RIGHT;
340 break;
341 default:
342 _mesa_error( ctx, GL_INVALID_ENUM, "glReadBuffer" );
343 return;
344 }
345
346 ctx->Pixel.ReadBuffer = mode;
347 ctx->NewState |= _NEW_PIXEL;
348 }
349
350
351 /*
352 * GL_MESA_resize_buffers extension
353 * When this function is called, we'll ask the window system how large
354 * the current window is. If it's not what we expect, we'll have to
355 * resize/reallocate the software accum/stencil/depth/alpha buffers.
356 */
357 void
358 _mesa_ResizeBuffersMESA( void )
359 {
360 GLcontext *ctx = _mesa_get_current_context();
361
362 if (MESA_VERBOSE & VERBOSE_API)
363 fprintf(stderr, "glResizeBuffersMESA\n");
364
365 if (ctx) {
366 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH( ctx );
367
368 if (ctx->DrawBuffer) {
369 GLuint buf_width, buf_height;
370 GLframebuffer *buffer = ctx->DrawBuffer;
371
372 /* ask device driver for size of output buffer */
373 (*ctx->Driver.GetBufferSize)( buffer, &buf_width, &buf_height );
374
375 /* see if size of device driver's color buffer (window) has changed */
376 if (buffer->Width == (GLint) buf_width &&
377 buffer->Height == (GLint) buf_height)
378 return; /* size is as expected */
379
380 buffer->Width = buf_width;
381 buffer->Height = buf_height;
382
383 ctx->Driver.ResizeBuffers( buffer );
384 }
385
386 if (ctx->ReadBuffer && ctx->ReadBuffer != ctx->DrawBuffer) {
387 GLuint buf_width, buf_height;
388 GLframebuffer *buffer = ctx->DrawBuffer;
389
390 /* ask device driver for size of output buffer */
391 (*ctx->Driver.GetBufferSize)( buffer, &buf_width, &buf_height );
392
393 /* see if size of device driver's color buffer (window) has changed */
394 if (buffer->Width == (GLint) buf_width &&
395 buffer->Height == (GLint) buf_height)
396 return; /* size is as expected */
397
398 buffer->Width = buf_width;
399 buffer->Height = buf_height;
400
401 ctx->Driver.ResizeBuffers( buffer );
402 }
403
404 ctx->NewState |= _NEW_BUFFERS; /* to update scissor / window bounds */
405 }
406 }
407
408
409 void
410 _mesa_Scissor( GLint x, GLint y, GLsizei width, GLsizei height )
411 {
412 GET_CURRENT_CONTEXT(ctx);
413 ASSERT_OUTSIDE_BEGIN_END(ctx);
414
415 if (width < 0 || height < 0) {
416 _mesa_error( ctx, GL_INVALID_VALUE, "glScissor" );
417 return;
418 }
419
420 if (MESA_VERBOSE & VERBOSE_API)
421 fprintf(stderr, "glScissor %d %d %d %d\n", x, y, width, height);
422
423 if (x == ctx->Scissor.X &&
424 y == ctx->Scissor.Y &&
425 width == ctx->Scissor.Width &&
426 height == ctx->Scissor.Height)
427 return;
428
429 FLUSH_VERTICES(ctx, _NEW_SCISSOR);
430 ctx->Scissor.X = x;
431 ctx->Scissor.Y = y;
432 ctx->Scissor.Width = width;
433 ctx->Scissor.Height = height;
434
435 if (ctx->Driver.Scissor)
436 ctx->Driver.Scissor( ctx, x, y, width, height );
437 }
438
439
440 /*
441 * XXX move somewhere else someday?
442 */
443 void
444 _mesa_SampleCoverageARB(GLclampf value, GLboolean invert)
445 {
446 GLcontext *ctx = _mesa_get_current_context();
447
448 if (!ctx->Extensions.ARB_multisample) {
449 _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleCoverageARB");
450 return;
451 }
452
453 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH( ctx );
454 ctx->Multisample.SampleCoverageValue = (GLfloat) CLAMP(value, 0.0, 1.0);
455 ctx->Multisample.SampleCoverageInvert = invert;
456 ctx->NewState |= _NEW_MULTISAMPLE;
457 }
458