Home | History | Annotate | Download | only in main
      1 /*
      2  * Mesa 3-D graphics library
      3  * Version:  7.1
      4  *
      5  * Copyright (C) 1999-2008  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 #include "glheader.h"
     26 #include "imports.h"
     27 #include "bufferobj.h"
     28 #include "context.h"
     29 #include "drawpix.h"
     30 #include "enums.h"
     31 #include "feedback.h"
     32 #include "framebuffer.h"
     33 #include "image.h"
     34 #include "mfeatures.h"
     35 #include "pbo.h"
     36 #include "state.h"
     37 #include "dispatch.h"
     38 #include "glformats.h"
     39 #include "fbobject.h"
     40 
     41 
     42 #if FEATURE_drawpix
     43 
     44 
     45 /*
     46  * Execute glDrawPixels
     47  */
     48 static void GLAPIENTRY
     49 _mesa_DrawPixels( GLsizei width, GLsizei height,
     50                   GLenum format, GLenum type, const GLvoid *pixels )
     51 {
     52    GLenum err;
     53    GET_CURRENT_CONTEXT(ctx);
     54    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
     55 
     56    if (MESA_VERBOSE & VERBOSE_API)
     57       _mesa_debug(ctx, "glDrawPixels(%d, %d, %s, %s, %p) // to %s at %d, %d\n",
     58                   width, height,
     59                   _mesa_lookup_enum_by_nr(format),
     60                   _mesa_lookup_enum_by_nr(type),
     61                   pixels,
     62                   _mesa_lookup_enum_by_nr(ctx->DrawBuffer->ColorDrawBuffer[0]),
     63                   IROUND(ctx->Current.RasterPos[0]),
     64                   IROUND(ctx->Current.RasterPos[1]));
     65 
     66 
     67    if (width < 0 || height < 0) {
     68       _mesa_error( ctx, GL_INVALID_VALUE, "glDrawPixels(width or height < 0)" );
     69       return;
     70    }
     71 
     72    /* We're not using the current vertex program, and the driver may install
     73     * its own.  Note: this may dirty some state.
     74     */
     75    _mesa_set_vp_override(ctx, GL_TRUE);
     76 
     77    /* Note: this call does state validation */
     78    if (!_mesa_valid_to_render(ctx, "glDrawPixels")) {
     79       goto end;      /* the error code was recorded */
     80    }
     81 
     82    /* GL 3.0 introduced a new restriction on glDrawPixels() over what was in
     83     * GL_EXT_texture_integer.  From section 3.7.4 ("Rasterization of Pixel
     84     * Rectangles) on page 151 of the GL 3.0 specification:
     85     *
     86     *     "If format contains integer components, as shown in table 3.6, an
     87     *      INVALID OPERATION error is generated."
     88     *
     89     * Since DrawPixels rendering would be merely undefined if not an error (due
     90     * to a lack of defined mapping from integer data to gl_Color fragment shader
     91     * input), NVIDIA's implementation also just returns this error despite
     92     * exposing GL_EXT_texture_integer, just return an error regardless.
     93     */
     94    if (_mesa_is_enum_format_integer(format)) {
     95       _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels(integer format)");
     96       goto end;
     97    }
     98 
     99    err = _mesa_error_check_format_and_type(ctx, format, type);
    100    if (err != GL_NO_ERROR) {
    101       _mesa_error(ctx, err, "glDrawPixels(invalid format %s and/or type %s)",
    102                   _mesa_lookup_enum_by_nr(format),
    103                   _mesa_lookup_enum_by_nr(type));
    104       goto end;
    105    }
    106 
    107    /* do special format-related checks */
    108    switch (format) {
    109    case GL_STENCIL_INDEX:
    110    case GL_DEPTH_COMPONENT:
    111    case GL_DEPTH_STENCIL_EXT:
    112       /* these buffers must exist */
    113       if (!_mesa_dest_buffer_exists(ctx, format)) {
    114          _mesa_error(ctx, GL_INVALID_OPERATION,
    115                      "glDrawPixels(missing deest buffer)");
    116          goto end;
    117       }
    118       break;
    119    case GL_COLOR_INDEX:
    120       if (ctx->PixelMaps.ItoR.Size == 0 ||
    121           ctx->PixelMaps.ItoG.Size == 0 ||
    122           ctx->PixelMaps.ItoB.Size == 0) {
    123          _mesa_error(ctx, GL_INVALID_OPERATION,
    124                 "glDrawPixels(drawing color index pixels into RGB buffer)");
    125          goto end;
    126       }
    127       break;
    128    default:
    129       /* for color formats it's not an error if the destination color
    130        * buffer doesn't exist.
    131        */
    132       break;
    133    }
    134 
    135    if (ctx->RasterDiscard) {
    136       goto end;
    137    }
    138 
    139    if (!ctx->Current.RasterPosValid) {
    140       goto end;  /* no-op, not an error */
    141    }
    142 
    143    if (ctx->RenderMode == GL_RENDER) {
    144       if (width > 0 && height > 0) {
    145          /* Round, to satisfy conformance tests (matches SGI's OpenGL) */
    146          GLint x = IROUND(ctx->Current.RasterPos[0]);
    147          GLint y = IROUND(ctx->Current.RasterPos[1]);
    148 
    149          if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) {
    150             /* unpack from PBO */
    151             if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height,
    152                                            1, format, type, INT_MAX, pixels)) {
    153                _mesa_error(ctx, GL_INVALID_OPERATION,
    154                            "glDrawPixels(invalid PBO access)");
    155                goto end;
    156             }
    157             if (_mesa_bufferobj_mapped(ctx->Unpack.BufferObj)) {
    158                /* buffer is mapped - that's an error */
    159                _mesa_error(ctx, GL_INVALID_OPERATION,
    160                            "glDrawPixels(PBO is mapped)");
    161                goto end;
    162             }
    163          }
    164 
    165          ctx->Driver.DrawPixels(ctx, x, y, width, height, format, type,
    166                                 &ctx->Unpack, pixels);
    167       }
    168    }
    169    else if (ctx->RenderMode == GL_FEEDBACK) {
    170       /* Feedback the current raster pos info */
    171       FLUSH_CURRENT( ctx, 0 );
    172       _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN );
    173       _mesa_feedback_vertex( ctx,
    174                              ctx->Current.RasterPos,
    175                              ctx->Current.RasterColor,
    176                              ctx->Current.RasterTexCoords[0] );
    177    }
    178    else {
    179       ASSERT(ctx->RenderMode == GL_SELECT);
    180       /* Do nothing.  See OpenGL Spec, Appendix B, Corollary 6. */
    181    }
    182 
    183 end:
    184    _mesa_set_vp_override(ctx, GL_FALSE);
    185 
    186    if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
    187       _mesa_flush(ctx);
    188    }
    189 }
    190 
    191 
    192 static void GLAPIENTRY
    193 _mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height,
    194                   GLenum type )
    195 {
    196    GET_CURRENT_CONTEXT(ctx);
    197    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
    198 
    199    if (MESA_VERBOSE & VERBOSE_API)
    200       _mesa_debug(ctx,
    201                   "glCopyPixels(%d, %d, %d, %d, %s) // from %s to %s at %d, %d\n",
    202                   srcx, srcy, width, height,
    203                   _mesa_lookup_enum_by_nr(type),
    204                   _mesa_lookup_enum_by_nr(ctx->ReadBuffer->ColorReadBuffer),
    205                   _mesa_lookup_enum_by_nr(ctx->DrawBuffer->ColorDrawBuffer[0]),
    206                   IROUND(ctx->Current.RasterPos[0]),
    207                   IROUND(ctx->Current.RasterPos[1]));
    208 
    209    if (width < 0 || height < 0) {
    210       _mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)");
    211       return;
    212    }
    213 
    214    /* Note: more detailed 'type' checking is done by the
    215     * _mesa_source/dest_buffer_exists() calls below.  That's where we
    216     * check if the stencil buffer exists, etc.
    217     */
    218    if (type != GL_COLOR &&
    219        type != GL_DEPTH &&
    220        type != GL_STENCIL &&
    221        type != GL_DEPTH_STENCIL) {
    222       _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels(type=%s)",
    223                   _mesa_lookup_enum_by_nr(type));
    224       return;
    225    }
    226 
    227    /* We're not using the current vertex program, and the driver may install
    228     * it's own.  Note: this may dirty some state.
    229     */
    230    _mesa_set_vp_override(ctx, GL_TRUE);
    231 
    232    /* Note: this call does state validation */
    233    if (!_mesa_valid_to_render(ctx, "glCopyPixels")) {
    234       goto end;      /* the error code was recorded */
    235    }
    236 
    237    /* Check read buffer's status (draw buffer was already checked) */
    238    if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
    239       _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
    240                   "glCopyPixels(incomplete framebuffer)" );
    241       goto end;
    242    }
    243 
    244    if (_mesa_is_user_fbo(ctx->ReadBuffer) &&
    245        ctx->ReadBuffer->Visual.samples > 0) {
    246       _mesa_error(ctx, GL_INVALID_OPERATION,
    247 		  "glCopyPixels(multisample FBO)");
    248       goto end;
    249    }
    250 
    251    if (!_mesa_source_buffer_exists(ctx, type) ||
    252        !_mesa_dest_buffer_exists(ctx, type)) {
    253       _mesa_error(ctx, GL_INVALID_OPERATION,
    254                   "glCopyPixels(missing source or dest buffer)");
    255       goto end;
    256    }
    257 
    258    if (ctx->RasterDiscard) {
    259       goto end;
    260    }
    261 
    262    if (!ctx->Current.RasterPosValid || width == 0 || height == 0) {
    263       goto end; /* no-op, not an error */
    264    }
    265 
    266    if (ctx->RenderMode == GL_RENDER) {
    267       /* Round to satisfy conformance tests (matches SGI's OpenGL) */
    268       if (width > 0 && height > 0) {
    269          GLint destx = IROUND(ctx->Current.RasterPos[0]);
    270          GLint desty = IROUND(ctx->Current.RasterPos[1]);
    271          ctx->Driver.CopyPixels( ctx, srcx, srcy, width, height, destx, desty,
    272                                  type );
    273       }
    274    }
    275    else if (ctx->RenderMode == GL_FEEDBACK) {
    276       FLUSH_CURRENT( ctx, 0 );
    277       _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN );
    278       _mesa_feedback_vertex( ctx,
    279                              ctx->Current.RasterPos,
    280                              ctx->Current.RasterColor,
    281                              ctx->Current.RasterTexCoords[0] );
    282    }
    283    else {
    284       ASSERT(ctx->RenderMode == GL_SELECT);
    285       /* Do nothing.  See OpenGL Spec, Appendix B, Corollary 6. */
    286    }
    287 
    288 end:
    289    _mesa_set_vp_override(ctx, GL_FALSE);
    290 
    291    if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
    292       _mesa_flush(ctx);
    293    }
    294 }
    295 
    296 
    297 static void GLAPIENTRY
    298 _mesa_Bitmap( GLsizei width, GLsizei height,
    299               GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove,
    300               const GLubyte *bitmap )
    301 {
    302    GET_CURRENT_CONTEXT(ctx);
    303    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
    304 
    305    if (width < 0 || height < 0) {
    306       _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" );
    307       return;
    308    }
    309 
    310    if (!ctx->Current.RasterPosValid) {
    311       return;    /* do nothing */
    312    }
    313 
    314    /* Note: this call does state validation */
    315    if (!_mesa_valid_to_render(ctx, "glBitmap")) {
    316       /* the error code was recorded */
    317       return;
    318    }
    319 
    320    if (ctx->RasterDiscard)
    321       return;
    322 
    323    if (ctx->RenderMode == GL_RENDER) {
    324       /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */
    325       if (width > 0 && height > 0) {
    326          const GLfloat epsilon = 0.0001F;
    327          GLint x = IFLOOR(ctx->Current.RasterPos[0] + epsilon - xorig);
    328          GLint y = IFLOOR(ctx->Current.RasterPos[1] + epsilon - yorig);
    329 
    330          if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) {
    331             /* unpack from PBO */
    332             if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height,
    333                                            1, GL_COLOR_INDEX, GL_BITMAP,
    334                                            INT_MAX, (const GLvoid *) bitmap)) {
    335                _mesa_error(ctx, GL_INVALID_OPERATION,
    336                            "glBitmap(invalid PBO access)");
    337                return;
    338             }
    339             if (_mesa_bufferobj_mapped(ctx->Unpack.BufferObj)) {
    340                /* buffer is mapped - that's an error */
    341                _mesa_error(ctx, GL_INVALID_OPERATION,
    342                            "glBitmap(PBO is mapped)");
    343                return;
    344             }
    345          }
    346 
    347          ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap );
    348       }
    349    }
    350 #if _HAVE_FULL_GL
    351    else if (ctx->RenderMode == GL_FEEDBACK) {
    352       FLUSH_CURRENT(ctx, 0);
    353       _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN );
    354       _mesa_feedback_vertex( ctx,
    355                              ctx->Current.RasterPos,
    356                              ctx->Current.RasterColor,
    357                              ctx->Current.RasterTexCoords[0] );
    358    }
    359    else {
    360       ASSERT(ctx->RenderMode == GL_SELECT);
    361       /* Do nothing.  See OpenGL Spec, Appendix B, Corollary 6. */
    362    }
    363 #endif
    364 
    365    /* update raster position */
    366    ctx->Current.RasterPos[0] += xmove;
    367    ctx->Current.RasterPos[1] += ymove;
    368 
    369    if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
    370       _mesa_flush(ctx);
    371    }
    372 }
    373 
    374 
    375 void
    376 _mesa_init_drawpix_dispatch(struct _glapi_table *disp)
    377 {
    378    SET_Bitmap(disp, _mesa_Bitmap);
    379    SET_CopyPixels(disp, _mesa_CopyPixels);
    380    SET_DrawPixels(disp, _mesa_DrawPixels);
    381 }
    382 
    383 
    384 #endif /* FEATURE_drawpix */
    385