qword __float_unssidf (qword SI) { qword t0, t1, t2, t3, t4, t5, t6, t7; t0 = si_clz (SI); t1 = si_il (1054); t2 = si_shl (SI, t0); t3 = si_ceqi (t0, 32); t4 = si_sf (t0, t1); t5 = si_a (t2, t2); t6 = si_andc (t4, t3); t7 = si_shufb (t6, t5, *(const qword *) __sidf_pat); return si_shlqbii (t7, 4); }
qword __float_unsdidf (qword DI) { qword t0, t1, t2, t3, t4, t5, t6, t7, t8; t0 = si_clz (DI); t1 = si_shl (DI, t0); t2 = si_ceqi (t0, 32); t3 = si_sf (t0, *(const qword *) __didf_scale); t4 = si_a (t1, t1); t5 = si_andc (t3, t2); t6 = si_shufb (t5, t4, *(const qword *) __didf_pat); t7 = si_shlqbii (t6, 4); t8 = si_shlqbyi (t7, 8); return si_dfa (t7, t8); }
/** * Sort vertices from top to bottom. * Compute area and determine front vs. back facing. * Do coarse clip test against tile bounds * \return FALSE if tri is totally outside tile, TRUE otherwise */ static boolean setup_sort_vertices(const qword vs) { float area, sign; #if DEBUG_VERTS if (spu.init.id==0) { fprintf(stderr, "SPU %u: Triangle:\n", spu.init.id); print_vertex(v0); print_vertex(v1); print_vertex(v2); } #endif { /* Load the float values for various processing... */ const qword f0 = (qword)(((const struct vertex_header*)si_to_ptr(vs))->data[0]); const qword f1 = (qword)(((const struct vertex_header*)si_to_ptr(si_rotqbyi(vs, 4)))->data[0]); const qword f2 = (qword)(((const struct vertex_header*)si_to_ptr(si_rotqbyi(vs, 8)))->data[0]); /* Check if triangle is completely outside the tile bounds * Find the min and max x and y positions of the three poits */ const qword minf = min3fq(f0, f1, f2); const qword maxf = max3fq(f0, f1, f2); /* Compare min and max against cliprect vals */ const qword maxsmins = si_shufb(maxf, minf, SHUFB4(A,B,a,b)); const qword outside = si_fcgt(maxsmins, si_csflt(setup.cliprect, 0)); /* Use a little magic to work out of the tri is visible or not */ if(si_to_uint(si_xori(si_gb(outside), 0xc))) return FALSE; /* determine bottom to top order of vertices */ /* A table of shuffle patterns for putting vertex_header pointers into correct order. Quite magical. */ const qword sort_order_patterns[] = { SHUFB4(A,B,C,C), SHUFB4(C,A,B,C), SHUFB4(A,C,B,C), SHUFB4(B,C,A,C), SHUFB4(B,A,C,C), SHUFB4(C,B,A,C) }; /* Collate y values into two vectors for comparison. Using only one shuffle constant! ;) */ const qword y_02_ = si_shufb(f0, f2, SHUFB4(0,B,b,C)); const qword y_10_ = si_shufb(f1, f0, SHUFB4(0,B,b,C)); const qword y_012 = si_shufb(y_02_, f1, SHUFB4(0,B,b,C)); const qword y_120 = si_shufb(y_10_, f2, SHUFB4(0,B,b,C)); /* Perform comparison: {y0,y1,y2} > {y1,y2,y0} */ const qword compare = si_fcgt(y_012, y_120); /* Compress the result of the comparison into 4 bits */ const qword gather = si_gb(compare); /* Subtract one to attain the index into the LUT. Magical. */ const unsigned int index = si_to_uint(gather) - 1; /* Load the appropriate pattern and construct the desired vector. */ setup.vertex_headers = si_shufb(vs, vs, sort_order_patterns[index]); /* Using the result of the comparison, set sign. Very magical. */ sign = ((si_to_uint(si_cntb(gather)) == 2) ? 1.0f : -1.0f); } setup.ebot.ds = spu_sub(setup.vmid->data[0], setup.vmin->data[0]); setup.emaj.ds = spu_sub(setup.vmax->data[0], setup.vmin->data[0]); setup.etop.ds = spu_sub(setup.vmax->data[0], setup.vmid->data[0]); /* * Compute triangle's area. Use 1/area to compute partial * derivatives of attributes later. */ area = setup.emaj.dx * setup.ebot.dy - setup.ebot.dx * setup.emaj.dy; setup.oneOverArea = 1.0f / area; /* The product of area * sign indicates front/back orientation (0/1). * Just in case someone gets the bright idea of switching the front * and back constants without noticing that we're assuming their * values in this operation, also assert that the values are * what we think they are. */ ASSERT(CELL_FACING_FRONT == 0); ASSERT(CELL_FACING_BACK == 1); setup.facing = (area * sign > 0.0f) ^ (spu.rasterizer.front_winding == PIPE_WINDING_CW); return TRUE; }