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