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