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.
This commit is contained in:
José Fonseca
2010-06-02 18:43:35 +01:00
parent 5871b7ebc9
commit ead58101f9
2 changed files with 139 additions and 193 deletions
+135 -188
View File
@@ -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;
LLVMValueRef a0 = zero;
LLVMValueRef dadx = zero;
LLVMValueRef dady = zero;
LLVMValueRef dadxy = zero;
LLVMValueRef dadq;
LLVMValueRef dadq2;
LLVMValueRef a;
switch( interp ) {
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];
dadq2 = LLVMBuildAdd(builder, dadq, dadq, "");
/*
* a = a0 + x * dadx + y * dady
*/
if (attrib == 0 && chan == 0) {
a = bld->x;
}
else if (attrib == 0 && chan == 1) {
a = bld->y;
}
else {
LLVMValueRef a0 = bld->a0 [attrib][chan];
LLVMValueRef dadx = bld->dadx[attrib][chan];
LLVMValueRef dady = bld->dady[attrib][chan];
LLVMValueRef res;
res = a0;
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);
}
attrib_name(res, attrib, chan, "");
bld->attribs[attrib][chan] = res;
}
/*
* 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.
*/
a = LLVMBuildAdd(builder, a, dadq2, "");
/*
* 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];
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;
}
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];
/*
* 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);
}
+4 -5
View File
@@ -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];