Home | History | Annotate | Download | only in tnl_dd
      1 /*
      2  * Mesa 3-D graphics library
      3  *
      4  * Copyright (C) 1999-2006  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 #include <stdbool.h>
     28 
     29 /**
     30  * \file t_dd_dmatmp.h
     31  * Template for render stages which build and emit vertices directly
     32  * to fixed-size dma buffers.  Useful for rendering strips and other
     33  * native primitives where clipping and per-vertex tweaks such as
     34  * those in t_dd_tritmp.h are not required.
     35  *
     36  * Produces code for both inline triangles and indexed triangles.
     37  * Where various primitive types are unaccelerated by hardware, the
     38  * code attempts to fallback to other primitive types (quadstrips to
     39  * tristrips, lineloops to linestrips), or to indexed vertices.
     40  */
     41 
     42 #if !HAVE_TRIANGLES || !HAVE_LINES || !HAVE_LINE_STRIPS || !HAVE_TRI_STRIPS || !HAVE_TRI_FANS
     43 #error "must have lines, line strips, triangles, triangle fans, and triangle strips to use render template"
     44 #endif
     45 
     46 #if HAVE_QUAD_STRIPS || HAVE_QUADS || HAVE_ELTS
     47 #error "ELTs, quads, and quad strips not supported by render template"
     48 #endif
     49 
     50 
     51 /**********************************************************************/
     52 /*                  Render whole begin/end objects                    */
     53 /**********************************************************************/
     54 
     55 static inline void *TAG(emit_verts)(struct gl_context *ctx, GLuint start,
     56                                     GLuint count, void *buf)
     57 {
     58    return EMIT_VERTS(ctx, start, count, buf);
     59 }
     60 
     61 /***********************************************************************
     62  *                    Render non-indexed primitives.
     63  ***********************************************************************/
     64 
     65 static void TAG(render_points_verts)(struct gl_context *ctx,
     66                                      GLuint start,
     67                                      GLuint count,
     68                                      GLuint flags)
     69 {
     70    if (HAVE_POINTS) {
     71       LOCAL_VARS;
     72       const unsigned dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
     73       unsigned currentsz;
     74       GLuint j, nr;
     75 
     76       INIT(GL_POINTS);
     77 
     78       currentsz = GET_CURRENT_VB_MAX_VERTS();
     79       if (currentsz < 8)
     80          currentsz = dmasz;
     81 
     82       for (j = 0; j < count; j += nr) {
     83          nr = MIN2(currentsz, count - j);
     84          TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
     85          currentsz = dmasz;
     86       }
     87    } else {
     88       unreachable("Cannot draw primitive; validate_render should have "
     89                   "prevented this");
     90    }
     91 }
     92 
     93 static void TAG(render_lines_verts)(struct gl_context *ctx,
     94                                     GLuint start,
     95                                     GLuint count,
     96                                     GLuint flags)
     97 {
     98    LOCAL_VARS;
     99    const unsigned dmasz = GET_SUBSEQUENT_VB_MAX_VERTS() & ~1;
    100    unsigned currentsz;
    101    GLuint j, nr;
    102 
    103    INIT(GL_LINES);
    104 
    105    /* Emit whole number of lines in total and in each buffer:
    106     */
    107    count -= count & 1;
    108    currentsz = GET_CURRENT_VB_MAX_VERTS();
    109    currentsz -= currentsz & 1;
    110 
    111    if (currentsz < 8)
    112       currentsz = dmasz;
    113 
    114    for (j = 0; j < count; j += nr) {
    115       nr = MIN2(currentsz, count - j);
    116       TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
    117       currentsz = dmasz;
    118    }
    119 }
    120 
    121 
    122 static void TAG(render_line_strip_verts)(struct gl_context *ctx,
    123                                          GLuint start,
    124                                          GLuint count,
    125                                          GLuint flags)
    126 {
    127    LOCAL_VARS;
    128    const unsigned dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
    129    unsigned currentsz;
    130    GLuint j, nr;
    131 
    132    INIT(GL_LINE_STRIP);
    133 
    134    currentsz = GET_CURRENT_VB_MAX_VERTS();
    135    if (currentsz < 8)
    136       currentsz = dmasz;
    137 
    138    for (j = 0; j + 1 < count; j += nr - 1) {
    139       nr = MIN2(currentsz, count - j);
    140       TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
    141       currentsz = dmasz;
    142    }
    143 
    144    FLUSH();
    145 }
    146 
    147 
    148 static void TAG(render_line_loop_verts)(struct gl_context *ctx,
    149                                         GLuint start,
    150                                         GLuint count,
    151                                         GLuint flags)
    152 {
    153    LOCAL_VARS;
    154    const unsigned dmasz = GET_SUBSEQUENT_VB_MAX_VERTS() - 1;
    155    unsigned currentsz;
    156    GLuint j, nr;
    157 
    158    INIT(GL_LINE_STRIP);
    159 
    160    j = (flags & PRIM_BEGIN) ? 0 : 1;
    161 
    162    /* Ensure last vertex won't wrap buffers:
    163     */
    164    currentsz = GET_CURRENT_VB_MAX_VERTS();
    165    currentsz--;
    166 
    167    if (currentsz < 8)
    168       currentsz = dmasz;
    169 
    170    if (j + 1 < count) {
    171       for (/* empty */; j + 1 < count; j += nr - 1) {
    172          nr = MIN2(currentsz, count - j);
    173 
    174          if (j + nr >= count &&
    175              count > 1 &&
    176              (flags & PRIM_END)) {
    177             void *tmp;
    178             tmp = ALLOC_VERTS(nr+1);
    179             tmp = TAG(emit_verts)(ctx, start + j, nr, tmp);
    180             tmp = TAG(emit_verts)( ctx, start, 1, tmp );
    181             (void) tmp;
    182          } else {
    183             TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
    184             currentsz = dmasz;
    185          }
    186       }
    187    } else if (count > 1 && (flags & PRIM_END)) {
    188       void *tmp;
    189       tmp = ALLOC_VERTS(2);
    190       tmp = TAG(emit_verts)( ctx, start+1, 1, tmp );
    191       tmp = TAG(emit_verts)( ctx, start, 1, tmp );
    192       (void) tmp;
    193    }
    194 
    195    FLUSH();
    196 }
    197 
    198 
    199 static void TAG(render_triangles_verts)(struct gl_context *ctx,
    200                                         GLuint start,
    201                                         GLuint count,
    202                                         GLuint flags)
    203 {
    204    LOCAL_VARS;
    205    const unsigned dmasz = (GET_SUBSEQUENT_VB_MAX_VERTS() / 3) * 3;
    206    unsigned currentsz;
    207    GLuint j, nr;
    208 
    209    INIT(GL_TRIANGLES);
    210 
    211    currentsz = (GET_CURRENT_VB_MAX_VERTS() / 3) * 3;
    212 
    213    /* Emit whole number of tris in total.  dmasz is already a multiple
    214     * of 3.
    215     */
    216    count -= count % 3;
    217 
    218    if (currentsz < 8)
    219       currentsz = dmasz;
    220 
    221    for (j = 0; j < count; j += nr) {
    222       nr = MIN2(currentsz, count - j);
    223       TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
    224       currentsz = dmasz;
    225    }
    226 }
    227 
    228 
    229 
    230 static void TAG(render_tri_strip_verts)(struct gl_context *ctx,
    231                                         GLuint start,
    232                                         GLuint count,
    233                                         GLuint flags)
    234 {
    235    LOCAL_VARS;
    236    GLuint j, nr;
    237    const unsigned dmasz = GET_SUBSEQUENT_VB_MAX_VERTS() & ~1;
    238    unsigned currentsz;
    239 
    240    INIT(GL_TRIANGLE_STRIP);
    241 
    242    currentsz = GET_CURRENT_VB_MAX_VERTS();
    243 
    244    if (currentsz < 8)
    245       currentsz = dmasz;
    246 
    247    /* From here on emit even numbers of tris when wrapping over buffers:
    248     */
    249    currentsz -= (currentsz & 1);
    250 
    251    for (j = 0; j + 2 < count; j += nr - 2) {
    252       nr = MIN2(currentsz, count - j);
    253       TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
    254       currentsz = dmasz;
    255    }
    256 
    257    FLUSH();
    258 }
    259 
    260 static void TAG(render_tri_fan_verts)(struct gl_context *ctx,
    261                                       GLuint start,
    262                                       GLuint count,
    263                                       GLuint flags)
    264 {
    265    LOCAL_VARS;
    266    GLuint j, nr;
    267    const unsigned dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
    268    unsigned currentsz;
    269 
    270    INIT(GL_TRIANGLE_FAN);
    271 
    272    currentsz = GET_CURRENT_VB_MAX_VERTS();
    273    if (currentsz < 8)
    274       currentsz = dmasz;
    275 
    276    for (j = 1; j + 1 < count; j += nr - 2) {
    277       void *tmp;
    278       nr = MIN2(currentsz, count - j + 1);
    279       tmp = ALLOC_VERTS(nr);
    280       tmp = TAG(emit_verts)(ctx, start, 1, tmp);
    281       tmp = TAG(emit_verts)(ctx, start + j, nr - 1, tmp);
    282       (void) tmp;
    283       currentsz = dmasz;
    284    }
    285 
    286    FLUSH();
    287 }
    288 
    289 
    290 static void TAG(render_poly_verts)(struct gl_context *ctx,
    291                                    GLuint start,
    292                                    GLuint count,
    293                                    GLuint flags)
    294 {
    295    if (HAVE_POLYGONS) {
    296       LOCAL_VARS;
    297       GLuint j, nr;
    298       const unsigned dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
    299       unsigned currentsz;
    300 
    301       INIT(GL_POLYGON);
    302 
    303       currentsz = GET_CURRENT_VB_MAX_VERTS();
    304       if (currentsz < 8) {
    305          currentsz = dmasz;
    306       }
    307 
    308       for (j = 1; j + 1 < count; j += nr - 2) {
    309          void *tmp;
    310          nr = MIN2(currentsz, count - j + 1);
    311          tmp = ALLOC_VERTS(nr);
    312          tmp = TAG(emit_verts)(ctx, start, 1, tmp);
    313          tmp = TAG(emit_verts)(ctx, start + j, nr - 1, tmp);
    314          (void) tmp;
    315          currentsz = dmasz;
    316       }
    317 
    318       FLUSH();
    319    } else if (ctx->Light.ShadeModel == GL_SMOOTH ||
    320               ctx->Light.ProvokingVertex == GL_FIRST_VERTEX_CONVENTION) {
    321       TAG(render_tri_fan_verts)( ctx, start, count, flags );
    322    } else {
    323       unreachable("Cannot draw primitive; validate_render should have "
    324                   "prevented this");
    325    }
    326 }
    327 
    328 static void TAG(render_quad_strip_verts)(struct gl_context *ctx,
    329                                          GLuint start,
    330                                          GLuint count,
    331                                          GLuint flags)
    332 {
    333    GLuint j, nr;
    334 
    335    if (ctx->Light.ShadeModel == GL_SMOOTH) {
    336       LOCAL_VARS;
    337       const unsigned dmasz = GET_SUBSEQUENT_VB_MAX_VERTS() & ~1;
    338       unsigned currentsz;
    339 
    340       /* Emit smooth-shaded quadstrips as tristrips:
    341        */
    342       FLUSH();
    343       INIT(GL_TRIANGLE_STRIP);
    344 
    345       /* Emit whole number of quads in total, and in each buffer.
    346        */
    347       currentsz = GET_CURRENT_VB_MAX_VERTS();
    348       currentsz -= currentsz & 1;
    349       count -= count & 1;
    350 
    351       if (currentsz < 8)
    352          currentsz = dmasz;
    353 
    354       for (j = 0; j + 3 < count; j += nr - 2) {
    355          nr = MIN2(currentsz, count - j);
    356          TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
    357          currentsz = dmasz;
    358       }
    359 
    360       FLUSH();
    361    } else {
    362       unreachable("Cannot draw primitive; validate_render should have "
    363                   "prevented this");
    364    }
    365 }
    366 
    367 
    368 static void TAG(render_quads_verts)(struct gl_context *ctx,
    369                                     GLuint start,
    370                                     GLuint count,
    371                                     GLuint flags)
    372 {
    373    if (ctx->Light.ShadeModel == GL_SMOOTH ||
    374        ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION) {
    375       LOCAL_VARS;
    376       GLuint j;
    377 
    378       /* Emit whole number of quads in total. */
    379       count -= count & 3;
    380 
    381       /* Hardware doesn't have a quad primitive type -- try to simulate it using
    382        * triangle primitive.  This is a win for gears, but is it useful in the
    383        * broader world?
    384        */
    385       INIT(GL_TRIANGLES);
    386 
    387       for (j = 0; j + 3 < count; j += 4) {
    388          void *tmp = ALLOC_VERTS(6);
    389          /* Send v0, v1, v3
    390           */
    391          tmp = EMIT_VERTS(ctx, start + j,     2, tmp);
    392          tmp = EMIT_VERTS(ctx, start + j + 3, 1, tmp);
    393          /* Send v1, v2, v3
    394           */
    395          tmp = EMIT_VERTS(ctx, start + j + 1, 3, tmp);
    396          (void) tmp;
    397       }
    398    } else {
    399       unreachable("Cannot draw primitive");
    400    }
    401 }
    402 
    403 static void TAG(render_noop)(struct gl_context *ctx,
    404                              GLuint start,
    405                              GLuint count,
    406                              GLuint flags)
    407 {
    408    (void) ctx;
    409    (void) start;
    410    (void) count;
    411    (void) flags;
    412 }
    413 
    414 static const tnl_render_func TAG(render_tab_verts)[GL_POLYGON+2] =
    415 {
    416    TAG(render_points_verts),
    417    TAG(render_lines_verts),
    418    TAG(render_line_loop_verts),
    419    TAG(render_line_strip_verts),
    420    TAG(render_triangles_verts),
    421    TAG(render_tri_strip_verts),
    422    TAG(render_tri_fan_verts),
    423    TAG(render_quads_verts),
    424    TAG(render_quad_strip_verts),
    425    TAG(render_poly_verts),
    426    TAG(render_noop),
    427 };
    428 
    429 /* Pre-check the primitives in the VB to prevent the need for
    430  * fallbacks later on.
    431  */
    432 static bool TAG(validate_render)(struct gl_context *ctx,
    433                                  struct vertex_buffer *VB)
    434 {
    435    GLint i;
    436 
    437    if (VB->ClipOrMask & ~CLIP_CULL_BIT)
    438       return false;
    439 
    440    if (VB->Elts)
    441       return false;
    442 
    443    for (i = 0 ; i < VB->PrimitiveCount ; i++) {
    444       GLuint prim = VB->Primitive[i].mode;
    445       GLuint count = VB->Primitive[i].count;
    446       bool ok = false;
    447 
    448       if (!count)
    449          continue;
    450 
    451       switch (prim & PRIM_MODE_MASK) {
    452       case GL_POINTS:
    453          ok = HAVE_POINTS;
    454          break;
    455       case GL_LINES:
    456       case GL_LINE_STRIP:
    457       case GL_LINE_LOOP:
    458          ok = !ctx->Line.StippleFlag;
    459          break;
    460       case GL_TRIANGLES:
    461       case GL_TRIANGLE_STRIP:
    462       case GL_TRIANGLE_FAN:
    463          ok = true;
    464          break;
    465       case GL_POLYGON:
    466          ok = (HAVE_POLYGONS) || ctx->Light.ShadeModel == GL_SMOOTH ||
    467               ctx->Light.ProvokingVertex == GL_FIRST_VERTEX_CONVENTION;
    468          break;
    469       case GL_QUAD_STRIP:
    470          ok = VB->Elts || ctx->Light.ShadeModel == GL_SMOOTH;
    471          break;
    472       case GL_QUADS:
    473          ok = ctx->Light.ShadeModel == GL_SMOOTH ||
    474               ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION;
    475          break;
    476       default:
    477          break;
    478       }
    479 
    480       if (!ok) {
    481 /*          fprintf(stderr, "not ok %s\n", _mesa_enum_to_string(prim & PRIM_MODE_MASK)); */
    482          return false;
    483       }
    484    }
    485 
    486    return true;
    487 }
    488 
    489