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