diff options
author | Roland Scheidegger <[email protected]> | 2016-01-02 04:59:09 +0100 |
---|---|---|
committer | Roland Scheidegger <[email protected]> | 2016-01-08 00:34:14 +0100 |
commit | 2923c7a0ed92a29da029183356e81ad55e615cf7 (patch) | |
tree | bd4f83e3bd33c2109472a7c4fc76dcdc6638cc01 /src/gallium/drivers | |
parent | fad283ba9e691d0d5d170f388e75542f2c39e559 (diff) |
llvmpipe: do 64bit plane calculations in the sse path
The sse path was pretty much disabled for practical purposes because the
largest allowed fb size was 128x128. So, adapt it for 64bit plane calculations.
This is actually not that difficult, though a problem is that we can't do
a signed 32x32->64bit mul, only unsigned, so need to fix that up. Overall,
the code still looks reasonable, though it's not like changes there in
setup really make much of a difference in the end...
Reviewed-by: Jose Fonseca <[email protected]>
Reviewed-by: Brian Paul <[email protected]>
Diffstat (limited to 'src/gallium/drivers')
-rw-r--r-- | src/gallium/drivers/llvmpipe/lp_setup_line.c | 16 | ||||
-rw-r--r-- | src/gallium/drivers/llvmpipe/lp_setup_tri.c | 104 |
2 files changed, 70 insertions, 50 deletions
diff --git a/src/gallium/drivers/llvmpipe/lp_setup_line.c b/src/gallium/drivers/llvmpipe/lp_setup_line.c index fac1cd61d77..a0de599c9c6 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup_line.c +++ b/src/gallium/drivers/llvmpipe/lp_setup_line.c @@ -644,19 +644,25 @@ try_setup_line( struct lp_setup_context *setup, line->inputs.layer = layer; line->inputs.viewport_index = viewport_index; + /* + * XXX: this code is mostly identical to the one in lp_setup_tri, except it + * uses 4 planes instead of 3. Could share the code (including the sse + * assembly, in fact we'd get the 4th plane for free). + * The only difference apart from storing the 4th plane would be some + * different shuffle for calculating dcdx/dcdy. + */ for (i = 0; i < 4; i++) { - /* half-edge constants, will be interated over the whole render + /* half-edge constants, will be iterated over the whole render * target. */ plane[i].c = IMUL64(plane[i].dcdx, x[i]) - IMUL64(plane[i].dcdy, y[i]); - - /* correct for top-left vs. bottom-left fill convention. - */ + /* correct for top-left vs. bottom-left fill convention. + */ if (plane[i].dcdx < 0) { /* both fill conventions want this - adjust for left edges */ - plane[i].c++; + plane[i].c++; } else if (plane[i].dcdx == 0) { if (setup->pixel_offset == 0) { diff --git a/src/gallium/drivers/llvmpipe/lp_setup_tri.c b/src/gallium/drivers/llvmpipe/lp_setup_tri.c index a1631fdaee9..358da442ea7 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup_tri.c +++ b/src/gallium/drivers/llvmpipe/lp_setup_tri.c @@ -390,26 +390,18 @@ do_triangle_ccw(struct lp_setup_context *setup, plane = GET_PLANES(tri); #if defined(PIPE_ARCH_SSE) - /* - * XXX this code is effectively disabled for all practical purposes, - * as the allowed fb size is tiny if FIXED_ORDER is 8. - */ - if (setup->fb.width <= MAX_FIXED_LENGTH32 && - setup->fb.height <= MAX_FIXED_LENGTH32 && - (bbox.x1 - bbox.x0) <= MAX_FIXED_LENGTH32 && - (bbox.y1 - bbox.y0) <= MAX_FIXED_LENGTH32) { + if (1) { __m128i vertx, verty; __m128i shufx, shufy; - __m128i dcdx, dcdy, c; - __m128i unused; + __m128i dcdx, dcdy; + __m128i cdx02, cdx13, cdy02, cdy13, c02, c13; + __m128i c01, c23, unused; __m128i dcdx_neg_mask; __m128i dcdy_neg_mask; __m128i dcdx_zero_mask; - __m128i top_left_flag; - __m128i c_inc_mask, c_inc; + __m128i top_left_flag, c_dec; __m128i eo, p0, p1, p2; __m128i zero = _mm_setzero_si128(); - PIPE_ALIGN_VAR(16) int32_t temp_vec[4]; vertx = _mm_load_si128((__m128i *)position->x); /* vertex x coords */ verty = _mm_load_si128((__m128i *)position->y); /* vertex y coords */ @@ -426,48 +418,70 @@ do_triangle_ccw(struct lp_setup_context *setup, top_left_flag = _mm_set1_epi32((setup->bottom_edge_rule == 0) ? ~0 : 0); - c_inc_mask = _mm_or_si128(dcdx_neg_mask, - _mm_and_si128(dcdx_zero_mask, - _mm_xor_si128(dcdy_neg_mask, - top_left_flag))); - - c_inc = _mm_srli_epi32(c_inc_mask, 31); - - c = _mm_sub_epi32(mm_mullo_epi32(dcdx, vertx), - mm_mullo_epi32(dcdy, verty)); + c_dec = _mm_or_si128(dcdx_neg_mask, + _mm_and_si128(dcdx_zero_mask, + _mm_xor_si128(dcdy_neg_mask, + top_left_flag))); - c = _mm_add_epi32(c, c_inc); + /* + * 64 bit arithmetic. + * Note we need _signed_ mul (_mm_mul_epi32) which we emulate. + */ + cdx02 = mm_mullohi_epi32(dcdx, vertx, &cdx13); + cdy02 = mm_mullohi_epi32(dcdy, verty, &cdy13); + c02 = _mm_sub_epi64(cdx02, cdy02); + c13 = _mm_sub_epi64(cdx13, cdy13); + c02 = _mm_sub_epi64(c02, _mm_shuffle_epi32(c_dec, + _MM_SHUFFLE(2,2,0,0))); + c13 = _mm_sub_epi64(c13, _mm_shuffle_epi32(c_dec, + _MM_SHUFFLE(3,3,1,1))); + + /* + * Useful for very small fbs/tris (or fewer subpixel bits) only: + * c = _mm_sub_epi32(mm_mullo_epi32(dcdx, vertx), + * mm_mullo_epi32(dcdy, verty)); + * + * c = _mm_sub_epi32(c, c_dec); + */ /* Scale up to match c: */ dcdx = _mm_slli_epi32(dcdx, FIXED_ORDER); dcdy = _mm_slli_epi32(dcdy, FIXED_ORDER); - /* Calculate trivial reject values: + /* + * Calculate trivial reject values: + * Note eo cannot overflow even if dcdx/dcdy would already have + * 31 bits (which they shouldn't have). This is because eo + * is never negative (albeit if we rely on that need to be careful...) */ eo = _mm_sub_epi32(_mm_andnot_si128(dcdy_neg_mask, dcdy), _mm_and_si128(dcdx_neg_mask, dcdx)); /* ei = _mm_sub_epi32(_mm_sub_epi32(dcdy, dcdx), eo); */ - /* Pointless transpose which gets undone immediately in - * rasterization: + /* + * Pointless transpose which gets undone immediately in + * rasterization. + * It is actually difficult to do away with it - would essentially + * need GET_PLANES_DX, GET_PLANES_DY etc., but the calculations + * for this then would need to depend on the number of planes. + * The transpose is quite special here due to c being 64bit... + * The store has to be unaligned (unless we'd make the plane size + * a multiple of 128), and of course storing eo separately... */ - transpose4_epi32(&c, &dcdx, &dcdy, &eo, - &p0, &p1, &p2, &unused); - -#define STORE_PLANE(plane, vec) do { \ - _mm_store_si128((__m128i *)&temp_vec, vec); \ - plane.c = (int64_t)temp_vec[0]; \ - plane.dcdx = temp_vec[1]; \ - plane.dcdy = temp_vec[2]; \ - plane.eo = temp_vec[3]; \ - } while(0) - - STORE_PLANE(plane[0], p0); - STORE_PLANE(plane[1], p1); - STORE_PLANE(plane[2], p2); -#undef STORE_PLANE + c01 = _mm_unpacklo_epi64(c02, c13); + c23 = _mm_unpackhi_epi64(c02, c13); + transpose2_64_2_32(&c01, &c23, &dcdx, &dcdy, + &p0, &p1, &p2, &unused); + _mm_storeu_si128((__m128i *)&plane[0], p0); + plane[0].eo = (uint32_t)_mm_cvtsi128_si32(eo); + _mm_storeu_si128((__m128i *)&plane[1], p1); + eo = _mm_shuffle_epi32(eo, _MM_SHUFFLE(3,2,0,1)); + plane[1].eo = (uint32_t)_mm_cvtsi128_si32(eo); + _mm_storeu_si128((__m128i *)&plane[2], p2); + eo = _mm_shuffle_epi32(eo, _MM_SHUFFLE(0,0,0,2)); + plane[2].eo = (uint32_t)_mm_cvtsi128_si32(eo); } else #elif defined(_ARCH_PWR8) && defined(PIPE_ARCH_LITTLE_ENDIAN) /* @@ -577,17 +591,17 @@ do_triangle_ccw(struct lp_setup_context *setup, plane[2].dcdx = position->dy20; for (i = 0; i < 3; i++) { - /* half-edge constants, will be interated over the whole render + /* half-edge constants, will be iterated over the whole render * target. */ plane[i].c = IMUL64(plane[i].dcdx, position->x[i]) - - IMUL64(plane[i].dcdy, position->y[i]); + IMUL64(plane[i].dcdy, position->y[i]); /* correct for top-left vs. bottom-left fill convention. - */ + */ if (plane[i].dcdx < 0) { /* both fill conventions want this - adjust for left edges */ - plane[i].c++; + plane[i].c++; } else if (plane[i].dcdx == 0) { if (setup->bottom_edge_rule == 0){ |