buffers.c revision 9c4f016d2171319ad8cde2366d76fd7f70520621
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
48void
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
62void
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 */
89static void
90clear_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 */
139static void
140clear_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 */
203static void
204clear_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
239void
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
314void
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
467void
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 */
527void
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}
565