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