X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fauxiliary%2Ftgsi%2Ftgsi_exec.c;h=126259fc0f86612c5a990a8df94fde7c210c93c8;hb=d335b6abc0eaa7506203df7c99898645214b4c72;hp=3de15730e759508fd9ab998b6770ba1b8894c2c1;hpb=88db6f0a73cd988b14e95e5f506b4e5ac355f065;p=mesa.git diff --git a/src/gallium/auxiliary/tgsi/tgsi_exec.c b/src/gallium/auxiliary/tgsi/tgsi_exec.c index 3de15730e75..126259fc0f8 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_exec.c +++ b/src/gallium/auxiliary/tgsi/tgsi_exec.c @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright 2007-2008 VMware, Inc. * All Rights Reserved. * Copyright 2009-2010 VMware, Inc. All rights Reserved. * @@ -19,7 +19,7 @@ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -58,6 +58,7 @@ #include "tgsi/tgsi_parse.h" #include "tgsi/tgsi_util.h" #include "tgsi_exec.h" +#include "util/u_half.h" #include "util/u_memory.h" #include "util/u_math.h" @@ -72,6 +73,16 @@ #define TILE_BOTTOM_LEFT 2 #define TILE_BOTTOM_RIGHT 3 +union tgsi_double_channel { + double d[TGSI_QUAD_SIZE]; + unsigned u[TGSI_QUAD_SIZE][2]; +}; + +struct tgsi_double_vector { + union tgsi_double_channel xy; + union tgsi_double_channel zw; +}; + static void micro_abs(union tgsi_exec_channel *dst, const union tgsi_exec_channel *src) @@ -136,18 +147,6 @@ micro_cmp(union tgsi_exec_channel *dst, dst->f[3] = src0->f[3] < 0.0f ? src1->f[3] : src2->f[3]; } -static void -micro_cnd(union tgsi_exec_channel *dst, - const union tgsi_exec_channel *src0, - const union tgsi_exec_channel *src1, - const union tgsi_exec_channel *src2) -{ - dst->f[0] = src2->f[0] > 0.5f ? src0->f[0] : src1->f[0]; - dst->f[1] = src2->f[1] > 0.5f ? src0->f[1] : src1->f[1]; - dst->f[2] = src2->f[2] > 0.5f ? src0->f[2] : src1->f[2]; - dst->f[3] = src2->f[3] > 0.5f ? src0->f[3] : src1->f[3]; -} - static void micro_cos(union tgsi_exec_channel *dst, const union tgsi_exec_channel *src) @@ -158,6 +157,55 @@ micro_cos(union tgsi_exec_channel *dst, dst->f[3] = cosf(src->f[3]); } +static void +micro_d2f(union tgsi_exec_channel *dst, + const union tgsi_double_channel *src) +{ + dst->f[0] = (float)src->d[0]; + dst->f[1] = (float)src->d[1]; + dst->f[2] = (float)src->d[2]; + dst->f[3] = (float)src->d[3]; +} + +static void +micro_d2i(union tgsi_exec_channel *dst, + const union tgsi_double_channel *src) +{ + dst->i[0] = (int)src->d[0]; + dst->i[1] = (int)src->d[1]; + dst->i[2] = (int)src->d[2]; + dst->i[3] = (int)src->d[3]; +} + +static void +micro_d2u(union tgsi_exec_channel *dst, + const union tgsi_double_channel *src) +{ + dst->u[0] = (unsigned)src->d[0]; + dst->u[1] = (unsigned)src->d[1]; + dst->u[2] = (unsigned)src->d[2]; + dst->u[3] = (unsigned)src->d[3]; +} +static void +micro_dabs(union tgsi_double_channel *dst, + const union tgsi_double_channel *src) +{ + dst->d[0] = src->d[0] >= 0.0 ? src->d[0] : -src->d[0]; + dst->d[1] = src->d[1] >= 0.0 ? src->d[1] : -src->d[1]; + dst->d[2] = src->d[2] >= 0.0 ? src->d[2] : -src->d[2]; + dst->d[3] = src->d[3] >= 0.0 ? src->d[3] : -src->d[3]; +} + +static void +micro_dadd(union tgsi_double_channel *dst, + const union tgsi_double_channel *src) +{ + dst->d[0] = src[0].d[0] + src[1].d[0]; + dst->d[1] = src[0].d[1] + src[1].d[1]; + dst->d[2] = src[0].d[2] + src[1].d[2]; + dst->d[3] = src[0].d[3] + src[1].d[3]; +} + static void micro_ddx(union tgsi_exec_channel *dst, const union tgsi_exec_channel *src) @@ -178,6 +226,158 @@ micro_ddy(union tgsi_exec_channel *dst, dst->f[3] = src->f[TILE_BOTTOM_LEFT] - src->f[TILE_TOP_LEFT]; } +static void +micro_dmul(union tgsi_double_channel *dst, + const union tgsi_double_channel *src) +{ + dst->d[0] = src[0].d[0] * src[1].d[0]; + dst->d[1] = src[0].d[1] * src[1].d[1]; + dst->d[2] = src[0].d[2] * src[1].d[2]; + dst->d[3] = src[0].d[3] * src[1].d[3]; +} + +static void +micro_dmax(union tgsi_double_channel *dst, + const union tgsi_double_channel *src) +{ + dst->d[0] = src[0].d[0] > src[1].d[0] ? src[0].d[0] : src[1].d[0]; + dst->d[1] = src[0].d[1] > src[1].d[1] ? src[0].d[1] : src[1].d[1]; + dst->d[2] = src[0].d[2] > src[1].d[2] ? src[0].d[2] : src[1].d[2]; + dst->d[3] = src[0].d[3] > src[1].d[3] ? src[0].d[3] : src[1].d[3]; +} + +static void +micro_dmin(union tgsi_double_channel *dst, + const union tgsi_double_channel *src) +{ + dst->d[0] = src[0].d[0] < src[1].d[0] ? src[0].d[0] : src[1].d[0]; + dst->d[1] = src[0].d[1] < src[1].d[1] ? src[0].d[1] : src[1].d[1]; + dst->d[2] = src[0].d[2] < src[1].d[2] ? src[0].d[2] : src[1].d[2]; + dst->d[3] = src[0].d[3] < src[1].d[3] ? src[0].d[3] : src[1].d[3]; +} + +static void +micro_dneg(union tgsi_double_channel *dst, + const union tgsi_double_channel *src) +{ + dst->d[0] = -src->d[0]; + dst->d[1] = -src->d[1]; + dst->d[2] = -src->d[2]; + dst->d[3] = -src->d[3]; +} + +static void +micro_dslt(union tgsi_double_channel *dst, + const union tgsi_double_channel *src) +{ + dst->u[0][0] = src[0].d[0] < src[1].d[0] ? ~0U : 0U; + dst->u[1][0] = src[0].d[1] < src[1].d[1] ? ~0U : 0U; + dst->u[2][0] = src[0].d[2] < src[1].d[2] ? ~0U : 0U; + dst->u[3][0] = src[0].d[3] < src[1].d[3] ? ~0U : 0U; +} + +static void +micro_dsne(union tgsi_double_channel *dst, + const union tgsi_double_channel *src) +{ + dst->u[0][0] = src[0].d[0] != src[1].d[0] ? ~0U : 0U; + dst->u[1][0] = src[0].d[1] != src[1].d[1] ? ~0U : 0U; + dst->u[2][0] = src[0].d[2] != src[1].d[2] ? ~0U : 0U; + dst->u[3][0] = src[0].d[3] != src[1].d[3] ? ~0U : 0U; +} + +static void +micro_dsge(union tgsi_double_channel *dst, + const union tgsi_double_channel *src) +{ + dst->u[0][0] = src[0].d[0] >= src[1].d[0] ? ~0U : 0U; + dst->u[1][0] = src[0].d[1] >= src[1].d[1] ? ~0U : 0U; + dst->u[2][0] = src[0].d[2] >= src[1].d[2] ? ~0U : 0U; + dst->u[3][0] = src[0].d[3] >= src[1].d[3] ? ~0U : 0U; +} + +static void +micro_dseq(union tgsi_double_channel *dst, + const union tgsi_double_channel *src) +{ + dst->u[0][0] = src[0].d[0] == src[1].d[0] ? ~0U : 0U; + dst->u[1][0] = src[0].d[1] == src[1].d[1] ? ~0U : 0U; + dst->u[2][0] = src[0].d[2] == src[1].d[2] ? ~0U : 0U; + dst->u[3][0] = src[0].d[3] == src[1].d[3] ? ~0U : 0U; +} + +static void +micro_drcp(union tgsi_double_channel *dst, + const union tgsi_double_channel *src) +{ + dst->d[0] = 1.0 / src->d[0]; + dst->d[1] = 1.0 / src->d[1]; + dst->d[2] = 1.0 / src->d[2]; + dst->d[3] = 1.0 / src->d[3]; +} + +static void +micro_dsqrt(union tgsi_double_channel *dst, + const union tgsi_double_channel *src) +{ + dst->d[0] = sqrt(src->d[0]); + dst->d[1] = sqrt(src->d[1]); + dst->d[2] = sqrt(src->d[2]); + dst->d[3] = sqrt(src->d[3]); +} + +static void +micro_drsq(union tgsi_double_channel *dst, + const union tgsi_double_channel *src) +{ + dst->d[0] = 1.0 / sqrt(src->d[0]); + dst->d[1] = 1.0 / sqrt(src->d[1]); + dst->d[2] = 1.0 / sqrt(src->d[2]); + dst->d[3] = 1.0 / sqrt(src->d[3]); +} + +static void +micro_dmad(union tgsi_double_channel *dst, + const union tgsi_double_channel *src) +{ + dst->d[0] = src[0].d[0] * src[1].d[0] + src[2].d[0]; + dst->d[1] = src[0].d[1] * src[1].d[1] + src[2].d[1]; + dst->d[2] = src[0].d[2] * src[1].d[2] + src[2].d[2]; + dst->d[3] = src[0].d[3] * src[1].d[3] + src[2].d[3]; +} + +static void +micro_dfrac(union tgsi_double_channel *dst, + const union tgsi_double_channel *src) +{ + dst->d[0] = src->d[0] - floor(src->d[0]); + dst->d[1] = src->d[1] - floor(src->d[1]); + dst->d[2] = src->d[2] - floor(src->d[2]); + dst->d[3] = src->d[3] - floor(src->d[3]); +} + +static void +micro_dldexp(union tgsi_double_channel *dst, + const union tgsi_double_channel *src0, + union tgsi_exec_channel *src1) +{ + dst->d[0] = ldexp(src0->d[0], src1->i[0]); + dst->d[1] = ldexp(src0->d[1], src1->i[1]); + dst->d[2] = ldexp(src0->d[2], src1->i[2]); + dst->d[3] = ldexp(src0->d[3], src1->i[3]); +} + +static void +micro_dfracexp(union tgsi_double_channel *dst, + union tgsi_exec_channel *dst_exp, + const union tgsi_double_channel *src) +{ + dst->d[0] = frexp(src->d[0], &dst_exp->i[0]); + dst->d[1] = frexp(src->d[1], &dst_exp->i[1]); + dst->d[2] = frexp(src->d[2], &dst_exp->i[2]); + dst->d[3] = frexp(src->d[3], &dst_exp->i[3]); +} + static void micro_exp2(union tgsi_exec_channel *dst, const union tgsi_exec_channel *src) @@ -212,6 +412,16 @@ micro_exp2(union tgsi_exec_channel *dst, #endif /* FAST_MATH */ } +static void +micro_f2d(union tgsi_double_channel *dst, + const union tgsi_exec_channel *src) +{ + dst->d[0] = (double)src->f[0]; + dst->d[1] = (double)src->f[1]; + dst->d[2] = (double)src->f[2]; + dst->d[3] = (double)src->f[3]; +} + static void micro_flr(union tgsi_exec_channel *dst, const union tgsi_exec_channel *src) @@ -232,6 +442,16 @@ micro_frc(union tgsi_exec_channel *dst, dst->f[3] = src->f[3] - floorf(src->f[3]); } +static void +micro_i2d(union tgsi_double_channel *dst, + const union tgsi_exec_channel *src) +{ + dst->d[0] = (double)src->i[0]; + dst->d[1] = (double)src->i[1]; + dst->d[2] = (double)src->i[2]; + dst->d[3] = (double)src->i[3]; +} + static void micro_iabs(union tgsi_exec_channel *dst, const union tgsi_exec_channel *src) @@ -339,20 +559,20 @@ micro_rsq(union tgsi_exec_channel *dst, assert(src->f[2] != 0.0f); assert(src->f[3] != 0.0f); #endif - dst->f[0] = 1.0f / sqrtf(fabsf(src->f[0])); - dst->f[1] = 1.0f / sqrtf(fabsf(src->f[1])); - dst->f[2] = 1.0f / sqrtf(fabsf(src->f[2])); - dst->f[3] = 1.0f / sqrtf(fabsf(src->f[3])); + dst->f[0] = 1.0f / sqrtf(src->f[0]); + dst->f[1] = 1.0f / sqrtf(src->f[1]); + dst->f[2] = 1.0f / sqrtf(src->f[2]); + dst->f[3] = 1.0f / sqrtf(src->f[3]); } static void micro_sqrt(union tgsi_exec_channel *dst, const union tgsi_exec_channel *src) { - dst->f[0] = sqrtf(fabsf(src->f[0])); - dst->f[1] = sqrtf(fabsf(src->f[1])); - dst->f[2] = sqrtf(fabsf(src->f[2])); - dst->f[3] = sqrtf(fabsf(src->f[3])); + dst->f[0] = sqrtf(src->f[0]); + dst->f[1] = sqrtf(src->f[1]); + dst->f[2] = sqrtf(src->f[2]); + dst->f[3] = sqrtf(src->f[3]); } static void @@ -451,24 +671,6 @@ micro_sne(union tgsi_exec_channel *dst, dst->f[3] = src0->f[3] != src1->f[3] ? 1.0f : 0.0f; } -static void -micro_sfl(union tgsi_exec_channel *dst) -{ - dst->f[0] = 0.0f; - dst->f[1] = 0.0f; - dst->f[2] = 0.0f; - dst->f[3] = 0.0f; -} - -static void -micro_str(union tgsi_exec_channel *dst) -{ - dst->f[0] = 1.0f; - dst->f[1] = 1.0f; - dst->f[2] = 1.0f; - dst->f[3] = 1.0f; -} - static void micro_trunc(union tgsi_exec_channel *dst, const union tgsi_exec_channel *src) @@ -479,11 +681,21 @@ micro_trunc(union tgsi_exec_channel *dst, dst->f[3] = (float)(int)src->f[3]; } +static void +micro_u2d(union tgsi_double_channel *dst, + const union tgsi_exec_channel *src) +{ + dst->d[0] = (double)src->u[0]; + dst->d[1] = (double)src->u[1]; + dst->d[2] = (double)src->u[2]; + dst->d[3] = (double)src->u[3]; +} enum tgsi_exec_datatype { TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_INT, - TGSI_EXEC_DATA_UINT + TGSI_EXEC_DATA_UINT, + TGSI_EXEC_DATA_DOUBLE }; /* @@ -524,7 +736,7 @@ static const union tgsi_exec_channel M128Vec = { * not lead to crashes, etc. But when debugging, it's helpful to catch * them. */ -static INLINE void +static inline void check_inf_or_nan(const union tgsi_exec_channel *chan) { assert(!util_is_inf_or_nan((chan)->f[0])); @@ -689,7 +901,7 @@ tgsi_exec_machine_bind_shader( struct tgsi_exec_vector *outputs; inputs = align_malloc(sizeof(struct tgsi_exec_vector) * - TGSI_MAX_PRIM_VERTICES * PIPE_MAX_ATTRIBS, + TGSI_MAX_PRIM_VERTICES * PIPE_MAX_SHADER_INPUTS, 16); if (!inputs) @@ -789,6 +1001,11 @@ tgsi_exec_machine_bind_shader( break; case TGSI_TOKEN_TYPE_PROPERTY: + if (mach->Processor == TGSI_PROCESSOR_GEOMETRY) { + if (parse.FullToken.FullProperty.Property.PropertyName == TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES) { + mach->MaxOutputVertices = parse.FullToken.FullProperty.u[0].Data; + } + } break; default: @@ -823,8 +1040,8 @@ tgsi_exec_machine_create( void ) mach->MaxGeometryShaderOutputs = TGSI_MAX_TOTAL_VERTICES; mach->Predicates = &mach->Temps[TGSI_EXEC_TEMP_P0]; - mach->Inputs = align_malloc(sizeof(struct tgsi_exec_vector) * PIPE_MAX_ATTRIBS, 16); - mach->Outputs = align_malloc(sizeof(struct tgsi_exec_vector) * PIPE_MAX_ATTRIBS, 16); + mach->Inputs = align_malloc(sizeof(struct tgsi_exec_vector) * PIPE_MAX_SHADER_INPUTS, 16); + mach->Outputs = align_malloc(sizeof(struct tgsi_exec_vector) * PIPE_MAX_SHADER_OUTPUTS, 16); if (!mach->Inputs || !mach->Outputs) goto fail; @@ -905,40 +1122,6 @@ micro_div( } } -static void -micro_rcc(union tgsi_exec_channel *dst, - const union tgsi_exec_channel *src) -{ - uint i; - - for (i = 0; i < 4; i++) { - float recip = 1.0f / src->f[i]; - - if (recip > 0.0f) { - if (recip > 1.884467e+019f) { - dst->f[i] = 1.884467e+019f; - } - else if (recip < 5.42101e-020f) { - dst->f[i] = 5.42101e-020f; - } - else { - dst->f[i] = recip; - } - } - else { - if (recip < -1.884467e+019f) { - dst->f[i] = -1.884467e+019f; - } - else if (recip > -5.42101e-020f) { - dst->f[i] = -5.42101e-020f; - } - else { - dst->f[i] = recip; - } - } - } -} - static void micro_lt( union tgsi_exec_channel *dst, @@ -1149,11 +1332,11 @@ fetch_src_file_channel(const struct tgsi_exec_machine *mach, } static void -fetch_source(const struct tgsi_exec_machine *mach, - union tgsi_exec_channel *chan, - const struct tgsi_full_src_register *reg, - const uint chan_index, - enum tgsi_exec_datatype src_datatype) +fetch_source_d(const struct tgsi_exec_machine *mach, + union tgsi_exec_channel *chan, + const struct tgsi_full_src_register *reg, + const uint chan_index, + enum tgsi_exec_datatype src_datatype) { union tgsi_exec_channel index; union tgsi_exec_channel index2D; @@ -1296,6 +1479,16 @@ fetch_source(const struct tgsi_exec_machine *mach, &index, &index2D, chan); +} + +static void +fetch_source(const struct tgsi_exec_machine *mach, + union tgsi_exec_channel *chan, + const struct tgsi_full_src_register *reg, + const uint chan_index, + enum tgsi_exec_datatype src_datatype) +{ + fetch_source_d(mach, chan, reg, chan_index, src_datatype); if (reg->Register.Absolute) { if (src_datatype == TGSI_EXEC_DATA_FLOAT) { @@ -1314,16 +1507,16 @@ fetch_source(const struct tgsi_exec_machine *mach, } } -static void -store_dest(struct tgsi_exec_machine *mach, - const union tgsi_exec_channel *chan, - const struct tgsi_full_dst_register *reg, - const struct tgsi_full_instruction *inst, - uint chan_index, - enum tgsi_exec_datatype dst_datatype) +static union tgsi_exec_channel * +store_dest_dstret(struct tgsi_exec_machine *mach, + const union tgsi_exec_channel *chan, + const struct tgsi_full_dst_register *reg, + const struct tgsi_full_instruction *inst, + uint chan_index, + enum tgsi_exec_datatype dst_datatype) { uint i; - union tgsi_exec_channel null; + static union tgsi_exec_channel null; union tgsi_exec_channel *dst; union tgsi_exec_channel index2D; uint execmask = mach->ExecMask; @@ -1486,7 +1679,7 @@ store_dest(struct tgsi_exec_machine *mach, default: assert( 0 ); - return; + return NULL; } if (inst->Instruction.Predicate) { @@ -1508,7 +1701,7 @@ store_dest(struct tgsi_exec_machine *mach, break; default: assert(0); - return; + return NULL; } assert(inst->Predicate.Index == 0); @@ -1530,14 +1723,55 @@ store_dest(struct tgsi_exec_machine *mach, } } - switch (inst->Instruction.Saturate) { - case TGSI_SAT_NONE: + return dst; +} + +static void +store_dest_double(struct tgsi_exec_machine *mach, + const union tgsi_exec_channel *chan, + const struct tgsi_full_dst_register *reg, + const struct tgsi_full_instruction *inst, + uint chan_index, + enum tgsi_exec_datatype dst_datatype) +{ + union tgsi_exec_channel *dst; + const uint execmask = mach->ExecMask; + int i; + + dst = store_dest_dstret(mach, chan, reg, inst, chan_index, + dst_datatype); + if (!dst) + return; + + /* doubles path */ + for (i = 0; i < TGSI_QUAD_SIZE; i++) + if (execmask & (1 << i)) + dst->i[i] = chan->i[i]; +} + +static void +store_dest(struct tgsi_exec_machine *mach, + const union tgsi_exec_channel *chan, + const struct tgsi_full_dst_register *reg, + const struct tgsi_full_instruction *inst, + uint chan_index, + enum tgsi_exec_datatype dst_datatype) +{ + union tgsi_exec_channel *dst; + const uint execmask = mach->ExecMask; + int i; + + dst = store_dest_dstret(mach, chan, reg, inst, chan_index, + dst_datatype); + if (!dst) + return; + + if (!inst->Instruction.Saturate) { for (i = 0; i < TGSI_QUAD_SIZE; i++) if (execmask & (1 << i)) dst->i[i] = chan->i[i]; - break; - - case TGSI_SAT_ZERO_ONE: + } + else { for (i = 0; i < TGSI_QUAD_SIZE; i++) if (execmask & (1 << i)) { if (chan->f[i] < 0.0f) @@ -1547,22 +1781,6 @@ store_dest(struct tgsi_exec_machine *mach, else dst->i[i] = chan->i[i]; } - break; - - case TGSI_SAT_MINUS_PLUS_ONE: - for (i = 0; i < TGSI_QUAD_SIZE; i++) - if (execmask & (1 << i)) { - if (chan->f[i] < -1.0f) - dst->f[i] = -1.0f; - else if (chan->f[i] > 1.0f) - dst->f[i] = 1.0f; - else - dst->i[i] = chan->i[i]; - } - break; - - default: - assert( 0 ); } } @@ -1578,8 +1796,8 @@ store_dest(struct tgsi_exec_machine *mach, * Kill fragment if any of the four values is less than zero. */ static void -exec_kil(struct tgsi_exec_machine *mach, - const struct tgsi_full_instruction *inst) +exec_kill_if(struct tgsi_exec_machine *mach, + const struct tgsi_full_instruction *inst) { uint uniquemask; uint chan_index; @@ -1610,20 +1828,22 @@ exec_kil(struct tgsi_exec_machine *mach, kilmask |= 1 << i; } + /* restrict to fragments currently executing */ + kilmask &= mach->ExecMask; + mach->Temps[TEMP_KILMASK_I].xyzw[TEMP_KILMASK_C].u[0] |= kilmask; } /** - * Execute NVIDIA-style KIL which is predicated by a condition code. - * Kill fragment if the condition code is TRUE. + * Unconditional fragment kill/discard. */ static void -exec_kilp(struct tgsi_exec_machine *mach, +exec_kill(struct tgsi_exec_machine *mach, const struct tgsi_full_instruction *inst) { uint kilmask; /* bit 0 = pixel 0, bit 1 = pixel 1, etc */ - /* "unconditional" kil */ + /* kill fragment for all fragments currently executing */ kilmask = mach->ExecMask; mach->Temps[TEMP_KILMASK_I].xyzw[TEMP_KILMASK_C].u[0] |= kilmask; } @@ -1637,6 +1857,9 @@ emit_vertex(struct tgsi_exec_machine *mach) if ((mach->ExecMask & (1 << i))) */ if (mach->ExecMask) { + if (mach->Primitives[mach->Temps[TEMP_PRIMITIVE_I].xyzw[TEMP_PRIMITIVE_C].u[0]] >= mach->MaxOutputVertices) + return; + mach->Temps[TEMP_OUTPUT_I].xyzw[TEMP_OUTPUT_C].u[0] += mach->NumOutputs; mach->Primitives[mach->Temps[TEMP_PRIMITIVE_I].xyzw[TEMP_PRIMITIVE_C].u[0]]++; } @@ -1712,7 +1935,7 @@ fetch_texel( struct tgsi_sampler *sampler, #define TEX_MODIFIER_LOD_BIAS 2 #define TEX_MODIFIER_EXPLICIT_LOD 3 #define TEX_MODIFIER_LEVEL_ZERO 4 - +#define TEX_MODIFIER_GATHER 5 /* * Fetch all 3 (for s,t,r coords) texel offsets, put them into int array. @@ -1766,11 +1989,40 @@ fetch_assign_deriv_channel(struct tgsi_exec_machine *mach, derivs[1][3] = d.f[3]; } +static uint +fetch_sampler_unit(struct tgsi_exec_machine *mach, + const struct tgsi_full_instruction *inst, + uint sampler) +{ + uint unit; + + if (inst->Src[sampler].Register.Indirect) { + const struct tgsi_full_src_register *reg = &inst->Src[sampler]; + union tgsi_exec_channel indir_index, index2; + + index2.i[0] = + index2.i[1] = + index2.i[2] = + index2.i[3] = reg->Indirect.Index; + + fetch_src_file_channel(mach, + 0, + reg->Indirect.File, + reg->Indirect.Swizzle, + &index2, + &ZeroVec, + &indir_index); + unit = inst->Src[sampler].Register.Index + indir_index.i[0]; + } else { + unit = inst->Src[sampler].Register.Index; + } + return unit; +} /* * execute a texture instruction. * - * modifier is used to control the channel routing for the\ + * modifier is used to control the channel routing for the * instruction variants like proj, lod, and texture with lod bias. * sampler indicates which src register the sampler is contained in. */ @@ -1779,202 +2031,90 @@ exec_tex(struct tgsi_exec_machine *mach, const struct tgsi_full_instruction *inst, uint modifier, uint sampler) { - const uint unit = inst->Src[sampler].Register.Index; - union tgsi_exec_channel r[4], cubearraycomp, cubelod; - const union tgsi_exec_channel *lod = &ZeroVec; - enum tgsi_sampler_control control = tgsi_sampler_lod_none; + const union tgsi_exec_channel *args[5], *proj = NULL; + union tgsi_exec_channel r[5]; + enum tgsi_sampler_control control = TGSI_SAMPLER_LOD_NONE; uint chan; + uint unit; int8_t offsets[3]; + int dim, shadow_ref, i; + unit = fetch_sampler_unit(mach, inst, sampler); /* always fetch all 3 offsets, overkill but keeps code simple */ fetch_texel_offsets(mach, inst, offsets); assert(modifier != TEX_MODIFIER_LEVEL_ZERO); + assert(inst->Texture.Texture != TGSI_TEXTURE_BUFFER); - if (modifier != TEX_MODIFIER_NONE && (sampler == 1)) { - FETCH(&r[3], 0, TGSI_CHAN_W); - if (modifier != TEX_MODIFIER_PROJECTED) { - lod = &r[3]; - } - } + dim = tgsi_util_get_texture_coord_dim(inst->Texture.Texture, &shadow_ref); - if (modifier == TEX_MODIFIER_EXPLICIT_LOD) { - control = tgsi_sampler_lod_explicit; - } else if (modifier == TEX_MODIFIER_LOD_BIAS){ - control = tgsi_sampler_lod_bias; - } + assert(dim <= 4); + if (shadow_ref >= 0) + assert(shadow_ref >= dim && shadow_ref < Elements(args)); - switch (inst->Texture.Texture) { - case TGSI_TEXTURE_1D: - FETCH(&r[0], 0, TGSI_CHAN_X); + /* fetch modifier to the last argument */ + if (modifier != TEX_MODIFIER_NONE) { + const int last = Elements(args) - 1; - if (modifier == TEX_MODIFIER_PROJECTED) { - micro_div(&r[0], &r[0], &r[3]); + /* fetch modifier from src0.w or src1.x */ + if (sampler == 1) { + assert(dim <= TGSI_CHAN_W && shadow_ref != TGSI_CHAN_W); + FETCH(&r[last], 0, TGSI_CHAN_W); + } + else { + assert(shadow_ref != 4); + FETCH(&r[last], 1, TGSI_CHAN_X); } - fetch_texel(mach->Sampler, unit, unit, - &r[0], &ZeroVec, &ZeroVec, &ZeroVec, lod, /* S, T, P, C, LOD */ - NULL, offsets, control, - &r[0], &r[1], &r[2], &r[3]); /* R, G, B, A */ - break; + if (modifier != TEX_MODIFIER_PROJECTED) { + args[last] = &r[last]; + } + else { + proj = &r[last]; + args[last] = &ZeroVec; + } - case TGSI_TEXTURE_SHADOW1D: - FETCH(&r[0], 0, TGSI_CHAN_X); - FETCH(&r[2], 0, TGSI_CHAN_Z); + /* point unused arguments to zero vector */ + for (i = dim; i < last; i++) + args[i] = &ZeroVec; - if (modifier == TEX_MODIFIER_PROJECTED) { - micro_div(&r[0], &r[0], &r[3]); - micro_div(&r[2], &r[2], &r[3]); - } + if (modifier == TEX_MODIFIER_EXPLICIT_LOD) + control = TGSI_SAMPLER_LOD_EXPLICIT; + else if (modifier == TEX_MODIFIER_LOD_BIAS) + control = TGSI_SAMPLER_LOD_BIAS; + else if (modifier == TEX_MODIFIER_GATHER) + control = TGSI_SAMPLER_GATHER; + } + else { + for (i = dim; i < Elements(args); i++) + args[i] = &ZeroVec; + } - fetch_texel(mach->Sampler, unit, unit, - &r[0], &ZeroVec, &r[2], &ZeroVec, lod, /* S, T, P, C, LOD */ - NULL, offsets, control, - &r[0], &r[1], &r[2], &r[3]); /* R, G, B, A */ - break; + /* fetch coordinates */ + for (i = 0; i < dim; i++) { + FETCH(&r[i], 0, TGSI_CHAN_X + i); - case TGSI_TEXTURE_2D: - case TGSI_TEXTURE_RECT: - FETCH(&r[0], 0, TGSI_CHAN_X); - FETCH(&r[1], 0, TGSI_CHAN_Y); + if (proj) + micro_div(&r[i], &r[i], proj); - if (modifier == TEX_MODIFIER_PROJECTED) { - micro_div(&r[0], &r[0], &r[3]); - micro_div(&r[1], &r[1], &r[3]); - } + args[i] = &r[i]; + } - fetch_texel(mach->Sampler, unit, unit, - &r[0], &r[1], &ZeroVec, &ZeroVec, lod, /* S, T, P, C, LOD */ - NULL, offsets, control, - &r[0], &r[1], &r[2], &r[3]); /* outputs */ - break; + /* fetch reference value */ + if (shadow_ref >= 0) { + FETCH(&r[shadow_ref], shadow_ref / 4, TGSI_CHAN_X + (shadow_ref % 4)); - case TGSI_TEXTURE_SHADOW2D: - case TGSI_TEXTURE_SHADOWRECT: - FETCH(&r[0], 0, TGSI_CHAN_X); - FETCH(&r[1], 0, TGSI_CHAN_Y); - FETCH(&r[2], 0, TGSI_CHAN_Z); - - if (modifier == TEX_MODIFIER_PROJECTED) { - micro_div(&r[0], &r[0], &r[3]); - micro_div(&r[1], &r[1], &r[3]); - micro_div(&r[2], &r[2], &r[3]); - } - - fetch_texel(mach->Sampler, unit, unit, - &r[0], &r[1], &r[2], &ZeroVec, lod, /* S, T, P, C, LOD */ - NULL, offsets, control, - &r[0], &r[1], &r[2], &r[3]); /* outputs */ - break; - - case TGSI_TEXTURE_1D_ARRAY: - FETCH(&r[0], 0, TGSI_CHAN_X); - FETCH(&r[1], 0, TGSI_CHAN_Y); - - if (modifier == TEX_MODIFIER_PROJECTED) { - micro_div(&r[0], &r[0], &r[3]); - } + if (proj) + micro_div(&r[shadow_ref], &r[shadow_ref], proj); - fetch_texel(mach->Sampler, unit, unit, - &r[0], &r[1], &ZeroVec, &ZeroVec, lod, /* S, T, P, C, LOD */ - NULL, offsets, control, - &r[0], &r[1], &r[2], &r[3]); /* outputs */ - break; - case TGSI_TEXTURE_SHADOW1D_ARRAY: - FETCH(&r[0], 0, TGSI_CHAN_X); - FETCH(&r[1], 0, TGSI_CHAN_Y); - FETCH(&r[2], 0, TGSI_CHAN_Z); - - if (modifier == TEX_MODIFIER_PROJECTED) { - micro_div(&r[0], &r[0], &r[3]); - micro_div(&r[2], &r[2], &r[3]); - } - - fetch_texel(mach->Sampler, unit, unit, - &r[0], &r[1], &r[2], &ZeroVec, lod, /* S, T, P, C, LOD */ - NULL, offsets, control, - &r[0], &r[1], &r[2], &r[3]); /* outputs */ - break; - - case TGSI_TEXTURE_2D_ARRAY: - FETCH(&r[0], 0, TGSI_CHAN_X); - FETCH(&r[1], 0, TGSI_CHAN_Y); - FETCH(&r[2], 0, TGSI_CHAN_Z); - - if (modifier == TEX_MODIFIER_PROJECTED) { - micro_div(&r[0], &r[0], &r[3]); - micro_div(&r[1], &r[1], &r[3]); - } - - fetch_texel(mach->Sampler, unit, unit, - &r[0], &r[1], &r[2], &ZeroVec, lod, /* S, T, P, C, LOD */ - NULL, offsets, control, - &r[0], &r[1], &r[2], &r[3]); /* outputs */ - break; - case TGSI_TEXTURE_SHADOW2D_ARRAY: - case TGSI_TEXTURE_SHADOWCUBE: - FETCH(&r[0], 0, TGSI_CHAN_X); - FETCH(&r[1], 0, TGSI_CHAN_Y); - FETCH(&r[2], 0, TGSI_CHAN_Z); - FETCH(&r[3], 0, TGSI_CHAN_W); - - fetch_texel(mach->Sampler, unit, unit, - &r[0], &r[1], &r[2], &r[3], &ZeroVec, /* S, T, P, C, LOD */ - NULL, offsets, control, - &r[0], &r[1], &r[2], &r[3]); /* outputs */ - break; - case TGSI_TEXTURE_CUBE_ARRAY: - FETCH(&r[0], 0, TGSI_CHAN_X); - FETCH(&r[1], 0, TGSI_CHAN_Y); - FETCH(&r[2], 0, TGSI_CHAN_Z); - FETCH(&r[3], 0, TGSI_CHAN_W); - - if (modifier == TEX_MODIFIER_EXPLICIT_LOD || - modifier == TEX_MODIFIER_LOD_BIAS) - FETCH(&cubelod, 1, TGSI_CHAN_X); - else - cubelod = ZeroVec; - - fetch_texel(mach->Sampler, unit, unit, - &r[0], &r[1], &r[2], &r[3], &cubelod, /* S, T, P, C, LOD */ - NULL, offsets, control, - &r[0], &r[1], &r[2], &r[3]); /* outputs */ - break; - case TGSI_TEXTURE_3D: - case TGSI_TEXTURE_CUBE: - FETCH(&r[0], 0, TGSI_CHAN_X); - FETCH(&r[1], 0, TGSI_CHAN_Y); - FETCH(&r[2], 0, TGSI_CHAN_Z); - - if (modifier == TEX_MODIFIER_PROJECTED) { - micro_div(&r[0], &r[0], &r[3]); - micro_div(&r[1], &r[1], &r[3]); - micro_div(&r[2], &r[2], &r[3]); - } - - fetch_texel(mach->Sampler, unit, unit, - &r[0], &r[1], &r[2], &ZeroVec, lod, - NULL, offsets, control, - &r[0], &r[1], &r[2], &r[3]); - break; - - case TGSI_TEXTURE_SHADOWCUBE_ARRAY: - FETCH(&r[0], 0, TGSI_CHAN_X); - FETCH(&r[1], 0, TGSI_CHAN_Y); - FETCH(&r[2], 0, TGSI_CHAN_Z); - FETCH(&r[3], 0, TGSI_CHAN_W); - - FETCH(&cubearraycomp, 1, TGSI_CHAN_X); - - fetch_texel(mach->Sampler, unit, unit, - &r[0], &r[1], &r[2], &r[3], &cubearraycomp, /* S, T, P, C, LOD */ - NULL, offsets, control, - &r[0], &r[1], &r[2], &r[3]); /* outputs */ - break; - default: - assert(0); + args[shadow_ref] = &r[shadow_ref]; } + fetch_texel(mach->Sampler, unit, unit, + args[0], args[1], args[2], args[3], args[4], + NULL, offsets, control, + &r[0], &r[1], &r[2], &r[3]); /* R, G, B, A */ + #if 0 debug_printf("fetch r: %g %g %g %g\n", r[0].f[0], r[0].f[1], r[0].f[2], r[0].f[3]); @@ -1993,17 +2133,58 @@ exec_tex(struct tgsi_exec_machine *mach, } } +static void +exec_lodq(struct tgsi_exec_machine *mach, + const struct tgsi_full_instruction *inst) +{ + uint unit; + int dim; + int i; + union tgsi_exec_channel coords[4]; + const union tgsi_exec_channel *args[Elements(coords)]; + union tgsi_exec_channel r[2]; + + unit = fetch_sampler_unit(mach, inst, 1); + dim = tgsi_util_get_texture_coord_dim(inst->Texture.Texture, NULL); + assert(dim <= Elements(coords)); + /* fetch coordinates */ + for (i = 0; i < dim; i++) { + FETCH(&coords[i], 0, TGSI_CHAN_X + i); + args[i] = &coords[i]; + } + for (i = dim; i < Elements(coords); i++) { + args[i] = &ZeroVec; + } + mach->Sampler->query_lod(mach->Sampler, unit, unit, + args[0]->f, + args[1]->f, + args[2]->f, + args[3]->f, + TGSI_SAMPLER_LOD_NONE, + r[0].f, + r[1].f); + + if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_X) { + store_dest(mach, &r[0], &inst->Dst[0], inst, TGSI_CHAN_X, + TGSI_EXEC_DATA_FLOAT); + } + if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Y) { + store_dest(mach, &r[1], &inst->Dst[0], inst, TGSI_CHAN_Y, + TGSI_EXEC_DATA_FLOAT); + } +} static void exec_txd(struct tgsi_exec_machine *mach, const struct tgsi_full_instruction *inst) { - const uint unit = inst->Src[3].Register.Index; union tgsi_exec_channel r[4]; float derivs[3][2][TGSI_QUAD_SIZE]; uint chan; + uint unit; int8_t offsets[3]; + unit = fetch_sampler_unit(mach, inst, 3); /* always fetch all 3 offsets, overkill but keeps code simple */ fetch_texel_offsets(mach, inst, offsets); @@ -2015,7 +2196,7 @@ exec_txd(struct tgsi_exec_machine *mach, fetch_texel(mach->Sampler, unit, unit, &r[0], &ZeroVec, &ZeroVec, &ZeroVec, &ZeroVec, /* S, T, P, C, LOD */ - derivs, offsets, tgsi_sampler_derivs_explicit, + derivs, offsets, TGSI_SAMPLER_DERIVS_EXPLICIT, &r[0], &r[1], &r[2], &r[3]); /* R, G, B, A */ break; @@ -2031,7 +2212,7 @@ exec_txd(struct tgsi_exec_machine *mach, fetch_texel(mach->Sampler, unit, unit, &r[0], &r[1], &r[2], &ZeroVec, &ZeroVec, /* S, T, P, C, LOD */ - derivs, offsets, tgsi_sampler_derivs_explicit, + derivs, offsets, TGSI_SAMPLER_DERIVS_EXPLICIT, &r[0], &r[1], &r[2], &r[3]); /* R, G, B, A */ break; @@ -2045,7 +2226,7 @@ exec_txd(struct tgsi_exec_machine *mach, fetch_texel(mach->Sampler, unit, unit, &r[0], &r[1], &ZeroVec, &ZeroVec, &ZeroVec, /* S, T, P, C, LOD */ - derivs, offsets, tgsi_sampler_derivs_explicit, + derivs, offsets, TGSI_SAMPLER_DERIVS_EXPLICIT, &r[0], &r[1], &r[2], &r[3]); /* R, G, B, A */ break; @@ -2065,14 +2246,15 @@ exec_txd(struct tgsi_exec_machine *mach, fetch_texel(mach->Sampler, unit, unit, &r[0], &r[1], &r[2], &r[3], &ZeroVec, /* inputs */ - derivs, offsets, tgsi_sampler_derivs_explicit, + derivs, offsets, TGSI_SAMPLER_DERIVS_EXPLICIT, &r[0], &r[1], &r[2], &r[3]); /* outputs */ break; case TGSI_TEXTURE_3D: case TGSI_TEXTURE_CUBE: case TGSI_TEXTURE_CUBE_ARRAY: - /* only TEXTURE_CUBE_ARRAY actually needs W */ + case TGSI_TEXTURE_SHADOWCUBE: + /* only TEXTURE_CUBE_ARRAY and TEXTURE_SHADOWCUBE actually need W */ FETCH(&r[0], 0, TGSI_CHAN_X); FETCH(&r[1], 0, TGSI_CHAN_Y); FETCH(&r[2], 0, TGSI_CHAN_Z); @@ -2084,7 +2266,7 @@ exec_txd(struct tgsi_exec_machine *mach, fetch_texel(mach->Sampler, unit, unit, &r[0], &r[1], &r[2], &r[3], &ZeroVec, /* inputs */ - derivs, offsets, tgsi_sampler_derivs_explicit, + derivs, offsets, TGSI_SAMPLER_DERIVS_EXPLICIT, &r[0], &r[1], &r[2], &r[3]); /* outputs */ break; @@ -2104,20 +2286,22 @@ static void exec_txf(struct tgsi_exec_machine *mach, const struct tgsi_full_instruction *inst) { - const uint unit = inst->Src[1].Register.Index; union tgsi_exec_channel r[4]; uint chan; + uint unit; float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]; int j; int8_t offsets[3]; unsigned target; + unit = fetch_sampler_unit(mach, inst, 1); /* always fetch all 3 offsets, overkill but keeps code simple */ fetch_texel_offsets(mach, inst, offsets); IFETCH(&r[3], 0, TGSI_CHAN_W); - if (inst->Instruction.Opcode == TGSI_OPCODE_SAMPLE_I) { + if (inst->Instruction.Opcode == TGSI_OPCODE_SAMPLE_I || + inst->Instruction.Opcode == TGSI_OPCODE_SAMPLE_I_MS) { target = mach->SamplerViews[unit].Resource; } else { @@ -2127,6 +2311,7 @@ exec_txf(struct tgsi_exec_machine *mach, case TGSI_TEXTURE_3D: case TGSI_TEXTURE_2D_ARRAY: case TGSI_TEXTURE_SHADOW2D_ARRAY: + case TGSI_TEXTURE_2D_ARRAY_MSAA: IFETCH(&r[2], 0, TGSI_CHAN_Z); /* fallthrough */ case TGSI_TEXTURE_2D: @@ -2135,6 +2320,7 @@ exec_txf(struct tgsi_exec_machine *mach, case TGSI_TEXTURE_SHADOW2D: case TGSI_TEXTURE_SHADOWRECT: case TGSI_TEXTURE_1D_ARRAY: + case TGSI_TEXTURE_2D_MSAA: IFETCH(&r[1], 0, TGSI_CHAN_Y); /* fallthrough */ case TGSI_TEXTURE_BUFFER: @@ -2157,9 +2343,26 @@ exec_txf(struct tgsi_exec_machine *mach, r[3].f[j] = rgba[3][j]; } - for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { - if (inst->Dst[0].Register.WriteMask & (1 << chan)) { - store_dest(mach, &r[chan], &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); + if (inst->Instruction.Opcode == TGSI_OPCODE_SAMPLE_I || + inst->Instruction.Opcode == TGSI_OPCODE_SAMPLE_I_MS) { + unsigned char swizzles[4]; + swizzles[0] = inst->Src[1].Register.SwizzleX; + swizzles[1] = inst->Src[1].Register.SwizzleY; + swizzles[2] = inst->Src[1].Register.SwizzleZ; + swizzles[3] = inst->Src[1].Register.SwizzleW; + + for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { + if (inst->Dst[0].Register.WriteMask & (1 << chan)) { + store_dest(mach, &r[swizzles[chan]], + &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); + } + } + } + else { + for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { + if (inst->Dst[0].Register.WriteMask & (1 << chan)) { + store_dest(mach, &r[chan], &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); + } } } } @@ -2168,14 +2371,17 @@ static void exec_txq(struct tgsi_exec_machine *mach, const struct tgsi_full_instruction *inst) { - const uint unit = inst->Src[1].Register.Index; int result[4]; union tgsi_exec_channel r[4], src; uint chan; + uint unit; int i,j; + unit = fetch_sampler_unit(mach, inst, 1); + fetch_source(mach, &src, &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_INT); + /* XXX: This interface can't return per-pixel values */ mach->Sampler->get_dims(mach->Sampler, unit, src.i[0], result); for (i = 0; i < TGSI_QUAD_SIZE; i++) { @@ -2199,10 +2405,11 @@ exec_sample(struct tgsi_exec_machine *mach, { const uint resource_unit = inst->Src[1].Register.Index; const uint sampler_unit = inst->Src[2].Register.Index; - union tgsi_exec_channel r[4], c1; + union tgsi_exec_channel r[5], c1; const union tgsi_exec_channel *lod = &ZeroVec; - enum tgsi_sampler_control control = tgsi_sampler_lod_none; + enum tgsi_sampler_control control = TGSI_SAMPLER_LOD_NONE; uint chan; + unsigned char swizzles[4]; int8_t offsets[3]; /* always fetch all 3 offsets, overkill but keeps code simple */ @@ -2214,16 +2421,16 @@ exec_sample(struct tgsi_exec_machine *mach, if (modifier == TEX_MODIFIER_LOD_BIAS) { FETCH(&c1, 3, TGSI_CHAN_X); lod = &c1; - control = tgsi_sampler_lod_bias; + control = TGSI_SAMPLER_LOD_BIAS; } else if (modifier == TEX_MODIFIER_EXPLICIT_LOD) { FETCH(&c1, 3, TGSI_CHAN_X); lod = &c1; - control = tgsi_sampler_lod_explicit; + control = TGSI_SAMPLER_LOD_EXPLICIT; } else { assert(modifier == TEX_MODIFIER_LEVEL_ZERO); - control = tgsi_sampler_lod_zero; + control = TGSI_SAMPLER_LOD_ZERO; } } @@ -2309,9 +2516,15 @@ exec_sample(struct tgsi_exec_machine *mach, assert(0); } + swizzles[0] = inst->Src[1].Register.SwizzleX; + swizzles[1] = inst->Src[1].Register.SwizzleY; + swizzles[2] = inst->Src[1].Register.SwizzleZ; + swizzles[3] = inst->Src[1].Register.SwizzleW; + for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { if (inst->Dst[0].Register.WriteMask & (1 << chan)) { - store_dest(mach, &r[chan], &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); + store_dest(mach, &r[swizzles[chan]], + &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); } } } @@ -2325,6 +2538,7 @@ exec_sample_d(struct tgsi_exec_machine *mach, union tgsi_exec_channel r[4]; float derivs[3][2][TGSI_QUAD_SIZE]; uint chan; + unsigned char swizzles[4]; int8_t offsets[3]; /* always fetch all 3 offsets, overkill but keeps code simple */ @@ -2342,7 +2556,7 @@ exec_sample_d(struct tgsi_exec_machine *mach, fetch_texel(mach->Sampler, resource_unit, sampler_unit, &r[0], &r[1], &ZeroVec, &ZeroVec, &ZeroVec, /* S, T, P, C, LOD */ - derivs, offsets, tgsi_sampler_derivs_explicit, + derivs, offsets, TGSI_SAMPLER_DERIVS_EXPLICIT, &r[0], &r[1], &r[2], &r[3]); /* R, G, B, A */ break; @@ -2358,7 +2572,7 @@ exec_sample_d(struct tgsi_exec_machine *mach, fetch_texel(mach->Sampler, resource_unit, sampler_unit, &r[0], &r[1], &r[2], &ZeroVec, &ZeroVec, /* inputs */ - derivs, offsets, tgsi_sampler_derivs_explicit, + derivs, offsets, TGSI_SAMPLER_DERIVS_EXPLICIT, &r[0], &r[1], &r[2], &r[3]); /* outputs */ break; @@ -2376,7 +2590,7 @@ exec_sample_d(struct tgsi_exec_machine *mach, fetch_texel(mach->Sampler, resource_unit, sampler_unit, &r[0], &r[1], &r[2], &r[3], &ZeroVec, - derivs, offsets, tgsi_sampler_derivs_explicit, + derivs, offsets, TGSI_SAMPLER_DERIVS_EXPLICIT, &r[0], &r[1], &r[2], &r[3]); break; @@ -2384,9 +2598,15 @@ exec_sample_d(struct tgsi_exec_machine *mach, assert(0); } + swizzles[0] = inst->Src[1].Register.SwizzleX; + swizzles[1] = inst->Src[1].Register.SwizzleY; + swizzles[2] = inst->Src[1].Register.SwizzleZ; + swizzles[3] = inst->Src[1].Register.SwizzleW; + for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { if (inst->Dst[0].Register.WriteMask & (1 << chan)) { - store_dest(mach, &r[chan], &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); + store_dest(mach, &r[swizzles[chan]], + &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); } } } @@ -2551,27 +2771,6 @@ exec_declaration(struct tgsi_exec_machine *mach, } } - -typedef void (* micro_op)(union tgsi_exec_channel *dst); - -static void -exec_vector(struct tgsi_exec_machine *mach, - const struct tgsi_full_instruction *inst, - micro_op op, - enum tgsi_exec_datatype dst_datatype) -{ - unsigned int chan; - - for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { - if (inst->Dst[0].Register.WriteMask & (1 << chan)) { - union tgsi_exec_channel dst; - - op(&dst); - store_dest(mach, &dst, &inst->Dst[0], inst, chan, dst_datatype); - } - } -} - typedef void (* micro_unary_op)(union tgsi_exec_channel *dst, const union tgsi_exec_channel *src); @@ -2636,7 +2835,7 @@ exec_scalar_binary(struct tgsi_exec_machine *mach, union tgsi_exec_channel dst; fetch_source(mach, &src[0], &inst->Src[0], TGSI_CHAN_X, src_datatype); - fetch_source(mach, &src[1], &inst->Src[1], TGSI_CHAN_Y, src_datatype); + fetch_source(mach, &src[1], &inst->Src[1], TGSI_CHAN_X, src_datatype); op(&dst, &src[0], &src[1]); for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { if (inst->Dst[0].Register.WriteMask & (1 << chan)) { @@ -2703,6 +2902,40 @@ exec_vector_trinary(struct tgsi_exec_machine *mach, } } +typedef void (* micro_quaternary_op)(union tgsi_exec_channel *dst, + const union tgsi_exec_channel *src0, + const union tgsi_exec_channel *src1, + const union tgsi_exec_channel *src2, + const union tgsi_exec_channel *src3); + +static void +exec_vector_quaternary(struct tgsi_exec_machine *mach, + const struct tgsi_full_instruction *inst, + micro_quaternary_op op, + enum tgsi_exec_datatype dst_datatype, + enum tgsi_exec_datatype src_datatype) +{ + unsigned int chan; + struct tgsi_exec_vector dst; + + for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { + if (inst->Dst[0].Register.WriteMask & (1 << chan)) { + union tgsi_exec_channel src[4]; + + fetch_source(mach, &src[0], &inst->Src[0], chan, src_datatype); + fetch_source(mach, &src[1], &inst->Src[1], chan, src_datatype); + fetch_source(mach, &src[2], &inst->Src[2], chan, src_datatype); + fetch_source(mach, &src[3], &inst->Src[3], chan, src_datatype); + op(&dst.xyzw[chan], &src[0], &src[1], &src[2], &src[3]); + } + } + for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { + if (inst->Dst[0].Register.WriteMask & (1 << chan)) { + store_dest(mach, &dst.xyzw[chan], &inst->Dst[0], inst, chan, dst_datatype); + } + } +} + static void exec_dp3(struct tgsi_exec_machine *mach, const struct tgsi_full_instruction *inst) @@ -2828,66 +3061,41 @@ exec_dp2(struct tgsi_exec_machine *mach, } static void -exec_nrm4(struct tgsi_exec_machine *mach, +exec_pk2h(struct tgsi_exec_machine *mach, const struct tgsi_full_instruction *inst) { - unsigned int chan; - union tgsi_exec_channel arg[4]; - union tgsi_exec_channel scale; + unsigned chan; + union tgsi_exec_channel arg[2], dst; fetch_source(mach, &arg[0], &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); - micro_mul(&scale, &arg[0], &arg[0]); - - for (chan = TGSI_CHAN_Y; chan <= TGSI_CHAN_W; chan++) { - union tgsi_exec_channel product; - - fetch_source(mach, &arg[chan], &inst->Src[0], chan, TGSI_EXEC_DATA_FLOAT); - micro_mul(&product, &arg[chan], &arg[chan]); - micro_add(&scale, &scale, &product); + fetch_source(mach, &arg[1], &inst->Src[0], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); + for (chan = 0; chan < TGSI_QUAD_SIZE; chan++) { + dst.u[chan] = util_float_to_half(arg[0].f[chan]) | + (util_float_to_half(arg[1].f[chan]) << 16); } - - micro_rsq(&scale, &scale); - - for (chan = TGSI_CHAN_X; chan <= TGSI_CHAN_W; chan++) { + for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { if (inst->Dst[0].Register.WriteMask & (1 << chan)) { - micro_mul(&arg[chan], &arg[chan], &scale); - store_dest(mach, &arg[chan], &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); + store_dest(mach, &dst, &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_UINT); } } } static void -exec_nrm3(struct tgsi_exec_machine *mach, +exec_up2h(struct tgsi_exec_machine *mach, const struct tgsi_full_instruction *inst) { - if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_XYZ) { - unsigned int chan; - union tgsi_exec_channel arg[3]; - union tgsi_exec_channel scale; + unsigned chan; + union tgsi_exec_channel arg, dst[2]; - fetch_source(mach, &arg[0], &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); - micro_mul(&scale, &arg[0], &arg[0]); - - for (chan = TGSI_CHAN_Y; chan <= TGSI_CHAN_Z; chan++) { - union tgsi_exec_channel product; - - fetch_source(mach, &arg[chan], &inst->Src[0], chan, TGSI_EXEC_DATA_FLOAT); - micro_mul(&product, &arg[chan], &arg[chan]); - micro_add(&scale, &scale, &product); - } - - micro_rsq(&scale, &scale); - - for (chan = TGSI_CHAN_X; chan <= TGSI_CHAN_Z; chan++) { - if (inst->Dst[0].Register.WriteMask & (1 << chan)) { - micro_mul(&arg[chan], &arg[chan], &scale); - store_dest(mach, &arg[chan], &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); - } - } + fetch_source(mach, &arg, &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_UINT); + for (chan = 0; chan < TGSI_QUAD_SIZE; chan++) { + dst[0].f[chan] = util_half_to_float(arg.u[chan] & 0xffff); + dst[1].f[chan] = util_half_to_float(arg.u[chan] >> 16); } - - if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_W) { - store_dest(mach, &OneVec, &inst->Dst[0], inst, TGSI_CHAN_W, TGSI_EXEC_DATA_FLOAT); + for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { + if (inst->Dst[0].Register.WriteMask & (1 << chan)) { + store_dest(mach, &dst[chan & 1], &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); + } } } @@ -2918,99 +3126,6 @@ exec_scs(struct tgsi_exec_machine *mach, } } -static void -exec_x2d(struct tgsi_exec_machine *mach, - const struct tgsi_full_instruction *inst) -{ - union tgsi_exec_channel r[4]; - union tgsi_exec_channel d[2]; - - fetch_source(mach, &r[0], &inst->Src[1], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); - fetch_source(mach, &r[1], &inst->Src[1], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); - if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_XZ) { - fetch_source(mach, &r[2], &inst->Src[2], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); - micro_mul(&r[2], &r[2], &r[0]); - fetch_source(mach, &r[3], &inst->Src[2], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); - micro_mul(&r[3], &r[3], &r[1]); - micro_add(&r[2], &r[2], &r[3]); - fetch_source(mach, &r[3], &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); - micro_add(&d[0], &r[2], &r[3]); - } - if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_YW) { - fetch_source(mach, &r[2], &inst->Src[2], TGSI_CHAN_Z, TGSI_EXEC_DATA_FLOAT); - micro_mul(&r[2], &r[2], &r[0]); - fetch_source(mach, &r[3], &inst->Src[2], TGSI_CHAN_W, TGSI_EXEC_DATA_FLOAT); - micro_mul(&r[3], &r[3], &r[1]); - micro_add(&r[2], &r[2], &r[3]); - fetch_source(mach, &r[3], &inst->Src[0], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); - micro_add(&d[1], &r[2], &r[3]); - } - if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_X) { - store_dest(mach, &d[0], &inst->Dst[0], inst, TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); - } - if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Y) { - store_dest(mach, &d[1], &inst->Dst[0], inst, TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); - } - if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Z) { - store_dest(mach, &d[0], &inst->Dst[0], inst, TGSI_CHAN_Z, TGSI_EXEC_DATA_FLOAT); - } - if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_W) { - store_dest(mach, &d[1], &inst->Dst[0], inst, TGSI_CHAN_W, TGSI_EXEC_DATA_FLOAT); - } -} - -static void -exec_rfl(struct tgsi_exec_machine *mach, - const struct tgsi_full_instruction *inst) -{ - union tgsi_exec_channel r[9]; - - if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_XYZ) { - /* r0 = dp3(src0, src0) */ - fetch_source(mach, &r[2], &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); - micro_mul(&r[0], &r[2], &r[2]); - fetch_source(mach, &r[4], &inst->Src[0], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); - micro_mul(&r[8], &r[4], &r[4]); - micro_add(&r[0], &r[0], &r[8]); - fetch_source(mach, &r[6], &inst->Src[0], TGSI_CHAN_Z, TGSI_EXEC_DATA_FLOAT); - micro_mul(&r[8], &r[6], &r[6]); - micro_add(&r[0], &r[0], &r[8]); - - /* r1 = dp3(src0, src1) */ - fetch_source(mach, &r[3], &inst->Src[1], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); - micro_mul(&r[1], &r[2], &r[3]); - fetch_source(mach, &r[5], &inst->Src[1], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); - micro_mul(&r[8], &r[4], &r[5]); - micro_add(&r[1], &r[1], &r[8]); - fetch_source(mach, &r[7], &inst->Src[1], TGSI_CHAN_Z, TGSI_EXEC_DATA_FLOAT); - micro_mul(&r[8], &r[6], &r[7]); - micro_add(&r[1], &r[1], &r[8]); - - /* r1 = 2 * r1 / r0 */ - micro_add(&r[1], &r[1], &r[1]); - micro_div(&r[1], &r[1], &r[0]); - - if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_X) { - micro_mul(&r[2], &r[2], &r[1]); - micro_sub(&r[2], &r[2], &r[3]); - store_dest(mach, &r[2], &inst->Dst[0], inst, TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); - } - if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Y) { - micro_mul(&r[4], &r[4], &r[1]); - micro_sub(&r[4], &r[4], &r[5]); - store_dest(mach, &r[4], &inst->Dst[0], inst, TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); - } - if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Z) { - micro_mul(&r[6], &r[6], &r[1]); - micro_sub(&r[6], &r[6], &r[7]); - store_dest(mach, &r[6], &inst->Dst[0], inst, TGSI_CHAN_Z, TGSI_EXEC_DATA_FLOAT); - } - } - if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_W) { - store_dest(mach, &OneVec, &inst->Dst[0], inst, TGSI_CHAN_W, TGSI_EXEC_DATA_FLOAT); - } -} - static void exec_xpd(struct tgsi_exec_machine *mach, const struct tgsi_full_instruction *inst) @@ -3213,51 +3328,379 @@ static void exec_case(struct tgsi_exec_machine *mach, const struct tgsi_full_instruction *inst) { - uint prevMask = mach->SwitchStack[mach->SwitchStackTop - 1].mask; + uint prevMask = mach->SwitchStack[mach->SwitchStackTop - 1].mask; + union tgsi_exec_channel src; + uint mask = 0; + + fetch_source(mach, &src, &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_UINT); + + if (mach->Switch.selector.u[0] == src.u[0]) { + mask |= 0x1; + } + if (mach->Switch.selector.u[1] == src.u[1]) { + mask |= 0x2; + } + if (mach->Switch.selector.u[2] == src.u[2]) { + mask |= 0x4; + } + if (mach->Switch.selector.u[3] == src.u[3]) { + mask |= 0x8; + } + + mach->Switch.defaultMask |= mask; + + mach->Switch.mask |= mask & prevMask; + + UPDATE_EXEC_MASK(mach); +} + +/* FIXME: this will only work if default is last */ +static void +exec_default(struct tgsi_exec_machine *mach) +{ + uint prevMask = mach->SwitchStack[mach->SwitchStackTop - 1].mask; + + mach->Switch.mask |= ~mach->Switch.defaultMask & prevMask; + + UPDATE_EXEC_MASK(mach); +} + +static void +exec_endswitch(struct tgsi_exec_machine *mach) +{ + mach->Switch = mach->SwitchStack[--mach->SwitchStackTop]; + mach->BreakType = mach->BreakStack[--mach->BreakStackTop]; + + UPDATE_EXEC_MASK(mach); +} + +typedef void (* micro_dop)(union tgsi_double_channel *dst, + const union tgsi_double_channel *src); + +static void +fetch_double_channel(struct tgsi_exec_machine *mach, + union tgsi_double_channel *chan, + const struct tgsi_full_src_register *reg, + uint chan_0, + uint chan_1) +{ + union tgsi_exec_channel src[2]; + uint i; + + fetch_source_d(mach, &src[0], reg, chan_0, TGSI_EXEC_DATA_UINT); + fetch_source_d(mach, &src[1], reg, chan_1, TGSI_EXEC_DATA_UINT); + + for (i = 0; i < TGSI_QUAD_SIZE; i++) { + chan->u[i][0] = src[0].u[i]; + chan->u[i][1] = src[1].u[i]; + } + if (reg->Register.Absolute) { + micro_dabs(chan, chan); + } + if (reg->Register.Negate) { + micro_dneg(chan, chan); + } +} + +static void +store_double_channel(struct tgsi_exec_machine *mach, + const union tgsi_double_channel *chan, + const struct tgsi_full_dst_register *reg, + const struct tgsi_full_instruction *inst, + uint chan_0, + uint chan_1) +{ + union tgsi_exec_channel dst[2]; + uint i; + union tgsi_double_channel temp; + const uint execmask = mach->ExecMask; + + if (!inst->Instruction.Saturate) { + for (i = 0; i < TGSI_QUAD_SIZE; i++) + if (execmask & (1 << i)) { + dst[0].u[i] = chan->u[i][0]; + dst[1].u[i] = chan->u[i][1]; + } + } + else { + for (i = 0; i < TGSI_QUAD_SIZE; i++) + if (execmask & (1 << i)) { + if (chan->d[i] < 0.0) + temp.d[i] = 0.0; + else if (chan->d[i] > 1.0) + temp.d[i] = 1.0; + else + temp.d[i] = chan->d[i]; + + dst[0].u[i] = temp.u[i][0]; + dst[1].u[i] = temp.u[i][1]; + } + } + + store_dest_double(mach, &dst[0], reg, inst, chan_0, TGSI_EXEC_DATA_UINT); + if (chan_1 != -1) + store_dest_double(mach, &dst[1], reg, inst, chan_1, TGSI_EXEC_DATA_UINT); +} + +static void +exec_double_unary(struct tgsi_exec_machine *mach, + const struct tgsi_full_instruction *inst, + micro_dop op) +{ + union tgsi_double_channel src; + union tgsi_double_channel dst; + + if ((inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_XY) == TGSI_WRITEMASK_XY) { + fetch_double_channel(mach, &src, &inst->Src[0], TGSI_CHAN_X, TGSI_CHAN_Y); + op(&dst, &src); + store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_X, TGSI_CHAN_Y); + } + if ((inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_ZW) == TGSI_WRITEMASK_ZW) { + fetch_double_channel(mach, &src, &inst->Src[0], TGSI_CHAN_Z, TGSI_CHAN_W); + op(&dst, &src); + store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_Z, TGSI_CHAN_W); + } +} + +static void +exec_double_binary(struct tgsi_exec_machine *mach, + const struct tgsi_full_instruction *inst, + micro_dop op, + enum tgsi_exec_datatype dst_datatype) +{ + union tgsi_double_channel src[2]; + union tgsi_double_channel dst; + int first_dest_chan, second_dest_chan; + int wmask; + + wmask = inst->Dst[0].Register.WriteMask; + /* these are & because of the way DSLT etc store their destinations */ + if (wmask & TGSI_WRITEMASK_XY) { + first_dest_chan = TGSI_CHAN_X; + second_dest_chan = TGSI_CHAN_Y; + if (dst_datatype == TGSI_EXEC_DATA_UINT) { + first_dest_chan = (wmask & TGSI_WRITEMASK_X) ? TGSI_CHAN_X : TGSI_CHAN_Y; + second_dest_chan = -1; + } + + fetch_double_channel(mach, &src[0], &inst->Src[0], TGSI_CHAN_X, TGSI_CHAN_Y); + fetch_double_channel(mach, &src[1], &inst->Src[1], TGSI_CHAN_X, TGSI_CHAN_Y); + op(&dst, src); + store_double_channel(mach, &dst, &inst->Dst[0], inst, first_dest_chan, second_dest_chan); + } + + if (wmask & TGSI_WRITEMASK_ZW) { + first_dest_chan = TGSI_CHAN_Z; + second_dest_chan = TGSI_CHAN_W; + if (dst_datatype == TGSI_EXEC_DATA_UINT) { + first_dest_chan = (wmask & TGSI_WRITEMASK_Z) ? TGSI_CHAN_Z : TGSI_CHAN_W; + second_dest_chan = -1; + } + + fetch_double_channel(mach, &src[0], &inst->Src[0], TGSI_CHAN_Z, TGSI_CHAN_W); + fetch_double_channel(mach, &src[1], &inst->Src[1], TGSI_CHAN_Z, TGSI_CHAN_W); + op(&dst, src); + store_double_channel(mach, &dst, &inst->Dst[0], inst, first_dest_chan, second_dest_chan); + } +} + +static void +exec_double_trinary(struct tgsi_exec_machine *mach, + const struct tgsi_full_instruction *inst, + micro_dop op) +{ + union tgsi_double_channel src[3]; + union tgsi_double_channel dst; + + if ((inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_XY) == TGSI_WRITEMASK_XY) { + fetch_double_channel(mach, &src[0], &inst->Src[0], TGSI_CHAN_X, TGSI_CHAN_Y); + fetch_double_channel(mach, &src[1], &inst->Src[1], TGSI_CHAN_X, TGSI_CHAN_Y); + fetch_double_channel(mach, &src[2], &inst->Src[2], TGSI_CHAN_X, TGSI_CHAN_Y); + op(&dst, src); + store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_X, TGSI_CHAN_Y); + } + if ((inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_ZW) == TGSI_WRITEMASK_ZW) { + fetch_double_channel(mach, &src[0], &inst->Src[0], TGSI_CHAN_Z, TGSI_CHAN_W); + fetch_double_channel(mach, &src[1], &inst->Src[1], TGSI_CHAN_Z, TGSI_CHAN_W); + fetch_double_channel(mach, &src[2], &inst->Src[2], TGSI_CHAN_Z, TGSI_CHAN_W); + op(&dst, src); + store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_Z, TGSI_CHAN_W); + } +} + +static void +exec_f2d(struct tgsi_exec_machine *mach, + const struct tgsi_full_instruction *inst) +{ + union tgsi_exec_channel src; + union tgsi_double_channel dst; + + if ((inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_XY) == TGSI_WRITEMASK_XY) { + fetch_source(mach, &src, &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); + micro_f2d(&dst, &src); + store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_X, TGSI_CHAN_Y); + } + if ((inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_ZW) == TGSI_WRITEMASK_ZW) { + fetch_source(mach, &src, &inst->Src[0], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); + micro_f2d(&dst, &src); + store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_Z, TGSI_CHAN_W); + } +} + +static void +exec_d2f(struct tgsi_exec_machine *mach, + const struct tgsi_full_instruction *inst) +{ + union tgsi_double_channel src; + union tgsi_exec_channel dst; + int wm = inst->Dst[0].Register.WriteMask; + int i; + int bit; + for (i = 0; i < 2; i++) { + bit = ffs(wm); + if (bit) { + wm &= ~(1 << (bit - 1)); + if (i == 0) + fetch_double_channel(mach, &src, &inst->Src[0], TGSI_CHAN_X, TGSI_CHAN_Y); + else + fetch_double_channel(mach, &src, &inst->Src[0], TGSI_CHAN_Z, TGSI_CHAN_W); + micro_d2f(&dst, &src); + store_dest(mach, &dst, &inst->Dst[0], inst, bit - 1, TGSI_EXEC_DATA_FLOAT); + } + } +} + +static void +exec_i2d(struct tgsi_exec_machine *mach, + const struct tgsi_full_instruction *inst) +{ + union tgsi_exec_channel src; + union tgsi_double_channel dst; + + if ((inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_XY) == TGSI_WRITEMASK_XY) { + fetch_source(mach, &src, &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_INT); + micro_i2d(&dst, &src); + store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_X, TGSI_CHAN_Y); + } + if ((inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_ZW) == TGSI_WRITEMASK_ZW) { + fetch_source(mach, &src, &inst->Src[0], TGSI_CHAN_Y, TGSI_EXEC_DATA_INT); + micro_i2d(&dst, &src); + store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_Z, TGSI_CHAN_W); + } +} + +static void +exec_d2i(struct tgsi_exec_machine *mach, + const struct tgsi_full_instruction *inst) +{ + union tgsi_double_channel src; + union tgsi_exec_channel dst; + int wm = inst->Dst[0].Register.WriteMask; + int i; + int bit; + for (i = 0; i < 2; i++) { + bit = ffs(wm); + if (bit) { + wm &= ~(1 << (bit - 1)); + if (i == 0) + fetch_double_channel(mach, &src, &inst->Src[0], TGSI_CHAN_X, TGSI_CHAN_Y); + else + fetch_double_channel(mach, &src, &inst->Src[0], TGSI_CHAN_Z, TGSI_CHAN_W); + micro_d2i(&dst, &src); + store_dest(mach, &dst, &inst->Dst[0], inst, bit - 1, TGSI_EXEC_DATA_INT); + } + } +} +static void +exec_u2d(struct tgsi_exec_machine *mach, + const struct tgsi_full_instruction *inst) +{ union tgsi_exec_channel src; - uint mask = 0; - - fetch_source(mach, &src, &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_UINT); + union tgsi_double_channel dst; - if (mach->Switch.selector.u[0] == src.u[0]) { - mask |= 0x1; - } - if (mach->Switch.selector.u[1] == src.u[1]) { - mask |= 0x2; - } - if (mach->Switch.selector.u[2] == src.u[2]) { - mask |= 0x4; + if ((inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_XY) == TGSI_WRITEMASK_XY) { + fetch_source(mach, &src, &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_UINT); + micro_u2d(&dst, &src); + store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_X, TGSI_CHAN_Y); } - if (mach->Switch.selector.u[3] == src.u[3]) { - mask |= 0x8; + if ((inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_ZW) == TGSI_WRITEMASK_ZW) { + fetch_source(mach, &src, &inst->Src[0], TGSI_CHAN_Y, TGSI_EXEC_DATA_UINT); + micro_u2d(&dst, &src); + store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_Z, TGSI_CHAN_W); } - - mach->Switch.defaultMask |= mask; - - mach->Switch.mask |= mask & prevMask; - - UPDATE_EXEC_MASK(mach); } static void -exec_default(struct tgsi_exec_machine *mach) +exec_d2u(struct tgsi_exec_machine *mach, + const struct tgsi_full_instruction *inst) { - uint prevMask = mach->SwitchStack[mach->SwitchStackTop - 1].mask; + union tgsi_double_channel src; + union tgsi_exec_channel dst; + int wm = inst->Dst[0].Register.WriteMask; + int i; + int bit; + for (i = 0; i < 2; i++) { + bit = ffs(wm); + if (bit) { + wm &= ~(1 << (bit - 1)); + if (i == 0) + fetch_double_channel(mach, &src, &inst->Src[0], TGSI_CHAN_X, TGSI_CHAN_Y); + else + fetch_double_channel(mach, &src, &inst->Src[0], TGSI_CHAN_Z, TGSI_CHAN_W); + micro_d2u(&dst, &src); + store_dest(mach, &dst, &inst->Dst[0], inst, bit - 1, TGSI_EXEC_DATA_UINT); + } + } +} - mach->Switch.mask |= ~mach->Switch.defaultMask & prevMask; +static void +exec_dldexp(struct tgsi_exec_machine *mach, + const struct tgsi_full_instruction *inst) +{ + union tgsi_double_channel src0; + union tgsi_exec_channel src1; + union tgsi_double_channel dst; + int wmask; + + wmask = inst->Dst[0].Register.WriteMask; + if (wmask & TGSI_WRITEMASK_XY) { + fetch_double_channel(mach, &src0, &inst->Src[0], TGSI_CHAN_X, TGSI_CHAN_Y); + fetch_source(mach, &src1, &inst->Src[1], TGSI_CHAN_X, TGSI_EXEC_DATA_INT); + micro_dldexp(&dst, &src0, &src1); + store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_X, TGSI_CHAN_Y); + } - UPDATE_EXEC_MASK(mach); + if (wmask & TGSI_WRITEMASK_ZW) { + fetch_double_channel(mach, &src0, &inst->Src[0], TGSI_CHAN_Z, TGSI_CHAN_W); + fetch_source(mach, &src1, &inst->Src[1], TGSI_CHAN_Z, TGSI_EXEC_DATA_INT); + micro_dldexp(&dst, &src0, &src1); + store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_Z, TGSI_CHAN_W); + } } static void -exec_endswitch(struct tgsi_exec_machine *mach) +exec_dfracexp(struct tgsi_exec_machine *mach, + const struct tgsi_full_instruction *inst) { - mach->Switch = mach->SwitchStack[--mach->SwitchStackTop]; - mach->BreakType = mach->BreakStack[--mach->BreakStackTop]; + union tgsi_double_channel src; + union tgsi_double_channel dst; + union tgsi_exec_channel dst_exp; - UPDATE_EXEC_MASK(mach); + if (((inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_XY) == TGSI_WRITEMASK_XY)) { + fetch_double_channel(mach, &src, &inst->Src[0], TGSI_CHAN_X, TGSI_CHAN_Y); + micro_dfracexp(&dst, &dst_exp, &src); + store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_X, TGSI_CHAN_Y); + store_dest(mach, &dst_exp, &inst->Dst[1], inst, ffs(inst->Dst[1].Register.WriteMask) - 1, TGSI_EXEC_DATA_INT); + } + if (((inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_ZW) == TGSI_WRITEMASK_ZW)) { + fetch_double_channel(mach, &src, &inst->Src[0], TGSI_CHAN_Z, TGSI_CHAN_W); + micro_dfracexp(&dst, &dst_exp, &src); + store_double_channel(mach, &dst, &inst->Dst[0], inst, TGSI_CHAN_Z, TGSI_CHAN_W); + store_dest(mach, &dst_exp, &inst->Dst[1], inst, ffs(inst->Dst[1].Register.WriteMask) - 1, TGSI_EXEC_DATA_INT); + } } + static void micro_i2f(union tgsi_exec_channel *dst, const union tgsi_exec_channel *src) @@ -3283,10 +3726,15 @@ micro_shl(union tgsi_exec_channel *dst, const union tgsi_exec_channel *src0, const union tgsi_exec_channel *src1) { - dst->u[0] = src0->u[0] << src1->u[0]; - dst->u[1] = src0->u[1] << src1->u[1]; - dst->u[2] = src0->u[2] << src1->u[2]; - dst->u[3] = src0->u[3] << src1->u[3]; + unsigned masked_count; + masked_count = src1->u[0] & 0x1f; + dst->u[0] = src0->u[0] << masked_count; + masked_count = src1->u[1] & 0x1f; + dst->u[1] = src0->u[1] << masked_count; + masked_count = src1->u[2] & 0x1f; + dst->u[2] = src0->u[2] << masked_count; + masked_count = src1->u[3] & 0x1f; + dst->u[3] = src0->u[3] << masked_count; } static void @@ -3343,15 +3791,59 @@ micro_f2i(union tgsi_exec_channel *dst, dst->i[3] = (int)src->f[3]; } +static void +micro_fseq(union tgsi_exec_channel *dst, + const union tgsi_exec_channel *src0, + const union tgsi_exec_channel *src1) +{ + dst->u[0] = src0->f[0] == src1->f[0] ? ~0 : 0; + dst->u[1] = src0->f[1] == src1->f[1] ? ~0 : 0; + dst->u[2] = src0->f[2] == src1->f[2] ? ~0 : 0; + dst->u[3] = src0->f[3] == src1->f[3] ? ~0 : 0; +} + +static void +micro_fsge(union tgsi_exec_channel *dst, + const union tgsi_exec_channel *src0, + const union tgsi_exec_channel *src1) +{ + dst->u[0] = src0->f[0] >= src1->f[0] ? ~0 : 0; + dst->u[1] = src0->f[1] >= src1->f[1] ? ~0 : 0; + dst->u[2] = src0->f[2] >= src1->f[2] ? ~0 : 0; + dst->u[3] = src0->f[3] >= src1->f[3] ? ~0 : 0; +} + +static void +micro_fslt(union tgsi_exec_channel *dst, + const union tgsi_exec_channel *src0, + const union tgsi_exec_channel *src1) +{ + dst->u[0] = src0->f[0] < src1->f[0] ? ~0 : 0; + dst->u[1] = src0->f[1] < src1->f[1] ? ~0 : 0; + dst->u[2] = src0->f[2] < src1->f[2] ? ~0 : 0; + dst->u[3] = src0->f[3] < src1->f[3] ? ~0 : 0; +} + +static void +micro_fsne(union tgsi_exec_channel *dst, + const union tgsi_exec_channel *src0, + const union tgsi_exec_channel *src1) +{ + dst->u[0] = src0->f[0] != src1->f[0] ? ~0 : 0; + dst->u[1] = src0->f[1] != src1->f[1] ? ~0 : 0; + dst->u[2] = src0->f[2] != src1->f[2] ? ~0 : 0; + dst->u[3] = src0->f[3] != src1->f[3] ? ~0 : 0; +} + static void micro_idiv(union tgsi_exec_channel *dst, const union tgsi_exec_channel *src0, const union tgsi_exec_channel *src1) { - dst->i[0] = src0->i[0] / src1->i[0]; - dst->i[1] = src0->i[1] / src1->i[1]; - dst->i[2] = src0->i[2] / src1->i[2]; - dst->i[3] = src0->i[3] / src1->i[3]; + dst->i[0] = src1->i[0] ? src0->i[0] / src1->i[0] : 0; + dst->i[1] = src1->i[1] ? src0->i[1] / src1->i[1] : 0; + dst->i[2] = src1->i[2] ? src0->i[2] / src1->i[2] : 0; + dst->i[3] = src1->i[3] ? src0->i[3] / src1->i[3] : 0; } static void @@ -3392,10 +3884,15 @@ micro_ishr(union tgsi_exec_channel *dst, const union tgsi_exec_channel *src0, const union tgsi_exec_channel *src1) { - dst->i[0] = src0->i[0] >> src1->i[0]; - dst->i[1] = src0->i[1] >> src1->i[1]; - dst->i[2] = src0->i[2] >> src1->i[2]; - dst->i[3] = src0->i[3] >> src1->i[3]; + unsigned masked_count; + masked_count = src1->i[0] & 0x1f; + dst->i[0] = src0->i[0] >> masked_count; + masked_count = src1->i[1] & 0x1f; + dst->i[1] = src0->i[1] >> masked_count; + masked_count = src1->i[2] & 0x1f; + dst->i[2] = src0->i[2] >> masked_count; + masked_count = src1->i[3] & 0x1f; + dst->i[3] = src0->i[3] >> masked_count; } static void @@ -3507,6 +4004,32 @@ micro_umul(union tgsi_exec_channel *dst, dst->u[3] = src0->u[3] * src1->u[3]; } +static void +micro_imul_hi(union tgsi_exec_channel *dst, + const union tgsi_exec_channel *src0, + const union tgsi_exec_channel *src1) +{ +#define I64M(x, y) ((((int64_t)x) * ((int64_t)y)) >> 32) + dst->i[0] = I64M(src0->i[0], src1->i[0]); + dst->i[1] = I64M(src0->i[1], src1->i[1]); + dst->i[2] = I64M(src0->i[2], src1->i[2]); + dst->i[3] = I64M(src0->i[3], src1->i[3]); +#undef I64M +} + +static void +micro_umul_hi(union tgsi_exec_channel *dst, + const union tgsi_exec_channel *src0, + const union tgsi_exec_channel *src1) +{ +#define U64M(x, y) ((((uint64_t)x) * ((uint64_t)y)) >> 32) + dst->u[0] = U64M(src0->u[0], src1->u[0]); + dst->u[1] = U64M(src0->u[1], src1->u[1]); + dst->u[2] = U64M(src0->u[2], src1->u[2]); + dst->u[3] = U64M(src0->u[3], src1->u[3]); +#undef U64M +} + static void micro_useq(union tgsi_exec_channel *dst, const union tgsi_exec_channel *src0, @@ -3534,10 +4057,15 @@ micro_ushr(union tgsi_exec_channel *dst, const union tgsi_exec_channel *src0, const union tgsi_exec_channel *src1) { - dst->u[0] = src0->u[0] >> src1->u[0]; - dst->u[1] = src0->u[1] >> src1->u[1]; - dst->u[2] = src0->u[2] >> src1->u[2]; - dst->u[3] = src0->u[3] >> src1->u[3]; + unsigned masked_count; + masked_count = src1->u[0] & 0x1f; + dst->u[0] = src0->u[0] >> masked_count; + masked_count = src1->u[1] & 0x1f; + dst->u[1] = src0->u[1] >> masked_count; + masked_count = src1->u[2] & 0x1f; + dst->u[2] = src0->u[2] >> masked_count; + masked_count = src1->u[3] & 0x1f; + dst->u[3] = src0->u[3] >> masked_count; } static void @@ -3584,6 +4112,119 @@ micro_ucmp(union tgsi_exec_channel *dst, dst->u[3] = src0->u[3] ? src1->u[3] : src2->u[3]; } +/** + * Signed bitfield extract (i.e. sign-extend the extracted bits) + */ +static void +micro_ibfe(union tgsi_exec_channel *dst, + const union tgsi_exec_channel *src0, + const union tgsi_exec_channel *src1, + const union tgsi_exec_channel *src2) +{ + int i; + for (i = 0; i < 4; i++) { + int width = src2->i[i] & 0x1f; + int offset = src1->i[i] & 0x1f; + if (width == 0) + dst->i[i] = 0; + else if (width + offset < 32) + dst->i[i] = (src0->i[i] << (32 - width - offset)) >> (32 - width); + else + dst->i[i] = src0->i[i] >> offset; + } +} + +/** + * Unsigned bitfield extract + */ +static void +micro_ubfe(union tgsi_exec_channel *dst, + const union tgsi_exec_channel *src0, + const union tgsi_exec_channel *src1, + const union tgsi_exec_channel *src2) +{ + int i; + for (i = 0; i < 4; i++) { + int width = src2->u[i] & 0x1f; + int offset = src1->u[i] & 0x1f; + if (width == 0) + dst->u[i] = 0; + else if (width + offset < 32) + dst->u[i] = (src0->u[i] << (32 - width - offset)) >> (32 - width); + else + dst->u[i] = src0->u[i] >> offset; + } +} + +/** + * Bitfield insert: copy low bits from src1 into a region of src0. + */ +static void +micro_bfi(union tgsi_exec_channel *dst, + const union tgsi_exec_channel *src0, + const union tgsi_exec_channel *src1, + const union tgsi_exec_channel *src2, + const union tgsi_exec_channel *src3) +{ + int i; + for (i = 0; i < 4; i++) { + int width = src3->u[i] & 0x1f; + int offset = src2->u[i] & 0x1f; + int bitmask = ((1 << width) - 1) << offset; + dst->u[i] = ((src1->u[i] << offset) & bitmask) | (src0->u[i] & ~bitmask); + } +} + +static void +micro_brev(union tgsi_exec_channel *dst, + const union tgsi_exec_channel *src) +{ + dst->u[0] = util_bitreverse(src->u[0]); + dst->u[1] = util_bitreverse(src->u[1]); + dst->u[2] = util_bitreverse(src->u[2]); + dst->u[3] = util_bitreverse(src->u[3]); +} + +static void +micro_popc(union tgsi_exec_channel *dst, + const union tgsi_exec_channel *src) +{ + dst->u[0] = util_bitcount(src->u[0]); + dst->u[1] = util_bitcount(src->u[1]); + dst->u[2] = util_bitcount(src->u[2]); + dst->u[3] = util_bitcount(src->u[3]); +} + +static void +micro_lsb(union tgsi_exec_channel *dst, + const union tgsi_exec_channel *src) +{ + dst->i[0] = ffs(src->u[0]) - 1; + dst->i[1] = ffs(src->u[1]) - 1; + dst->i[2] = ffs(src->u[2]) - 1; + dst->i[3] = ffs(src->u[3]) - 1; +} + +static void +micro_imsb(union tgsi_exec_channel *dst, + const union tgsi_exec_channel *src) +{ + dst->i[0] = util_last_bit_signed(src->i[0]) - 1; + dst->i[1] = util_last_bit_signed(src->i[1]) - 1; + dst->i[2] = util_last_bit_signed(src->i[2]) - 1; + dst->i[3] = util_last_bit_signed(src->i[3]) - 1; +} + +static void +micro_umsb(union tgsi_exec_channel *dst, + const union tgsi_exec_channel *src) +{ + dst->i[0] = util_last_bit(src->u[0]) - 1; + dst->i[1] = util_last_bit(src->u[1]) - 1; + dst->i[2] = util_last_bit(src->u[2]) - 1; + dst->i[3] = util_last_bit(src->u[3]) - 1; +} + static void exec_instruction( struct tgsi_exec_machine *mach, @@ -3671,12 +4312,8 @@ exec_instruction( exec_vector_trinary(mach, inst, micro_lrp, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); break; - case TGSI_OPCODE_CND: - exec_vector_trinary(mach, inst, micro_cnd, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); - break; - case TGSI_OPCODE_SQRT: - exec_vector_unary(mach, inst, micro_sqrt, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); + exec_scalar_unary(mach, inst, micro_sqrt, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); break; case TGSI_OPCODE_DP2A: @@ -3719,10 +4356,6 @@ exec_instruction( exec_vector_unary(mach, inst, micro_abs, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); break; - case TGSI_OPCODE_RCC: - exec_scalar_unary(mach, inst, micro_rcc, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); - break; - case TGSI_OPCODE_DPH: exec_dph(mach, inst); break; @@ -3739,16 +4372,16 @@ exec_instruction( exec_vector_unary(mach, inst, micro_ddy, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); break; - case TGSI_OPCODE_KILP: - exec_kilp (mach, inst); + case TGSI_OPCODE_KILL: + exec_kill (mach, inst); break; - case TGSI_OPCODE_KIL: - exec_kil (mach, inst); + case TGSI_OPCODE_KILL_IF: + exec_kill_if (mach, inst); break; case TGSI_OPCODE_PK2H: - assert (0); + exec_pk2h(mach, inst); break; case TGSI_OPCODE_PK2US: @@ -3763,18 +4396,10 @@ exec_instruction( assert (0); break; - case TGSI_OPCODE_RFL: - exec_rfl(mach, inst); - break; - case TGSI_OPCODE_SEQ: exec_vector_binary(mach, inst, micro_seq, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); break; - case TGSI_OPCODE_SFL: - exec_vector(mach, inst, micro_sfl, TGSI_EXEC_DATA_FLOAT); - break; - case TGSI_OPCODE_SGT: exec_vector_binary(mach, inst, micro_sgt, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); break; @@ -3791,10 +4416,6 @@ exec_instruction( exec_vector_binary(mach, inst, micro_sne, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); break; - case TGSI_OPCODE_STR: - exec_vector(mach, inst, micro_str, TGSI_EXEC_DATA_FLOAT); - break; - case TGSI_OPCODE_TEX: /* simple texture lookup */ /* src[0] = texcoord */ @@ -3832,8 +4453,21 @@ exec_instruction( exec_tex(mach, inst, TEX_MODIFIER_PROJECTED, 1); break; + case TGSI_OPCODE_TG4: + /* src[0] = texcoord */ + /* src[1] = component */ + /* src[2] = sampler unit */ + exec_tex(mach, inst, TEX_MODIFIER_GATHER, 2); + break; + + case TGSI_OPCODE_LODQ: + /* src[0] = texcoord */ + /* src[1] = sampler unit */ + exec_lodq(mach, inst); + break; + case TGSI_OPCODE_UP2H: - assert (0); + exec_up2h(mach, inst); break; case TGSI_OPCODE_UP2US: @@ -3848,22 +4482,10 @@ exec_instruction( assert (0); break; - case TGSI_OPCODE_X2D: - exec_x2d(mach, inst); - break; - - case TGSI_OPCODE_ARA: - assert (0); - break; - case TGSI_OPCODE_ARR: exec_vector_unary(mach, inst, micro_arr, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_FLOAT); break; - case TGSI_OPCODE_BRA: - assert (0); - break; - case TGSI_OPCODE_CAL: /* skip the call if no execution channels are enabled */ if (mach->ExecMask) { @@ -3901,8 +4523,12 @@ exec_instruction( mach->BreakStack[mach->BreakStackTop++] = mach->BreakType; mach->FuncStack[mach->FuncStackTop++] = mach->FuncMask; - /* Finally, jump to the subroutine */ + /* Finally, jump to the subroutine. The label is a pointer + * (an instruction number) to the BGNSUB instruction. + */ *pc = inst->Label.Label; + assert(mach->Instructions[*pc].Instruction.Opcode + == TGSI_OPCODE_BGNSUB); } break; @@ -3960,14 +4586,6 @@ exec_instruction( exec_scs(mach, inst); break; - case TGSI_OPCODE_NRM: - exec_nrm3(mach, inst); - break; - - case TGSI_OPCODE_NRM4: - exec_nrm4(mach, inst); - break; - case TGSI_OPCODE_DIV: exec_vector_binary(mach, inst, micro_div, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); break; @@ -4200,7 +4818,7 @@ exec_instruction( break; case TGSI_OPCODE_BREAKC: - FETCH(&r[0], 0, TGSI_CHAN_X); + IFETCH(&r[0], 0, TGSI_CHAN_X); /* update CondMask */ if (r[0].u[0] && (mach->ExecMask & 0x1)) { mach->LoopMask &= ~0x1; @@ -4222,6 +4840,22 @@ exec_instruction( exec_vector_unary(mach, inst, micro_f2i, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_FLOAT); break; + case TGSI_OPCODE_FSEQ: + exec_vector_binary(mach, inst, micro_fseq, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_FLOAT); + break; + + case TGSI_OPCODE_FSGE: + exec_vector_binary(mach, inst, micro_fsge, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_FLOAT); + break; + + case TGSI_OPCODE_FSLT: + exec_vector_binary(mach, inst, micro_fslt, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_FLOAT); + break; + + case TGSI_OPCODE_FSNE: + exec_vector_binary(mach, inst, micro_fsne, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_FLOAT); + break; + case TGSI_OPCODE_IDIV: exec_vector_binary(mach, inst, micro_idiv, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_INT); break; @@ -4286,6 +4920,14 @@ exec_instruction( exec_vector_binary(mach, inst, micro_umul, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); break; + case TGSI_OPCODE_IMUL_HI: + exec_vector_binary(mach, inst, micro_imul_hi, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_INT); + break; + + case TGSI_OPCODE_UMUL_HI: + exec_vector_binary(mach, inst, micro_umul_hi, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); + break; + case TGSI_OPCODE_USEQ: exec_vector_binary(mach, inst, micro_useq, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); break; @@ -4327,7 +4969,7 @@ exec_instruction( break; case TGSI_OPCODE_SAMPLE_I_MS: - assert(0); + exec_txf(mach, inst); break; case TGSI_OPCODE_SAMPLE: @@ -4407,6 +5049,123 @@ exec_instruction( /* src[2] = sampler unit */ exec_tex(mach, inst, TEX_MODIFIER_EXPLICIT_LOD, 2); break; + + case TGSI_OPCODE_IBFE: + exec_vector_trinary(mach, inst, micro_ibfe, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_INT); + break; + case TGSI_OPCODE_UBFE: + exec_vector_trinary(mach, inst, micro_ubfe, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); + break; + case TGSI_OPCODE_BFI: + exec_vector_quaternary(mach, inst, micro_bfi, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); + break; + case TGSI_OPCODE_BREV: + exec_vector_unary(mach, inst, micro_brev, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); + break; + case TGSI_OPCODE_POPC: + exec_vector_unary(mach, inst, micro_popc, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); + break; + case TGSI_OPCODE_LSB: + exec_vector_unary(mach, inst, micro_lsb, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_UINT); + break; + case TGSI_OPCODE_IMSB: + exec_vector_unary(mach, inst, micro_imsb, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_INT); + break; + case TGSI_OPCODE_UMSB: + exec_vector_unary(mach, inst, micro_umsb, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_UINT); + break; + + case TGSI_OPCODE_F2D: + exec_f2d(mach, inst); + break; + + case TGSI_OPCODE_D2F: + exec_d2f(mach, inst); + break; + + case TGSI_OPCODE_DABS: + exec_double_unary(mach, inst, micro_dabs); + break; + + case TGSI_OPCODE_DNEG: + exec_double_unary(mach, inst, micro_dneg); + break; + + case TGSI_OPCODE_DADD: + exec_double_binary(mach, inst, micro_dadd, TGSI_EXEC_DATA_DOUBLE); + break; + + case TGSI_OPCODE_DMUL: + exec_double_binary(mach, inst, micro_dmul, TGSI_EXEC_DATA_DOUBLE); + break; + + case TGSI_OPCODE_DMAX: + exec_double_binary(mach, inst, micro_dmax, TGSI_EXEC_DATA_DOUBLE); + break; + + case TGSI_OPCODE_DMIN: + exec_double_binary(mach, inst, micro_dmin, TGSI_EXEC_DATA_DOUBLE); + break; + + case TGSI_OPCODE_DSLT: + exec_double_binary(mach, inst, micro_dslt, TGSI_EXEC_DATA_UINT); + break; + + case TGSI_OPCODE_DSGE: + exec_double_binary(mach, inst, micro_dsge, TGSI_EXEC_DATA_UINT); + break; + + case TGSI_OPCODE_DSEQ: + exec_double_binary(mach, inst, micro_dseq, TGSI_EXEC_DATA_UINT); + break; + + case TGSI_OPCODE_DSNE: + exec_double_binary(mach, inst, micro_dsne, TGSI_EXEC_DATA_UINT); + break; + + case TGSI_OPCODE_DRCP: + exec_double_unary(mach, inst, micro_drcp); + break; + + case TGSI_OPCODE_DSQRT: + exec_double_unary(mach, inst, micro_dsqrt); + break; + + case TGSI_OPCODE_DRSQ: + exec_double_unary(mach, inst, micro_drsq); + break; + + case TGSI_OPCODE_DMAD: + exec_double_trinary(mach, inst, micro_dmad); + break; + + case TGSI_OPCODE_DFRAC: + exec_double_unary(mach, inst, micro_dfrac); + break; + + case TGSI_OPCODE_DLDEXP: + exec_dldexp(mach, inst); + break; + + case TGSI_OPCODE_DFRACEXP: + exec_dfracexp(mach, inst); + break; + + case TGSI_OPCODE_I2D: + exec_i2d(mach, inst); + break; + + case TGSI_OPCODE_D2I: + exec_d2i(mach, inst); + break; + + case TGSI_OPCODE_U2D: + exec_u2d(mach, inst); + break; + + case TGSI_OPCODE_D2U: + exec_d2u(mach, inst); + break; default: assert( 0 ); } @@ -4422,14 +5181,25 @@ tgsi_exec_machine_run( struct tgsi_exec_machine *mach ) { uint i; int pc = 0; + uint default_mask = 0xf; + + mach->Temps[TEMP_KILMASK_I].xyzw[TEMP_KILMASK_C].u[0] = 0; + mach->Temps[TEMP_OUTPUT_I].xyzw[TEMP_OUTPUT_C].u[0] = 0; + + if( mach->Processor == TGSI_PROCESSOR_GEOMETRY ) { + mach->Temps[TEMP_PRIMITIVE_I].xyzw[TEMP_PRIMITIVE_C].u[0] = 0; + mach->Primitives[0] = 0; + /* GS runs on a single primitive for now */ + default_mask = 0x1; + } - mach->CondMask = 0xf; - mach->LoopMask = 0xf; - mach->ContMask = 0xf; - mach->FuncMask = 0xf; - mach->ExecMask = 0xf; + mach->CondMask = default_mask; + mach->LoopMask = default_mask; + mach->ContMask = default_mask; + mach->FuncMask = default_mask; + mach->ExecMask = default_mask; - mach->Switch.mask = 0xf; + mach->Switch.mask = default_mask; assert(mach->CondStackTop == 0); assert(mach->LoopStackTop == 0); @@ -4438,13 +5208,6 @@ tgsi_exec_machine_run( struct tgsi_exec_machine *mach ) assert(mach->BreakStackTop == 0); assert(mach->CallStackTop == 0); - mach->Temps[TEMP_KILMASK_I].xyzw[TEMP_KILMASK_C].u[0] = 0; - mach->Temps[TEMP_OUTPUT_I].xyzw[TEMP_OUTPUT_C].u[0] = 0; - - if( mach->Processor == TGSI_PROCESSOR_GEOMETRY ) { - mach->Temps[TEMP_PRIMITIVE_I].xyzw[TEMP_PRIMITIVE_C].u[0] = 0; - mach->Primitives[0] = 0; - } /* execute declarations (interpolants) */ for (i = 0; i < mach->NumDeclarations; i++) {