diff options
author | José Fonseca <[email protected]> | 2010-06-02 18:43:35 +0100 |
---|---|---|
committer | José Fonseca <[email protected]> | 2010-06-02 18:43:35 +0100 |
commit | ead58101f91e82279b25676dfe822120be611995 (patch) | |
tree | 2698c9fa8f327726c57e5cda971c88447ce134b1 /src | |
parent | 5871b7ebc9f9629c076c9fe3c9c32aa9fd531eba (diff) |
llvmpipe: Per quad interpolation.
First interpolate the 4 quads upper left corners, then sub-interpolate
each quad pixel. Do the perspective divide once per quad.
Saves some muls and reciprocates. But doesn't seem to make a
noticeable improvement.
It make the code simpler and more compact, so commiting anyway.
Diffstat (limited to 'src')
-rw-r--r-- | src/gallium/drivers/llvmpipe/lp_bld_interp.c | 317 | ||||
-rw-r--r-- | src/gallium/drivers/llvmpipe/lp_bld_interp.h | 9 |
2 files changed, 136 insertions, 190 deletions
diff --git a/src/gallium/drivers/llvmpipe/lp_bld_interp.c b/src/gallium/drivers/llvmpipe/lp_bld_interp.c index f0a0a0b6cfc..e73733e51c4 100644 --- a/src/gallium/drivers/llvmpipe/lp_bld_interp.c +++ b/src/gallium/drivers/llvmpipe/lp_bld_interp.c @@ -101,117 +101,141 @@ coeffs_init(struct lp_build_interp_soa_context *bld, { struct lp_build_context *coeff_bld = &bld->coeff_bld; LLVMBuilderRef builder = coeff_bld->builder; + LLVMValueRef zero = LLVMConstNull(coeff_bld->elem_type); + LLVMValueRef one = LLVMConstReal(coeff_bld->elem_type, 1.0); + LLVMValueRef i0 = LLVMConstInt(LLVMInt32Type(), 0, 0); + LLVMValueRef i1 = LLVMConstInt(LLVMInt32Type(), 1, 0); + LLVMValueRef i2 = LLVMConstInt(LLVMInt32Type(), 2, 0); + LLVMValueRef i3 = LLVMConstInt(LLVMInt32Type(), 3, 0); + LLVMValueRef oow = NULL; unsigned attrib; unsigned chan; - for(attrib = 0; attrib < bld->num_attribs; ++attrib) { + /* TODO: Use more vector operations */ + + for (attrib = 0; attrib < bld->num_attribs; ++attrib) { const unsigned mask = bld->mask[attrib]; const unsigned interp = bld->interp[attrib]; - for(chan = 0; chan < NUM_CHANNELS; ++chan) { - if(mask & (1 << chan)) { + for (chan = 0; chan < NUM_CHANNELS; ++chan) { + if (mask & (1 << chan)) { LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), attrib*NUM_CHANNELS + chan, 0); - LLVMValueRef a0 = coeff_bld->undef; - LLVMValueRef dadx = coeff_bld->undef; - LLVMValueRef dady = coeff_bld->undef; - - switch( interp ) { + LLVMValueRef a0 = zero; + LLVMValueRef dadx = zero; + LLVMValueRef dady = zero; + LLVMValueRef dadxy = zero; + LLVMValueRef dadq; + LLVMValueRef dadq2; + LLVMValueRef a; + + switch (interp) { case LP_INTERP_PERSPECTIVE: /* fall-through */ case LP_INTERP_LINEAR: - dadx = LLVMBuildLoad(builder, LLVMBuildGEP(builder, dadx_ptr, &index, 1, ""), ""); - dady = LLVMBuildLoad(builder, LLVMBuildGEP(builder, dady_ptr, &index, 1, ""), ""); - dadx = lp_build_broadcast_scalar(coeff_bld, dadx); - dady = lp_build_broadcast_scalar(coeff_bld, dady); - attrib_name(dadx, attrib, chan, ".dadx"); - attrib_name(dady, attrib, chan, ".dady"); + if (attrib == 0 && chan == 0) { + dadxy = dadx = one; + } + else if (attrib == 0 && chan == 1) { + dadxy = dady = one; + } + else { + dadx = LLVMBuildLoad(builder, LLVMBuildGEP(builder, dadx_ptr, &index, 1, ""), ""); + dady = LLVMBuildLoad(builder, LLVMBuildGEP(builder, dady_ptr, &index, 1, ""), ""); + dadxy = LLVMBuildAdd(builder, dadx, dady, ""); + attrib_name(dadx, attrib, chan, ".dadx"); + attrib_name(dady, attrib, chan, ".dady"); + attrib_name(dadxy, attrib, chan, ".dadxy"); + } /* fall-through */ case LP_INTERP_CONSTANT: case LP_INTERP_FACING: a0 = LLVMBuildLoad(builder, LLVMBuildGEP(builder, a0_ptr, &index, 1, ""), ""); - a0 = lp_build_broadcast_scalar(coeff_bld, a0); attrib_name(a0, attrib, chan, ".a0"); break; case LP_INTERP_POSITION: /* Nothing to do as the position coeffs are already setup in slot 0 */ - break; + continue; default: assert(0); break; } - bld->a0 [attrib][chan] = a0; - bld->dadx[attrib][chan] = dadx; - bld->dady[attrib][chan] = dady; - } - } - } -} + /* + * dadq = {0, dadx, dady, dadx + dady} + */ + dadq = coeff_bld->undef; + dadq = LLVMBuildInsertElement(builder, dadq, zero, i0, ""); + dadq = LLVMBuildInsertElement(builder, dadq, dadx, i1, ""); + dadq = LLVMBuildInsertElement(builder, dadq, dady, i2, ""); + dadq = LLVMBuildInsertElement(builder, dadq, dadxy, i3, ""); -/** - * Emit LLVM code to compute the fragment shader input attribute values. - * For example, for a color input, we'll compute red, green, blue and alpha - * values for the four pixels in a quad. - * Recall that we're operating on 4-element vectors so each arithmetic - * operation is operating on the four pixels in a quad. - */ -static void -attribs_init(struct lp_build_interp_soa_context *bld) -{ - struct lp_build_context *coeff_bld = &bld->coeff_bld; - LLVMValueRef x = bld->pos[0]; - LLVMValueRef y = bld->pos[1]; - LLVMValueRef oow = NULL; - unsigned attrib; - unsigned chan; + /* + * dadq2 = 2 * dq + */ - for(attrib = 0; attrib < bld->num_attribs; ++attrib) { - const unsigned mask = bld->mask[attrib]; - const unsigned interp = bld->interp[attrib]; - for(chan = 0; chan < NUM_CHANNELS; ++chan) { - if(mask & (1 << chan)) { - if (interp == LP_INTERP_POSITION) { - assert(attrib > 0); - bld->attribs[attrib][chan] = bld->attribs[0][chan]; - } - else { - LLVMValueRef a0 = bld->a0 [attrib][chan]; - LLVMValueRef dadx = bld->dadx[attrib][chan]; - LLVMValueRef dady = bld->dady[attrib][chan]; - LLVMValueRef res; + dadq2 = LLVMBuildAdd(builder, dadq, dadq, ""); - res = a0; + /* + * a = a0 + x * dadx + y * dady + */ + if (attrib == 0 && chan == 0) { + a = bld->x; + } + else if (attrib == 0 && chan == 1) { + a = bld->y; + } + else { + a = a0; if (interp != LP_INTERP_CONSTANT && interp != LP_INTERP_FACING) { - /* res = res + x * dadx */ - res = lp_build_add(coeff_bld, res, lp_build_mul(coeff_bld, x, dadx)); - /* res = res + y * dady */ - res = lp_build_add(coeff_bld, res, lp_build_mul(coeff_bld, y, dady)); + a = LLVMBuildAdd(builder, a, + LLVMBuildMul(builder, bld->x, dadx, ""), + ""); + a = LLVMBuildAdd(builder, a, + LLVMBuildMul(builder, bld->y, dady, ""), + ""); } + } - /* Keep the value of the attribute before perspective divide - * for faster updates. - */ - bld->attribs_pre[attrib][chan] = res; - - if (interp == LP_INTERP_PERSPECTIVE) { - LLVMValueRef w = bld->pos[3]; - assert(attrib != 0); - assert(bld->mask[0] & TGSI_WRITEMASK_W); - if(!oow) - oow = lp_build_rcp(coeff_bld, w); - res = lp_build_mul(coeff_bld, res, oow); - } + /* + * a = {a, a, a, a} + */ + + a = lp_build_broadcast(builder, coeff_bld->vec_type, a); + + /* + * Compute the attrib values on the upper-left corner of each quad. + */ - attrib_name(res, attrib, chan, ""); + a = LLVMBuildAdd(builder, a, dadq2, ""); - bld->attribs[attrib][chan] = res; + /* + * a *= 1 / w + * dadq *= 1 / w + */ + + if (interp == LP_INTERP_PERSPECTIVE) { + LLVMValueRef w = bld->a[0][3]; + assert(attrib != 0); + assert(bld->mask[0] & TGSI_WRITEMASK_W); + if (!oow) { + oow = lp_build_rcp(coeff_bld, w); + lp_build_name(oow, "oow"); + } + a = lp_build_mul(coeff_bld, a, oow); + dadq = lp_build_mul(coeff_bld, dadq, oow); } + + attrib_name(a, attrib, chan, ".a"); + attrib_name(dadq, attrib, chan, ".dadq"); + + bld->a [attrib][chan] = a; + bld->dadq[attrib][chan] = dadq; } } } @@ -226,7 +250,7 @@ static void attribs_update(struct lp_build_interp_soa_context *bld, int quad_index) { struct lp_build_context *coeff_bld = &bld->coeff_bld; - LLVMValueRef oow = NULL; + LLVMValueRef shuffle = lp_build_const_int_vec(coeff_bld->type, quad_index); unsigned attrib; unsigned chan; @@ -235,50 +259,36 @@ attribs_update(struct lp_build_interp_soa_context *bld, int quad_index) for(attrib = 0; attrib < bld->num_attribs; ++attrib) { const unsigned mask = bld->mask[attrib]; const unsigned interp = bld->interp[attrib]; + for(chan = 0; chan < NUM_CHANNELS; ++chan) { + if(mask & (1 << chan)) { + LLVMValueRef a = coeff_bld->undef; + if (interp == LP_INTERP_CONSTANT && + interp == LP_INTERP_FACING) { + a = bld->a[attrib][chan]; + } + else if (interp == LP_INTERP_POSITION) { + assert(attrib > 0); + a = bld->attribs[0][chan]; + } + else { + a = bld->a[attrib][chan]; - if (interp != LP_INTERP_CONSTANT && - interp != LP_INTERP_FACING) { - for(chan = 0; chan < NUM_CHANNELS; ++chan) { - if(mask & (1 << chan)) { - if (interp == LP_INTERP_POSITION) { - assert(attrib > 0); - bld->attribs[attrib][chan] = bld->attribs[0][chan]; - } - else { - LLVMValueRef dadx = bld->dadx[attrib][chan]; - LLVMValueRef dady = bld->dady[attrib][chan]; - LLVMValueRef res; - - res = bld->attribs_pre[attrib][chan]; - - if (quad_index == 1 || quad_index == 3) { - /* top-right or bottom-right quad */ - /* build res = res + dadx + dadx */ - res = lp_build_add(coeff_bld, res, dadx); - res = lp_build_add(coeff_bld, res, dadx); - } - - if (quad_index == 2 || quad_index == 3) { - /* bottom-left or bottom-right quad */ - /* build res = res + dady + dady */ - res = lp_build_add(coeff_bld, res, dady); - res = lp_build_add(coeff_bld, res, dady); - } - - if (interp == LP_INTERP_PERSPECTIVE) { - LLVMValueRef w = bld->pos[3]; - assert(attrib != 0); - assert(bld->mask[0] & TGSI_WRITEMASK_W); - if(!oow) - oow = lp_build_rcp(coeff_bld, w); - res = lp_build_mul(coeff_bld, res, oow); - } - - attrib_name(res, attrib, chan, ""); - - bld->attribs[attrib][chan] = res; - } + /* + * Broadcast the attribute value for this quad into all elements + */ + + a = LLVMBuildShuffleVector(coeff_bld->builder, + a, coeff_bld->undef, shuffle, ""); + + /* + * Add the derivatives + */ + + a = lp_build_add(coeff_bld, a, bld->dadq[attrib][chan]); + + attrib_name(a, attrib, chan, ""); } + bld->attribs[attrib][chan] = a; } } } @@ -296,70 +306,9 @@ pos_init(struct lp_build_interp_soa_context *bld, LLVMValueRef y0) { struct lp_build_context *coeff_bld = &bld->coeff_bld; - LLVMValueRef x_offsets[QUAD_SIZE]; - LLVMValueRef y_offsets[QUAD_SIZE]; - unsigned i; - - /* - * Derive from the quad's upper left scalar coordinates the coordinates for - * all other quad pixels - */ - - x0 = lp_build_broadcast(coeff_bld->builder, coeff_bld->int_vec_type, x0); - y0 = lp_build_broadcast(coeff_bld->builder, coeff_bld->int_vec_type, y0); - - for(i = 0; i < QUAD_SIZE; ++i) { - x_offsets[i] = LLVMConstInt(coeff_bld->int_elem_type, quad_offset_x[i], 0); - y_offsets[i] = LLVMConstInt(coeff_bld->int_elem_type, quad_offset_y[i], 0); - } - x0 = LLVMBuildAdd(coeff_bld->builder, x0, LLVMConstVector(x_offsets, QUAD_SIZE), ""); - y0 = LLVMBuildAdd(coeff_bld->builder, y0, LLVMConstVector(y_offsets, QUAD_SIZE), ""); - - x0 = LLVMBuildSIToFP(coeff_bld->builder, x0, coeff_bld->vec_type, ""); - y0 = LLVMBuildSIToFP(coeff_bld->builder, y0, coeff_bld->vec_type, ""); - - lp_build_name(x0, "pos.x"); - lp_build_name(y0, "pos.y"); - - bld->attribs[0][0] = x0; - bld->attribs[0][1] = y0; -} - - -/** - * Update quad position values when moving to the next quad. - */ -static void -pos_update(struct lp_build_interp_soa_context *bld, int quad_index) -{ - struct lp_build_context *coeff_bld = &bld->coeff_bld; - LLVMValueRef x = bld->attribs[0][0]; - LLVMValueRef y = bld->attribs[0][1]; - const int xstep = 2, ystep = 2; - - if (quad_index == 1 || quad_index == 3) { - /* top-right or bottom-right quad in block */ - /* build x += xstep */ - x = lp_build_add(coeff_bld, x, - lp_build_const_vec(coeff_bld->type, xstep)); - } - - if (quad_index == 2) { - /* bottom-left quad in block */ - /* build y += ystep */ - y = lp_build_add(coeff_bld, y, - lp_build_const_vec(coeff_bld->type, ystep)); - /* build x -= xstep */ - x = lp_build_sub(coeff_bld, x, - lp_build_const_vec(coeff_bld->type, xstep)); - } - - lp_build_name(x, "pos.x"); - lp_build_name(y, "pos.y"); - - bld->attribs[0][0] = x; - bld->attribs[0][1] = y; + bld->x = LLVMBuildSIToFP(coeff_bld->builder, x0, coeff_bld->elem_type, ""); + bld->y = LLVMBuildSIToFP(coeff_bld->builder, y0, coeff_bld->elem_type, ""); } @@ -401,7 +350,7 @@ lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld, /* Position */ bld->num_attribs = 1; - bld->mask[0] = TGSI_WRITEMASK_ZW; + bld->mask[0] = TGSI_WRITEMASK_XYZW; bld->interp[0] = LP_INTERP_LINEAR; /* Inputs */ @@ -418,11 +367,11 @@ lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld, } } - coeffs_init(bld, a0_ptr, dadx_ptr, dady_ptr); - pos_init(bld, x0, y0); - attribs_init(bld); + coeffs_init(bld, a0_ptr, dadx_ptr, dady_ptr); + + attribs_update(bld, 0); } @@ -435,7 +384,5 @@ lp_build_interp_soa_update(struct lp_build_interp_soa_context *bld, { assert(quad_index < 4); - pos_update(bld, quad_index); - attribs_update(bld, quad_index); } diff --git a/src/gallium/drivers/llvmpipe/lp_bld_interp.h b/src/gallium/drivers/llvmpipe/lp_bld_interp.h index 45a430701fb..29055133011 100644 --- a/src/gallium/drivers/llvmpipe/lp_bld_interp.h +++ b/src/gallium/drivers/llvmpipe/lp_bld_interp.h @@ -58,12 +58,11 @@ struct lp_build_interp_soa_context unsigned mask[1 + PIPE_MAX_SHADER_INPUTS]; /**< TGSI_WRITE_MASK_x */ enum lp_interp interp[1 + PIPE_MAX_SHADER_INPUTS]; - LLVMValueRef a0 [1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS]; - LLVMValueRef dadx[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS]; - LLVMValueRef dady[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS]; + LLVMValueRef x; + LLVMValueRef y; - /* Attribute values before perspective divide */ - LLVMValueRef attribs_pre[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS]; + LLVMValueRef a [1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS]; + LLVMValueRef dadq[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS]; LLVMValueRef attribs[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS]; |