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