dd87009031febb29fae29f0f0a36877e64b5cce8
[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 const GLuint colorMask = *((GLuint *) &ctx->Color.ColorMask);
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
156 ASSERT(colorMask == 0xffffffff);
157
158 for (i = 0; i < width; i++) {
159 span[i][RCOMP] = r;
160 span[i][GCOMP] = g;
161 span[i][BCOMP] = b;
162 span[i][ACOMP] = a;
163 }
164 for (i = 0; i < height; i++) {
165 (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y + i,
166 (CONST GLubyte (*)[4]) span, NULL );
167 }
168 }
169 else {
170 /* Color index mode */
171 ASSERT(ctx->Color.IndexMask == ~0);
172 if (ctx->Visual->IndexBits == 8) {
173 /* 8-bit clear */
174 GLubyte span[MAX_WIDTH];
175 GLint i;
176 MEMSET(span, ctx->Color.ClearIndex, width);
177 for (i = 0; i < height; i++) {
178 (*ctx->Driver.WriteCI8Span)( ctx, width, x, y + i, span, NULL );
179 }
180 }
181 else {
182 /* non 8-bit clear */
183 GLuint span[MAX_WIDTH];
184 GLint i;
185 for (i = 0; i < width; i++) {
186 span[i] = ctx->Color.ClearIndex;
187 }
188 for (i = 0; i < height; i++) {
189 (*ctx->Driver.WriteCI32Span)( ctx, width, x, y + i, span, NULL );
190 }
191 }
192 }
193 }
194
195
196
197 /*
198 * Clear the front/back/left/right color buffers.
199 * This function is usually only called if we need to clear the
200 * buffers with masking.
201 */
202 static void
203 clear_color_buffers(GLcontext *ctx)
204 {
205 const GLuint colorMask = *((GLuint *) &ctx->Color.ColorMask);
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 (colorMask != 0xffffffff) {
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) _mesa_clear_stencil_buffer(ctx);
298 }
299
300 /* clear software-based alpha buffer(s) */
301 if ( (mask & GL_COLOR_BUFFER_BIT)
302 && ctx->DrawBuffer->UseSoftwareAlphaBuffers
303 && ctx->Color.ColorMask[ACOMP]) {
304 _mesa_clear_alpha_buffers( ctx );
305 }
306
307 #ifdef PROFILE
308 ctx->ClearTime += gl_time() - t0;
309 ctx->ClearCount++;
310 #endif
311 }
312 }
313
314
315 void
316 _mesa_DrawBuffer( GLenum mode )
317 {
318 GET_CURRENT_CONTEXT(ctx);
319 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDrawBuffer");
320
321 if (MESA_VERBOSE & VERBOSE_API)
322 fprintf(stderr, "glDrawBuffer %s\n", gl_lookup_enum_by_nr(mode));
323
324 switch (mode) {
325 case GL_AUX0:
326 case GL_AUX1:
327 case GL_AUX2:
328 case GL_AUX3:
329 /* AUX buffers not implemented in Mesa at this time */
330 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
331 return;
332 case GL_RIGHT:
333 if (!ctx->Visual->StereoFlag) {
334 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
335 return;
336 }
337 if (ctx->Visual->DBflag)
338 ctx->Color.DrawDestMask = FRONT_RIGHT_BIT | BACK_RIGHT_BIT;
339 else
340 ctx->Color.DrawDestMask = FRONT_RIGHT_BIT;
341 break;
342 case GL_FRONT_RIGHT:
343 if (!ctx->Visual->StereoFlag) {
344 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
345 return;
346 }
347 ctx->Color.DrawDestMask = FRONT_RIGHT_BIT;
348 break;
349 case GL_BACK_RIGHT:
350 if (!ctx->Visual->StereoFlag) {
351 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
352 return;
353 }
354 if (!ctx->Visual->DBflag) {
355 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
356 return;
357 }
358 ctx->Color.DrawDestMask = BACK_RIGHT_BIT;
359 break;
360 case GL_BACK_LEFT:
361 if (!ctx->Visual->DBflag) {
362 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
363 return;
364 }
365 ctx->Color.DrawDestMask = BACK_LEFT_BIT;
366 break;
367 case GL_FRONT_AND_BACK:
368 if (!ctx->Visual->DBflag) {
369 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
370 return;
371 }
372 if (ctx->Visual->StereoFlag)
373 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT
374 | FRONT_RIGHT_BIT | BACK_RIGHT_BIT;
375 else
376 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT;
377 break;
378 case GL_BACK:
379 if (!ctx->Visual->DBflag) {
380 gl_error( ctx, GL_INVALID_OPERATION, "glDrawBuffer" );
381 return;
382 }
383 if (ctx->Visual->StereoFlag)
384 ctx->Color.DrawDestMask = BACK_LEFT_BIT | BACK_RIGHT_BIT;
385 else
386 ctx->Color.DrawDestMask = BACK_LEFT_BIT;
387 break;
388 case GL_LEFT:
389 /* never an error */
390 if (ctx->Visual->DBflag)
391 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | BACK_LEFT_BIT;
392 else
393 ctx->Color.DrawDestMask = FRONT_LEFT_BIT;
394 break;
395 case GL_FRONT_LEFT:
396 /* never an error */
397 ctx->Color.DrawDestMask = FRONT_LEFT_BIT;
398 break;
399 case GL_FRONT:
400 /* never an error */
401 if (ctx->Visual->StereoFlag)
402 ctx->Color.DrawDestMask = FRONT_LEFT_BIT | FRONT_RIGHT_BIT;
403 else
404 ctx->Color.DrawDestMask = FRONT_LEFT_BIT;
405 break;
406 case GL_NONE:
407 /* never an error */
408 ctx->Color.DrawDestMask = 0;
409 break;
410 default:
411 gl_error( ctx, GL_INVALID_ENUM, "glDrawBuffer" );
412 return;
413 }
414
415 /*
416 * Make the dest buffer mode more precise if possible
417 */
418 if (mode == GL_LEFT && !ctx->Visual->DBflag)
419 ctx->Color.DriverDrawBuffer = GL_FRONT_LEFT;
420 else if (mode == GL_RIGHT && !ctx->Visual->DBflag)
421 ctx->Color.DriverDrawBuffer = GL_FRONT_RIGHT;
422 else if (mode == GL_FRONT && !ctx->Visual->StereoFlag)
423 ctx->Color.DriverDrawBuffer = GL_FRONT_LEFT;
424 else if (mode == GL_BACK && !ctx->Visual->StereoFlag)
425 ctx->Color.DriverDrawBuffer = GL_BACK_LEFT;
426 else
427 ctx->Color.DriverDrawBuffer = mode;
428
429 /*
430 * Set current alpha buffer pointer
431 */
432 if (ctx->DrawBuffer->UseSoftwareAlphaBuffers) {
433 if (ctx->Color.DriverDrawBuffer == GL_FRONT_LEFT)
434 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontLeftAlpha;
435 else if (ctx->Color.DriverDrawBuffer == GL_BACK_LEFT)
436 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackLeftAlpha;
437 else if (ctx->Color.DriverDrawBuffer == GL_FRONT_RIGHT)
438 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontRightAlpha;
439 else if (ctx->Color.DriverDrawBuffer == GL_BACK_RIGHT)
440 ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackRightAlpha;
441 }
442
443 /*
444 * If we get here there can't have been an error.
445 * Now see if device driver can implement the drawing to the target
446 * buffer(s). The driver may not be able to do GL_FRONT_AND_BACK mode
447 * for example. We'll take care of that in the core code by looping
448 * over the individual buffers.
449 */
450 ASSERT(ctx->Driver.SetDrawBuffer);
451 if ( (*ctx->Driver.SetDrawBuffer)(ctx, ctx->Color.DriverDrawBuffer) ) {
452 /* All OK, the driver will do all buffer writes */
453 ctx->Color.MultiDrawBuffer = GL_FALSE;
454 }
455 else {
456 /* We'll have to loop over the multiple draw buffer targets */
457 ctx->Color.MultiDrawBuffer = GL_TRUE;
458 /* Set drawing buffer to front for now */
459 (void) (*ctx->Driver.SetDrawBuffer)(ctx, GL_FRONT_LEFT);
460 }
461
462 ctx->Color.DrawBuffer = mode;
463 ctx->NewState |= NEW_RASTER_OPS;
464 }
465
466
467
468 void
469 _mesa_ReadBuffer( GLenum mode )
470 {
471 GET_CURRENT_CONTEXT(ctx);
472 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glReadBuffer");
473
474 if (MESA_VERBOSE & VERBOSE_API)
475 fprintf(stderr, "glReadBuffer %s\n", gl_lookup_enum_by_nr(mode));
476
477 switch (mode) {
478 case GL_AUX0:
479 case GL_AUX1:
480 case GL_AUX2:
481 case GL_AUX3:
482 /* AUX buffers not implemented in Mesa at this time */
483 gl_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
484 return;
485 case GL_LEFT:
486 case GL_FRONT:
487 case GL_FRONT_LEFT:
488 /* Front-Left buffer, always exists */
489 ctx->Pixel.DriverReadBuffer = GL_FRONT_LEFT;
490 break;
491 case GL_BACK:
492 case GL_BACK_LEFT:
493 /* Back-Left buffer, requires double buffering */
494 if (!ctx->Visual->DBflag) {
495 gl_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
496 return;
497 }
498 ctx->Pixel.DriverReadBuffer = GL_BACK_LEFT;
499 break;
500 case GL_FRONT_RIGHT:
501 case GL_RIGHT:
502 if (!ctx->Visual->StereoFlag) {
503 gl_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
504 return;
505 }
506 ctx->Pixel.DriverReadBuffer = GL_FRONT_RIGHT;
507 break;
508 case GL_BACK_RIGHT:
509 if (!ctx->Visual->StereoFlag || !ctx->Visual->DBflag) {
510 gl_error( ctx, GL_INVALID_OPERATION, "glReadBuffer" );
511 return;
512 }
513 ctx->Pixel.DriverReadBuffer = GL_BACK_RIGHT;
514 break;
515 default:
516 gl_error( ctx, GL_INVALID_ENUM, "glReadBuffer" );
517 return;
518 }
519
520 ctx->Pixel.ReadBuffer = mode;
521 ctx->NewState |= NEW_RASTER_OPS;
522 }
523
524
525 /*
526 * GL_MESA_resize_buffers extension
527 */
528 void
529 _mesa_ResizeBuffersMESA( void )
530 {
531 GLcontext *ctx = gl_get_current_context();
532
533 GLuint buf_width, buf_height;
534
535 if (MESA_VERBOSE & VERBOSE_API)
536 fprintf(stderr, "glResizeBuffersMESA\n");
537
538 /* ask device driver for size of output buffer */
539 (*ctx->Driver.GetBufferSize)( ctx, &buf_width, &buf_height );
540
541 /* see if size of device driver's color buffer (window) has changed */
542 if (ctx->DrawBuffer->Width == (GLint) buf_width &&
543 ctx->DrawBuffer->Height == (GLint) buf_height)
544 return;
545
546 ctx->NewState |= NEW_RASTER_OPS; /* to update scissor / window bounds */
547
548 /* save buffer size */
549 ctx->DrawBuffer->Width = buf_width;
550 ctx->DrawBuffer->Height = buf_height;
551
552 /* Reallocate other buffers if needed. */
553 if (ctx->DrawBuffer->UseSoftwareDepthBuffer) {
554 _mesa_alloc_depth_buffer( ctx );
555 }
556 if (ctx->DrawBuffer->UseSoftwareStencilBuffer) {
557 _mesa_alloc_stencil_buffer( ctx );
558 }
559 if (ctx->DrawBuffer->UseSoftwareAccumBuffer) {
560 _mesa_alloc_accum_buffer( ctx );
561 }
562 if (ctx->DrawBuffer->UseSoftwareAlphaBuffers) {
563 _mesa_alloc_alpha_buffers( ctx );
564 }
565 }