Home | History | Annotate | Download | only in tnl
      1 /*
      2  * Copyright 2003 Tungsten Graphics, 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  * TUNGSTEN GRAPHICS 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) tungstengraphics.com>
     26  */
     27 
     28 #include "main/glheader.h"
     29 #include "main/context.h"
     30 #include "main/colormac.h"
     31 #include "main/simple_list.h"
     32 #include "main/enums.h"
     33 #include "swrast/s_chan.h"
     34 #include "t_context.h"
     35 #include "t_vertex.h"
     36 
     37 #if defined(USE_SSE_ASM)
     38 
     39 #include "x86/rtasm/x86sse.h"
     40 #include "x86/common_x86_asm.h"
     41 
     42 
     43 /**
     44  * Number of bytes to allocate for generated SSE functions
     45  */
     46 #define MAX_SSE_CODE_SIZE 1024
     47 
     48 
     49 #define X    0
     50 #define Y    1
     51 #define Z    2
     52 #define W    3
     53 
     54 
     55 struct x86_program {
     56    struct x86_function func;
     57 
     58    struct gl_context *ctx;
     59    GLboolean inputs_safe;
     60    GLboolean outputs_safe;
     61    GLboolean have_sse2;
     62 
     63    struct x86_reg identity;
     64    struct x86_reg chan0;
     65 };
     66 
     67 
     68 static struct x86_reg get_identity( struct x86_program *p )
     69 {
     70    return p->identity;
     71 }
     72 
     73 static void emit_load4f_4( struct x86_program *p,
     74 			   struct x86_reg dest,
     75 			   struct x86_reg arg0 )
     76 {
     77    sse_movups(&p->func, dest, arg0);
     78 }
     79 
     80 static void emit_load4f_3( struct x86_program *p,
     81 			   struct x86_reg dest,
     82 			   struct x86_reg arg0 )
     83 {
     84    /* Have to jump through some hoops:
     85     *
     86     * c 0 0 0
     87     * c 0 0 1
     88     * 0 0 c 1
     89     * a b c 1
     90     */
     91    sse_movss(&p->func, dest, x86_make_disp(arg0, 8));
     92    sse_shufps(&p->func, dest, get_identity(p), SHUF(X,Y,Z,W) );
     93    sse_shufps(&p->func, dest, dest, SHUF(Y,Z,X,W) );
     94    sse_movlps(&p->func, dest, arg0);
     95 }
     96 
     97 static void emit_load4f_2( struct x86_program *p,
     98 			   struct x86_reg dest,
     99 			   struct x86_reg arg0 )
    100 {
    101    /* Initialize from identity, then pull in low two words:
    102     */
    103    sse_movups(&p->func, dest, get_identity(p));
    104    sse_movlps(&p->func, dest, arg0);
    105 }
    106 
    107 static void emit_load4f_1( struct x86_program *p,
    108 			   struct x86_reg dest,
    109 			   struct x86_reg arg0 )
    110 {
    111    /* Pull in low word, then swizzle in identity */
    112    sse_movss(&p->func, dest, arg0);
    113    sse_shufps(&p->func, dest, get_identity(p), SHUF(X,Y,Z,W) );
    114 }
    115 
    116 
    117 
    118 static void emit_load3f_3( struct x86_program *p,
    119 			   struct x86_reg dest,
    120 			   struct x86_reg arg0 )
    121 {
    122    /* Over-reads by 1 dword - potential SEGV if input is a vertex
    123     * array.
    124     */
    125    if (p->inputs_safe) {
    126       sse_movups(&p->func, dest, arg0);
    127    }
    128    else {
    129       /* c 0 0 0
    130        * c c c c
    131        * a b c c
    132        */
    133       sse_movss(&p->func, dest, x86_make_disp(arg0, 8));
    134       sse_shufps(&p->func, dest, dest, SHUF(X,X,X,X));
    135       sse_movlps(&p->func, dest, arg0);
    136    }
    137 }
    138 
    139 static void emit_load3f_2( struct x86_program *p,
    140 			   struct x86_reg dest,
    141 			   struct x86_reg arg0 )
    142 {
    143    emit_load4f_2(p, dest, arg0);
    144 }
    145 
    146 static void emit_load3f_1( struct x86_program *p,
    147 			   struct x86_reg dest,
    148 			   struct x86_reg arg0 )
    149 {
    150    /* Loading from memory erases the upper bits. */
    151    sse_movss(&p->func, dest, arg0);
    152 }
    153 
    154 static void emit_load2f_2( struct x86_program *p,
    155 			   struct x86_reg dest,
    156 			   struct x86_reg arg0 )
    157 {
    158    sse_movlps(&p->func, dest, arg0);
    159 }
    160 
    161 static void emit_load2f_1( struct x86_program *p,
    162 			   struct x86_reg dest,
    163 			   struct x86_reg arg0 )
    164 {
    165    /* Loading from memory erases the upper bits. */
    166    sse_movss(&p->func, dest, arg0);
    167 }
    168 
    169 static void emit_load1f_1( struct x86_program *p,
    170 			   struct x86_reg dest,
    171 			   struct x86_reg arg0 )
    172 {
    173    sse_movss(&p->func, dest, arg0);
    174 }
    175 
    176 static void (*load[4][4])( struct x86_program *p,
    177 			   struct x86_reg dest,
    178 			   struct x86_reg arg0 ) = {
    179    { emit_load1f_1,
    180      emit_load1f_1,
    181      emit_load1f_1,
    182      emit_load1f_1 },
    183 
    184    { emit_load2f_1,
    185      emit_load2f_2,
    186      emit_load2f_2,
    187      emit_load2f_2 },
    188 
    189    { emit_load3f_1,
    190      emit_load3f_2,
    191      emit_load3f_3,
    192      emit_load3f_3 },
    193 
    194    { emit_load4f_1,
    195      emit_load4f_2,
    196      emit_load4f_3,
    197      emit_load4f_4 }
    198 };
    199 
    200 static void emit_load( struct x86_program *p,
    201 		       struct x86_reg dest,
    202 		       GLuint sz,
    203 		       struct x86_reg src,
    204 		       GLuint src_sz)
    205 {
    206    load[sz-1][src_sz-1](p, dest, src);
    207 }
    208 
    209 static void emit_store4f( struct x86_program *p,
    210 			  struct x86_reg dest,
    211 			  struct x86_reg arg0 )
    212 {
    213    sse_movups(&p->func, dest, arg0);
    214 }
    215 
    216 static void emit_store3f( struct x86_program *p,
    217 			  struct x86_reg dest,
    218 			  struct x86_reg arg0 )
    219 {
    220    if (p->outputs_safe) {
    221       /* Emit the extra dword anyway.  This may hurt writecombining,
    222        * may cause other problems.
    223        */
    224       sse_movups(&p->func, dest, arg0);
    225    }
    226    else {
    227       /* Alternate strategy - emit two, shuffle, emit one.
    228        */
    229       sse_movlps(&p->func, dest, arg0);
    230       sse_shufps(&p->func, arg0, arg0, SHUF(Z,Z,Z,Z) ); /* NOTE! destructive */
    231       sse_movss(&p->func, x86_make_disp(dest,8), arg0);
    232    }
    233 }
    234 
    235 static void emit_store2f( struct x86_program *p,
    236 			   struct x86_reg dest,
    237 			   struct x86_reg arg0 )
    238 {
    239    sse_movlps(&p->func, dest, arg0);
    240 }
    241 
    242 static void emit_store1f( struct x86_program *p,
    243 			  struct x86_reg dest,
    244 			  struct x86_reg arg0 )
    245 {
    246    sse_movss(&p->func, dest, arg0);
    247 }
    248 
    249 
    250 static void (*store[4])( struct x86_program *p,
    251 			 struct x86_reg dest,
    252 			 struct x86_reg arg0 ) =
    253 {
    254    emit_store1f,
    255    emit_store2f,
    256    emit_store3f,
    257    emit_store4f
    258 };
    259 
    260 static void emit_store( struct x86_program *p,
    261 			struct x86_reg dest,
    262 			GLuint sz,
    263 			struct x86_reg temp )
    264 
    265 {
    266    store[sz-1](p, dest, temp);
    267 }
    268 
    269 static void emit_pack_store_4ub( struct x86_program *p,
    270 				 struct x86_reg dest,
    271 				 struct x86_reg temp )
    272 {
    273    /* Scale by 255.0
    274     */
    275    sse_mulps(&p->func, temp, p->chan0);
    276 
    277    if (p->have_sse2) {
    278       sse2_cvtps2dq(&p->func, temp, temp);
    279       sse2_packssdw(&p->func, temp, temp);
    280       sse2_packuswb(&p->func, temp, temp);
    281       sse_movss(&p->func, dest, temp);
    282    }
    283    else {
    284       struct x86_reg mmx0 = x86_make_reg(file_MMX, 0);
    285       struct x86_reg mmx1 = x86_make_reg(file_MMX, 1);
    286       sse_cvtps2pi(&p->func, mmx0, temp);
    287       sse_movhlps(&p->func, temp, temp);
    288       sse_cvtps2pi(&p->func, mmx1, temp);
    289       mmx_packssdw(&p->func, mmx0, mmx1);
    290       mmx_packuswb(&p->func, mmx0, mmx0);
    291       mmx_movd(&p->func, dest, mmx0);
    292    }
    293 }
    294 
    295 static GLint get_offset( const void *a, const void *b )
    296 {
    297    return (const char *)b - (const char *)a;
    298 }
    299 
    300 /* Not much happens here.  Eventually use this function to try and
    301  * avoid saving/reloading the source pointers each vertex (if some of
    302  * them can fit in registers).
    303  */
    304 static void get_src_ptr( struct x86_program *p,
    305 			 struct x86_reg srcREG,
    306 			 struct x86_reg vtxREG,
    307 			 struct tnl_clipspace_attr *a )
    308 {
    309    struct tnl_clipspace *vtx = GET_VERTEX_STATE(p->ctx);
    310    struct x86_reg ptr_to_src = x86_make_disp(vtxREG, get_offset(vtx, &a->inputptr));
    311 
    312    /* Load current a[j].inputptr
    313     */
    314    x86_mov(&p->func, srcREG, ptr_to_src);
    315 }
    316 
    317 static void update_src_ptr( struct x86_program *p,
    318 			 struct x86_reg srcREG,
    319 			 struct x86_reg vtxREG,
    320 			 struct tnl_clipspace_attr *a )
    321 {
    322    if (a->inputstride) {
    323       struct tnl_clipspace *vtx = GET_VERTEX_STATE(p->ctx);
    324       struct x86_reg ptr_to_src = x86_make_disp(vtxREG, get_offset(vtx, &a->inputptr));
    325 
    326       /* add a[j].inputstride (hardcoded value - could just as easily
    327        * pull the stride value from memory each time).
    328        */
    329       x86_lea(&p->func, srcREG, x86_make_disp(srcREG, a->inputstride));
    330 
    331       /* save new value of a[j].inputptr
    332        */
    333       x86_mov(&p->func, ptr_to_src, srcREG);
    334    }
    335 }
    336 
    337 
    338 /* Lots of hardcoding
    339  *
    340  * EAX -- pointer to current output vertex
    341  * ECX -- pointer to current attribute
    342  *
    343  */
    344 static GLboolean build_vertex_emit( struct x86_program *p )
    345 {
    346    struct gl_context *ctx = p->ctx;
    347    TNLcontext *tnl = TNL_CONTEXT(ctx);
    348    struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
    349    GLuint j = 0;
    350 
    351    struct x86_reg vertexEAX = x86_make_reg(file_REG32, reg_AX);
    352    struct x86_reg srcECX = x86_make_reg(file_REG32, reg_CX);
    353    struct x86_reg countEBP = x86_make_reg(file_REG32, reg_BP);
    354    struct x86_reg vtxESI = x86_make_reg(file_REG32, reg_SI);
    355    struct x86_reg temp = x86_make_reg(file_XMM, 0);
    356    struct x86_reg vp0 = x86_make_reg(file_XMM, 1);
    357    struct x86_reg vp1 = x86_make_reg(file_XMM, 2);
    358    struct x86_reg temp2 = x86_make_reg(file_XMM, 3);
    359    GLubyte *fixup, *label;
    360 
    361    /* Push a few regs?
    362     */
    363    x86_push(&p->func, countEBP);
    364    x86_push(&p->func, vtxESI);
    365 
    366 
    367    /* Get vertex count, compare to zero
    368     */
    369    x86_xor(&p->func, srcECX, srcECX);
    370    x86_mov(&p->func, countEBP, x86_fn_arg(&p->func, 2));
    371    x86_cmp(&p->func, countEBP, srcECX);
    372    fixup = x86_jcc_forward(&p->func, cc_E);
    373 
    374    /* Initialize destination register.
    375     */
    376    x86_mov(&p->func, vertexEAX, x86_fn_arg(&p->func, 3));
    377 
    378    /* Dereference ctx to get tnl, then vtx:
    379     */
    380    x86_mov(&p->func, vtxESI, x86_fn_arg(&p->func, 1));
    381    x86_mov(&p->func, vtxESI, x86_make_disp(vtxESI, get_offset(ctx, &ctx->swtnl_context)));
    382    vtxESI = x86_make_disp(vtxESI, get_offset(tnl, &tnl->clipspace));
    383 
    384 
    385    /* Possibly load vp0, vp1 for viewport calcs:
    386     */
    387    if (vtx->need_viewport) {
    388       sse_movups(&p->func, vp0, x86_make_disp(vtxESI, get_offset(vtx, &vtx->vp_scale[0])));
    389       sse_movups(&p->func, vp1, x86_make_disp(vtxESI, get_offset(vtx, &vtx->vp_xlate[0])));
    390    }
    391 
    392    /* always load, needed or not:
    393     */
    394    sse_movups(&p->func, p->chan0, x86_make_disp(vtxESI, get_offset(vtx, &vtx->chan_scale[0])));
    395    sse_movups(&p->func, p->identity, x86_make_disp(vtxESI, get_offset(vtx, &vtx->identity[0])));
    396 
    397    /* Note address for loop jump */
    398    label = x86_get_label(&p->func);
    399 
    400    /* Emit code for each of the attributes.  Currently routes
    401     * everything through SSE registers, even when it might be more
    402     * efficient to stick with regular old x86.  No optimization or
    403     * other tricks - enough new ground to cover here just getting
    404     * things working.
    405     */
    406    while (j < vtx->attr_count) {
    407       struct tnl_clipspace_attr *a = &vtx->attr[j];
    408       struct x86_reg dest = x86_make_disp(vertexEAX, a->vertoffset);
    409 
    410       /* Now, load an XMM reg from src, perhaps transform, then save.
    411        * Could be shortcircuited in specific cases:
    412        */
    413       switch (a->format) {
    414       case EMIT_1F:
    415 	 get_src_ptr(p, srcECX, vtxESI, a);
    416 	 emit_load(p, temp, 1, x86_deref(srcECX), a->inputsize);
    417 	 emit_store(p, dest, 1, temp);
    418 	 update_src_ptr(p, srcECX, vtxESI, a);
    419 	 break;
    420       case EMIT_2F:
    421 	 get_src_ptr(p, srcECX, vtxESI, a);
    422 	 emit_load(p, temp, 2, x86_deref(srcECX), a->inputsize);
    423 	 emit_store(p, dest, 2, temp);
    424 	 update_src_ptr(p, srcECX, vtxESI, a);
    425 	 break;
    426       case EMIT_3F:
    427 	 /* Potentially the worst case - hardcode 2+1 copying:
    428 	  */
    429 	 if (0) {
    430 	    get_src_ptr(p, srcECX, vtxESI, a);
    431 	    emit_load(p, temp, 3, x86_deref(srcECX), a->inputsize);
    432 	    emit_store(p, dest, 3, temp);
    433 	    update_src_ptr(p, srcECX, vtxESI, a);
    434 	 }
    435 	 else {
    436 	    get_src_ptr(p, srcECX, vtxESI, a);
    437 	    emit_load(p, temp, 2, x86_deref(srcECX), a->inputsize);
    438 	    emit_store(p, dest, 2, temp);
    439 	    if (a->inputsize > 2) {
    440 	       emit_load(p, temp, 1, x86_make_disp(srcECX, 8), 1);
    441 	       emit_store(p, x86_make_disp(dest,8), 1, temp);
    442 	    }
    443 	    else {
    444 	       sse_movss(&p->func, x86_make_disp(dest,8), get_identity(p));
    445 	    }
    446 	    update_src_ptr(p, srcECX, vtxESI, a);
    447 	 }
    448 	 break;
    449       case EMIT_4F:
    450 	 get_src_ptr(p, srcECX, vtxESI, a);
    451 	 emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize);
    452 	 emit_store(p, dest, 4, temp);
    453 	 update_src_ptr(p, srcECX, vtxESI, a);
    454 	 break;
    455       case EMIT_2F_VIEWPORT:
    456 	 get_src_ptr(p, srcECX, vtxESI, a);
    457 	 emit_load(p, temp, 2, x86_deref(srcECX), a->inputsize);
    458 	 sse_mulps(&p->func, temp, vp0);
    459 	 sse_addps(&p->func, temp, vp1);
    460 	 emit_store(p, dest, 2, temp);
    461 	 update_src_ptr(p, srcECX, vtxESI, a);
    462 	 break;
    463       case EMIT_3F_VIEWPORT:
    464 	 get_src_ptr(p, srcECX, vtxESI, a);
    465 	 emit_load(p, temp, 3, x86_deref(srcECX), a->inputsize);
    466 	 sse_mulps(&p->func, temp, vp0);
    467 	 sse_addps(&p->func, temp, vp1);
    468 	 emit_store(p, dest, 3, temp);
    469 	 update_src_ptr(p, srcECX, vtxESI, a);
    470 	 break;
    471       case EMIT_4F_VIEWPORT:
    472 	 get_src_ptr(p, srcECX, vtxESI, a);
    473 	 emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize);
    474 	 sse_mulps(&p->func, temp, vp0);
    475 	 sse_addps(&p->func, temp, vp1);
    476 	 emit_store(p, dest, 4, temp);
    477 	 update_src_ptr(p, srcECX, vtxESI, a);
    478 	 break;
    479       case EMIT_3F_XYW:
    480 	 get_src_ptr(p, srcECX, vtxESI, a);
    481 	 emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize);
    482 	 sse_shufps(&p->func, temp, temp, SHUF(X,Y,W,Z));
    483 	 emit_store(p, dest, 3, temp);
    484 	 update_src_ptr(p, srcECX, vtxESI, a);
    485 	 break;
    486 
    487       case EMIT_1UB_1F:
    488 	 /* Test for PAD3 + 1UB:
    489 	  */
    490 	 if (j > 0 &&
    491 	     a[-1].vertoffset + a[-1].vertattrsize <= a->vertoffset - 3)
    492 	 {
    493 	    get_src_ptr(p, srcECX, vtxESI, a);
    494 	    emit_load(p, temp, 1, x86_deref(srcECX), a->inputsize);
    495 	    sse_shufps(&p->func, temp, temp, SHUF(X,X,X,X));
    496 	    emit_pack_store_4ub(p, x86_make_disp(dest, -3), temp); /* overkill! */
    497 	    update_src_ptr(p, srcECX, vtxESI, a);
    498 	 }
    499 	 else {
    500 	    printf("Can't emit 1ub %x %x %d\n", a->vertoffset, a[-1].vertoffset, a[-1].vertattrsize );
    501 	    return GL_FALSE;
    502 	 }
    503 	 break;
    504       case EMIT_3UB_3F_RGB:
    505       case EMIT_3UB_3F_BGR:
    506 	 /* Test for 3UB + PAD1:
    507 	  */
    508 	 if (j == vtx->attr_count - 1 ||
    509 	     a[1].vertoffset >= a->vertoffset + 4) {
    510 	    get_src_ptr(p, srcECX, vtxESI, a);
    511 	    emit_load(p, temp, 3, x86_deref(srcECX), a->inputsize);
    512 	    if (a->format == EMIT_3UB_3F_BGR)
    513 	       sse_shufps(&p->func, temp, temp, SHUF(Z,Y,X,W));
    514 	    emit_pack_store_4ub(p, dest, temp);
    515 	    update_src_ptr(p, srcECX, vtxESI, a);
    516 	 }
    517 	 /* Test for 3UB + 1UB:
    518 	  */
    519 	 else if (j < vtx->attr_count - 1 &&
    520 		  a[1].format == EMIT_1UB_1F &&
    521 		  a[1].vertoffset == a->vertoffset + 3) {
    522 	    get_src_ptr(p, srcECX, vtxESI, a);
    523 	    emit_load(p, temp, 3, x86_deref(srcECX), a->inputsize);
    524 	    update_src_ptr(p, srcECX, vtxESI, a);
    525 
    526 	    /* Make room for incoming value:
    527 	     */
    528 	    sse_shufps(&p->func, temp, temp, SHUF(W,X,Y,Z));
    529 
    530 	    get_src_ptr(p, srcECX, vtxESI, &a[1]);
    531 	    emit_load(p, temp2, 1, x86_deref(srcECX), a[1].inputsize);
    532 	    sse_movss(&p->func, temp, temp2);
    533 	    update_src_ptr(p, srcECX, vtxESI, &a[1]);
    534 
    535 	    /* Rearrange and possibly do BGR conversion:
    536 	     */
    537 	    if (a->format == EMIT_3UB_3F_BGR)
    538 	       sse_shufps(&p->func, temp, temp, SHUF(W,Z,Y,X));
    539 	    else
    540 	       sse_shufps(&p->func, temp, temp, SHUF(Y,Z,W,X));
    541 
    542 	    emit_pack_store_4ub(p, dest, temp);
    543 	    j++;		/* NOTE: two attrs consumed */
    544 	 }
    545 	 else {
    546 	    printf("Can't emit 3ub\n");
    547 	    return GL_FALSE;	/* add this later */
    548 	 }
    549 	 break;
    550 
    551       case EMIT_4UB_4F_RGBA:
    552 	 get_src_ptr(p, srcECX, vtxESI, a);
    553 	 emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize);
    554 	 emit_pack_store_4ub(p, dest, temp);
    555 	 update_src_ptr(p, srcECX, vtxESI, a);
    556 	 break;
    557       case EMIT_4UB_4F_BGRA:
    558 	 get_src_ptr(p, srcECX, vtxESI, a);
    559 	 emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize);
    560 	 sse_shufps(&p->func, temp, temp, SHUF(Z,Y,X,W));
    561 	 emit_pack_store_4ub(p, dest, temp);
    562 	 update_src_ptr(p, srcECX, vtxESI, a);
    563 	 break;
    564       case EMIT_4UB_4F_ARGB:
    565 	 get_src_ptr(p, srcECX, vtxESI, a);
    566 	 emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize);
    567 	 sse_shufps(&p->func, temp, temp, SHUF(W,X,Y,Z));
    568 	 emit_pack_store_4ub(p, dest, temp);
    569 	 update_src_ptr(p, srcECX, vtxESI, a);
    570 	 break;
    571       case EMIT_4UB_4F_ABGR:
    572 	 get_src_ptr(p, srcECX, vtxESI, a);
    573 	 emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize);
    574 	 sse_shufps(&p->func, temp, temp, SHUF(W,Z,Y,X));
    575 	 emit_pack_store_4ub(p, dest, temp);
    576 	 update_src_ptr(p, srcECX, vtxESI, a);
    577 	 break;
    578       case EMIT_4CHAN_4F_RGBA:
    579 	 switch (CHAN_TYPE) {
    580 	 case GL_UNSIGNED_BYTE:
    581 	    get_src_ptr(p, srcECX, vtxESI, a);
    582 	    emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize);
    583 	    emit_pack_store_4ub(p, dest, temp);
    584 	    update_src_ptr(p, srcECX, vtxESI, a);
    585 	    break;
    586 	 case GL_FLOAT:
    587 	    get_src_ptr(p, srcECX, vtxESI, a);
    588 	    emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize);
    589 	    emit_store(p, dest, 4, temp);
    590 	    update_src_ptr(p, srcECX, vtxESI, a);
    591 	    break;
    592 	 case GL_UNSIGNED_SHORT:
    593 	 default:
    594 	    printf("unknown CHAN_TYPE %s\n", _mesa_lookup_enum_by_nr(CHAN_TYPE));
    595 	    return GL_FALSE;
    596 	 }
    597 	 break;
    598       default:
    599 	 printf("unknown a[%d].format %d\n", j, a->format);
    600 	 return GL_FALSE;	/* catch any new opcodes */
    601       }
    602 
    603       /* Increment j by at least 1 - may have been incremented above also:
    604        */
    605       j++;
    606    }
    607 
    608    /* Next vertex:
    609     */
    610    x86_lea(&p->func, vertexEAX, x86_make_disp(vertexEAX, vtx->vertex_size));
    611 
    612    /* decr count, loop if not zero
    613     */
    614    x86_dec(&p->func, countEBP);
    615    x86_test(&p->func, countEBP, countEBP);
    616    x86_jcc(&p->func, cc_NZ, label);
    617 
    618    /* Exit mmx state?
    619     */
    620    if (p->func.need_emms)
    621       mmx_emms(&p->func);
    622 
    623    /* Land forward jump here:
    624     */
    625    x86_fixup_fwd_jump(&p->func, fixup);
    626 
    627    /* Pop regs and return
    628     */
    629    x86_pop(&p->func, x86_get_base_reg(vtxESI));
    630    x86_pop(&p->func, countEBP);
    631    x86_ret(&p->func);
    632 
    633    assert(!vtx->emit);
    634    vtx->emit = (tnl_emit_func)x86_get_func(&p->func);
    635 
    636    assert( (char *) p->func.csr - (char *) p->func.store <= MAX_SSE_CODE_SIZE );
    637    return GL_TRUE;
    638 }
    639 
    640 
    641 
    642 void _tnl_generate_sse_emit( struct gl_context *ctx )
    643 {
    644    struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
    645    struct x86_program p;
    646 
    647    if (!cpu_has_xmm) {
    648       vtx->codegen_emit = NULL;
    649       return;
    650    }
    651 
    652    memset(&p, 0, sizeof(p));
    653 
    654    p.ctx = ctx;
    655    p.inputs_safe = 0;		/* for now */
    656    p.outputs_safe = 0;		/* for now */
    657    p.have_sse2 = cpu_has_xmm2;
    658    p.identity = x86_make_reg(file_XMM, 6);
    659    p.chan0 = x86_make_reg(file_XMM, 7);
    660 
    661    if (!x86_init_func_size(&p.func, MAX_SSE_CODE_SIZE)) {
    662       vtx->emit = NULL;
    663       return;
    664    }
    665 
    666    if (build_vertex_emit(&p)) {
    667       _tnl_register_fastpath( vtx, GL_TRUE );
    668    }
    669    else {
    670       /* Note the failure so that we don't keep trying to codegen an
    671        * impossible state:
    672        */
    673       _tnl_register_fastpath( vtx, GL_FALSE );
    674       x86_release_func(&p.func);
    675    }
    676 }
    677 
    678 #else
    679 
    680 void _tnl_generate_sse_emit( struct gl_context *ctx )
    681 {
    682    /* Dummy version for when USE_SSE_ASM not defined */
    683 }
    684 
    685 #endif
    686