buffers.c revision c7048f9d9f91ef8c3ef35e31976adbf686349c41
1/*
2 * Mesa 3-D graphics library
3 * Version:  7.1
4 *
5 * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26/**
27 * \file buffers.c
28 * glReadBuffer, DrawBuffer functions.
29 */
30
31
32
33#include "glheader.h"
34#include "buffers.h"
35#include "colormac.h"
36#include "context.h"
37#include "enums.h"
38#include "fbobject.h"
39#include "state.h"
40
41
42#define BAD_MASK ~0u
43
44
45/**
46 * Return bitmask of BUFFER_BIT_* flags indicating which color buffers are
47 * available to the rendering context (for drawing or reading).
48 * This depends on the type of framebuffer.  For window system framebuffers
49 * we look at the framebuffer's visual.  But for user-create framebuffers we
50 * look at the number of supported color attachments.
51 * \param fb  the framebuffer to draw to, or read from
52 * \return  bitmask of BUFFER_BIT_* flags
53 */
54static GLbitfield
55supported_buffer_bitmask(const GLcontext *ctx, const struct gl_framebuffer *fb)
56{
57   GLbitfield mask = 0x0;
58
59   if (fb->Name > 0) {
60      /* A user-created renderbuffer */
61      GLuint i;
62      ASSERT(ctx->Extensions.EXT_framebuffer_object);
63      for (i = 0; i < ctx->Const.MaxColorAttachments; i++) {
64         mask |= (BUFFER_BIT_COLOR0 << i);
65      }
66   }
67   else {
68      /* A window system framebuffer */
69      GLint i;
70      mask = BUFFER_BIT_FRONT_LEFT; /* always have this */
71      if (fb->Visual.stereoMode) {
72         mask |= BUFFER_BIT_FRONT_RIGHT;
73         if (fb->Visual.doubleBufferMode) {
74            mask |= BUFFER_BIT_BACK_LEFT | BUFFER_BIT_BACK_RIGHT;
75         }
76      }
77      else if (fb->Visual.doubleBufferMode) {
78         mask |= BUFFER_BIT_BACK_LEFT;
79      }
80
81      for (i = 0; i < fb->Visual.numAuxBuffers; i++) {
82         mask |= (BUFFER_BIT_AUX0 << i);
83      }
84   }
85
86   return mask;
87}
88
89
90/**
91 * Helper routine used by glDrawBuffer and glDrawBuffersARB.
92 * Given a GLenum naming one or more color buffers (such as
93 * GL_FRONT_AND_BACK), return the corresponding bitmask of BUFFER_BIT_* flags.
94 */
95static GLbitfield
96draw_buffer_enum_to_bitmask(GLenum buffer)
97{
98   switch (buffer) {
99      case GL_NONE:
100         return 0;
101      case GL_FRONT:
102         return BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_FRONT_RIGHT;
103      case GL_BACK:
104         return BUFFER_BIT_BACK_LEFT | BUFFER_BIT_BACK_RIGHT;
105      case GL_RIGHT:
106         return BUFFER_BIT_FRONT_RIGHT | BUFFER_BIT_BACK_RIGHT;
107      case GL_FRONT_RIGHT:
108         return BUFFER_BIT_FRONT_RIGHT;
109      case GL_BACK_RIGHT:
110         return BUFFER_BIT_BACK_RIGHT;
111      case GL_BACK_LEFT:
112         return BUFFER_BIT_BACK_LEFT;
113      case GL_FRONT_AND_BACK:
114         return BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT
115              | BUFFER_BIT_FRONT_RIGHT | BUFFER_BIT_BACK_RIGHT;
116      case GL_LEFT:
117         return BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT;
118      case GL_FRONT_LEFT:
119         return BUFFER_BIT_FRONT_LEFT;
120      case GL_AUX0:
121         return BUFFER_BIT_AUX0;
122      case GL_AUX1:
123      case GL_AUX2:
124      case GL_AUX3:
125         return 1 << BUFFER_COUNT; /* invalid, but not BAD_MASK */
126      case GL_COLOR_ATTACHMENT0_EXT:
127         return BUFFER_BIT_COLOR0;
128      case GL_COLOR_ATTACHMENT1_EXT:
129         return BUFFER_BIT_COLOR1;
130      case GL_COLOR_ATTACHMENT2_EXT:
131         return BUFFER_BIT_COLOR2;
132      case GL_COLOR_ATTACHMENT3_EXT:
133         return BUFFER_BIT_COLOR3;
134      case GL_COLOR_ATTACHMENT4_EXT:
135         return BUFFER_BIT_COLOR4;
136      case GL_COLOR_ATTACHMENT5_EXT:
137         return BUFFER_BIT_COLOR5;
138      case GL_COLOR_ATTACHMENT6_EXT:
139         return BUFFER_BIT_COLOR6;
140      case GL_COLOR_ATTACHMENT7_EXT:
141         return BUFFER_BIT_COLOR7;
142      default:
143         /* error */
144         return BAD_MASK;
145   }
146}
147
148
149/**
150 * Helper routine used by glReadBuffer.
151 * Given a GLenum naming a color buffer, return the index of the corresponding
152 * renderbuffer (a BUFFER_* value).
153 * return -1 for an invalid buffer.
154 */
155static GLint
156read_buffer_enum_to_index(GLenum buffer)
157{
158   switch (buffer) {
159      case GL_FRONT:
160         return BUFFER_FRONT_LEFT;
161      case GL_BACK:
162         return BUFFER_BACK_LEFT;
163      case GL_RIGHT:
164         return BUFFER_FRONT_RIGHT;
165      case GL_FRONT_RIGHT:
166         return BUFFER_FRONT_RIGHT;
167      case GL_BACK_RIGHT:
168         return BUFFER_BACK_RIGHT;
169      case GL_BACK_LEFT:
170         return BUFFER_BACK_LEFT;
171      case GL_LEFT:
172         return BUFFER_FRONT_LEFT;
173      case GL_FRONT_LEFT:
174         return BUFFER_FRONT_LEFT;
175      case GL_AUX0:
176         return BUFFER_AUX0;
177      case GL_AUX1:
178      case GL_AUX2:
179      case GL_AUX3:
180         return BUFFER_COUNT; /* invalid, but not -1 */
181      case GL_COLOR_ATTACHMENT0_EXT:
182         return BUFFER_COLOR0;
183      case GL_COLOR_ATTACHMENT1_EXT:
184         return BUFFER_COLOR1;
185      case GL_COLOR_ATTACHMENT2_EXT:
186         return BUFFER_COLOR2;
187      case GL_COLOR_ATTACHMENT3_EXT:
188         return BUFFER_COLOR3;
189      case GL_COLOR_ATTACHMENT4_EXT:
190         return BUFFER_COLOR4;
191      case GL_COLOR_ATTACHMENT5_EXT:
192         return BUFFER_COLOR5;
193      case GL_COLOR_ATTACHMENT6_EXT:
194         return BUFFER_COLOR6;
195      case GL_COLOR_ATTACHMENT7_EXT:
196         return BUFFER_COLOR7;
197      default:
198         /* error */
199         return -1;
200   }
201}
202
203
204/**
205 * Called by glDrawBuffer().
206 * Specify which renderbuffer(s) to draw into for the first color output.
207 * <buffer> can name zero, one, two or four renderbuffers!
208 * \sa _mesa_DrawBuffersARB
209 *
210 * \param buffer  buffer token such as GL_LEFT or GL_FRONT_AND_BACK, etc.
211 *
212 * Note that the behaviour of this function depends on whether the
213 * current ctx->DrawBuffer is a window-system framebuffer (Name=0) or
214 * a user-created framebuffer object (Name!=0).
215 *   In the former case, we update the per-context ctx->Color.DrawBuffer
216 *   state var _and_ the FB's ColorDrawBuffer state.
217 *   In the later case, we update the FB's ColorDrawBuffer state only.
218 *
219 * Furthermore, upon a MakeCurrent() or BindFramebuffer() call, if the
220 * new FB is a window system FB, we need to re-update the FB's
221 * ColorDrawBuffer state to match the context.  This is handled in
222 * _mesa_update_framebuffer().
223 *
224 * See the GL_EXT_framebuffer_object spec for more info.
225 */
226void GLAPIENTRY
227_mesa_DrawBuffer(GLenum buffer)
228{
229   GLbitfield destMask;
230   GET_CURRENT_CONTEXT(ctx);
231   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex... */
232
233   if (MESA_VERBOSE & VERBOSE_API) {
234      _mesa_debug(ctx, "glDrawBuffer %s\n", _mesa_lookup_enum_by_nr(buffer));
235   }
236
237   if (buffer == GL_NONE) {
238      destMask = 0x0;
239   }
240   else {
241      const GLbitfield supportedMask
242         = supported_buffer_bitmask(ctx, ctx->DrawBuffer);
243      destMask = draw_buffer_enum_to_bitmask(buffer);
244      if (destMask == BAD_MASK) {
245         /* totally bogus buffer */
246         _mesa_error(ctx, GL_INVALID_ENUM, "glDrawBuffer(buffer=0x%x)", buffer);
247         return;
248      }
249      destMask &= supportedMask;
250      if (destMask == 0x0) {
251         /* none of the named color buffers exist! */
252         _mesa_error(ctx, GL_INVALID_OPERATION,
253                     "glDrawBuffer(buffer=0x%x)", buffer);
254         return;
255      }
256   }
257
258   /* if we get here, there's no error so set new state */
259   _mesa_drawbuffers(ctx, 1, &buffer, &destMask);
260
261   /*
262    * Call device driver function.
263    */
264   if (ctx->Driver.DrawBuffers)
265      ctx->Driver.DrawBuffers(ctx, 1, &buffer);
266   else if (ctx->Driver.DrawBuffer)
267      ctx->Driver.DrawBuffer(ctx, buffer);
268}
269
270
271/**
272 * Called by glDrawBuffersARB; specifies the destination color renderbuffers
273 * for N fragment program color outputs.
274 * \sa _mesa_DrawBuffer
275 * \param n  number of outputs
276 * \param buffers  array [n] of renderbuffer names.  Unlike glDrawBuffer, the
277 *                 names cannot specify more than one buffer.  For example,
278 *                 GL_FRONT_AND_BACK is illegal.
279 */
280void GLAPIENTRY
281_mesa_DrawBuffersARB(GLsizei n, const GLenum *buffers)
282{
283   GLint output;
284   GLbitfield usedBufferMask, supportedMask;
285   GLbitfield destMask[MAX_DRAW_BUFFERS];
286   GET_CURRENT_CONTEXT(ctx);
287   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
288
289   /* Turns out n==0 is a valid input that should not produce an error.
290    * The remaining code below correctly handles the n==0 case.
291    */
292   if (n < 0 || n > (GLsizei) ctx->Const.MaxDrawBuffers) {
293      _mesa_error(ctx, GL_INVALID_VALUE, "glDrawBuffersARB(n)");
294      return;
295   }
296
297   supportedMask = supported_buffer_bitmask(ctx, ctx->DrawBuffer);
298   usedBufferMask = 0x0;
299
300   /* complicated error checking... */
301   for (output = 0; output < n; output++) {
302      if (buffers[output] == GL_NONE) {
303         destMask[output] = 0x0;
304      }
305      else {
306         destMask[output] = draw_buffer_enum_to_bitmask(buffers[output]);
307         if (destMask[output] == BAD_MASK
308             || _mesa_bitcount(destMask[output]) > 1) {
309            _mesa_error(ctx, GL_INVALID_ENUM, "glDrawBuffersARB(buffer)");
310            return;
311         }
312         destMask[output] &= supportedMask;
313         if (destMask[output] == 0) {
314            _mesa_error(ctx, GL_INVALID_OPERATION,
315                        "glDrawBuffersARB(unsupported buffer)");
316            return;
317         }
318         if (destMask[output] & usedBufferMask) {
319            /* can't specify a dest buffer more than once! */
320            _mesa_error(ctx, GL_INVALID_OPERATION,
321                        "glDrawBuffersARB(duplicated buffer)");
322            return;
323         }
324
325         /* update bitmask */
326         usedBufferMask |= destMask[output];
327      }
328   }
329
330   /* OK, if we get here, there were no errors so set the new state */
331   _mesa_drawbuffers(ctx, n, buffers, destMask);
332
333   /*
334    * Call device driver function.  Note that n can be equal to 0,
335    * in which case we don't want to reference buffers[0], which
336    * may not be valid.
337    */
338   if (ctx->Driver.DrawBuffers)
339      ctx->Driver.DrawBuffers(ctx, n, buffers);
340   else if (ctx->Driver.DrawBuffer)
341      ctx->Driver.DrawBuffer(ctx, n>0? buffers[0]:GL_NONE);
342}
343
344
345/**
346 * Helper function to set the GL_DRAW_BUFFER state in the context and
347 * current FBO.  Called via glDrawBuffer(), glDrawBuffersARB()
348 *
349 * All error checking will have been done prior to calling this function
350 * so nothing should go wrong at this point.
351 *
352 * \param ctx  current context
353 * \param n    number of color outputs to set
354 * \param buffers  array[n] of colorbuffer names, like GL_LEFT.
355 * \param destMask  array[n] of BUFFER_BIT_* bitmasks which correspond to the
356 *                  colorbuffer names.  (i.e. GL_FRONT_AND_BACK =>
357 *                  BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT).
358 */
359void
360_mesa_drawbuffers(GLcontext *ctx, GLuint n, const GLenum *buffers,
361                  const GLbitfield *destMask)
362{
363   struct gl_framebuffer *fb = ctx->DrawBuffer;
364   GLbitfield mask[MAX_DRAW_BUFFERS];
365   GLboolean newState = GL_FALSE;
366
367   if (!destMask) {
368      /* compute destMask values now */
369      const GLbitfield supportedMask = supported_buffer_bitmask(ctx, fb);
370      GLuint output;
371      for (output = 0; output < n; output++) {
372         mask[output] = draw_buffer_enum_to_bitmask(buffers[output]);
373         ASSERT(mask[output] != BAD_MASK);
374         mask[output] &= supportedMask;
375      }
376      destMask = mask;
377   }
378
379   /*
380    * If n==1, destMask[0] may have up to four bits set.
381    * Otherwise, destMask[x] can only have one bit set.
382    */
383   if (n == 1) {
384      GLuint count = 0, destMask0 = destMask[0];
385      /* init to -1 to help catch errors */
386      //fb->_ColorDrawBufferIndexes[0] = -1;
387      while (destMask0) {
388         GLint bufIndex = _mesa_ffs(destMask0) - 1;
389         if (fb->_ColorDrawBufferIndexes[count] != bufIndex) {
390            fb->_ColorDrawBufferIndexes[count] = bufIndex;
391            newState = GL_TRUE;
392         }
393         count++;
394         destMask0 &= ~(1 << bufIndex);
395      }
396      fb->ColorDrawBuffer[0] = buffers[0];
397      if (fb->_NumColorDrawBuffers != count) {
398         fb->_NumColorDrawBuffers = count;
399         newState = GL_TRUE;
400      }
401   }
402   else {
403      GLuint buf, count = 0;
404      for (buf = 0; buf < n; buf++ ) {
405         if (destMask[buf]) {
406            GLint bufIndex = _mesa_ffs(destMask[buf]) - 1;
407            /* only one bit should be set in the destMask[buf] field */
408            ASSERT(_mesa_bitcount(destMask[buf]) == 1);
409            if (fb->_ColorDrawBufferIndexes[buf] != bufIndex) {
410               fb->_ColorDrawBufferIndexes[buf] = bufIndex;
411               newState = GL_TRUE;
412            }
413            fb->ColorDrawBuffer[buf] = buffers[buf];
414            count = buf + 1;
415         }
416         else {
417            if (fb->_ColorDrawBufferIndexes[buf] != -1) {
418               fb->_ColorDrawBufferIndexes[buf] = -1;
419               newState = GL_TRUE;
420            }
421         }
422      }
423      /* set remaining outputs to -1 (GL_NONE) */
424      while (buf < ctx->Const.MaxDrawBuffers) {
425         if (fb->_ColorDrawBufferIndexes[buf] != -1) {
426            fb->_ColorDrawBufferIndexes[buf] = -1;
427            buf++;
428         }
429         fb->ColorDrawBuffer[buf] = GL_NONE;
430      }
431      fb->_NumColorDrawBuffers = count;
432   }
433
434   if (fb->Name == 0) {
435      /* also set context drawbuffer state */
436      GLuint buf;
437      for (buf = 0; buf < ctx->Const.MaxDrawBuffers; buf++) {
438         if (ctx->Color.DrawBuffer[buf] != fb->ColorDrawBuffer[buf]) {
439            ctx->Color.DrawBuffer[buf] = fb->ColorDrawBuffer[buf];
440            newState = GL_TRUE;
441         }
442      }
443   }
444
445   if (newState)
446      FLUSH_VERTICES(ctx, _NEW_BUFFERS);
447}
448
449
450/**
451 * Like \sa _mesa_drawbuffers(), this is a helper function for setting
452 * GL_READ_BUFFER state in the context and current FBO.
453 * \param ctx  the rendering context
454 * \param buffer  GL_FRONT, GL_BACK, GL_COLOR_ATTACHMENT0, etc.
455 * \param bufferIndex  the numerical index corresponding to 'buffer'
456 */
457void
458_mesa_readbuffer(GLcontext *ctx, GLenum buffer, GLint bufferIndex)
459{
460   struct gl_framebuffer *fb = ctx->ReadBuffer;
461
462   if (fb->Name == 0) {
463      /* Only update the per-context READ_BUFFER state if we're bound to
464       * a window-system framebuffer.
465       */
466      ctx->Pixel.ReadBuffer = buffer;
467   }
468
469   fb->ColorReadBuffer = buffer;
470   fb->_ColorReadBufferIndex = bufferIndex;
471
472   ctx->NewState |= _NEW_BUFFERS;
473}
474
475
476
477/**
478 * Called by glReadBuffer to set the source renderbuffer for reading pixels.
479 * \param mode color buffer such as GL_FRONT, GL_BACK, etc.
480 */
481void GLAPIENTRY
482_mesa_ReadBuffer(GLenum buffer)
483{
484   struct gl_framebuffer *fb;
485   GLbitfield supportedMask;
486   GLint srcBuffer;
487   GET_CURRENT_CONTEXT(ctx);
488   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
489
490   if (MESA_VERBOSE & VERBOSE_API)
491      _mesa_debug(ctx, "glReadBuffer %s\n", _mesa_lookup_enum_by_nr(buffer));
492
493   fb = ctx->ReadBuffer;
494
495   if (MESA_VERBOSE & VERBOSE_API)
496      _mesa_debug(ctx, "glReadBuffer %s\n", _mesa_lookup_enum_by_nr(buffer));
497
498   if (fb->Name > 0 && buffer == GL_NONE) {
499      /* This is legal for user-created framebuffer objects */
500      srcBuffer = -1;
501   }
502   else {
503      /* general case / window-system framebuffer */
504      srcBuffer = read_buffer_enum_to_index(buffer);
505      if (srcBuffer == -1) {
506         _mesa_error(ctx, GL_INVALID_ENUM,
507                     "glReadBuffer(buffer=0x%x)", buffer);
508         return;
509      }
510      supportedMask = supported_buffer_bitmask(ctx, fb);
511      if (((1 << srcBuffer) & supportedMask) == 0) {
512         _mesa_error(ctx, GL_INVALID_OPERATION,
513                     "glReadBuffer(buffer=0x%x)", buffer);
514         return;
515      }
516   }
517
518   /* OK, all error checking has been completed now */
519
520   _mesa_readbuffer(ctx, buffer, srcBuffer);
521   ctx->NewState |= _NEW_BUFFERS;
522
523   /*
524    * Call device driver function.
525    */
526   if (ctx->Driver.ReadBuffer)
527      (*ctx->Driver.ReadBuffer)(ctx, buffer);
528}
529