Home | History | Annotate | Download | only in vbo
      1 /*
      2  * Mesa 3-D graphics library
      3  *
      4  * Copyright (C) 1999-2005  Brian Paul   All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included
     14  * in all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors:
     25  *    Keith Whitwell <keithw (at) vmware.com>
     26  */
     27 
     28 
     29 #include "main/api_arrayelt.h"
     30 #include "main/glheader.h"
     31 #include "main/mtypes.h"
     32 #include "main/vtxfmt.h"
     33 #include "vbo_context.h"
     34 
     35 
     36 
     37 void vbo_exec_init( struct gl_context *ctx )
     38 {
     39    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
     40 
     41    exec->ctx = ctx;
     42 
     43    /* Initialize the arrayelt helper
     44     */
     45    if (!ctx->aelt_context &&
     46        !_ae_create_context( ctx ))
     47       return;
     48 
     49    vbo_exec_vtx_init( exec );
     50 
     51    ctx->Driver.NeedFlush = 0;
     52    ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
     53 
     54    vbo_exec_invalidate_state( ctx, ~0 );
     55 }
     56 
     57 
     58 void vbo_exec_destroy( struct gl_context *ctx )
     59 {
     60    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
     61 
     62    if (ctx->aelt_context) {
     63       _ae_destroy_context( ctx );
     64       ctx->aelt_context = NULL;
     65    }
     66 
     67    vbo_exec_vtx_destroy( exec );
     68 }
     69 
     70 
     71 /**
     72  * Really want to install these callbacks to a central facility to be
     73  * invoked according to the state flags.  That will have to wait for a
     74  * mesa rework:
     75  */
     76 void vbo_exec_invalidate_state( struct gl_context *ctx, GLbitfield new_state )
     77 {
     78    struct vbo_context *vbo = vbo_context(ctx);
     79    struct vbo_exec_context *exec = &vbo->exec;
     80 
     81    if (!exec->validating && new_state & (_NEW_PROGRAM|_NEW_ARRAY)) {
     82       exec->array.recalculate_inputs = GL_TRUE;
     83    }
     84 
     85    if (new_state & _NEW_EVAL)
     86       exec->eval.recalculate_maps = GL_TRUE;
     87 
     88    _ae_invalidate_state(ctx, new_state);
     89 }
     90 
     91 
     92 /**
     93  * Figure out the number of transform feedback primitives that will be output
     94  * considering the drawing mode, number of vertices, and instance count,
     95  * assuming that no geometry shading is done and primitive restart is not
     96  * used.
     97  *
     98  * This is used by driver back-ends in implementing the PRIMITIVES_GENERATED
     99  * and TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN queries.  It is also used to
    100  * pre-validate draw calls in GLES3 (where draw calls only succeed if there is
    101  * enough room in the transform feedback buffer for the result).
    102  */
    103 size_t
    104 vbo_count_tessellated_primitives(GLenum mode, GLuint count,
    105                                  GLuint num_instances)
    106 {
    107    size_t num_primitives;
    108    switch (mode) {
    109    case GL_POINTS:
    110       num_primitives = count;
    111       break;
    112    case GL_LINE_STRIP:
    113       num_primitives = count >= 2 ? count - 1 : 0;
    114       break;
    115    case GL_LINE_LOOP:
    116       num_primitives = count >= 2 ? count : 0;
    117       break;
    118    case GL_LINES:
    119       num_primitives = count / 2;
    120       break;
    121    case GL_TRIANGLE_STRIP:
    122    case GL_TRIANGLE_FAN:
    123    case GL_POLYGON:
    124       num_primitives = count >= 3 ? count - 2 : 0;
    125       break;
    126    case GL_TRIANGLES:
    127       num_primitives = count / 3;
    128       break;
    129    case GL_QUAD_STRIP:
    130       num_primitives = count >= 4 ? ((count / 2) - 1) * 2 : 0;
    131       break;
    132    case GL_QUADS:
    133       num_primitives = (count / 4) * 2;
    134       break;
    135    case GL_LINES_ADJACENCY:
    136       num_primitives = count / 4;
    137       break;
    138    case GL_LINE_STRIP_ADJACENCY:
    139       num_primitives = count >= 4 ? count - 3 : 0;
    140       break;
    141    case GL_TRIANGLES_ADJACENCY:
    142       num_primitives = count / 6;
    143       break;
    144    case GL_TRIANGLE_STRIP_ADJACENCY:
    145       num_primitives = count >= 6 ? (count - 4) / 2 : 0;
    146       break;
    147    default:
    148       assert(!"Unexpected primitive type in count_tessellated_primitives");
    149       num_primitives = 0;
    150       break;
    151    }
    152    return num_primitives * num_instances;
    153 }
    154 
    155 
    156 
    157 /**
    158  * In some degenarate cases we can improve our ability to merge
    159  * consecutive primitives.  For example:
    160  * glBegin(GL_LINE_STRIP);
    161  * glVertex(1);
    162  * glVertex(1);
    163  * glEnd();
    164  * glBegin(GL_LINE_STRIP);
    165  * glVertex(1);
    166  * glVertex(1);
    167  * glEnd();
    168  * Can be merged as a GL_LINES prim with four vertices.
    169  *
    170  * This function converts 2-vertex line strips/loops into GL_LINES, etc.
    171  */
    172 void
    173 vbo_try_prim_conversion(struct _mesa_prim *p)
    174 {
    175    if (p->mode == GL_LINE_STRIP && p->count == 2) {
    176       /* convert 2-vertex line strip to a separate line */
    177       p->mode = GL_LINES;
    178    }
    179    else if ((p->mode == GL_TRIANGLE_STRIP || p->mode == GL_TRIANGLE_FAN)
    180        && p->count == 3) {
    181       /* convert 3-vertex tri strip or fan to a separate triangle */
    182       p->mode = GL_TRIANGLES;
    183    }
    184 
    185    /* Note: we can't convert a 4-vertex quad strip to a separate quad
    186     * because the vertex ordering is different.  We'd have to muck
    187     * around in the vertex data to make it work.
    188     */
    189 }
    190 
    191 
    192 /**
    193  * Helper function for determining if two subsequent glBegin/glEnd
    194  * primitives can be combined.  This is only possible for GL_POINTS,
    195  * GL_LINES, GL_TRIANGLES and GL_QUADS.
    196  * If we return true, it means that we can concatenate p1 onto p0 (and
    197  * discard p1).
    198  */
    199 bool
    200 vbo_can_merge_prims(const struct _mesa_prim *p0, const struct _mesa_prim *p1)
    201 {
    202    if (!p0->begin ||
    203        !p1->begin ||
    204        !p0->end ||
    205        !p1->end)
    206       return false;
    207 
    208    /* The prim mode must match (ex: both GL_TRIANGLES) */
    209    if (p0->mode != p1->mode)
    210       return false;
    211 
    212    /* p1's vertices must come right after p0 */
    213    if (p0->start + p0->count != p1->start)
    214       return false;
    215 
    216    if (p0->basevertex != p1->basevertex ||
    217        p0->num_instances != p1->num_instances ||
    218        p0->base_instance != p1->base_instance)
    219       return false;
    220 
    221    /* can always merge subsequent GL_POINTS primitives */
    222    if (p0->mode == GL_POINTS)
    223       return true;
    224 
    225    /* independent lines with no extra vertices */
    226    if (p0->mode == GL_LINES && p0->count % 2 == 0 && p1->count % 2 == 0)
    227       return true;
    228 
    229    /* independent tris */
    230    if (p0->mode == GL_TRIANGLES && p0->count % 3 == 0 && p1->count % 3 == 0)
    231       return true;
    232 
    233    /* independent quads */
    234    if (p0->mode == GL_QUADS && p0->count % 4 == 0 && p1->count % 4 == 0)
    235       return true;
    236 
    237    return false;
    238 }
    239 
    240 
    241 /**
    242  * If we've determined that p0 and p1 can be merged, this function
    243  * concatenates p1 onto p0.
    244  */
    245 void
    246 vbo_merge_prims(struct _mesa_prim *p0, const struct _mesa_prim *p1)
    247 {
    248    assert(vbo_can_merge_prims(p0, p1));
    249 
    250    p0->count += p1->count;
    251    p0->end = p1->end;
    252 }
    253