diff options
author | Tom Stellard <tstellar@gmail.com> | 2010-07-13 21:25:27 -0700 |
---|---|---|
committer | Tom Stellard <tstellar@gmail.com> | 2010-09-10 18:18:08 -0700 |
commit | 63432ecfce5415fbf07f1781ec77b5ea3efff599 (patch) | |
tree | 903818a193704d2053ce79cf0c8a2d43c3cbaa88 /src/mesa/drivers/dri/r300/compiler/radeon_program_pair.c | |
parent | d8a36620089e72d431ae853ec168f193f3376782 (diff) |
r300/compiler: Enable presubtract sources
The r300 compiler can now emit instructions that select from the presubtract
source. A peephole optimization has been added to convert instructions like:
ADD Temp[0].x, none.1, -Temp[1].x into the INV (1 - src0) presubtract
operation.
Diffstat (limited to 'src/mesa/drivers/dri/r300/compiler/radeon_program_pair.c')
-rw-r--r-- | src/mesa/drivers/dri/r300/compiler/radeon_program_pair.c | 185 |
1 files changed, 174 insertions, 11 deletions
diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_program_pair.c b/src/mesa/drivers/dri/r300/compiler/radeon_program_pair.c index ee839596aa..5a50584b72 100644 --- a/src/mesa/drivers/dri/r300/compiler/radeon_program_pair.c +++ b/src/mesa/drivers/dri/r300/compiler/radeon_program_pair.c @@ -38,26 +38,52 @@ int rc_pair_alloc_source(struct rc_pair_instruction *pair, { int candidate = -1; int candidate_quality = -1; + unsigned int alpha_used = 0; + unsigned int rgb_used = 0; int i; if ((!rgb && !alpha) || file == RC_FILE_NONE) return 0; + if (rgb && pair->RGB.Src[RC_PAIR_PRESUB_SRC].Used) { + if (file == RC_FILE_PRESUB) { + if (index != pair->RGB.Src[RC_PAIR_PRESUB_SRC].Index) { + return -1; + } + } else { + rgb_used++; + } + } + + if (alpha && pair->Alpha.Src[RC_PAIR_PRESUB_SRC].Used) { + if (file == RC_FILE_PRESUB) { + if (index != pair->Alpha.Src[RC_PAIR_PRESUB_SRC].Index) { + return -1; + } + } else { + alpha_used++; + } + } + for(i = 0; i < 3; ++i) { int q = 0; if (rgb) { if (pair->RGB.Src[i].Used) { if (pair->RGB.Src[i].File != file || - pair->RGB.Src[i].Index != index) + pair->RGB.Src[i].Index != index) { + rgb_used++; continue; + } q++; } } if (alpha) { if (pair->Alpha.Src[i].Used) { if (pair->Alpha.Src[i].File != file || - pair->Alpha.Src[i].Index != index) + pair->Alpha.Src[i].Index != index) { + alpha_used++; continue; + } q++; } } @@ -66,19 +92,156 @@ int rc_pair_alloc_source(struct rc_pair_instruction *pair, candidate = i; } } + if (candidate < 0 || (rgb && rgb_used > 2) || (alpha && alpha_used > 2)) + return -1; - if (candidate >= 0) { - if (rgb) { - pair->RGB.Src[candidate].Used = 1; - pair->RGB.Src[candidate].File = file; - pair->RGB.Src[candidate].Index = index; + /* candidate >= 0 */ + + /* Even if we have a presub src, the above loop needs to run, + * because we still need to make sure there is a free source. + */ + if (file == RC_FILE_PRESUB) + candidate = RC_PAIR_PRESUB_SRC; + + if (rgb) { + pair->RGB.Src[candidate].Used = 1; + pair->RGB.Src[candidate].File = file; + pair->RGB.Src[candidate].Index = index; + if (candidate == RC_PAIR_PRESUB_SRC) { + /* For registers with the RC_FILE_PRESUB file, + * the index stores the presubtract op. */ + int src_regs = rc_presubtract_src_reg_count(index); + for(i = 0; i < src_regs; i++) { + pair->RGB.Src[i].Used = 1; + } } - if (alpha) { - pair->Alpha.Src[candidate].Used = 1; - pair->Alpha.Src[candidate].File = file; - pair->Alpha.Src[candidate].Index = index; + } + if (alpha) { + pair->Alpha.Src[candidate].Used = 1; + pair->Alpha.Src[candidate].File = file; + pair->Alpha.Src[candidate].Index = index; + if (candidate == RC_PAIR_PRESUB_SRC) { + /* For registers with the RC_FILE_PRESUB file, + * the index stores the presubtract op. */ + int src_regs = rc_presubtract_src_reg_count(index); + for(i=0; i < src_regs; i++) { + pair->Alpha.Src[i].Used = 1; + } } } return candidate; } + +static void pair_foreach_source_callback( + struct rc_pair_instruction * pair, + void * data, + rc_pair_foreach_src_fn cb, + unsigned int swz, + unsigned int src) +{ + /* swz > 3 means that the swizzle is either not used, or a constant + * swizzle (e.g. 0, 1, 0.5). */ + if(swz > 3) + return; + + if(swz == RC_SWIZZLE_W) { + if (src == RC_PAIR_PRESUB_SRC) { + unsigned int i; + unsigned int src_count = rc_presubtract_src_reg_count( + pair->Alpha.Src[RC_PAIR_PRESUB_SRC].Index); + for(i = 0; i < src_count; i++) { + cb(data, &pair->Alpha.Src[i]); + } + } else { + cb(data, &pair->Alpha.Src[src]); + } + } else { + if (src == RC_PAIR_PRESUB_SRC) { + unsigned int i; + unsigned int src_count = rc_presubtract_src_reg_count( + pair->RGB.Src[RC_PAIR_PRESUB_SRC].Index); + for(i = 0; i < src_count; i++) { + cb(data, &pair->RGB.Src[i]); + } + } + else { + cb(data, &pair->RGB.Src[src]); + } + } +} + +void rc_pair_foreach_source_that_alpha_reads( + struct rc_pair_instruction * pair, + void * data, + rc_pair_foreach_src_fn cb) +{ + unsigned int i; + const struct rc_opcode_info * info = + rc_get_opcode_info(pair->Alpha.Opcode); + for(i = 0; i < info->NumSrcRegs; i++) { + pair_foreach_source_callback(pair, data, cb, + GET_SWZ(pair->Alpha.Arg[i].Swizzle, 0), + pair->Alpha.Arg[i].Source); + } +} + +void rc_pair_foreach_source_that_rgb_reads( + struct rc_pair_instruction * pair, + void * data, + rc_pair_foreach_src_fn cb) +{ + unsigned int i; + const struct rc_opcode_info * info = + rc_get_opcode_info(pair->RGB.Opcode); + for(i = 0; i < info->NumSrcRegs; i++) { + unsigned int chan; + unsigned int swz = RC_SWIZZLE_UNUSED; + /* Find a swizzle that is either X,Y,Z,or W. We assume here + * that if one channel swizzles X,Y, or Z, then none of the + * other channels swizzle W, and vice-versa. */ + for(chan = 0; chan < 4; chan++) { + swz = GET_SWZ(pair->RGB.Arg[i].Swizzle, chan); + if(swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y + || swz == RC_SWIZZLE_Z || swz == RC_SWIZZLE_W) + continue; + } + pair_foreach_source_callback(pair, data, cb, + swz, + pair->RGB.Arg[i].Source); + } +} + +/*return 0 for rgb, 1 for alpha -1 for error. */ + +rc_pair_source_type rc_source_type_that_arg_reads( + unsigned int source, + unsigned int swizzle, + unsigned int channels) +{ + unsigned int chan; + unsigned int swz = RC_SWIZZLE_UNUSED; + int isRGB = 0; + int isAlpha = 0; + /* Find a swizzle that is either X,Y,Z,or W. We assume here + * that if one channel swizzles X,Y, or Z, then none of the + * other channels swizzle W, and vice-versa. */ + for(chan = 0; chan < channels; chan++) { + swz = GET_SWZ(swizzle, chan); + if (swz == RC_SWIZZLE_W) { + isAlpha = 1; + } else if (swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y + || swz == RC_SWIZZLE_Z) { + isRGB = 1; + } + } + assert(!isRGB || !isAlpha); + + if(!isRGB && !isAlpha) + return RC_PAIR_SOURCE_NONE; + + if (isRGB) + return RC_PAIR_SOURCE_RGB; + /*isAlpha*/ + return RC_PAIR_SOURCE_ALPHA; +} |