Merge branch 'gallium-tex-surfaces' into gallium-0.1
[profile/ivi/mesa.git] / src / gallium / auxiliary / draw / draw_vs_aos.c
1 /*
2  * Mesa 3-D graphics library
3  * Version:  6.3
4  *
5  * Copyright (C) 1999-2004  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 /**
26  * Translate tgsi vertex programs to x86/x87/SSE/SSE2 machine code
27  * using the rtasm runtime assembler.  Based on the old
28  * t_vb_arb_program_sse.c
29  */
30
31
32 #include "pipe/p_util.h"
33 #include "pipe/p_shader_tokens.h"
34 #include "tgsi/util/tgsi_parse.h"
35 #include "tgsi/util/tgsi_util.h"
36 #include "tgsi/exec/tgsi_exec.h"
37 #include "tgsi/util/tgsi_dump.h"
38
39 #include "draw_vs.h"
40 #include "draw_vs_aos.h"
41
42 #include "rtasm/rtasm_x86sse.h"
43
44 #ifdef PIPE_ARCH_X86
45 #define DISASSEM 0
46
47 static const char *files[] =
48 {
49    "NULL",
50    "CONST",
51    "IN",
52    "OUT",
53    "TEMP",
54    "SAMP",
55    "ADDR",
56    "IMM",
57    "INTERNAL",
58 };
59
60 static INLINE boolean eq( struct x86_reg a,
61                             struct x86_reg b )
62 {
63    return (a.file == b.file &&
64            a.idx == b.idx &&
65            a.mod == b.mod &&
66            a.disp == b.disp);
67 }
68       
69 struct x86_reg aos_get_x86( struct aos_compilation *cp,
70                             unsigned value )
71 {
72    if (cp->ebp != value) {
73       unsigned offset;
74
75       switch (value) {
76       case X86_IMMEDIATES:
77          offset = Offset(struct aos_machine, immediates);
78          break;
79       case X86_CONSTANTS:
80          offset = Offset(struct aos_machine, constants);
81          break;
82       case X86_ATTRIBS:
83          offset = Offset(struct aos_machine, attrib);
84          break;
85       default:
86          assert(0);
87          offset = 0;
88       }
89
90       x86_mov(cp->func, cp->temp_EBP, 
91               x86_make_disp(cp->machine_EDX, offset));
92       /* x86_deref(x86_make_disp(cp->machine_EDX, offset))); */
93
94       cp->ebp = value;
95    }
96
97    return cp->temp_EBP;
98 }
99
100
101 static struct x86_reg get_reg_ptr(struct aos_compilation *cp,
102                                   unsigned file,
103                                   unsigned idx )
104 {
105    struct x86_reg ptr = cp->machine_EDX;
106
107    switch (file) {
108    case TGSI_FILE_INPUT:
109       return x86_make_disp(ptr, Offset(struct aos_machine, input[idx]));
110
111    case TGSI_FILE_OUTPUT:
112       return x86_make_disp(ptr, Offset(struct aos_machine, output[idx]));
113
114    case TGSI_FILE_TEMPORARY:
115       return x86_make_disp(ptr, Offset(struct aos_machine, temp[idx]));
116
117    case AOS_FILE_INTERNAL:
118       return x86_make_disp(ptr, Offset(struct aos_machine, internal[idx]));
119
120    case TGSI_FILE_IMMEDIATE: 
121       return x86_make_disp(aos_get_x86(cp, X86_IMMEDIATES), idx * 4 * sizeof(float));
122
123    case TGSI_FILE_CONSTANT: 
124       return x86_make_disp(aos_get_x86(cp, X86_CONSTANTS), idx * 4 * sizeof(float));
125
126    default:
127       ERROR(cp, "unknown reg file");
128       return x86_make_reg(0,0);
129    }
130 }
131                 
132
133
134 #define X87_CW_EXCEPTION_INV_OP       (1<<0)
135 #define X87_CW_EXCEPTION_DENORM_OP    (1<<1)
136 #define X87_CW_EXCEPTION_ZERO_DIVIDE  (1<<2)
137 #define X87_CW_EXCEPTION_OVERFLOW     (1<<3)
138 #define X87_CW_EXCEPTION_UNDERFLOW    (1<<4)
139 #define X87_CW_EXCEPTION_PRECISION    (1<<5)
140 #define X87_CW_PRECISION_SINGLE       (0<<8)
141 #define X87_CW_PRECISION_RESERVED     (1<<8)
142 #define X87_CW_PRECISION_DOUBLE       (2<<8)
143 #define X87_CW_PRECISION_DOUBLE_EXT   (3<<8)
144 #define X87_CW_PRECISION_MASK         (3<<8)
145 #define X87_CW_ROUND_NEAREST          (0<<10)
146 #define X87_CW_ROUND_DOWN             (1<<10)
147 #define X87_CW_ROUND_UP               (2<<10)
148 #define X87_CW_ROUND_ZERO             (3<<10)
149 #define X87_CW_ROUND_MASK             (3<<10)
150 #define X87_CW_INFINITY               (1<<12)
151
152
153
154
155 static void spill( struct aos_compilation *cp, unsigned idx )
156 {
157    if (!cp->xmm[idx].dirty ||
158        (cp->xmm[idx].file != TGSI_FILE_INPUT && /* inputs are fetched into xmm & set dirty */
159         cp->xmm[idx].file != TGSI_FILE_OUTPUT &&
160         cp->xmm[idx].file != TGSI_FILE_TEMPORARY)) {
161       ERROR(cp, "invalid spill");
162       return;
163    }
164    else {
165       struct x86_reg oldval = get_reg_ptr(cp,
166                                           cp->xmm[idx].file,
167                                           cp->xmm[idx].idx);
168      
169       if (0) debug_printf("\nspill %s[%d]", 
170                           files[cp->xmm[idx].file],
171                           cp->xmm[idx].idx);
172  
173       assert(cp->xmm[idx].dirty);
174       sse_movaps(cp->func, oldval, x86_make_reg(file_XMM, idx));
175       cp->xmm[idx].dirty = 0;
176    }
177 }
178
179
180 static struct x86_reg get_xmm_writable( struct aos_compilation *cp,
181                                         struct x86_reg reg )
182 {
183    if (reg.file != file_XMM ||
184        cp->xmm[reg.idx].file != TGSI_FILE_NULL)
185    {
186       struct x86_reg tmp = aos_get_xmm_reg(cp);
187       sse_movaps(cp->func, tmp, reg);
188       reg = tmp;
189    }
190
191    cp->xmm[reg.idx].last_used = cp->insn_counter;
192    return reg;
193 }
194
195 static struct x86_reg get_xmm( struct aos_compilation *cp,
196                                struct x86_reg reg )
197 {
198    if (reg.file != file_XMM) 
199    {
200       struct x86_reg tmp = aos_get_xmm_reg(cp);
201       sse_movaps(cp->func, tmp, reg);
202       reg = tmp;
203    }
204
205    cp->xmm[reg.idx].last_used = cp->insn_counter;
206    return reg;
207 }
208
209
210 /* Allocate an empty xmm register, either as a temporary or later to
211  * "adopt" as a shader reg.
212  */
213 struct x86_reg aos_get_xmm_reg( struct aos_compilation *cp )
214 {
215    unsigned i;
216    unsigned oldest = 0;
217    boolean found = FALSE;
218
219    for (i = 0; i < 8; i++) 
220       if (cp->xmm[i].last_used != cp->insn_counter &&
221           cp->xmm[i].file == TGSI_FILE_NULL) {
222          oldest = i;
223          found = TRUE;
224       }
225
226    if (!found) {
227       for (i = 0; i < 8; i++) 
228          if (cp->xmm[i].last_used < cp->xmm[oldest].last_used)
229             oldest = i;
230    }
231
232    /* Need to write out the old value?
233     */
234    if (cp->xmm[oldest].dirty) 
235       spill(cp, oldest);
236
237    assert(cp->xmm[oldest].last_used != cp->insn_counter);
238
239    cp->xmm[oldest].file = TGSI_FILE_NULL;
240    cp->xmm[oldest].idx = 0;
241    cp->xmm[oldest].dirty = 0;
242    cp->xmm[oldest].last_used = cp->insn_counter;
243    return x86_make_reg(file_XMM, oldest);
244 }
245
246 void aos_release_xmm_reg( struct aos_compilation *cp,
247                           unsigned idx )
248 {
249    cp->xmm[idx].file = TGSI_FILE_NULL;
250    cp->xmm[idx].idx = 0;
251    cp->xmm[idx].dirty = 0;
252    cp->xmm[idx].last_used = 0;
253 }
254
255
256
257      
258 /* Mark an xmm reg as holding the current copy of a shader reg.
259  */
260 void aos_adopt_xmm_reg( struct aos_compilation *cp,
261                         struct x86_reg reg,
262                         unsigned file,
263                         unsigned idx,
264                         unsigned dirty )
265 {
266    unsigned i;
267
268    if (reg.file != file_XMM) {
269       assert(0);
270       return;
271    }
272
273
274    /* If any xmm reg thinks it holds this shader reg, break the
275     * illusion.
276     */
277    for (i = 0; i < 8; i++) {
278       if (cp->xmm[i].file == file && 
279           cp->xmm[i].idx == idx) 
280       {
281          /* If an xmm reg is already holding this shader reg, take into account its
282           * dirty flag...
283           */
284          dirty |= cp->xmm[i].dirty;
285          aos_release_xmm_reg(cp, i);
286       }
287    }
288
289    cp->xmm[reg.idx].file = file;
290    cp->xmm[reg.idx].idx = idx;
291    cp->xmm[reg.idx].dirty = dirty;
292    cp->xmm[reg.idx].last_used = cp->insn_counter;
293 }
294
295
296 /* Return a pointer to the in-memory copy of the reg, making sure it is uptodate.
297  */
298 static struct x86_reg aos_get_shader_reg_ptr( struct aos_compilation *cp, 
299                                               unsigned file,
300                                               unsigned idx )
301 {
302    unsigned i;
303
304    /* Ensure the in-memory copy of this reg is up-to-date
305     */
306    for (i = 0; i < 8; i++) {
307       if (cp->xmm[i].file == file && 
308           cp->xmm[i].idx == idx &&
309           cp->xmm[i].dirty) {
310          spill(cp, i);
311       }
312    }
313
314    return get_reg_ptr( cp, file, idx );
315 }
316
317
318 /* As above, but return a pointer.  Note - this pointer may alias
319  * those returned by get_arg_ptr().
320  */
321 static struct x86_reg get_dst_ptr( struct aos_compilation *cp, 
322                                    const struct tgsi_full_dst_register *dst )
323 {
324    unsigned file = dst->DstRegister.File;
325    unsigned idx = dst->DstRegister.Index;
326    unsigned i;
327    
328
329    /* Ensure in-memory copy of this reg is up-to-date and invalidate
330     * any xmm copies.
331     */
332    for (i = 0; i < 8; i++) {
333       if (cp->xmm[i].file == file &&
334           cp->xmm[i].idx == idx)
335       {
336          if (cp->xmm[i].dirty) 
337             spill(cp, i);
338          
339          aos_release_xmm_reg(cp, i);
340       }
341    }
342
343    return get_reg_ptr( cp, file, idx );
344 }
345
346
347
348
349
350 /* Return an XMM reg if the argument is resident, otherwise return a
351  * base+offset pointer to the saved value.
352  */
353 struct x86_reg aos_get_shader_reg( struct aos_compilation *cp, 
354                                    unsigned file,
355                                    unsigned idx )
356 {
357    unsigned i;
358
359    for (i = 0; i < 8; i++) {
360       if (cp->xmm[i].file == file &&
361           cp->xmm[i].idx  == idx) 
362       {
363          cp->xmm[i].last_used = cp->insn_counter;
364          return x86_make_reg(file_XMM, i);
365       }
366    }
367
368    /* If not found in the XMM register file, return an indirect
369     * reference to the in-memory copy:
370     */
371    return get_reg_ptr( cp, file, idx );
372 }
373
374
375
376 static struct x86_reg aos_get_shader_reg_xmm( struct aos_compilation *cp, 
377                                               unsigned file,
378                                               unsigned idx )
379 {
380    struct x86_reg reg = get_xmm( cp,
381                                  aos_get_shader_reg( cp, file, idx ) );
382
383    aos_adopt_xmm_reg( cp,
384                       reg,
385                       file,
386                       idx,
387                       FALSE );
388    
389    return reg;
390 }
391
392
393
394 struct x86_reg aos_get_internal_xmm( struct aos_compilation *cp,
395                                      unsigned imm )
396 {
397    return aos_get_shader_reg_xmm( cp, AOS_FILE_INTERNAL, imm );
398 }
399
400
401 struct x86_reg aos_get_internal( struct aos_compilation *cp,
402                                  unsigned imm )
403 {
404    return aos_get_shader_reg( cp, AOS_FILE_INTERNAL, imm );
405 }
406
407
408
409
410
411 /* Emulate pshufd insn in regular SSE, if necessary:
412  */
413 static void emit_pshufd( struct aos_compilation *cp,
414                          struct x86_reg dst,
415                          struct x86_reg arg0,
416                          ubyte shuf )
417 {
418    if (cp->have_sse2) {
419       sse2_pshufd(cp->func, dst, arg0, shuf);
420    }
421    else {
422       if (!eq(dst, arg0)) 
423          sse_movaps(cp->func, dst, arg0);
424
425       sse_shufps(cp->func, dst, dst, shuf);
426    }
427 }
428
429 /* load masks (pack into negs??)
430  * pshufd - shuffle according to writemask
431  * and - result, mask
432  * nand - dest, mask
433  * or - dest, result
434  */
435 static boolean mask_write( struct aos_compilation *cp,
436                            struct x86_reg dst,
437                            struct x86_reg result,
438                            unsigned mask )
439 {
440    struct x86_reg imm_swz = aos_get_internal_xmm(cp, IMM_SWZ);
441    struct x86_reg tmp = aos_get_xmm_reg(cp);
442    
443    emit_pshufd(cp, tmp, imm_swz, 
444                SHUF((mask & 1) ? 2 : 3,
445                     (mask & 2) ? 2 : 3,
446                     (mask & 4) ? 2 : 3,
447                     (mask & 8) ? 2 : 3));
448
449    sse_andps(cp->func, dst, tmp);
450    sse_andnps(cp->func, tmp, result);
451    sse_orps(cp->func, dst, tmp);
452
453    aos_release_xmm_reg(cp, tmp.idx);
454    return TRUE;
455 }
456
457
458
459
460 /* Helper for writemask:
461  */
462 static boolean emit_shuf_copy2( struct aos_compilation *cp,
463                                   struct x86_reg dst,
464                                   struct x86_reg arg0,
465                                   struct x86_reg arg1,
466                                   ubyte shuf )
467 {
468    struct x86_reg tmp = aos_get_xmm_reg(cp);
469
470    emit_pshufd(cp, dst, arg1, shuf);
471    emit_pshufd(cp, tmp, arg0, shuf);
472    sse_shufps(cp->func, dst, tmp, SHUF(X, Y, Z, W));
473    emit_pshufd(cp, dst, dst, shuf);
474
475    aos_release_xmm_reg(cp, tmp.idx);
476    return TRUE;
477 }
478
479
480
481 #define SSE_SWIZZLE_NOOP ((0<<0) | (1<<2) | (2<<4) | (3<<6))
482
483
484 /* Locate a source register and perform any required (simple) swizzle.  
485  * 
486  * Just fail on complex swizzles at this point.
487  */
488 static struct x86_reg fetch_src( struct aos_compilation *cp, 
489                                  const struct tgsi_full_src_register *src ) 
490 {
491    struct x86_reg arg0 = aos_get_shader_reg(cp, 
492                                             src->SrcRegister.File, 
493                                             src->SrcRegister.Index);
494    unsigned i;
495    ubyte swz = 0;
496    unsigned negs = 0;
497    unsigned abs = 0;
498
499    for (i = 0; i < 4; i++) {
500       unsigned swizzle = tgsi_util_get_full_src_register_extswizzle( src, i );
501       unsigned neg = tgsi_util_get_full_src_register_sign_mode( src, i );
502
503       switch (swizzle) {
504       case TGSI_EXTSWIZZLE_ZERO:
505       case TGSI_EXTSWIZZLE_ONE:
506          ERROR(cp, "not supporting full swizzles yet in tgsi_aos_sse2");
507          break;
508
509       default:
510          swz |= (swizzle & 0x3) << (i * 2);
511          break;
512       }
513
514       switch (neg) {
515       case TGSI_UTIL_SIGN_TOGGLE:
516          negs |= (1<<i);
517          break;
518          
519       case TGSI_UTIL_SIGN_KEEP:
520          break;
521
522       case TGSI_UTIL_SIGN_CLEAR:
523          abs |= (1<<i);
524          break;
525
526       default:
527          ERROR(cp, "unsupported sign-mode");
528          break;
529       }
530    }
531
532    if (swz != SSE_SWIZZLE_NOOP || negs != 0 || abs != 0) {
533       struct x86_reg dst = aos_get_xmm_reg(cp);
534
535       if (swz != SSE_SWIZZLE_NOOP)
536          emit_pshufd(cp, dst, arg0, swz);
537       else
538          sse_movaps(cp->func, dst, arg0);
539
540       if (negs && negs != 0xf) {
541          struct x86_reg imm_swz = aos_get_internal_xmm(cp, IMM_SWZ);
542          struct x86_reg tmp = aos_get_xmm_reg(cp);
543
544          /* Load 1,-1,0,0
545           * Use neg as arg to pshufd
546           * Multiply
547           */
548          emit_pshufd(cp, tmp, imm_swz, 
549                      SHUF((negs & 1) ? 1 : 0,
550                           (negs & 2) ? 1 : 0,
551                           (negs & 4) ? 1 : 0,
552                           (negs & 8) ? 1 : 0));
553          sse_mulps(cp->func, dst, tmp);
554
555          aos_release_xmm_reg(cp, tmp.idx);
556       }
557       else if (negs) {
558          struct x86_reg imm_negs = aos_get_internal_xmm(cp, IMM_NEGS);
559          sse_mulps(cp->func, dst, imm_negs);
560       }
561
562
563       if (abs && abs != 0xf) {
564          ERROR(cp, "unsupported partial abs");
565       }
566       else if (abs) {
567          struct x86_reg neg = aos_get_internal(cp, IMM_NEGS);
568          struct x86_reg tmp = aos_get_xmm_reg(cp);
569
570          sse_movaps(cp->func, tmp, dst);
571          sse_mulps(cp->func, tmp, neg);
572          sse_maxps(cp->func, dst, tmp);
573
574          aos_release_xmm_reg(cp, tmp.idx);
575       }
576
577       return dst;
578    }
579       
580    return arg0;
581 }
582
583 static void x87_fld_src( struct aos_compilation *cp, 
584                          const struct tgsi_full_src_register *src,
585                          unsigned channel ) 
586 {
587    struct x86_reg arg0 = aos_get_shader_reg_ptr(cp, 
588                                                 src->SrcRegister.File, 
589                                                 src->SrcRegister.Index);
590
591    unsigned swizzle = tgsi_util_get_full_src_register_extswizzle( src, channel );
592    unsigned neg = tgsi_util_get_full_src_register_sign_mode( src, channel );
593
594    switch (swizzle) {
595    case TGSI_EXTSWIZZLE_ZERO:
596       x87_fldz( cp->func );
597       break;
598
599    case TGSI_EXTSWIZZLE_ONE:
600       x87_fld1( cp->func );
601       break;
602
603    default:
604       x87_fld( cp->func, x86_make_disp(arg0, (swizzle & 3) * sizeof(float)) );
605       break;
606    }
607    
608
609    switch (neg) {
610    case TGSI_UTIL_SIGN_TOGGLE:
611       /* Flip the sign:
612        */
613       x87_fchs( cp->func );
614       break;
615          
616    case TGSI_UTIL_SIGN_KEEP:
617       break;
618
619    case TGSI_UTIL_SIGN_CLEAR:
620       x87_fabs( cp->func );
621       break;
622
623    case TGSI_UTIL_SIGN_SET:
624       x87_fabs( cp->func );
625       x87_fchs( cp->func );
626       break;
627
628    default:
629       ERROR(cp, "unsupported sign-mode");
630       break;
631    }
632 }
633
634
635
636
637
638
639 /* Used to implement write masking.  This and most of the other instructions
640  * here would be easier to implement if there had been a translation
641  * to a 2 argument format (dst/arg0, arg1) at the shader level before
642  * attempting to translate to x86/sse code.
643  */
644 static void store_dest( struct aos_compilation *cp, 
645                         const struct tgsi_full_dst_register *reg,
646                         struct x86_reg result )
647 {
648    struct x86_reg dst;
649
650    switch (reg->DstRegister.WriteMask) {
651    case 0:
652       return;
653    
654    case TGSI_WRITEMASK_XYZW:
655       aos_adopt_xmm_reg(cp, 
656                         get_xmm_writable(cp, result), 
657                         reg->DstRegister.File,
658                         reg->DstRegister.Index,
659                         TRUE);
660       return;
661    default: 
662       break;
663    }
664
665    dst = aos_get_shader_reg_xmm(cp, 
666                                 reg->DstRegister.File,
667                                 reg->DstRegister.Index);
668
669    switch (reg->DstRegister.WriteMask) {
670    case TGSI_WRITEMASK_X:
671       sse_movss(cp->func, dst, get_xmm(cp, result));
672       break;
673       
674    case TGSI_WRITEMASK_ZW:
675       sse_shufps(cp->func, dst, get_xmm(cp, result), SHUF(X, Y, Z, W));
676       break;
677
678    case TGSI_WRITEMASK_XY: 
679       result = get_xmm_writable(cp, result);
680       sse_shufps(cp->func, result, dst, SHUF(X, Y, Z, W));
681       dst = result;
682       break;
683
684    case TGSI_WRITEMASK_YZW: 
685       result = get_xmm_writable(cp, result);
686       sse_movss(cp->func, result, dst);
687       dst = result;
688       break;
689
690    default:
691       mask_write(cp, dst, result, reg->DstRegister.WriteMask);
692       break;
693    }
694
695    aos_adopt_xmm_reg(cp, 
696                      dst, 
697                      reg->DstRegister.File,
698                      reg->DstRegister.Index,
699                      TRUE);
700
701 }
702
703 static void inject_scalar( struct aos_compilation *cp,
704                            struct x86_reg dst,
705                            struct x86_reg result,
706                            ubyte swizzle )
707 {
708    sse_shufps(cp->func, dst, dst, swizzle);
709    sse_movss(cp->func, dst, result);
710    sse_shufps(cp->func, dst, dst, swizzle);
711 }
712
713
714 static void store_scalar_dest( struct aos_compilation *cp, 
715                                const struct tgsi_full_dst_register *reg,
716                                struct x86_reg result )
717 {
718    unsigned writemask = reg->DstRegister.WriteMask;
719    struct x86_reg dst;
720
721    if (writemask != TGSI_WRITEMASK_X &&
722        writemask != TGSI_WRITEMASK_Y &&
723        writemask != TGSI_WRITEMASK_Z &&
724        writemask != TGSI_WRITEMASK_W &&
725        writemask != 0) 
726    {
727       result = get_xmm_writable(cp, result); /* already true, right? */
728       sse_shufps(cp->func, result, result, SHUF(X,X,X,X));
729       store_dest(cp, reg, result);
730       return;
731    }
732
733    result = get_xmm(cp, result);
734    dst = aos_get_shader_reg_xmm(cp, 
735                                 reg->DstRegister.File,
736                                 reg->DstRegister.Index);
737
738
739
740    switch (reg->DstRegister.WriteMask) {
741    case TGSI_WRITEMASK_X:
742       sse_movss(cp->func, dst, result);
743       break;
744
745    case TGSI_WRITEMASK_Y:
746       inject_scalar(cp, dst, result, SHUF(Y, X, Z, W));
747       break;
748
749    case TGSI_WRITEMASK_Z:
750       inject_scalar(cp, dst, result, SHUF(Z, Y, X, W));
751       break;
752
753    case TGSI_WRITEMASK_W:
754       inject_scalar(cp, dst, result, SHUF(W, Y, Z, X));
755       break;
756
757    default:
758       break;
759    }
760
761    aos_adopt_xmm_reg(cp, 
762                      dst, 
763                      reg->DstRegister.File,
764                      reg->DstRegister.Index,
765                      TRUE);
766 }
767    
768
769
770 static void x87_fst_or_nop( struct x86_function *func,
771                             unsigned writemask,
772                             unsigned channel,
773                             struct x86_reg ptr )
774 {
775    assert(ptr.file == file_REG32);
776    if (writemask & (1<<channel)) 
777       x87_fst( func, x86_make_disp(ptr, channel * sizeof(float)) );
778 }
779
780 static void x87_fstp_or_pop( struct x86_function *func,
781                              unsigned writemask,
782                              unsigned channel,
783                              struct x86_reg ptr )
784 {
785    assert(ptr.file == file_REG32);
786    if (writemask & (1<<channel)) 
787       x87_fstp( func, x86_make_disp(ptr, channel * sizeof(float)) );
788    else
789       x87_fstp( func, x86_make_reg( file_x87, 0 ));
790 }
791
792
793
794 /* 
795  */
796 static void x87_fstp_dest4( struct aos_compilation *cp,
797                             const struct tgsi_full_dst_register *dst )
798 {
799    struct x86_reg ptr = get_dst_ptr(cp, dst); 
800    unsigned writemask = dst->DstRegister.WriteMask;
801
802    x87_fst_or_nop(cp->func, writemask, 0, ptr);
803    x87_fst_or_nop(cp->func, writemask, 1, ptr);
804    x87_fst_or_nop(cp->func, writemask, 2, ptr);
805    x87_fstp_or_pop(cp->func, writemask, 3, ptr);
806 }
807
808 /* Save current x87 state and put it into single precision mode.
809  */
810 static void save_fpu_state( struct aos_compilation *cp )
811 {
812    x87_fnstcw( cp->func, x86_make_disp(cp->machine_EDX, 
813                                        Offset(struct aos_machine, fpu_restore)));
814 }
815
816 static void restore_fpu_state( struct aos_compilation *cp )
817 {
818    x87_fnclex(cp->func);
819    x87_fldcw( cp->func, x86_make_disp(cp->machine_EDX, 
820                                       Offset(struct aos_machine, fpu_restore)));
821 }
822
823 static void set_fpu_round_neg_inf( struct aos_compilation *cp )
824 {
825    if (cp->fpucntl != FPU_RND_NEG) {
826       cp->fpucntl = FPU_RND_NEG;
827       x87_fnclex(cp->func);
828       x87_fldcw( cp->func, x86_make_disp(cp->machine_EDX, 
829                                          Offset(struct aos_machine, fpu_rnd_neg_inf)));
830    }
831 }
832
833 static void set_fpu_round_nearest( struct aos_compilation *cp )
834 {
835    if (cp->fpucntl != FPU_RND_NEAREST) {
836       cp->fpucntl = FPU_RND_NEAREST;
837       x87_fnclex(cp->func);
838       x87_fldcw( cp->func, x86_make_disp(cp->machine_EDX, 
839                                          Offset(struct aos_machine, fpu_rnd_nearest)));
840    }
841 }
842
843
844 static void x87_emit_ex2( struct aos_compilation *cp )
845 {
846    struct x86_reg st0 = x86_make_reg(file_x87, 0);
847    struct x86_reg st1 = x86_make_reg(file_x87, 1);
848    int stack = cp->func->x87_stack;
849
850 //   set_fpu_round_neg_inf( cp );
851
852    x87_fld(cp->func, st0);      /* a a */
853    x87_fprndint( cp->func );    /* int(a) a*/
854    x87_fsubr(cp->func, st1, st0);    /* int(a) frc(a) */
855    x87_fxch(cp->func, st1);     /* frc(a) int(a) */
856    x87_f2xm1(cp->func);         /* (2^frc(a))-1 int(a) */
857    x87_fld1(cp->func);          /* 1 (2^frc(a))-1 int(a) */
858    x87_faddp(cp->func, st1);    /* 2^frac(a) int(a)  */
859    x87_fscale(cp->func);        /* (2^frac(a)*2^int(int(a))) int(a) */
860                                 /* 2^a int(a) */
861    x87_fstp(cp->func, st1);     /* 2^a */
862
863    assert( stack == cp->func->x87_stack);
864       
865 }
866
867 static void PIPE_CDECL print_reg( const char *msg,
868                                   const float *reg )
869 {
870    debug_printf("%s: %f %f %f %f\n", msg, reg[0], reg[1], reg[2], reg[3]);
871 }
872
873 static void emit_print( struct aos_compilation *cp,
874                         const char *message, /* must point to a static string! */
875                         unsigned file,
876                         unsigned idx )
877 {
878    struct x86_reg ecx = x86_make_reg( file_REG32, reg_CX );
879    struct x86_reg arg = aos_get_shader_reg_ptr( cp, file, idx );
880    unsigned i;
881
882    /* There shouldn't be anything on the x87 stack.  Can add this
883     * capacity later if need be.
884     */
885    assert(cp->func->x87_stack == 0);
886
887    /* For absolute correctness, need to spill/invalidate all XMM regs
888     * too.  We're obviously not concerned about performance on this
889     * debug path, so here goes:
890     */
891    for (i = 0; i < 8; i++) {
892       if (cp->xmm[i].dirty) 
893          spill(cp, i);
894
895       aos_release_xmm_reg(cp, i);
896    }
897
898    /* Push caller-save (ie scratch) regs.  
899     */
900    x86_cdecl_caller_push_regs( cp->func );
901
902
903    /* Push the arguments:
904     */
905    x86_lea( cp->func, ecx, arg );
906    x86_push( cp->func, ecx );
907    x86_push_imm32( cp->func, (int)message );
908
909    /* Call the helper.  Could call debug_printf directly, but
910     * print_reg is a nice place to put a breakpoint if need be.
911     */
912    x86_mov_reg_imm( cp->func, ecx, (int)print_reg );
913    x86_call( cp->func, ecx );
914    x86_pop( cp->func, ecx );
915    x86_pop( cp->func, ecx );
916
917    /* Pop caller-save regs 
918     */
919    x86_cdecl_caller_pop_regs( cp->func );
920
921    /* Done... 
922     */
923 }
924
925 /**
926  * The traditional instructions.  All operate on internal registers
927  * and ignore write masks and swizzling issues.
928  */
929
930 static boolean emit_ABS( struct aos_compilation *cp, const struct tgsi_full_instruction *op ) 
931 {
932    struct x86_reg arg0 = fetch_src(cp, &op->FullSrcRegisters[0]);
933    struct x86_reg neg = aos_get_internal(cp, IMM_NEGS);
934    struct x86_reg tmp = aos_get_xmm_reg(cp);
935
936    sse_movaps(cp->func, tmp, arg0);
937    sse_mulps(cp->func, tmp, neg);
938    sse_maxps(cp->func, tmp, arg0);
939    
940    store_dest(cp, &op->FullDstRegisters[0], tmp);
941    return TRUE;
942 }
943
944 static boolean emit_ADD( struct aos_compilation *cp, const struct tgsi_full_instruction *op )
945 {
946    struct x86_reg arg0 = fetch_src(cp, &op->FullSrcRegisters[0]);
947    struct x86_reg arg1 = fetch_src(cp, &op->FullSrcRegisters[1]);
948    struct x86_reg dst = get_xmm_writable(cp, arg0);
949
950    sse_addps(cp->func, dst, arg1);
951
952    store_dest(cp, &op->FullDstRegisters[0], dst);
953    return TRUE;
954 }
955
956 static boolean emit_COS( struct aos_compilation *cp, const struct tgsi_full_instruction *op ) 
957 {
958    x87_fld_src(cp, &op->FullSrcRegisters[0], 0);
959    x87_fcos(cp->func);
960    x87_fstp_dest4(cp, &op->FullDstRegisters[0]);
961    return TRUE;
962 }
963
964 /* The dotproduct instructions don't really do that well in sse:
965  * XXX: produces wrong results -- disabled.
966  */
967 static boolean emit_DP3( struct aos_compilation *cp, const struct tgsi_full_instruction *op )
968 {
969    struct x86_reg arg0 = fetch_src(cp, &op->FullSrcRegisters[0]);
970    struct x86_reg arg1 = fetch_src(cp, &op->FullSrcRegisters[1]);
971    struct x86_reg tmp = aos_get_xmm_reg(cp); 
972    struct x86_reg dst = get_xmm_writable(cp, arg0);
973
974    sse_mulps(cp->func, dst, arg1);
975    /* Now the hard bit: sum the first 3 values:
976     */ 
977    sse_movhlps(cp->func, tmp, dst);
978    sse_addss(cp->func, dst, tmp); /* a*x+c*z, b*y, ?, ? */
979    emit_pshufd(cp, tmp, dst, SHUF(Y,X,W,Z));
980    sse_addss(cp->func, dst, tmp);
981    
982    aos_release_xmm_reg(cp, tmp.idx);
983    store_scalar_dest(cp, &op->FullDstRegisters[0], dst);
984    return TRUE;
985 }
986
987 static boolean emit_DP4( struct aos_compilation *cp, const struct tgsi_full_instruction *op )
988 {
989    struct x86_reg arg0 = fetch_src(cp, &op->FullSrcRegisters[0]);
990    struct x86_reg arg1 = fetch_src(cp, &op->FullSrcRegisters[1]);
991    struct x86_reg tmp = aos_get_xmm_reg(cp);      
992    struct x86_reg dst = get_xmm_writable(cp, arg0);
993
994    sse_mulps(cp->func, dst, arg1);
995    
996    /* Now the hard bit: sum the values:
997     */ 
998    sse_movhlps(cp->func, tmp, dst);
999    sse_addps(cp->func, dst, tmp); /* a*x+c*z, b*y+d*w, a*x+c*z, b*y+d*w */
1000    emit_pshufd(cp, tmp, dst, SHUF(Y,X,W,Z));
1001    sse_addss(cp->func, dst, tmp);
1002
1003    aos_release_xmm_reg(cp, tmp.idx);
1004    store_scalar_dest(cp, &op->FullDstRegisters[0], dst);
1005    return TRUE;
1006 }
1007
1008 static boolean emit_DPH( struct aos_compilation *cp, const struct tgsi_full_instruction *op )
1009 {
1010    struct x86_reg arg0 = fetch_src(cp, &op->FullSrcRegisters[0]);
1011    struct x86_reg arg1 = fetch_src(cp, &op->FullSrcRegisters[1]);
1012    struct x86_reg tmp = aos_get_xmm_reg(cp);
1013    struct x86_reg dst = get_xmm_writable(cp, arg0);
1014
1015    sse_mulps(cp->func, dst, arg1);
1016
1017    /* Now the hard bit: sum the values (from DP3):
1018     */ 
1019    sse_movhlps(cp->func, tmp, dst);
1020    sse_addss(cp->func, dst, tmp); /* a*x+c*z, b*y, ?, ? */
1021    emit_pshufd(cp, tmp, dst, SHUF(Y,X,W,Z));
1022    sse_addss(cp->func, dst, tmp);
1023    emit_pshufd(cp, tmp, arg1, SHUF(W,W,W,W));
1024    sse_addss(cp->func, dst, tmp);
1025
1026    aos_release_xmm_reg(cp, tmp.idx);
1027    store_scalar_dest(cp, &op->FullDstRegisters[0], dst);
1028    return TRUE;
1029 }
1030
1031 static boolean emit_DST( struct aos_compilation *cp, const struct tgsi_full_instruction *op )
1032 {
1033     struct x86_reg arg0 = fetch_src(cp, &op->FullSrcRegisters[0]);
1034     struct x86_reg arg1 = fetch_src(cp, &op->FullSrcRegisters[1]);
1035     struct x86_reg dst = aos_get_xmm_reg(cp);
1036     struct x86_reg tmp = aos_get_xmm_reg(cp);
1037     struct x86_reg ones = aos_get_internal(cp, IMM_ONES);
1038
1039 /*    dst[0] = 1.0     * 1.0F; */
1040 /*    dst[1] = arg0[1] * arg1[1]; */
1041 /*    dst[2] = arg0[2] * 1.0; */
1042 /*    dst[3] = 1.0     * arg1[3]; */
1043
1044     emit_shuf_copy2(cp, dst, arg0, ones, SHUF(X,W,Z,Y));
1045     emit_shuf_copy2(cp, tmp, arg1, ones, SHUF(X,Z,Y,W));
1046     sse_mulps(cp->func, dst, tmp);
1047
1048     aos_release_xmm_reg(cp, tmp.idx);
1049     store_dest(cp, &op->FullDstRegisters[0], dst);
1050     return TRUE;
1051 }
1052
1053 static boolean emit_LG2( struct aos_compilation *cp, const struct tgsi_full_instruction *op ) 
1054 {
1055    x87_fld1(cp->func);          /* 1 */
1056    x87_fld_src(cp, &op->FullSrcRegisters[0], 0);        /* a0 1 */
1057    x87_fyl2x(cp->func); /* log2(a0) */
1058    x87_fstp_dest4(cp, &op->FullDstRegisters[0]);
1059    return TRUE;
1060 }
1061
1062
1063 static boolean emit_EX2( struct aos_compilation *cp, const struct tgsi_full_instruction *op ) 
1064 {
1065    x87_fld_src(cp, &op->FullSrcRegisters[0], 0);
1066    x87_emit_ex2(cp);
1067    x87_fstp_dest4(cp, &op->FullDstRegisters[0]);
1068    return TRUE;
1069 }
1070
1071
1072 static boolean emit_FLR( struct aos_compilation *cp, const struct tgsi_full_instruction *op ) 
1073 {
1074    struct x86_reg dst = get_dst_ptr(cp, &op->FullDstRegisters[0]); 
1075    unsigned writemask = op->FullDstRegisters[0].DstRegister.WriteMask;
1076    int i;
1077
1078    set_fpu_round_neg_inf( cp );
1079
1080    /* Load all sources first to avoid aliasing
1081     */
1082    for (i = 3; i >= 0; i--) {
1083       if (writemask & (1<<i)) {
1084          x87_fld_src(cp, &op->FullSrcRegisters[0], i);   
1085       }
1086    }
1087
1088    for (i = 0; i < 4; i++) {
1089       if (writemask & (1<<i)) {
1090          x87_fprndint( cp->func );   
1091          x87_fstp(cp->func, x86_make_disp(dst, i*4));
1092       }
1093    }
1094
1095    return TRUE;
1096 }
1097
1098
1099 static boolean emit_RND( struct aos_compilation *cp, const struct tgsi_full_instruction *op ) 
1100 {
1101    struct x86_reg dst = get_dst_ptr(cp, &op->FullDstRegisters[0]); 
1102    unsigned writemask = op->FullDstRegisters[0].DstRegister.WriteMask;
1103    int i;
1104
1105    set_fpu_round_nearest( cp );
1106
1107    /* Load all sources first to avoid aliasing
1108     */
1109    for (i = 3; i >= 0; i--) {
1110       if (writemask & (1<<i)) {
1111          x87_fld_src(cp, &op->FullSrcRegisters[0], i);   
1112       }
1113    }
1114
1115    for (i = 0; i < 4; i++) {
1116       if (writemask & (1<<i)) {
1117          x87_fprndint( cp->func );   
1118          x87_fstp(cp->func, x86_make_disp(dst, i*4));
1119       }
1120    }
1121
1122    return TRUE;
1123 }
1124
1125
1126 static boolean emit_FRC( struct aos_compilation *cp, const struct tgsi_full_instruction *op ) 
1127 {
1128    struct x86_reg dst = get_dst_ptr(cp, &op->FullDstRegisters[0]); 
1129    struct x86_reg st0 = x86_make_reg(file_x87, 0);
1130    struct x86_reg st1 = x86_make_reg(file_x87, 1);
1131    unsigned writemask = op->FullDstRegisters[0].DstRegister.WriteMask;
1132    int i;
1133
1134    set_fpu_round_neg_inf( cp );
1135
1136    /* suck all the source values onto the stack before writing out any
1137     * dst, which may alias...
1138     */
1139    for (i = 3; i >= 0; i--) {
1140       if (writemask & (1<<i)) {
1141          x87_fld_src(cp, &op->FullSrcRegisters[0], i);   
1142       }
1143    }
1144
1145    for (i = 0; i < 4; i++) {
1146       if (writemask & (1<<i)) {
1147          x87_fld(cp->func, st0);     /* a a */
1148          x87_fprndint( cp->func );   /* flr(a) a */
1149          x87_fsubp(cp->func, st1);  /* frc(a) */
1150          x87_fstp(cp->func, x86_make_disp(dst, i*4));
1151       }
1152    }
1153
1154    return TRUE;
1155 }
1156
1157
1158
1159
1160
1161
1162 static boolean emit_LIT( struct aos_compilation *cp, const struct tgsi_full_instruction *op )
1163 {
1164    struct x86_reg ecx = x86_make_reg( file_REG32, reg_CX );
1165    unsigned writemask = op->FullDstRegisters[0].DstRegister.WriteMask;
1166    unsigned lit_count = cp->lit_count++;
1167    struct x86_reg result, arg0;
1168    unsigned i;
1169
1170 #if 1
1171    /* For absolute correctness, need to spill/invalidate all XMM regs
1172     * too.  
1173     */
1174    for (i = 0; i < 8; i++) {
1175       if (cp->xmm[i].dirty) 
1176          spill(cp, i);
1177       aos_release_xmm_reg(cp, i);
1178    }
1179 #endif
1180
1181    if (writemask != TGSI_WRITEMASK_XYZW) 
1182       result = x86_make_disp(cp->machine_EDX, Offset(struct aos_machine, tmp[0]));
1183    else 
1184       result = get_dst_ptr(cp, &op->FullDstRegisters[0]);    
1185
1186    
1187    arg0 = fetch_src( cp, &op->FullSrcRegisters[0] );
1188    if (arg0.file == file_XMM) {
1189       struct x86_reg tmp = x86_make_disp(cp->machine_EDX, 
1190                                          Offset(struct aos_machine, tmp[1]));
1191       sse_movaps( cp->func, tmp, arg0 );
1192       arg0 = tmp;
1193    }
1194                   
1195       
1196
1197    /* Push caller-save (ie scratch) regs.  
1198     */
1199    x86_cdecl_caller_push_regs( cp->func );
1200
1201    /* Push the arguments:
1202     */
1203    x86_push_imm32( cp->func, lit_count );
1204
1205    x86_lea( cp->func, ecx, arg0 );
1206    x86_push( cp->func, ecx );
1207
1208    x86_lea( cp->func, ecx, result );
1209    x86_push( cp->func, ecx );
1210
1211    x86_push( cp->func, cp->machine_EDX );
1212
1213    if (lit_count < MAX_LIT_INFO) {
1214       x86_mov( cp->func, ecx, x86_make_disp( cp->machine_EDX, 
1215                                              Offset(struct aos_machine, lit_info) + 
1216                                              lit_count * sizeof(struct lit_info) + 
1217                                              Offset(struct lit_info, func)));
1218    }
1219    else {
1220       x86_mov_reg_imm( cp->func, ecx, (int)aos_do_lit );
1221    }
1222
1223    x86_call( cp->func, ecx );
1224             
1225    x86_pop( cp->func, ecx );    /* fixme... */
1226    x86_pop( cp->func, ecx );
1227    x86_pop( cp->func, ecx );
1228    x86_pop( cp->func, ecx );
1229
1230    x86_cdecl_caller_pop_regs( cp->func );
1231
1232    if (writemask != TGSI_WRITEMASK_XYZW) {
1233       store_dest( cp, 
1234                   &op->FullDstRegisters[0],
1235                   get_xmm_writable( cp, result ) );
1236    }
1237
1238    return TRUE;
1239 }
1240
1241 #if 0   
1242 static boolean emit_inline_LIT( struct aos_compilation *cp, const struct tgsi_full_instruction *op )
1243 {
1244    struct x86_reg dst = get_dst_ptr(cp, &op->FullDstRegisters[0]); 
1245    unsigned writemask = op->FullDstRegisters[0].DstRegister.WriteMask;
1246
1247    if (writemask & TGSI_WRITEMASK_YZ) {
1248       struct x86_reg st1 = x86_make_reg(file_x87, 1);
1249       struct x86_reg st2 = x86_make_reg(file_x87, 2);
1250
1251       /* a1' = a1 <= 0 ? 1 : a1;  
1252        */
1253       x87_fldz(cp->func);                           /* 1 0  */
1254 #if 1
1255       x87_fld1(cp->func);                           /* 1 0  */
1256 #else
1257       /* Correct but slow due to fp exceptions generated in fyl2x - fix me.
1258        */
1259       x87_fldz(cp->func);                           /* 1 0  */
1260 #endif
1261       x87_fld_src(cp, &op->FullSrcRegisters[0], 1); /* a1 1 0  */
1262       x87_fcomi(cp->func, st2);                     /* a1 1 0  */
1263       x87_fcmovb(cp->func, st1);                    /* a1' 1 0  */
1264       x87_fstp(cp->func, st1);                      /* a1' 0  */
1265       x87_fstp(cp->func, st1);                      /* a1'  */
1266
1267       x87_fld_src(cp, &op->FullSrcRegisters[0], 3); /* a3 a1'  */
1268       x87_fxch(cp->func, st1);                      /* a1' a3  */
1269       
1270
1271       /* Compute pow(a1, a3)
1272        */
1273       x87_fyl2x(cp->func);      /* a3*log2(a1)      */
1274       x87_emit_ex2( cp );       /* 2^(a3*log2(a1))   */
1275
1276
1277       /* a0' = max2(a0, 0):
1278        */
1279       x87_fldz(cp->func);                           /* 0 r2 */
1280       x87_fld_src(cp, &op->FullSrcRegisters[0], 0); /* a0 0 r2 */
1281       x87_fcomi(cp->func, st1); 
1282       x87_fcmovb(cp->func, st1);                    /* a0' 0 r2 */
1283
1284       x87_fst_or_nop(cp->func, writemask, 1, dst); /* result[1] = a0' */
1285
1286       x87_fcomi(cp->func, st1);  /* a0' 0 r2 */
1287       x87_fcmovnbe(cp->func, st2); /* r2' 0' r2 */
1288
1289       x87_fstp_or_pop(cp->func, writemask, 2, dst); /* 0 r2 */
1290       x87_fpop(cp->func);       /* r2 */
1291       x87_fpop(cp->func);
1292    }
1293
1294    if (writemask & TGSI_WRITEMASK_XW) {
1295       x87_fld1(cp->func);
1296       x87_fst_or_nop(cp->func, writemask, 0, dst);
1297       x87_fstp_or_pop(cp->func, writemask, 3, dst);
1298    }
1299
1300    return TRUE;
1301 }
1302 #endif
1303
1304
1305
1306 static boolean emit_MAX( struct aos_compilation *cp, const struct tgsi_full_instruction *op )
1307 {
1308    struct x86_reg arg0 = fetch_src(cp, &op->FullSrcRegisters[0]);
1309    struct x86_reg arg1 = fetch_src(cp, &op->FullSrcRegisters[1]);
1310    struct x86_reg dst = get_xmm_writable(cp, arg0);
1311
1312    sse_maxps(cp->func, dst, arg1);
1313
1314    store_dest(cp, &op->FullDstRegisters[0], dst);
1315    return TRUE;
1316 }
1317
1318
1319 static boolean emit_MIN( struct aos_compilation *cp, const struct tgsi_full_instruction *op )
1320 {
1321    struct x86_reg arg0 = fetch_src(cp, &op->FullSrcRegisters[0]);
1322    struct x86_reg arg1 = fetch_src(cp, &op->FullSrcRegisters[1]);
1323    struct x86_reg dst = get_xmm_writable(cp, arg0);
1324
1325    sse_minps(cp->func, dst, arg1);
1326
1327    store_dest(cp, &op->FullDstRegisters[0], dst);
1328    return TRUE;
1329 }
1330
1331 static boolean emit_MOV( struct aos_compilation *cp, const struct tgsi_full_instruction *op )
1332 {
1333    struct x86_reg arg0 = fetch_src(cp, &op->FullSrcRegisters[0]);
1334    struct x86_reg dst = get_xmm_writable(cp, arg0);
1335
1336    /* potentially nothing to do */
1337
1338    store_dest(cp, &op->FullDstRegisters[0], dst);
1339    return TRUE;
1340 }
1341
1342 static boolean emit_MUL( struct aos_compilation *cp, const struct tgsi_full_instruction *op )
1343 {
1344    struct x86_reg arg0 = fetch_src(cp, &op->FullSrcRegisters[0]);
1345    struct x86_reg arg1 = fetch_src(cp, &op->FullSrcRegisters[1]);
1346    struct x86_reg dst = get_xmm_writable(cp, arg0);
1347
1348    sse_mulps(cp->func, dst, arg1);
1349
1350    store_dest(cp, &op->FullDstRegisters[0], dst);
1351    return TRUE;
1352 }
1353
1354
1355 static boolean emit_MAD( struct aos_compilation *cp, const struct tgsi_full_instruction *op )
1356 {
1357    struct x86_reg arg0 = fetch_src(cp, &op->FullSrcRegisters[0]);
1358    struct x86_reg arg1 = fetch_src(cp, &op->FullSrcRegisters[1]);
1359    struct x86_reg arg2 = fetch_src(cp, &op->FullSrcRegisters[2]);
1360
1361    /* If we can't clobber old contents of arg0, get a temporary & copy
1362     * it there, then clobber it...
1363     */
1364    arg0 = get_xmm_writable(cp, arg0);
1365
1366    sse_mulps(cp->func, arg0, arg1);
1367    sse_addps(cp->func, arg0, arg2);
1368    store_dest(cp, &op->FullDstRegisters[0], arg0);
1369    return TRUE;
1370 }
1371
1372 /* A wrapper for powf().
1373  * Makes sure it is cdecl and operates on floats.
1374  */
1375 static float PIPE_CDECL _powerf( float x, float y )
1376 {
1377    return powf( x, y );
1378 }
1379
1380 /* Really not sufficient -- need to check for conditions that could
1381  * generate inf/nan values, which will slow things down hugely.
1382  */
1383 static boolean emit_POW( struct aos_compilation *cp, const struct tgsi_full_instruction *op ) 
1384 {
1385 #if 0
1386    x87_fld_src(cp, &op->FullSrcRegisters[1], 0);  /* a1.x */
1387    x87_fld_src(cp, &op->FullSrcRegisters[0], 0);        /* a0.x a1.x */
1388    x87_fyl2x(cp->func);                                 /* a1*log2(a0) */
1389
1390    x87_emit_ex2( cp );          /* 2^(a1*log2(a0)) */
1391
1392    x87_fstp_dest4(cp, &op->FullDstRegisters[0]);
1393 #else
1394    uint i;
1395
1396    /* For absolute correctness, need to spill/invalidate all XMM regs
1397     * too.  
1398     */
1399    for (i = 0; i < 8; i++) {
1400       if (cp->xmm[i].dirty) 
1401          spill(cp, i);
1402       aos_release_xmm_reg(cp, i);
1403    }
1404
1405    /* Push caller-save (ie scratch) regs.  
1406     */
1407    x86_cdecl_caller_push_regs( cp->func );
1408
1409    x86_lea( cp->func, cp->stack_ESP, x86_make_disp(cp->stack_ESP, -8) );
1410
1411    x87_fld_src( cp, &op->FullSrcRegisters[1], 0 );
1412    x87_fstp( cp->func, x86_make_disp( cp->stack_ESP, 4 ) );
1413    x87_fld_src( cp, &op->FullSrcRegisters[0], 0 );
1414    x87_fstp( cp->func, x86_make_disp( cp->stack_ESP, 0 ) );
1415
1416    x86_mov_reg_imm( cp->func, cp->tmp_EAX, (unsigned long) _powerf );
1417    x86_call( cp->func, cp->tmp_EAX );
1418
1419    x86_lea( cp->func, cp->stack_ESP, x86_make_disp(cp->stack_ESP, 8) );
1420
1421    x86_cdecl_caller_pop_regs( cp->func );
1422
1423    /* Note retval on x87 stack:
1424     */
1425    cp->func->x87_stack++;
1426
1427    x87_fstp_dest4( cp, &op->FullDstRegisters[0] );
1428 #endif
1429    return TRUE;
1430 }
1431
1432
1433 static boolean emit_RCP( struct aos_compilation *cp, const struct tgsi_full_instruction *op )
1434 {
1435    struct x86_reg arg0 = fetch_src(cp, &op->FullSrcRegisters[0]);
1436    struct x86_reg dst = aos_get_xmm_reg(cp);
1437
1438    if (cp->have_sse2) {
1439       sse2_rcpss(cp->func, dst, arg0);
1440       /* extend precision here...
1441        */
1442    }
1443    else {
1444       struct x86_reg ones = aos_get_internal(cp, IMM_ONES);
1445       sse_movss(cp->func, dst, ones);
1446       sse_divss(cp->func, dst, arg0);
1447    }
1448
1449    store_scalar_dest(cp, &op->FullDstRegisters[0], dst);
1450    return TRUE;
1451 }
1452
1453
1454 /* Although rsqrtps() and rcpps() are low precision on some/all SSE
1455  * implementations, it is possible to improve its precision at
1456  * fairly low cost, using a newton/raphson step, as below:
1457  * 
1458  * x1 = 2 * rcpps(a) - a * rcpps(a) * rcpps(a)
1459  * x1 = 0.5 * rsqrtps(a) * [3.0 - (a * rsqrtps(a))* rsqrtps(a)]
1460  * or:
1461  *   x1 = rsqrtps(a) * [1.5 - .5 * a * rsqrtps(a) * rsqrtps(a)]
1462  * 
1463  *
1464  * See: http://softwarecommunity.intel.com/articles/eng/1818.htm
1465  */
1466 static boolean emit_RSQ( struct aos_compilation *cp, const struct tgsi_full_instruction *op )
1467 {
1468
1469    if (0) {
1470       struct x86_reg arg0 = fetch_src(cp, &op->FullSrcRegisters[0]);
1471       struct x86_reg r = aos_get_xmm_reg(cp);
1472       sse_rsqrtss(cp->func, r, arg0);
1473       store_scalar_dest(cp, &op->FullDstRegisters[0], r);
1474       return TRUE;
1475    }
1476    else {
1477       struct x86_reg arg0 = fetch_src(cp, &op->FullSrcRegisters[0]);
1478       struct x86_reg r = aos_get_xmm_reg(cp);
1479
1480       struct x86_reg neg_half       = get_reg_ptr( cp, AOS_FILE_INTERNAL, IMM_RSQ );
1481       struct x86_reg one_point_five = x86_make_disp( neg_half, 4 );
1482       struct x86_reg src            = get_xmm_writable( cp, arg0 );
1483       
1484       sse_rsqrtss( cp->func, r, src  );             /* rsqrtss(a) */
1485       sse_mulss(   cp->func, src, neg_half  );      /* -.5 * a */
1486       sse_mulss(   cp->func, src,  r );             /* -.5 * a * r */
1487       sse_mulss(   cp->func, src,  r );             /* -.5 * a * r * r */
1488       sse_addss(   cp->func, src, one_point_five ); /* 1.5 - .5 * a * r * r */
1489       sse_mulss(   cp->func, r,  src );             /* r * (1.5 - .5 * a * r * r) */
1490
1491       store_scalar_dest(cp, &op->FullDstRegisters[0], r);
1492       return TRUE;
1493    }
1494 }
1495
1496
1497 static boolean emit_SGE( struct aos_compilation *cp, const struct tgsi_full_instruction *op )
1498 {
1499    struct x86_reg arg0 = fetch_src(cp, &op->FullSrcRegisters[0]);
1500    struct x86_reg arg1 = fetch_src(cp, &op->FullSrcRegisters[1]);
1501    struct x86_reg ones = aos_get_internal(cp, IMM_ONES);
1502    struct x86_reg dst = get_xmm_writable(cp, arg0);
1503
1504    sse_cmpps(cp->func, dst, arg1, cc_NotLessThan);
1505    sse_andps(cp->func, dst, ones);
1506
1507    store_dest(cp, &op->FullDstRegisters[0], dst);
1508    return TRUE;
1509 }
1510
1511 static boolean emit_SIN( struct aos_compilation *cp, const struct tgsi_full_instruction *op ) 
1512 {
1513    x87_fld_src(cp, &op->FullSrcRegisters[0], 0);
1514    x87_fsin(cp->func);
1515    x87_fstp_dest4(cp, &op->FullDstRegisters[0]);
1516    return TRUE;
1517 }
1518
1519
1520
1521 static boolean emit_SLT( struct aos_compilation *cp, const struct tgsi_full_instruction *op )
1522 {
1523    struct x86_reg arg0 = fetch_src(cp, &op->FullSrcRegisters[0]);
1524    struct x86_reg arg1 = fetch_src(cp, &op->FullSrcRegisters[1]);
1525    struct x86_reg ones = aos_get_internal(cp, IMM_ONES);
1526    struct x86_reg dst = get_xmm_writable(cp, arg0);
1527    
1528    sse_cmpps(cp->func, dst, arg1, cc_LessThan);
1529    sse_andps(cp->func, dst, ones);
1530
1531    store_dest(cp, &op->FullDstRegisters[0], dst);
1532    return TRUE;
1533 }
1534
1535 static boolean emit_SUB( struct aos_compilation *cp, const struct tgsi_full_instruction *op ) 
1536 {
1537    struct x86_reg arg0 = fetch_src(cp, &op->FullSrcRegisters[0]);
1538    struct x86_reg arg1 = fetch_src(cp, &op->FullSrcRegisters[1]);
1539    struct x86_reg dst = get_xmm_writable(cp, arg0);
1540
1541    sse_subps(cp->func, dst, arg1);
1542
1543    store_dest(cp, &op->FullDstRegisters[0], dst);
1544    return TRUE;
1545 }
1546
1547
1548 static boolean emit_XPD( struct aos_compilation *cp, const struct tgsi_full_instruction *op ) 
1549 {
1550    struct x86_reg arg0 = fetch_src(cp, &op->FullSrcRegisters[0]);
1551    struct x86_reg arg1 = fetch_src(cp, &op->FullSrcRegisters[1]);
1552    struct x86_reg tmp0 = aos_get_xmm_reg(cp);
1553    struct x86_reg tmp1 = aos_get_xmm_reg(cp);
1554
1555    emit_pshufd(cp, tmp1, arg1, SHUF(Y, Z, X, W));
1556    sse_mulps(cp->func, tmp1, arg0);
1557    emit_pshufd(cp, tmp0, arg0, SHUF(Y, Z, X, W));
1558    sse_mulps(cp->func, tmp0, arg1);
1559    sse_subps(cp->func, tmp1, tmp0);
1560    sse_shufps(cp->func, tmp1, tmp1, SHUF(Y, Z, X, W));
1561
1562 /*    dst[2] = arg0[0] * arg1[1] - arg0[1] * arg1[0]; */
1563 /*    dst[0] = arg0[1] * arg1[2] - arg0[2] * arg1[1]; */
1564 /*    dst[1] = arg0[2] * arg1[0] - arg0[0] * arg1[2]; */
1565 /*    dst[3] is undef */
1566
1567
1568    aos_release_xmm_reg(cp, tmp0.idx);
1569    store_dest(cp, &op->FullDstRegisters[0], tmp1);
1570    return TRUE;
1571 }
1572
1573
1574
1575 static boolean
1576 emit_instruction( struct aos_compilation *cp,
1577                   struct tgsi_full_instruction *inst )
1578 {
1579    x87_assert_stack_empty(cp->func);
1580
1581    switch( inst->Instruction.Opcode ) {
1582    case TGSI_OPCODE_MOV:
1583       return emit_MOV( cp, inst );
1584
1585    case TGSI_OPCODE_LIT:
1586       return emit_LIT(cp, inst);
1587
1588    case TGSI_OPCODE_RCP:
1589       return emit_RCP(cp, inst);
1590
1591    case TGSI_OPCODE_RSQ:
1592       return emit_RSQ(cp, inst);
1593
1594    case TGSI_OPCODE_EXP:
1595       /*return emit_EXP(cp, inst);*/
1596       return FALSE;
1597
1598    case TGSI_OPCODE_LOG:
1599       /*return emit_LOG(cp, inst);*/
1600       return FALSE;
1601
1602    case TGSI_OPCODE_MUL:
1603       return emit_MUL(cp, inst);
1604
1605    case TGSI_OPCODE_ADD:
1606       return emit_ADD(cp, inst);
1607
1608    case TGSI_OPCODE_DP3:
1609       return emit_DP3(cp, inst);
1610
1611    case TGSI_OPCODE_DP4:
1612       return emit_DP4(cp, inst);
1613
1614    case TGSI_OPCODE_DST:
1615       return emit_DST(cp, inst);
1616
1617    case TGSI_OPCODE_MIN:
1618       return emit_MIN(cp, inst);
1619
1620    case TGSI_OPCODE_MAX:
1621       return emit_MAX(cp, inst);
1622
1623    case TGSI_OPCODE_SLT:
1624       return emit_SLT(cp, inst);
1625
1626    case TGSI_OPCODE_SGE:
1627       return emit_SGE(cp, inst);
1628
1629    case TGSI_OPCODE_MAD:
1630       return emit_MAD(cp, inst);
1631
1632    case TGSI_OPCODE_SUB:
1633       return emit_SUB(cp, inst);
1634  
1635    case TGSI_OPCODE_LERP:
1636 //      return emit_LERP(cp, inst);
1637       return FALSE;
1638
1639    case TGSI_OPCODE_FRAC:
1640       return emit_FRC(cp, inst);
1641
1642    case TGSI_OPCODE_CLAMP:
1643 //      return emit_CLAMP(cp, inst);
1644       return FALSE;
1645
1646    case TGSI_OPCODE_FLOOR:
1647       return emit_FLR(cp, inst);
1648
1649    case TGSI_OPCODE_ROUND:
1650       return emit_RND(cp, inst);
1651
1652    case TGSI_OPCODE_EXPBASE2:
1653       return emit_EX2(cp, inst);
1654
1655    case TGSI_OPCODE_LOGBASE2:
1656       return emit_LG2(cp, inst);
1657
1658    case TGSI_OPCODE_POWER:
1659       return emit_POW(cp, inst);
1660
1661    case TGSI_OPCODE_CROSSPRODUCT:
1662       return emit_XPD(cp, inst);
1663
1664    case TGSI_OPCODE_ABS:
1665       return emit_ABS(cp, inst);
1666
1667    case TGSI_OPCODE_DPH:
1668       return emit_DPH(cp, inst);
1669
1670    case TGSI_OPCODE_COS:
1671       return emit_COS(cp, inst);
1672
1673    case TGSI_OPCODE_SIN:
1674       return emit_SIN(cp, inst);
1675
1676    case TGSI_OPCODE_END:
1677       return TRUE;
1678
1679    default:
1680       return FALSE;
1681    }
1682 }
1683
1684
1685 static boolean emit_viewport( struct aos_compilation *cp )
1686 {
1687    struct x86_reg pos = aos_get_shader_reg_xmm(cp, 
1688                                                TGSI_FILE_OUTPUT, 
1689                                                0);
1690
1691    struct x86_reg scale = x86_make_disp(cp->machine_EDX, 
1692                                         Offset(struct aos_machine, scale));
1693
1694    struct x86_reg translate = x86_make_disp(cp->machine_EDX, 
1695                                         Offset(struct aos_machine, translate));
1696
1697    sse_mulps(cp->func, pos, scale);
1698    sse_addps(cp->func, pos, translate);
1699
1700    aos_adopt_xmm_reg( cp,
1701                       pos,
1702                       TGSI_FILE_OUTPUT,
1703                       0,
1704                       TRUE );
1705    return TRUE;
1706 }
1707
1708
1709 /* This is useful to be able to see the results on softpipe.  Doesn't
1710  * do proper clipping, just assumes the backend can do it during
1711  * rasterization -- for debug only...
1712  */
1713 static boolean emit_rhw_viewport( struct aos_compilation *cp )
1714 {
1715    struct x86_reg tmp = aos_get_xmm_reg(cp);
1716    struct x86_reg pos = aos_get_shader_reg_xmm(cp, 
1717                                                TGSI_FILE_OUTPUT, 
1718                                                0);
1719
1720    struct x86_reg scale = x86_make_disp(cp->machine_EDX, 
1721                                         Offset(struct aos_machine, scale));
1722
1723    struct x86_reg translate = x86_make_disp(cp->machine_EDX, 
1724                                         Offset(struct aos_machine, translate));
1725
1726
1727
1728    emit_pshufd(cp, tmp, pos, SHUF(W, W, W, W));
1729    sse2_rcpss(cp->func, tmp, tmp);
1730    sse_shufps(cp->func, tmp, tmp, SHUF(X, X, X, X));
1731    
1732    sse_mulps(cp->func, pos, scale);
1733    sse_mulps(cp->func, pos, tmp);
1734    sse_addps(cp->func, pos, translate);
1735
1736    /* Set pos[3] = w 
1737     */
1738    mask_write(cp, pos, tmp, TGSI_WRITEMASK_W);
1739
1740    aos_adopt_xmm_reg( cp,
1741                       pos,
1742                       TGSI_FILE_OUTPUT,
1743                       0,
1744                       TRUE );
1745    return TRUE;
1746 }
1747
1748
1749 #if 0
1750 static boolean note_immediate( struct aos_compilation *cp,
1751                                struct tgsi_full_immediate *imm )
1752 {
1753    unsigned pos = cp->num_immediates++;
1754    unsigned j;
1755
1756    for (j = 0; j < imm->Immediate.Size; j++) {
1757       cp->vaos->machine->immediate[pos][j] = imm->u.ImmediateFloat32[j].Float;
1758    }
1759
1760    return TRUE;
1761 }
1762 #endif
1763
1764
1765
1766
1767 static void find_last_write_outputs( struct aos_compilation *cp )
1768 {
1769    struct tgsi_parse_context parse;
1770    unsigned this_instruction = 0;
1771    unsigned i;
1772
1773    tgsi_parse_init( &parse, cp->vaos->base.vs->state.tokens );
1774
1775    while (!tgsi_parse_end_of_tokens( &parse )) {
1776       
1777       tgsi_parse_token( &parse );
1778
1779       if (parse.FullToken.Token.Type != TGSI_TOKEN_TYPE_INSTRUCTION) 
1780          continue;
1781
1782       for (i = 0; i < TGSI_FULL_MAX_DST_REGISTERS; i++) {
1783          if (parse.FullToken.FullInstruction.FullDstRegisters[i].DstRegister.File ==
1784              TGSI_FILE_OUTPUT) 
1785          {
1786             unsigned idx = parse.FullToken.FullInstruction.FullDstRegisters[i].DstRegister.Index;
1787             cp->output_last_write[idx] = this_instruction;
1788          }
1789       }
1790
1791       this_instruction++;
1792    }
1793
1794    tgsi_parse_free( &parse );
1795 }
1796
1797
1798 #define ARG_MACHINE    1
1799 #define ARG_START_ELTS 2
1800 #define ARG_COUNT      3
1801 #define ARG_OUTBUF     4
1802
1803
1804 static boolean build_vertex_program( struct draw_vs_varient_aos_sse *varient,
1805                                      boolean linear )
1806
1807    struct tgsi_parse_context parse;
1808    struct aos_compilation cp;
1809    unsigned fixup, label;
1810
1811    tgsi_parse_init( &parse, varient->base.vs->state.tokens );
1812
1813    memset(&cp, 0, sizeof(cp));
1814
1815    cp.insn_counter = 1;
1816    cp.vaos = varient;
1817    cp.have_sse2 = 1;
1818    cp.func = &varient->func[ linear ? 0 : 1 ];
1819
1820    cp.tmp_EAX       = x86_make_reg(file_REG32, reg_AX);
1821    cp.idx_EBX      = x86_make_reg(file_REG32, reg_BX);
1822    cp.outbuf_ECX    = x86_make_reg(file_REG32, reg_CX);
1823    cp.machine_EDX   = x86_make_reg(file_REG32, reg_DX);
1824    cp.count_ESI     = x86_make_reg(file_REG32, reg_SI);
1825    cp.temp_EBP     = x86_make_reg(file_REG32, reg_BP);
1826    cp.stack_ESP = x86_make_reg( file_REG32, reg_SP );
1827
1828    x86_init_func(cp.func);
1829
1830    find_last_write_outputs(&cp);
1831
1832    x86_push(cp.func, cp.idx_EBX);
1833    x86_push(cp.func, cp.count_ESI);
1834    x86_push(cp.func, cp.temp_EBP);
1835
1836
1837    /* Load arguments into regs:
1838     */
1839    x86_mov(cp.func, cp.machine_EDX, x86_fn_arg(cp.func, ARG_MACHINE));
1840    x86_mov(cp.func, cp.idx_EBX, x86_fn_arg(cp.func, ARG_START_ELTS));
1841    x86_mov(cp.func, cp.count_ESI, x86_fn_arg(cp.func, ARG_COUNT));
1842    x86_mov(cp.func, cp.outbuf_ECX, x86_fn_arg(cp.func, ARG_OUTBUF));
1843
1844
1845    /* Compare count to zero and possibly bail.
1846     */
1847    x86_xor(cp.func, cp.tmp_EAX, cp.tmp_EAX);
1848    x86_cmp(cp.func, cp.count_ESI, cp.tmp_EAX);
1849    fixup = x86_jcc_forward(cp.func, cc_E);
1850
1851
1852    save_fpu_state( &cp );
1853    set_fpu_round_nearest( &cp );
1854
1855    /* Note address for loop jump 
1856     */
1857    label = x86_get_label(cp.func);
1858    {
1859       /* Fetch inputs...  TODO:  fetch lazily...
1860        */
1861       if (!aos_fetch_inputs( &cp, linear ))
1862          goto fail;
1863
1864       /* Emit the shader:
1865        */
1866       while( !tgsi_parse_end_of_tokens( &parse ) && !cp.error ) 
1867       {
1868          tgsi_parse_token( &parse );
1869
1870          switch (parse.FullToken.Token.Type) {
1871          case TGSI_TOKEN_TYPE_IMMEDIATE:
1872 #if 0
1873             if (!note_immediate( &cp, &parse.FullToken.FullImmediate ))
1874                goto fail;
1875 #endif
1876             break;
1877
1878          case TGSI_TOKEN_TYPE_INSTRUCTION:
1879             if (DISASSEM)
1880                tgsi_dump_instruction( &parse.FullToken.FullInstruction, cp.insn_counter );
1881
1882             if (!emit_instruction( &cp, &parse.FullToken.FullInstruction ))
1883                goto fail;
1884             break;
1885          }
1886
1887          x87_assert_stack_empty(cp.func);
1888          cp.insn_counter++;
1889
1890          if (DISASSEM)
1891             debug_printf("\n");
1892       }
1893
1894    
1895       {
1896          unsigned i;
1897          for (i = 0; i < 8; i++) {
1898             if (cp.xmm[i].file != TGSI_FILE_OUTPUT) {
1899                cp.xmm[i].file = TGSI_FILE_NULL;
1900                cp.xmm[i].dirty = 0;
1901             }
1902          }
1903       }
1904
1905       if (cp.error)
1906          goto fail;
1907
1908       if (cp.vaos->base.key.clip) {
1909          /* not really handling clipping, just do the rhw so we can
1910           * see the results...
1911           */
1912          emit_rhw_viewport(&cp); 
1913       }
1914       else if (cp.vaos->base.key.viewport) {
1915          emit_viewport(&cp);
1916       }
1917
1918       /* Emit output...  TODO: do this eagerly after the last write to a
1919        * given output.
1920        */
1921       if (!aos_emit_outputs( &cp ))
1922          goto fail;
1923
1924
1925       /* Next vertex:
1926        */
1927       x86_lea(cp.func, 
1928               cp.outbuf_ECX, 
1929               x86_make_disp(cp.outbuf_ECX, 
1930                             cp.vaos->base.key.output_stride));
1931
1932       /* Incr index
1933        */   
1934       if (linear) {
1935          x86_inc(cp.func, cp.idx_EBX);
1936       } 
1937       else {
1938          x86_lea(cp.func, cp.idx_EBX, x86_make_disp(cp.idx_EBX, 4));
1939       }
1940
1941    }
1942    /* decr count, loop if not zero
1943     */
1944    x86_dec(cp.func, cp.count_ESI);
1945    x86_jcc(cp.func, cc_NZ, label);
1946
1947    restore_fpu_state(&cp);
1948
1949    /* Land forward jump here:
1950     */
1951    x86_fixup_fwd_jump(cp.func, fixup);
1952
1953    /* Exit mmx state?
1954     */
1955    if (cp.func->need_emms)
1956       mmx_emms(cp.func);
1957
1958    x86_pop(cp.func, cp.temp_EBP);
1959    x86_pop(cp.func, cp.count_ESI);
1960    x86_pop(cp.func, cp.idx_EBX);
1961
1962    x87_assert_stack_empty(cp.func);
1963    x86_ret(cp.func);
1964
1965    tgsi_parse_free( &parse );
1966    return !cp.error;
1967
1968  fail:
1969    tgsi_parse_free( &parse );
1970    return FALSE;
1971 }
1972
1973
1974
1975 static void vaos_set_buffer( struct draw_vs_varient *varient,
1976                              unsigned buf,
1977                              const void *ptr,
1978                              unsigned stride )
1979 {
1980    struct draw_vs_varient_aos_sse *vaos = (struct draw_vs_varient_aos_sse *)varient;
1981    unsigned i;
1982
1983    for (i = 0; i < vaos->base.key.nr_inputs; i++) {
1984       if (vaos->base.key.element[i].in.buffer == buf) {
1985          vaos->attrib[i].input_ptr = ((char *)ptr +
1986                                       vaos->base.key.element[i].in.offset);
1987          vaos->attrib[i].input_stride = stride;
1988       }
1989    }
1990 }
1991
1992
1993
1994 static void PIPE_CDECL vaos_run_elts( struct draw_vs_varient *varient,
1995                                       const unsigned *elts,
1996                                       unsigned count,
1997                                       void *output_buffer )
1998 {
1999    struct draw_vs_varient_aos_sse *vaos = (struct draw_vs_varient_aos_sse *)varient;
2000    struct aos_machine *machine = vaos->draw->vs.aos_machine;
2001
2002    machine->internal[IMM_PSIZE][0] = vaos->draw->rasterizer->point_size;
2003    machine->constants = vaos->draw->vs.aligned_constants;
2004    machine->immediates = vaos->base.vs->immediates;
2005    machine->attrib = vaos->attrib;
2006
2007    vaos->gen_run_elts( machine,
2008                        elts,
2009                        count,
2010                        output_buffer );
2011 }
2012
2013 static void PIPE_CDECL vaos_run_linear( struct draw_vs_varient *varient,
2014                                         unsigned start,
2015                                         unsigned count,
2016                                         void *output_buffer )
2017 {
2018    struct draw_vs_varient_aos_sse *vaos = (struct draw_vs_varient_aos_sse *)varient;
2019    struct aos_machine *machine = vaos->draw->vs.aos_machine;
2020
2021    machine->internal[IMM_PSIZE][0] = vaos->draw->rasterizer->point_size;
2022    machine->constants = vaos->draw->vs.aligned_constants;
2023    machine->immediates = vaos->base.vs->immediates;
2024    machine->attrib = vaos->attrib;
2025
2026    vaos->gen_run_linear( machine,
2027                          start,
2028                          count,
2029                          output_buffer );
2030 }
2031
2032
2033
2034 static void vaos_destroy( struct draw_vs_varient *varient )
2035 {
2036    struct draw_vs_varient_aos_sse *vaos = (struct draw_vs_varient_aos_sse *)varient;
2037
2038    FREE( vaos->attrib );
2039
2040    x86_release_func( &vaos->func[0] );
2041    x86_release_func( &vaos->func[1] );
2042
2043    FREE(vaos);
2044 }
2045
2046
2047
2048 static struct draw_vs_varient *varient_aos_sse( struct draw_vertex_shader *vs,
2049                                                  const struct draw_vs_varient_key *key )
2050 {
2051    struct draw_vs_varient_aos_sse *vaos = CALLOC_STRUCT(draw_vs_varient_aos_sse);
2052
2053    if (!vaos)
2054       goto fail;
2055    
2056    vaos->base.key = *key;
2057    vaos->base.vs = vs;
2058    vaos->base.set_input = vaos_set_buffer;
2059    vaos->base.destroy = vaos_destroy;
2060    vaos->base.run_linear = vaos_run_linear;
2061    vaos->base.run_elts = vaos_run_elts;
2062
2063    vaos->draw = vs->draw;
2064
2065    vaos->attrib = MALLOC( key->nr_inputs * sizeof(vaos->attrib[0]) );
2066    if (!vaos->attrib)
2067       goto fail;
2068
2069    tgsi_dump(vs->state.tokens, 0);
2070
2071    if (!build_vertex_program( vaos, TRUE ))
2072       goto fail;
2073
2074    if (!build_vertex_program( vaos, FALSE ))
2075       goto fail;
2076
2077    vaos->gen_run_linear = (vaos_run_linear_func)x86_get_func(&vaos->func[0]);
2078    if (!vaos->gen_run_linear)
2079       goto fail;
2080
2081    vaos->gen_run_elts = (vaos_run_elts_func)x86_get_func(&vaos->func[1]);
2082    if (!vaos->gen_run_elts)
2083       goto fail;
2084
2085    return &vaos->base;
2086
2087  fail:
2088    if (vaos && vaos->attrib)
2089       FREE(vaos->attrib);
2090
2091    if (vaos)
2092       x86_release_func( &vaos->func[0] );
2093
2094    if (vaos)
2095       x86_release_func( &vaos->func[1] );
2096
2097    FREE(vaos);
2098    
2099    return NULL;
2100 }
2101
2102
2103 struct draw_vs_varient *draw_vs_varient_aos_sse( struct draw_vertex_shader *vs,
2104                                                  const struct draw_vs_varient_key *key )
2105 {
2106    struct draw_vs_varient *varient = varient_aos_sse( vs, key );
2107
2108    if (varient == NULL) {
2109       assert(0);
2110       varient = draw_vs_varient_generic( vs, key );
2111    }
2112
2113    return varient;
2114 }
2115
2116
2117
2118 #endif