Home | History | Annotate | Download | only in tnl
      1 /*
      2  * Copyright 2003 VMware, Inc.
      3  * All Rights Reserved.
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the "Software"),
      7  * to deal in the Software without restriction, including without limitation
      8  * on the rights to use, copy, modify, merge, publish, distribute, sub
      9  * license, and/or sell copies of the Software, and to permit persons to whom
     10  * the Software is furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the next
     13  * paragraph) shall be included in all copies or substantial portions of the
     14  * Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
     19  * VMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
     20  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     21  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
     22  * USE OR OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors:
     25  *    Keith Whitwell <keithw (at) vmware.com>
     26  */
     27 
     28 #include <stdio.h>
     29 #include "main/glheader.h"
     30 #include "main/context.h"
     31 #include "main/execmem.h"
     32 #include "swrast/s_chan.h"
     33 #include "t_context.h"
     34 #include "t_vertex.h"
     35 
     36 #define DBG 0
     37 
     38 /* Build and manage clipspace/ndc/window vertices.
     39  */
     40 
     41 static GLboolean match_fastpath( struct tnl_clipspace *vtx,
     42 				 const struct tnl_clipspace_fastpath *fp)
     43 {
     44    GLuint j;
     45 
     46    if (vtx->attr_count != fp->attr_count)
     47       return GL_FALSE;
     48 
     49    for (j = 0; j < vtx->attr_count; j++)
     50       if (vtx->attr[j].format != fp->attr[j].format ||
     51 	  vtx->attr[j].inputsize != fp->attr[j].size ||
     52 	  vtx->attr[j].vertoffset != fp->attr[j].offset)
     53 	 return GL_FALSE;
     54 
     55    if (fp->match_strides) {
     56       if (vtx->vertex_size != fp->vertex_size)
     57 	 return GL_FALSE;
     58 
     59       for (j = 0; j < vtx->attr_count; j++)
     60 	 if (vtx->attr[j].inputstride != fp->attr[j].stride)
     61 	    return GL_FALSE;
     62    }
     63 
     64    return GL_TRUE;
     65 }
     66 
     67 static GLboolean search_fastpath_emit( struct tnl_clipspace *vtx )
     68 {
     69    struct tnl_clipspace_fastpath *fp = vtx->fastpath;
     70 
     71    for ( ; fp ; fp = fp->next) {
     72       if (match_fastpath(vtx, fp)) {
     73          vtx->emit = fp->func;
     74 	 return GL_TRUE;
     75       }
     76    }
     77 
     78    return GL_FALSE;
     79 }
     80 
     81 void _tnl_register_fastpath( struct tnl_clipspace *vtx,
     82 			     GLboolean match_strides )
     83 {
     84    struct tnl_clipspace_fastpath *fastpath = CALLOC_STRUCT(tnl_clipspace_fastpath);
     85    GLuint i;
     86 
     87    if (fastpath == NULL) {
     88       _mesa_error_no_memory(__func__);
     89       return;
     90    }
     91 
     92    fastpath->vertex_size = vtx->vertex_size;
     93    fastpath->attr_count = vtx->attr_count;
     94    fastpath->match_strides = match_strides;
     95    fastpath->func = vtx->emit;
     96    fastpath->attr = malloc(vtx->attr_count * sizeof(fastpath->attr[0]));
     97 
     98    if (fastpath->attr == NULL) {
     99       free(fastpath);
    100       _mesa_error_no_memory(__func__);
    101       return;
    102    }
    103 
    104    for (i = 0; i < vtx->attr_count; i++) {
    105       fastpath->attr[i].format = vtx->attr[i].format;
    106       fastpath->attr[i].stride = vtx->attr[i].inputstride;
    107       fastpath->attr[i].size = vtx->attr[i].inputsize;
    108       fastpath->attr[i].offset = vtx->attr[i].vertoffset;
    109    }
    110 
    111    fastpath->next = vtx->fastpath;
    112    vtx->fastpath = fastpath;
    113 }
    114 
    115 
    116 
    117 /***********************************************************************
    118  * Build codegen functions or return generic ones:
    119  */
    120 static void choose_emit_func( struct gl_context *ctx, GLuint count, GLubyte *dest)
    121 {
    122    struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
    123    struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
    124    struct tnl_clipspace_attr *a = vtx->attr;
    125    const GLuint attr_count = vtx->attr_count;
    126    GLuint j;
    127 
    128    for (j = 0; j < attr_count; j++) {
    129       GLvector4f *vptr = VB->AttribPtr[a[j].attrib];
    130       a[j].inputstride = vptr->stride;
    131       a[j].inputsize = vptr->size;
    132       a[j].emit = a[j].insert[vptr->size - 1]; /* not always used */
    133    }
    134 
    135    vtx->emit = NULL;
    136 
    137    /* Does this match an existing (hardwired, codegen or known-bad)
    138     * fastpath?
    139     */
    140    if (search_fastpath_emit(vtx)) {
    141       /* Use this result.  If it is null, then it is already known
    142        * that the current state will fail for codegen and there is no
    143        * point trying again.
    144        */
    145    }
    146    else if (vtx->codegen_emit) {
    147       vtx->codegen_emit(ctx);
    148    }
    149 
    150    if (!vtx->emit) {
    151       _tnl_generate_hardwired_emit(ctx);
    152    }
    153 
    154    /* Otherwise use the generic version:
    155     */
    156    if (!vtx->emit)
    157       vtx->emit = _tnl_generic_emit;
    158 
    159    vtx->emit( ctx, count, dest );
    160 }
    161 
    162 
    163 
    164 static void choose_interp_func( struct gl_context *ctx,
    165 				GLfloat t,
    166 				GLuint edst, GLuint eout, GLuint ein,
    167 				GLboolean force_boundary )
    168 {
    169    struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
    170    GLboolean unfilled = (ctx->Polygon.FrontMode != GL_FILL ||
    171                          ctx->Polygon.BackMode != GL_FILL);
    172    GLboolean twosided = ctx->Light.Enabled && ctx->Light.Model.TwoSide;
    173 
    174    if (vtx->need_extras && (twosided || unfilled)) {
    175       vtx->interp = _tnl_generic_interp_extras;
    176    } else {
    177       vtx->interp = _tnl_generic_interp;
    178    }
    179 
    180    vtx->interp( ctx, t, edst, eout, ein, force_boundary );
    181 }
    182 
    183 
    184 static void choose_copy_pv_func(  struct gl_context *ctx, GLuint edst, GLuint esrc )
    185 {
    186    struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
    187    GLboolean unfilled = (ctx->Polygon.FrontMode != GL_FILL ||
    188                          ctx->Polygon.BackMode != GL_FILL);
    189 
    190    GLboolean twosided = ctx->Light.Enabled && ctx->Light.Model.TwoSide;
    191 
    192    if (vtx->need_extras && (twosided || unfilled)) {
    193       vtx->copy_pv = _tnl_generic_copy_pv_extras;
    194    } else {
    195       vtx->copy_pv = _tnl_generic_copy_pv;
    196    }
    197 
    198    vtx->copy_pv( ctx, edst, esrc );
    199 }
    200 
    201 
    202 /***********************************************************************
    203  * Public entrypoints, mostly dispatch to the above:
    204  */
    205 
    206 
    207 /* Interpolate between two vertices to produce a third:
    208  */
    209 void _tnl_interp( struct gl_context *ctx,
    210 		  GLfloat t,
    211 		  GLuint edst, GLuint eout, GLuint ein,
    212 		  GLboolean force_boundary )
    213 {
    214    struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
    215    vtx->interp( ctx, t, edst, eout, ein, force_boundary );
    216 }
    217 
    218 /* Copy colors from one vertex to another:
    219  */
    220 void _tnl_copy_pv(  struct gl_context *ctx, GLuint edst, GLuint esrc )
    221 {
    222    struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
    223    vtx->copy_pv( ctx, edst, esrc );
    224 }
    225 
    226 
    227 /* Extract a named attribute from a hardware vertex.  Will have to
    228  * reverse any viewport transformation, swizzling or other conversions
    229  * which may have been applied:
    230  */
    231 void _tnl_get_attr( struct gl_context *ctx, const void *vin,
    232 			      GLenum attr, GLfloat *dest )
    233 {
    234    struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
    235    const struct tnl_clipspace_attr *a = vtx->attr;
    236    const GLuint attr_count = vtx->attr_count;
    237    GLuint j;
    238 
    239    for (j = 0; j < attr_count; j++) {
    240       if (a[j].attrib == attr) {
    241 	 a[j].extract( &a[j], dest, (GLubyte *)vin + a[j].vertoffset );
    242 	 return;
    243       }
    244    }
    245 
    246    /* Else return the value from ctx->Current.
    247     */
    248    if (attr == _TNL_ATTRIB_POINTSIZE) {
    249       /* If the hardware vertex doesn't have point size then use size from
    250        * struct gl_context.  XXX this will be wrong if drawing attenuated points!
    251        */
    252       dest[0] = ctx->Point.Size;
    253    }
    254    else {
    255       memcpy( dest, ctx->Current.Attrib[attr], 4*sizeof(GLfloat));
    256    }
    257 }
    258 
    259 
    260 /* Complementary operation to the above.
    261  */
    262 void _tnl_set_attr( struct gl_context *ctx, void *vout,
    263 		    GLenum attr, const GLfloat *src )
    264 {
    265    struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
    266    const struct tnl_clipspace_attr *a = vtx->attr;
    267    const GLuint attr_count = vtx->attr_count;
    268    GLuint j;
    269 
    270    for (j = 0; j < attr_count; j++) {
    271       if (a[j].attrib == attr) {
    272 	 a[j].insert[4-1]( &a[j], (GLubyte *)vout + a[j].vertoffset, src );
    273 	 return;
    274       }
    275    }
    276 }
    277 
    278 
    279 void *_tnl_get_vertex( struct gl_context *ctx, GLuint nr )
    280 {
    281    struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
    282 
    283    return vtx->vertex_buf + nr * vtx->vertex_size;
    284 }
    285 
    286 void _tnl_invalidate_vertex_state( struct gl_context *ctx, GLuint new_state )
    287 {
    288    /* if two-sided lighting changes or filled/unfilled polygon state changes */
    289    if (new_state & (_NEW_LIGHT | _NEW_POLYGON) ) {
    290       struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
    291       vtx->new_inputs = ~0;
    292       vtx->interp = choose_interp_func;
    293       vtx->copy_pv = choose_copy_pv_func;
    294    }
    295 }
    296 
    297 static void invalidate_funcs( struct tnl_clipspace *vtx )
    298 {
    299    vtx->emit = choose_emit_func;
    300    vtx->interp = choose_interp_func;
    301    vtx->copy_pv = choose_copy_pv_func;
    302    vtx->new_inputs = ~0;
    303 }
    304 
    305 GLuint _tnl_install_attrs( struct gl_context *ctx, const struct tnl_attr_map *map,
    306 			   GLuint nr, const GLfloat *vp,
    307 			   GLuint unpacked_size )
    308 {
    309    struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
    310    GLuint offset = 0;
    311    GLuint i, j;
    312 
    313    assert(nr < _TNL_ATTRIB_MAX);
    314    assert(nr == 0 || map[0].attrib == VERT_ATTRIB_POS);
    315 
    316    vtx->new_inputs = ~0;
    317    vtx->need_viewport = GL_FALSE;
    318 
    319    if (vp) {
    320       vtx->need_viewport = GL_TRUE;
    321    }
    322 
    323    for (j = 0, i = 0; i < nr; i++) {
    324       const GLuint format = map[i].format;
    325       if (format == EMIT_PAD) {
    326 	 if (DBG)
    327 	    printf("%d: pad %d, offset %d\n", i,
    328 		   map[i].offset, offset);
    329 
    330 	 offset += map[i].offset;
    331 
    332       }
    333       else {
    334 	 GLuint tmpoffset;
    335 
    336 	 if (unpacked_size)
    337 	    tmpoffset = map[i].offset;
    338 	 else
    339 	    tmpoffset = offset;
    340 
    341 	 if (vtx->attr_count != j ||
    342 	     vtx->attr[j].attrib != map[i].attrib ||
    343 	     vtx->attr[j].format != format ||
    344 	     vtx->attr[j].vertoffset != tmpoffset) {
    345 	    invalidate_funcs(vtx);
    346 
    347 	    vtx->attr[j].attrib = map[i].attrib;
    348 	    vtx->attr[j].format = format;
    349 	    vtx->attr[j].vp = vp;
    350 	    vtx->attr[j].insert = _tnl_format_info[format].insert;
    351 	    vtx->attr[j].extract = _tnl_format_info[format].extract;
    352 	    vtx->attr[j].vertattrsize = _tnl_format_info[format].attrsize;
    353 	    vtx->attr[j].vertoffset = tmpoffset;
    354 	 }
    355 
    356 
    357 	 if (DBG)
    358 	    printf("%d: %s, vp %p, offset %d\n", i,
    359 		   _tnl_format_info[format].name, (void *)vp,
    360 		   vtx->attr[j].vertoffset);
    361 
    362 	 offset += _tnl_format_info[format].attrsize;
    363 	 j++;
    364       }
    365    }
    366 
    367    vtx->attr_count = j;
    368 
    369    if (unpacked_size)
    370       vtx->vertex_size = unpacked_size;
    371    else
    372       vtx->vertex_size = offset;
    373 
    374    assert(vtx->vertex_size <= vtx->max_vertex_size);
    375    return vtx->vertex_size;
    376 }
    377 
    378 
    379 
    380 void _tnl_invalidate_vertices( struct gl_context *ctx, GLuint newinputs )
    381 {
    382    struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
    383    vtx->new_inputs |= newinputs;
    384 }
    385 
    386 
    387 /* This event has broader use beyond this file - will move elsewhere
    388  * and probably invoke a driver callback.
    389  */
    390 void _tnl_notify_pipeline_output_change( struct gl_context *ctx )
    391 {
    392    struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
    393    invalidate_funcs(vtx);
    394 }
    395 
    396 
    397 static void adjust_input_ptrs( struct gl_context *ctx, GLint diff)
    398 {
    399    struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
    400    struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
    401    struct tnl_clipspace_attr *a = vtx->attr;
    402    const GLuint count = vtx->attr_count;
    403    GLuint j;
    404 
    405    diff -= 1;
    406    for (j=0; j<count; ++j) {
    407            register GLvector4f *vptr = VB->AttribPtr[a->attrib];
    408 	   (a++)->inputptr += diff*vptr->stride;
    409    }
    410 }
    411 
    412 static void update_input_ptrs( struct gl_context *ctx, GLuint start )
    413 {
    414    struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
    415    struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
    416    struct tnl_clipspace_attr *a = vtx->attr;
    417    const GLuint count = vtx->attr_count;
    418    GLuint j;
    419 
    420    for (j = 0; j < count; j++) {
    421       GLvector4f *vptr = VB->AttribPtr[a[j].attrib];
    422 
    423       if (vtx->emit != choose_emit_func) {
    424 	 assert(a[j].inputstride == vptr->stride);
    425 	 assert(a[j].inputsize == vptr->size);
    426       }
    427 
    428       a[j].inputptr = ((GLubyte *)vptr->data) + start * vptr->stride;
    429    }
    430 
    431    if (a->vp) {
    432       vtx->vp_scale[0] = a->vp[MAT_SX];
    433       vtx->vp_scale[1] = a->vp[MAT_SY];
    434       vtx->vp_scale[2] = a->vp[MAT_SZ];
    435       vtx->vp_scale[3] = 1.0;
    436       vtx->vp_xlate[0] = a->vp[MAT_TX];
    437       vtx->vp_xlate[1] = a->vp[MAT_TY];
    438       vtx->vp_xlate[2] = a->vp[MAT_TZ];
    439       vtx->vp_xlate[3] = 0.0;
    440    }
    441 }
    442 
    443 
    444 void _tnl_build_vertices( struct gl_context *ctx,
    445 			  GLuint start,
    446 			  GLuint end,
    447 			  GLuint newinputs )
    448 {
    449    struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
    450    update_input_ptrs( ctx, start );
    451    vtx->emit( ctx, end - start,
    452 	      (GLubyte *)(vtx->vertex_buf +
    453 			  start * vtx->vertex_size));
    454 }
    455 
    456 /* Emit VB vertices start..end to dest.  Note that VB vertex at
    457  * postion start will be emitted to dest at position zero.
    458  */
    459 void *_tnl_emit_vertices_to_buffer( struct gl_context *ctx,
    460 				    GLuint start,
    461 				    GLuint end,
    462 				    void *dest )
    463 {
    464    struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
    465 
    466    update_input_ptrs(ctx, start);
    467    /* Note: dest should not be adjusted for non-zero 'start' values:
    468     */
    469    vtx->emit( ctx, end - start, (GLubyte*) dest );
    470    return (void *)((GLubyte *)dest + vtx->vertex_size * (end - start));
    471 }
    472 
    473 /* Emit indexed VB vertices start..end to dest.  Note that VB vertex at
    474  * postion start will be emitted to dest at position zero.
    475  */
    476 
    477 void *_tnl_emit_indexed_vertices_to_buffer( struct gl_context *ctx,
    478 					    const GLuint *elts,
    479 					    GLuint start,
    480 					    GLuint end,
    481 					    void *dest )
    482 {
    483    struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
    484    GLuint oldIndex;
    485    GLubyte *cdest = dest;
    486 
    487    update_input_ptrs(ctx, oldIndex = elts[start++]);
    488    vtx->emit( ctx, 1, cdest );
    489    cdest += vtx->vertex_size;
    490 
    491    for (; start < end; ++start) {
    492       adjust_input_ptrs(ctx, elts[start] - oldIndex);
    493       oldIndex = elts[start];
    494       vtx->emit( ctx, 1, cdest);
    495       cdest += vtx->vertex_size;
    496    }
    497 
    498    return (void *) cdest;
    499 }
    500 
    501 
    502 void _tnl_init_vertices( struct gl_context *ctx,
    503 			GLuint vb_size,
    504 			GLuint max_vertex_size )
    505 {
    506    struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
    507 
    508    _tnl_install_attrs( ctx, NULL, 0, NULL, 0 );
    509 
    510    vtx->need_extras = GL_TRUE;
    511    if (max_vertex_size > vtx->max_vertex_size) {
    512       _tnl_free_vertices( ctx );
    513       vtx->max_vertex_size = max_vertex_size;
    514       vtx->vertex_buf = _mesa_align_calloc(vb_size * max_vertex_size, 32 );
    515       invalidate_funcs(vtx);
    516    }
    517 
    518    switch(CHAN_TYPE) {
    519    case GL_UNSIGNED_BYTE:
    520       vtx->chan_scale[0] = 255.0;
    521       vtx->chan_scale[1] = 255.0;
    522       vtx->chan_scale[2] = 255.0;
    523       vtx->chan_scale[3] = 255.0;
    524       break;
    525    case GL_UNSIGNED_SHORT:
    526       vtx->chan_scale[0] = 65535.0;
    527       vtx->chan_scale[1] = 65535.0;
    528       vtx->chan_scale[2] = 65535.0;
    529       vtx->chan_scale[3] = 65535.0;
    530       break;
    531    default:
    532       vtx->chan_scale[0] = 1.0;
    533       vtx->chan_scale[1] = 1.0;
    534       vtx->chan_scale[2] = 1.0;
    535       vtx->chan_scale[3] = 1.0;
    536       break;
    537    }
    538 
    539    vtx->identity[0] = 0.0;
    540    vtx->identity[1] = 0.0;
    541    vtx->identity[2] = 0.0;
    542    vtx->identity[3] = 1.0;
    543 
    544    vtx->codegen_emit = NULL;
    545 
    546 #ifdef USE_SSE_ASM
    547    if (!getenv("MESA_NO_CODEGEN"))
    548       vtx->codegen_emit = _tnl_generate_sse_emit;
    549 #endif
    550 }
    551 
    552 
    553 void _tnl_free_vertices( struct gl_context *ctx )
    554 {
    555    TNLcontext *tnl = TNL_CONTEXT(ctx);
    556    if (tnl) {
    557       struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
    558       struct tnl_clipspace_fastpath *fp, *tmp;
    559 
    560       _mesa_align_free(vtx->vertex_buf);
    561       vtx->vertex_buf = NULL;
    562 
    563       for (fp = vtx->fastpath ; fp ; fp = tmp) {
    564          tmp = fp->next;
    565          free(fp->attr);
    566 
    567          /* KW: At the moment, fp->func is constrained to be allocated by
    568           * _mesa_exec_alloc(), as the hardwired fastpaths in
    569           * t_vertex_generic.c are handled specially.  It would be nice
    570           * to unify them, but this probably won't change until this
    571           * module gets another overhaul.
    572           */
    573          _mesa_exec_free((void *) fp->func);
    574          free(fp);
    575       }
    576 
    577       vtx->fastpath = NULL;
    578    }
    579 }
    580