9e836276a513fc37e4c6bf4fa43d4669c0d6363a
[mesa.git] / src / mesa / main / buffers.c
1 /* $Id: buffers.c,v 1.4 2000/04/05 14:40:04 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.3
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 "alphabuf.h"
34 #include "buffers.h"
35 #include "context.h"
36 #include "depth.h"
37 #include "enums.h"
38 #include "macros.h"
39 #include "masking.h"
40 #include "mem.h"
41 #include "stencil.h"
42 #include "state.h"
43 #include "types.h"
44 #endif
45
46
47
48 void
49 _mesa_ClearIndex( GLfloat c )
50 {
51 GET_CURRENT_CONTEXT(ctx);
52 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glClearIndex");
53 ctx->Color.ClearIndex = (GLuint) c;
54 if (!ctx->Visual->RGBAflag) {
55 /* it's OK to call glClearIndex in RGBA mode but it should be a NOP */
56 (*ctx->Driver.ClearIndex)( ctx, ctx->Color.ClearIndex );
57 }
58 }
59
60
61
62 void
63 _mesa_ClearColor( GLclampf red, GLclampf green,
64 GLclampf blue, GLclampf alpha )
65 {
66 GET_CURRENT_CONTEXT(ctx);
67 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glClearColor");
68
69 ctx->Color.ClearColor[0] = CLAMP( red, 0.0F, 1.0F );
70 ctx->Color.ClearColor[1] = CLAMP( green, 0.0F, 1.0F );
71 ctx->Color.ClearColor[2] = CLAMP( blue, 0.0F, 1.0F );
72 ctx->Color.ClearColor[3] = CLAMP( alpha, 0.0F, 1.0F );
73
74 if (ctx->Visual->RGBAflag) {
75 GLubyte r = (GLint) (ctx->Color.ClearColor[0] * 255.0F);
76 GLubyte g = (GLint) (ctx->Color.ClearColor[1] * 255.0F);
77 GLubyte b = (GLint) (ctx->Color.ClearColor[2] * 255.0F);
78 GLubyte a = (GLint) (ctx->Color.ClearColor[3] * 255.0F);
79 (*ctx->Driver.ClearColor)( ctx, r, g, b, a );
80 }
81 }
82
83
84
85
86 /*
87 * Clear the color buffer when glColorMask or glIndexMask is in effect.
88 */
89 static void
90 clear_color_buffer_with_masking( GLcontext *ctx )
91 {
92 const GLint x = ctx->DrawBuffer->Xmin;
93 const GLint y = ctx->DrawBuffer->Ymin;
94 const GLint height = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin + 1;
95 const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin + 1;
96
97 if (ctx->Visual->RGBAflag) {
98 /* RGBA mode */
99 const GLubyte r = (GLint) (ctx->Color.ClearColor[0] * 255.0F);
100 const GLubyte g = (GLint) (ctx->Color.ClearColor[1] * 255.0F);
101 const GLubyte b = (GLint) (ctx->Color.ClearColor[2] * 255.0F);
102 const GLubyte a = (GLint) (ctx->Color.ClearColor[3] * 255.0F);
103 GLint i;
104 for (i = 0; i < height; i++) {
105 GLubyte rgba[MAX_WIDTH][4];
106 GLint j;
107 for (j=0; j<width; j++) {
108 rgba[j][RCOMP] = r;
109 rgba[j][GCOMP] = g;
110 rgba[j][BCOMP] = b;
111 rgba[j][ACOMP] = a;
112 }
113 _mesa_mask_rgba_span( ctx, width, x, y + i, rgba );
114 (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y + i,
115 (CONST GLubyte (*)[4])rgba, NULL );
116 }
117 }
118 else {
119 /* Color index mode */
120 GLuint span[MAX_WIDTH];
121 GLubyte mask[MAX_WIDTH];
122 GLint i, j;
123 MEMSET( mask, 1, width );
124 for (i=0;i<height;i++) {
125 for (j=0;j<width;j++) {
126 span[j] = ctx->Color.ClearIndex;
127 }
128 _mesa_mask_index_span( ctx, width, x, y + i, span );
129 (*ctx->Driver.WriteCI32Span)( ctx, width, x, y + i, span, mask );
130 }
131 }
132 }
133
134
135
136 /*
137 * Clear a color buffer without index/channel masking.
138 */
139 static void
140 clear_color_buffer(GLcontext *ctx)
141 {
142 const GLint x = ctx->DrawBuffer->Xmin;
143 const GLint y = ctx->DrawBuffer->Ymin;
144 const GLint height = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin + 1;
145 const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin + 1;
146
147 if (ctx->Visual->RGBAflag) {
148 /* RGBA mode */
149 const GLubyte r = (GLint) (ctx->Color.ClearColor[0] * 255.0F);
150 const GLubyte g = (GLint) (ctx->Color.ClearColor[1] * 255.0F);
151 const GLubyte b = (GLint) (ctx->Color.ClearColor[2] * 255.0F);
152 const GLubyte a = (GLint) (ctx->Color.ClearColor[3] * 255.0F);
153 GLubyte span[MAX_WIDTH][4];
154 GLint i;
155 ASSERT(ctx->Color.ColorMask[0] &&
156 ctx->Color.ColorMask[1] &&
157 ctx->Color.ColorMask[2] &&
158 ctx->Color.ColorMask[3]);
159 for (i = 0; i < width; i++) {
160 span[i][RCOMP] = r;
161 span[i][GCOMP] = g;
162 span[i][BCOMP] = b;
163 span[i][ACOMP] = a;
164 }
165 for (i = 0; i < height; i++) {
166 (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y + i,
167 (CONST GLubyte (*)[4]) span, NULL );
168 }
169 }
170 else {
171 /* Color index mode */
172 ASSERT(ctx->Color.IndexMask == ~0);
173 if (ctx->Visual->IndexBits == 8) {
174 /* 8-bit clear */
175 GLubyte span[MAX_WIDTH];
176 GLint i;
177 MEMSET(span, ctx->Color.ClearIndex, width);
178 for (i = 0; i < height; i++) {
179 (*ctx->Driver.WriteCI8Span)( ctx, width, x, y + i, span, NULL );
180 }
181 }
182 else {
183 /* non 8-bit clear */
184 GLuint span[MAX_WIDTH];
185 GLint i;
186 for (i = 0; i < width; i++) {
187 span[i] = ctx->Color.ClearIndex;
188 }
189 for (i = 0; i < height; i++) {
190 (*ctx->Driver.WriteCI32Span)( ctx, width, x, y + i, span, NULL );
191 }
192 }
193 }
194 }
195
196
197
198 /*
199 * Clear the front/back/left/right color buffers.
200 * This function is usually only called if we need to clear the
201 * buffers with masking.
202 */
203 static void
204 clear_color_buffers(GLcontext *ctx)
205 {
206 GLuint bufferBit;
207
208 /* loop over four possible dest color buffers */
209 for (bufferBit = 1; bufferBit <= 8; bufferBit = bufferBit << 1) {
210 if (bufferBit & ctx->Color.DrawDestMask) {
211 if (bufferBit == FRONT_LEFT_BIT) {
212 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_LEFT);
213 }
214 else if (bufferBit == FRONT_RIGHT_BIT) {
215 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_RIGHT);
216 }
217 else if (bufferBit == BACK_LEFT_BIT) {
218 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_LEFT);
219 }
220 else {
221 (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT);
222 }
223
224 if (ctx->Color.SWmasking) {
225 clear_color_buffer_with_masking(ctx);
226 }
227 else {
228 clear_color_buffer(ctx);
229 }
230 }
231 }
232
233 /* restore default dest buffer */
234 (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer );
235 }
236
237
238
239 void
240 _mesa_Clear( GLbitfield mask )
241 {
242 GET_CURRENT_CONTEXT(ctx);
243 #ifdef PROFILE
244 GLdouble t0 = gl_time();
245 #endif
246 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glClear");
247
248 if (MESA_VERBOSE & VERBOSE_API)
249 fprintf(stderr, "glClear 0x%x\n", mask);
250
251 if (ctx->NewState) {
252 gl_update_state( ctx );
253 }
254
255 if (ctx->RenderMode==GL_RENDER) {
256 const GLint x = ctx->DrawBuffer->Xmin;
257 const GLint y = ctx->DrawBuffer->Ymin;
258 const GLint height = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin + 1;
259 const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin + 1;
260 GLbitfield ddMask;
261 GLbitfield newMask;
262
263 /* don't clear depth buffer if depth writing disabled */
264 if (!ctx->Depth.Mask)
265 CLEAR_BITS(mask, GL_DEPTH_BUFFER_BIT);
266
267 /* Build bitmask to send to driver Clear function */
268 ddMask = mask & (GL_DEPTH_BUFFER_BIT |
269 GL_STENCIL_BUFFER_BIT |
270 GL_ACCUM_BUFFER_BIT);
271 if (mask & GL_COLOR_BUFFER_BIT) {
272 ddMask |= ctx->Color.DrawDestMask;
273 }
274
275 ASSERT(ctx->Driver.Clear);
276 newMask = (*ctx->Driver.Clear)( ctx, ddMask, !ctx->Scissor.Enabled,
277 x, y, width, height );
278
279 #ifdef DEBUG
280 {
281 GLbitfield legalBits = DD_FRONT_LEFT_BIT |
282 DD_FRONT_RIGHT_BIT |
283 DD_BACK_LEFT_BIT |
284 DD_BACK_RIGHT_BIT |
285 DD_DEPTH_BIT |
286 DD_STENCIL_BIT |
287 DD_ACCUM_BIT;
288 assert((newMask & (~legalBits)) == 0);
289 }
290 #endif
291
292 /* do software clearing here */
293 if (newMask) {
294 if (newMask & ctx->Color.DrawDestMask) clear_color_buffers( ctx );
295 if (newMask & GL_DEPTH_BUFFER_BIT) _mesa_clear_depth_buffer( ctx );
296 if (newMask & GL_ACCUM_BUFFER_BIT) _mesa_clear_accum_buffer( ctx );
297 if (newMask & GL_STENCIL_BUFFER_BIT) gl_clear_stencil_buffer( ctx );
298 }
299
300 /* clear software-based alpha buffer(s) */
301 if ( (mask & GL_COLOR_BUFFER_BIT) && ctx->Visual->SoftwareAlpha
302 && ctx->Color.ColorMask[RCOMP]) {
303 gl_clear_alpha_buffers( ctx );
304 }
305
306 #ifdef PROFILE
307 ctx->ClearTime += gl_time() - t0;
308 ctx->ClearCount++;
309 #endif
310 }
311 }
312
313
314 void
315 _mesa_DrawBuffer( GLenum mode )
316 {
317 GET_CURRENT_CONTEXT(ctx);
318 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDrawBuffer");
319
320 if (MESA_VERBOSE & VERBOSE_API)
321 fprintf(stderr, "glDrawBuffer %s\n", gl_lookup_enum_by_nr(mode));
322
323 switch (mode) {
324 case GL_AUX0:
325 case GL_AUX1:
326 case GL_AUX2:
327 case GL_AUX3:
328 /* AUX buffers not implemented in Mesa at this time */
329 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
330 return;
331 case GL_RIGHT:
332 if (!ctx->Visual->StereoFlag) {
333 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
334 return;
335 }
336 if (ctx->Visual->DBflag)
337 ctx->Color.DrawDestMask = FRONT_RIGHT_BIT | BACK_RIGHT_BIT;
338 else
339 ctx->Color.DrawDestMask = FRONT_RIGHT_BIT;
340 break;
341 case GL_FRONT_RIGHT:
342 if (!ctx->Visual->StereoFlag) {
343 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
344 return;
345 }
346 ctx->Color.DrawDestMask = FRONT_RIGHT_BIT;
347 break;
348 case GL_BACK_RIGHT:
349 if (!ctx->Visual->StereoFlag) {
350 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
351 return;
352 }
353 if (!ctx->Visual->DBflag) {
354 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
355 return;
356 }
357 ctx->Color.DrawDestMask = BACK_RIGHT_BIT;
358 break;
359 case GL_BACK_LEFT:
360 if (!ctx->Visual->DBflag) {
361 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
362 return;
363 }
364 ctx->Color.DrawDestMask = BACK_LEFT_BIT;
365 break;
366 case GL_FRONT_AND_BACK:
367 if (!ctx->Visual->DBflag) {
368 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
369 return;
370 }
371 if (ctx->Visual->StereoFlag)
372 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT
373 | FRONT_RIGHT_BIT | BACK_RIGHT_BIT;
374 else
375 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT;
376 break;
377 case GL_BACK:
378 if (!ctx->Visual->DBflag) {
379 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
380 return;
381 }
382 if (ctx->Visual->StereoFlag)
383 ctx->Color.DrawDestMask = BACK_LEFT_BIT | BACK_RIGHT_BIT;
384 else
385 ctx->Color.DrawDestMask = BACK_LEFT_BIT;
386 break;
387 case GL_LEFT:
388 /* never an error */
389 if (ctx->Visual->DBflag)
390 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT;
391 else
392 ctx->Color.DrawDestMask = FRONT_LEFT_BIT;
393 break;
394 case GL_FRONT_LEFT:
395 /* never an error */
396 ctx->Color.DrawDestMask = FRONT_LEFT_BIT;
397 break;
398 case GL_FRONT:
399 /* never an error */
400 if (ctx->Visual->StereoFlag)
401 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | FRONT_RIGHT_BIT;
402 else
403 ctx->Color.DrawDestMask = FRONT_LEFT_BIT;
404 break;
405 case GL_NONE:
406 /* never an error */
407 ctx->Color.DrawDestMask = 0;
408 break;
409 default:
410 gl_error( ctx, GL_INVALID_ENUM, "glDrawBuffer" );
411 return;
412 }
413
414 /*
415 * Make the dest buffer mode more precise if possible
416 */
417 if (mode == GL_LEFT && !ctx->Visual->DBflag)
418 ctx->Color.DriverDrawBuffer = GL_FRONT_LEFT;
419 else if (mode == GL_RIGHT && !ctx->Visual->DBflag)
420 ctx->Color.DriverDrawBuffer = GL_FRONT_RIGHT;
421 else if (mode == GL_FRONT && !ctx->Visual->StereoFlag)
422 ctx->Color.DriverDrawBuffer = GL_FRONT_LEFT;
423 else if (mode == GL_BACK && !ctx->Visual->StereoFlag)
424 ctx->Color.DriverDrawBuffer = GL_BACK_LEFT;
425 else
426 ctx->Color.DriverDrawBuffer = mode;
427
428 /*
429 * Set current alpha buffer pointer
430 */
431 if (ctx->Visual->SoftwareAlpha) {
432 if (ctx->Color.DriverDrawBuffer == GL_FRONT_LEFT)
433 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontLeftAlpha;
434 else if (ctx->Color.DriverDrawBuffer == GL_BACK_LEFT)
435 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackLeftAlpha;
436 else if (ctx->Color.DriverDrawBuffer == GL_FRONT_RIGHT)
437 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontRightAlpha;
438 else if (ctx->Color.DriverDrawBuffer == GL_BACK_RIGHT)
439 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackRightAlpha;
440 }
441
442 /*
443 * If we get here there can't have been an error.
444 * Now see if device driver can implement the drawing to the target
445 * buffer(s). The driver may not be able to do GL_FRONT_AND_BACK mode
446 * for example. We'll take care of that in the core code by looping
447 * over the individual buffers.
448 */
449 ASSERT(ctx->Driver.SetDrawBuffer);
450 if ( (*ctx->Driver.SetDrawBuffer)(ctx, ctx->Color.DriverDrawBuffer) ) {
451 /* All OK, the driver will do all buffer writes */
452 ctx->Color.MultiDrawBuffer = GL_FALSE;
453 }
454 else {
455 /* We'll have to loop over the multiple draw buffer targets */
456 ctx->Color.MultiDrawBuffer = GL_TRUE;
457 /* Set drawing buffer to front for now */
458 (void) (*ctx->Driver.SetDrawBuffer)(ctx, GL_FRONT_LEFT);
459 }
460
461 ctx->Color.DrawBuffer = mode;
462 ctx->NewState |= NEW_RASTER_OPS;
463 }
464
465
466
467 void
468 _mesa_ReadBuffer( GLenum mode )
469 {
470 GET_CURRENT_CONTEXT(ctx);
471 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glReadBuffer");
472
473 if (MESA_VERBOSE & VERBOSE_API)
474 fprintf(stderr, "glReadBuffer %s\n", gl_lookup_enum_by_nr(mode));
475
476 switch (mode) {
477 case GL_AUX0:
478 case GL_AUX1:
479 case GL_AUX2:
480 case GL_AUX3:
481 /* AUX buffers not implemented in Mesa at this time */
482 gl_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
483 return;
484 case GL_LEFT:
485 case GL_FRONT:
486 case GL_FRONT_LEFT:
487 /* Front-Left buffer, always exists */
488 ctx->Pixel.DriverReadBuffer = GL_FRONT_LEFT;
489 break;
490 case GL_BACK:
491 case GL_BACK_LEFT:
492 /* Back-Left buffer, requires double buffering */
493 if (!ctx->Visual->DBflag) {
494 gl_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
495 return;
496 }
497 ctx->Pixel.DriverReadBuffer = GL_BACK_LEFT;
498 break;
499 case GL_FRONT_RIGHT:
500 case GL_RIGHT:
501 if (!ctx->Visual->StereoFlag) {
502 gl_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
503 return;
504 }
505 ctx->Pixel.DriverReadBuffer = GL_FRONT_RIGHT;
506 break;
507 case GL_BACK_RIGHT:
508 if (!ctx->Visual->StereoFlag || !ctx->Visual->DBflag) {
509 gl_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
510 return;
511 }
512 ctx->Pixel.DriverReadBuffer = GL_BACK_RIGHT;
513 break;
514 default:
515 gl_error( ctx, GL_INVALID_ENUM, "glReadBuffer" );
516 return;
517 }
518
519 ctx->Pixel.ReadBuffer = mode;
520 ctx->NewState |= NEW_RASTER_OPS;
521 }
522
523
524 /*
525 * GL_MESA_resize_buffers extension
526 */
527 void
528 _mesa_ResizeBuffersMESA( void )
529 {
530 GLcontext *ctx = gl_get_current_context();
531
532 GLuint buf_width, buf_height;
533
534 if (MESA_VERBOSE & VERBOSE_API)
535 fprintf(stderr, "glResizeBuffersMESA\n");
536
537 /* ask device driver for size of output buffer */
538 (*ctx->Driver.GetBufferSize)( ctx, &buf_width, &buf_height );
539
540 /* see if size of device driver's color buffer (window) has changed */
541 if (ctx->DrawBuffer->Width == (GLint) buf_width &&
542 ctx->DrawBuffer->Height == (GLint) buf_height)
543 return;
544
545 ctx->NewState |= NEW_RASTER_OPS; /* to update scissor / window bounds */
546
547 /* save buffer size */
548 ctx->DrawBuffer->Width = buf_width;
549 ctx->DrawBuffer->Height = buf_height;
550
551 /* Reallocate other buffers if needed. */
552 if (ctx->DrawBuffer->UseSoftwareDepthBuffer) {
553 _mesa_alloc_depth_buffer( ctx );
554 }
555 if (ctx->DrawBuffer->UseSoftwareStencilBuffer) {
556 gl_alloc_stencil_buffer( ctx );
557 }
558 if (ctx->DrawBuffer->UseSoftwareAccumBuffer) {
559 _mesa_alloc_accum_buffer( ctx );
560 }
561 if (ctx->Visual->SoftwareAlpha) {
562 gl_alloc_alpha_buffers( ctx );
563 }
564 }