13464ebd5Sriastradh/*
23464ebd5Sriastradh * Mesa 3-D graphics library
33464ebd5Sriastradh *
43464ebd5Sriastradh * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
53464ebd5Sriastradh *
63464ebd5Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a
73464ebd5Sriastradh * copy of this software and associated documentation files (the "Software"),
83464ebd5Sriastradh * to deal in the Software without restriction, including without limitation
93464ebd5Sriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense,
103464ebd5Sriastradh * and/or sell copies of the Software, and to permit persons to whom the
113464ebd5Sriastradh * Software is furnished to do so, subject to the following conditions:
123464ebd5Sriastradh *
133464ebd5Sriastradh * The above copyright notice and this permission notice shall be included
143464ebd5Sriastradh * in all copies or substantial portions of the Software.
153464ebd5Sriastradh *
163464ebd5Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
173464ebd5Sriastradh * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
183464ebd5Sriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
233464ebd5Sriastradh */
243464ebd5Sriastradh
253464ebd5Sriastradh/**
263464ebd5Sriastradh * \file prog_execute.c
273464ebd5Sriastradh * Software interpreter for vertex/fragment programs.
283464ebd5Sriastradh * \author Brian Paul
293464ebd5Sriastradh */
303464ebd5Sriastradh
313464ebd5Sriastradh/*
323464ebd5Sriastradh * NOTE: we do everything in single-precision floating point; we don't
333464ebd5Sriastradh * currently observe the single/half/fixed-precision qualifiers.
343464ebd5Sriastradh *
353464ebd5Sriastradh */
363464ebd5Sriastradh
373464ebd5Sriastradh
3801e04c3fSmrg#include "c99_math.h"
3901e04c3fSmrg#include "main/errors.h"
403464ebd5Sriastradh#include "main/glheader.h"
413464ebd5Sriastradh#include "main/macros.h"
4201e04c3fSmrg#include "main/mtypes.h"
433464ebd5Sriastradh#include "prog_execute.h"
443464ebd5Sriastradh#include "prog_instruction.h"
453464ebd5Sriastradh#include "prog_parameter.h"
463464ebd5Sriastradh#include "prog_print.h"
473464ebd5Sriastradh#include "prog_noise.h"
483464ebd5Sriastradh
493464ebd5Sriastradh
503464ebd5Sriastradh/* debug predicate */
513464ebd5Sriastradh#define DEBUG_PROG 0
523464ebd5Sriastradh
533464ebd5Sriastradh
543464ebd5Sriastradh/**
553464ebd5Sriastradh * Set x to positive or negative infinity.
563464ebd5Sriastradh */
573464ebd5Sriastradh#define SET_POS_INFINITY(x)                  \
583464ebd5Sriastradh   do {                                      \
593464ebd5Sriastradh         fi_type fi;                         \
603464ebd5Sriastradh         fi.i = 0x7F800000;                  \
613464ebd5Sriastradh         x = fi.f;                           \
623464ebd5Sriastradh   } while (0)
633464ebd5Sriastradh#define SET_NEG_INFINITY(x)                  \
643464ebd5Sriastradh   do {                                      \
653464ebd5Sriastradh         fi_type fi;                         \
663464ebd5Sriastradh         fi.i = 0xFF800000;                  \
673464ebd5Sriastradh         x = fi.f;                           \
683464ebd5Sriastradh   } while (0)
693464ebd5Sriastradh
703464ebd5Sriastradh#define SET_FLOAT_BITS(x, bits) ((fi_type *) (void *) &(x))->i = bits
713464ebd5Sriastradh
723464ebd5Sriastradh
733464ebd5Sriastradhstatic const GLfloat ZeroVec[4] = { 0.0F, 0.0F, 0.0F, 0.0F };
743464ebd5Sriastradh
753464ebd5Sriastradh
763464ebd5Sriastradh/**
773464ebd5Sriastradh * Return a pointer to the 4-element float vector specified by the given
783464ebd5Sriastradh * source register.
793464ebd5Sriastradh */
80af69d88dSmrgstatic inline const GLfloat *
813464ebd5Sriastradhget_src_register_pointer(const struct prog_src_register *source,
823464ebd5Sriastradh                         const struct gl_program_machine *machine)
833464ebd5Sriastradh{
843464ebd5Sriastradh   const struct gl_program *prog = machine->CurProgram;
853464ebd5Sriastradh   GLint reg = source->Index;
863464ebd5Sriastradh
873464ebd5Sriastradh   if (source->RelAddr) {
883464ebd5Sriastradh      /* add address register value to src index/offset */
893464ebd5Sriastradh      reg += machine->AddressReg[0][0];
903464ebd5Sriastradh      if (reg < 0) {
913464ebd5Sriastradh         return ZeroVec;
923464ebd5Sriastradh      }
933464ebd5Sriastradh   }
943464ebd5Sriastradh
953464ebd5Sriastradh   switch (source->File) {
963464ebd5Sriastradh   case PROGRAM_TEMPORARY:
973464ebd5Sriastradh      if (reg >= MAX_PROGRAM_TEMPS)
983464ebd5Sriastradh         return ZeroVec;
993464ebd5Sriastradh      return machine->Temporaries[reg];
1003464ebd5Sriastradh
1013464ebd5Sriastradh   case PROGRAM_INPUT:
1023464ebd5Sriastradh      if (prog->Target == GL_VERTEX_PROGRAM_ARB) {
1033464ebd5Sriastradh         if (reg >= VERT_ATTRIB_MAX)
1043464ebd5Sriastradh            return ZeroVec;
1053464ebd5Sriastradh         return machine->VertAttribs[reg];
1063464ebd5Sriastradh      }
1073464ebd5Sriastradh      else {
108af69d88dSmrg         if (reg >= VARYING_SLOT_MAX)
1093464ebd5Sriastradh            return ZeroVec;
1103464ebd5Sriastradh         return machine->Attribs[reg][machine->CurElement];
1113464ebd5Sriastradh      }
1123464ebd5Sriastradh
1133464ebd5Sriastradh   case PROGRAM_OUTPUT:
1143464ebd5Sriastradh      if (reg >= MAX_PROGRAM_OUTPUTS)
1153464ebd5Sriastradh         return ZeroVec;
1163464ebd5Sriastradh      return machine->Outputs[reg];
1173464ebd5Sriastradh
1183464ebd5Sriastradh   case PROGRAM_STATE_VAR:
1197ec681f3Smrg      FALLTHROUGH;
1203464ebd5Sriastradh   case PROGRAM_CONSTANT:
1217ec681f3Smrg      FALLTHROUGH;
12201e04c3fSmrg   case PROGRAM_UNIFORM: {
1233464ebd5Sriastradh      if (reg >= (GLint) prog->Parameters->NumParameters)
1243464ebd5Sriastradh         return ZeroVec;
1253464ebd5Sriastradh
1267ec681f3Smrg      unsigned pvo = prog->Parameters->Parameters[reg].ValueOffset;
12701e04c3fSmrg      return (GLfloat *) prog->Parameters->ParameterValues + pvo;
12801e04c3fSmrg   }
1293464ebd5Sriastradh   case PROGRAM_SYSTEM_VALUE:
13001e04c3fSmrg      assert(reg < (GLint) ARRAY_SIZE(machine->SystemValues));
1313464ebd5Sriastradh      return machine->SystemValues[reg];
1323464ebd5Sriastradh
1333464ebd5Sriastradh   default:
1343464ebd5Sriastradh      _mesa_problem(NULL,
1353464ebd5Sriastradh         "Invalid src register file %d in get_src_register_pointer()",
1363464ebd5Sriastradh         source->File);
137af69d88dSmrg      return ZeroVec;
1383464ebd5Sriastradh   }
1393464ebd5Sriastradh}
1403464ebd5Sriastradh
1413464ebd5Sriastradh
1423464ebd5Sriastradh/**
1433464ebd5Sriastradh * Return a pointer to the 4-element float vector specified by the given
1443464ebd5Sriastradh * destination register.
1453464ebd5Sriastradh */
146af69d88dSmrgstatic inline GLfloat *
1473464ebd5Sriastradhget_dst_register_pointer(const struct prog_dst_register *dest,
1483464ebd5Sriastradh                         struct gl_program_machine *machine)
1493464ebd5Sriastradh{
1503464ebd5Sriastradh   static GLfloat dummyReg[4];
1513464ebd5Sriastradh   GLint reg = dest->Index;
1523464ebd5Sriastradh
1533464ebd5Sriastradh   if (dest->RelAddr) {
1543464ebd5Sriastradh      /* add address register value to src index/offset */
1553464ebd5Sriastradh      reg += machine->AddressReg[0][0];
1563464ebd5Sriastradh      if (reg < 0) {
1573464ebd5Sriastradh         return dummyReg;
1583464ebd5Sriastradh      }
1593464ebd5Sriastradh   }
1603464ebd5Sriastradh
1613464ebd5Sriastradh   switch (dest->File) {
1623464ebd5Sriastradh   case PROGRAM_TEMPORARY:
1633464ebd5Sriastradh      if (reg >= MAX_PROGRAM_TEMPS)
1643464ebd5Sriastradh         return dummyReg;
1653464ebd5Sriastradh      return machine->Temporaries[reg];
1663464ebd5Sriastradh
1673464ebd5Sriastradh   case PROGRAM_OUTPUT:
1683464ebd5Sriastradh      if (reg >= MAX_PROGRAM_OUTPUTS)
1693464ebd5Sriastradh         return dummyReg;
1703464ebd5Sriastradh      return machine->Outputs[reg];
1713464ebd5Sriastradh
1723464ebd5Sriastradh   default:
1733464ebd5Sriastradh      _mesa_problem(NULL,
1743464ebd5Sriastradh         "Invalid dest register file %d in get_dst_register_pointer()",
1753464ebd5Sriastradh         dest->File);
176af69d88dSmrg      return dummyReg;
1773464ebd5Sriastradh   }
1783464ebd5Sriastradh}
1793464ebd5Sriastradh
1803464ebd5Sriastradh
1813464ebd5Sriastradh
1823464ebd5Sriastradh/**
1833464ebd5Sriastradh * Fetch a 4-element float vector from the given source register.
1843464ebd5Sriastradh * Apply swizzling and negating as needed.
1853464ebd5Sriastradh */
1863464ebd5Sriastradhstatic void
1873464ebd5Sriastradhfetch_vector4(const struct prog_src_register *source,
1883464ebd5Sriastradh              const struct gl_program_machine *machine, GLfloat result[4])
1893464ebd5Sriastradh{
1903464ebd5Sriastradh   const GLfloat *src = get_src_register_pointer(source, machine);
1913464ebd5Sriastradh
1923464ebd5Sriastradh   if (source->Swizzle == SWIZZLE_NOOP) {
1933464ebd5Sriastradh      /* no swizzling */
1943464ebd5Sriastradh      COPY_4V(result, src);
1953464ebd5Sriastradh   }
1963464ebd5Sriastradh   else {
19701e04c3fSmrg      assert(GET_SWZ(source->Swizzle, 0) <= 3);
19801e04c3fSmrg      assert(GET_SWZ(source->Swizzle, 1) <= 3);
19901e04c3fSmrg      assert(GET_SWZ(source->Swizzle, 2) <= 3);
20001e04c3fSmrg      assert(GET_SWZ(source->Swizzle, 3) <= 3);
2013464ebd5Sriastradh      result[0] = src[GET_SWZ(source->Swizzle, 0)];
2023464ebd5Sriastradh      result[1] = src[GET_SWZ(source->Swizzle, 1)];
2033464ebd5Sriastradh      result[2] = src[GET_SWZ(source->Swizzle, 2)];
2043464ebd5Sriastradh      result[3] = src[GET_SWZ(source->Swizzle, 3)];
2053464ebd5Sriastradh   }
2063464ebd5Sriastradh
2073464ebd5Sriastradh   if (source->Negate) {
20801e04c3fSmrg      assert(source->Negate == NEGATE_XYZW);
2093464ebd5Sriastradh      result[0] = -result[0];
2103464ebd5Sriastradh      result[1] = -result[1];
2113464ebd5Sriastradh      result[2] = -result[2];
2123464ebd5Sriastradh      result[3] = -result[3];
2133464ebd5Sriastradh   }
2143464ebd5Sriastradh
2153464ebd5Sriastradh#ifdef NAN_CHECK
2167ec681f3Smrg   assert(!util_is_inf_or_nan(result[0]));
2177ec681f3Smrg   assert(!util_is_inf_or_nan(result[0]));
2187ec681f3Smrg   assert(!util_is_inf_or_nan(result[0]));
2197ec681f3Smrg   assert(!util_is_inf_or_nan(result[0]));
2203464ebd5Sriastradh#endif
2213464ebd5Sriastradh}
2223464ebd5Sriastradh
2233464ebd5Sriastradh
2243464ebd5Sriastradh/**
2253464ebd5Sriastradh * Fetch the derivative with respect to X or Y for the given register.
2263464ebd5Sriastradh * XXX this currently only works for fragment program input attribs.
2273464ebd5Sriastradh */
2283464ebd5Sriastradhstatic void
22901e04c3fSmrgfetch_vector4_deriv(const struct prog_src_register *source,
2303464ebd5Sriastradh                    const struct gl_program_machine *machine,
2313464ebd5Sriastradh                    char xOrY, GLfloat result[4])
2323464ebd5Sriastradh{
2333464ebd5Sriastradh   if (source->File == PROGRAM_INPUT &&
2343464ebd5Sriastradh       source->Index < (GLint) machine->NumDeriv) {
2353464ebd5Sriastradh      const GLint col = machine->CurElement;
236af69d88dSmrg      const GLfloat w = machine->Attribs[VARYING_SLOT_POS][col][3];
2373464ebd5Sriastradh      const GLfloat invQ = 1.0f / w;
2383464ebd5Sriastradh      GLfloat deriv[4];
2393464ebd5Sriastradh
2403464ebd5Sriastradh      if (xOrY == 'X') {
2413464ebd5Sriastradh         deriv[0] = machine->DerivX[source->Index][0] * invQ;
2423464ebd5Sriastradh         deriv[1] = machine->DerivX[source->Index][1] * invQ;
2433464ebd5Sriastradh         deriv[2] = machine->DerivX[source->Index][2] * invQ;
2443464ebd5Sriastradh         deriv[3] = machine->DerivX[source->Index][3] * invQ;
2453464ebd5Sriastradh      }
2463464ebd5Sriastradh      else {
2473464ebd5Sriastradh         deriv[0] = machine->DerivY[source->Index][0] * invQ;
2483464ebd5Sriastradh         deriv[1] = machine->DerivY[source->Index][1] * invQ;
2493464ebd5Sriastradh         deriv[2] = machine->DerivY[source->Index][2] * invQ;
2503464ebd5Sriastradh         deriv[3] = machine->DerivY[source->Index][3] * invQ;
2513464ebd5Sriastradh      }
2523464ebd5Sriastradh
2533464ebd5Sriastradh      result[0] = deriv[GET_SWZ(source->Swizzle, 0)];
2543464ebd5Sriastradh      result[1] = deriv[GET_SWZ(source->Swizzle, 1)];
2553464ebd5Sriastradh      result[2] = deriv[GET_SWZ(source->Swizzle, 2)];
2563464ebd5Sriastradh      result[3] = deriv[GET_SWZ(source->Swizzle, 3)];
2573464ebd5Sriastradh
2583464ebd5Sriastradh      if (source->Negate) {
25901e04c3fSmrg         assert(source->Negate == NEGATE_XYZW);
2603464ebd5Sriastradh         result[0] = -result[0];
2613464ebd5Sriastradh         result[1] = -result[1];
2623464ebd5Sriastradh         result[2] = -result[2];
2633464ebd5Sriastradh         result[3] = -result[3];
2643464ebd5Sriastradh      }
2653464ebd5Sriastradh   }
2663464ebd5Sriastradh   else {
2673464ebd5Sriastradh      ASSIGN_4V(result, 0.0, 0.0, 0.0, 0.0);
2683464ebd5Sriastradh   }
2693464ebd5Sriastradh}
2703464ebd5Sriastradh
2713464ebd5Sriastradh
2723464ebd5Sriastradh/**
2733464ebd5Sriastradh * As above, but only return result[0] element.
2743464ebd5Sriastradh */
2753464ebd5Sriastradhstatic void
2763464ebd5Sriastradhfetch_vector1(const struct prog_src_register *source,
2773464ebd5Sriastradh              const struct gl_program_machine *machine, GLfloat result[4])
2783464ebd5Sriastradh{
2793464ebd5Sriastradh   const GLfloat *src = get_src_register_pointer(source, machine);
2803464ebd5Sriastradh
2813464ebd5Sriastradh   result[0] = src[GET_SWZ(source->Swizzle, 0)];
2823464ebd5Sriastradh
2833464ebd5Sriastradh   if (source->Negate) {
2843464ebd5Sriastradh      result[0] = -result[0];
2853464ebd5Sriastradh   }
2863464ebd5Sriastradh}
2873464ebd5Sriastradh
2883464ebd5Sriastradh
2893464ebd5Sriastradh/**
2903464ebd5Sriastradh * Fetch texel from texture.  Use partial derivatives when possible.
2913464ebd5Sriastradh */
292af69d88dSmrgstatic inline void
2933464ebd5Sriastradhfetch_texel(struct gl_context *ctx,
2943464ebd5Sriastradh            const struct gl_program_machine *machine,
2953464ebd5Sriastradh            const struct prog_instruction *inst,
2963464ebd5Sriastradh            const GLfloat texcoord[4], GLfloat lodBias,
2973464ebd5Sriastradh            GLfloat color[4])
2983464ebd5Sriastradh{
2993464ebd5Sriastradh   const GLuint unit = machine->Samplers[inst->TexSrcUnit];
3003464ebd5Sriastradh
3013464ebd5Sriastradh   /* Note: we only have the right derivatives for fragment input attribs.
3023464ebd5Sriastradh    */
3033464ebd5Sriastradh   if (machine->NumDeriv > 0 &&
3043464ebd5Sriastradh       inst->SrcReg[0].File == PROGRAM_INPUT &&
305af69d88dSmrg       inst->SrcReg[0].Index == VARYING_SLOT_TEX0 + inst->TexSrcUnit) {
3063464ebd5Sriastradh      /* simple texture fetch for which we should have derivatives */
3073464ebd5Sriastradh      GLuint attr = inst->SrcReg[0].Index;
3083464ebd5Sriastradh      machine->FetchTexelDeriv(ctx, texcoord,
3093464ebd5Sriastradh                               machine->DerivX[attr],
3103464ebd5Sriastradh                               machine->DerivY[attr],
3113464ebd5Sriastradh                               lodBias, unit, color);
3123464ebd5Sriastradh   }
3133464ebd5Sriastradh   else {
3143464ebd5Sriastradh      machine->FetchTexelLod(ctx, texcoord, lodBias, unit, color);
3153464ebd5Sriastradh   }
3163464ebd5Sriastradh}
3173464ebd5Sriastradh
3183464ebd5Sriastradh
3193464ebd5Sriastradh/**
3203464ebd5Sriastradh * Store 4 floats into a register.  Observe the instructions saturate and
3213464ebd5Sriastradh * set-condition-code flags.
3223464ebd5Sriastradh */
3233464ebd5Sriastradhstatic void
3243464ebd5Sriastradhstore_vector4(const struct prog_instruction *inst,
3253464ebd5Sriastradh              struct gl_program_machine *machine, const GLfloat value[4])
3263464ebd5Sriastradh{
3273464ebd5Sriastradh   const struct prog_dst_register *dstReg = &(inst->DstReg);
32801e04c3fSmrg   const GLboolean clamp = inst->Saturate;
3293464ebd5Sriastradh   GLuint writeMask = dstReg->WriteMask;
3303464ebd5Sriastradh   GLfloat clampedValue[4];
3313464ebd5Sriastradh   GLfloat *dst = get_dst_register_pointer(dstReg, machine);
3323464ebd5Sriastradh
3333464ebd5Sriastradh#if 0
3343464ebd5Sriastradh   if (value[0] > 1.0e10 ||
3357ec681f3Smrg       util_is_inf_or_nan(value[0]) ||
3367ec681f3Smrg       util_is_inf_or_nan(value[1]) ||
3377ec681f3Smrg       util_is_inf_or_nan(value[2]) || util_is_inf_or_nan(value[3]))
3383464ebd5Sriastradh      printf("store %g %g %g %g\n", value[0], value[1], value[2], value[3]);
3393464ebd5Sriastradh#endif
3403464ebd5Sriastradh
3413464ebd5Sriastradh   if (clamp) {
3423464ebd5Sriastradh      clampedValue[0] = CLAMP(value[0], 0.0F, 1.0F);
3433464ebd5Sriastradh      clampedValue[1] = CLAMP(value[1], 0.0F, 1.0F);
3443464ebd5Sriastradh      clampedValue[2] = CLAMP(value[2], 0.0F, 1.0F);
3453464ebd5Sriastradh      clampedValue[3] = CLAMP(value[3], 0.0F, 1.0F);
3463464ebd5Sriastradh      value = clampedValue;
3473464ebd5Sriastradh   }
3483464ebd5Sriastradh
3493464ebd5Sriastradh#ifdef NAN_CHECK
3507ec681f3Smrg   assert(!util_is_inf_or_nan(value[0]));
3517ec681f3Smrg   assert(!util_is_inf_or_nan(value[0]));
3527ec681f3Smrg   assert(!util_is_inf_or_nan(value[0]));
3537ec681f3Smrg   assert(!util_is_inf_or_nan(value[0]));
3543464ebd5Sriastradh#endif
3553464ebd5Sriastradh
3563464ebd5Sriastradh   if (writeMask & WRITEMASK_X)
3573464ebd5Sriastradh      dst[0] = value[0];
3583464ebd5Sriastradh   if (writeMask & WRITEMASK_Y)
3593464ebd5Sriastradh      dst[1] = value[1];
3603464ebd5Sriastradh   if (writeMask & WRITEMASK_Z)
3613464ebd5Sriastradh      dst[2] = value[2];
3623464ebd5Sriastradh   if (writeMask & WRITEMASK_W)
3633464ebd5Sriastradh      dst[3] = value[3];
3643464ebd5Sriastradh}
3653464ebd5Sriastradh
3663464ebd5Sriastradh
3673464ebd5Sriastradh/**
3683464ebd5Sriastradh * Execute the given vertex/fragment program.
3693464ebd5Sriastradh *
3703464ebd5Sriastradh * \param ctx  rendering context
3713464ebd5Sriastradh * \param program  the program to execute
3723464ebd5Sriastradh * \param machine  machine state (must be initialized)
3733464ebd5Sriastradh * \return GL_TRUE if program completed or GL_FALSE if program executed KIL.
3743464ebd5Sriastradh */
3753464ebd5SriastradhGLboolean
3763464ebd5Sriastradh_mesa_execute_program(struct gl_context * ctx,
3773464ebd5Sriastradh                      const struct gl_program *program,
3783464ebd5Sriastradh                      struct gl_program_machine *machine)
3793464ebd5Sriastradh{
38001e04c3fSmrg   const GLuint numInst = program->arb.NumInstructions;
381af69d88dSmrg   const GLuint maxExec = 65536;
3823464ebd5Sriastradh   GLuint pc, numExec = 0;
3833464ebd5Sriastradh
3843464ebd5Sriastradh   machine->CurProgram = program;
3853464ebd5Sriastradh
3863464ebd5Sriastradh   if (DEBUG_PROG) {
3873464ebd5Sriastradh      printf("execute program %u --------------------\n", program->Id);
3883464ebd5Sriastradh   }
3893464ebd5Sriastradh
3903464ebd5Sriastradh   if (program->Target == GL_VERTEX_PROGRAM_ARB) {
3913464ebd5Sriastradh      machine->EnvParams = ctx->VertexProgram.Parameters;
3923464ebd5Sriastradh   }
3933464ebd5Sriastradh   else {
3943464ebd5Sriastradh      machine->EnvParams = ctx->FragmentProgram.Parameters;
3953464ebd5Sriastradh   }
3963464ebd5Sriastradh
3973464ebd5Sriastradh   for (pc = 0; pc < numInst; pc++) {
39801e04c3fSmrg      const struct prog_instruction *inst = program->arb.Instructions + pc;
3993464ebd5Sriastradh
4003464ebd5Sriastradh      if (DEBUG_PROG) {
4013464ebd5Sriastradh         _mesa_print_instruction(inst);
4023464ebd5Sriastradh      }
4033464ebd5Sriastradh
4043464ebd5Sriastradh      switch (inst->Opcode) {
4053464ebd5Sriastradh      case OPCODE_ABS:
4063464ebd5Sriastradh         {
4073464ebd5Sriastradh            GLfloat a[4], result[4];
4083464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
40901e04c3fSmrg            result[0] = fabsf(a[0]);
41001e04c3fSmrg            result[1] = fabsf(a[1]);
41101e04c3fSmrg            result[2] = fabsf(a[2]);
41201e04c3fSmrg            result[3] = fabsf(a[3]);
4133464ebd5Sriastradh            store_vector4(inst, machine, result);
4143464ebd5Sriastradh         }
4153464ebd5Sriastradh         break;
4163464ebd5Sriastradh      case OPCODE_ADD:
4173464ebd5Sriastradh         {
4183464ebd5Sriastradh            GLfloat a[4], b[4], result[4];
4193464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
4203464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[1], machine, b);
4213464ebd5Sriastradh            result[0] = a[0] + b[0];
4223464ebd5Sriastradh            result[1] = a[1] + b[1];
4233464ebd5Sriastradh            result[2] = a[2] + b[2];
4243464ebd5Sriastradh            result[3] = a[3] + b[3];
4253464ebd5Sriastradh            store_vector4(inst, machine, result);
4263464ebd5Sriastradh            if (DEBUG_PROG) {
4273464ebd5Sriastradh               printf("ADD (%g %g %g %g) = (%g %g %g %g) + (%g %g %g %g)\n",
4283464ebd5Sriastradh                      result[0], result[1], result[2], result[3],
4293464ebd5Sriastradh                      a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]);
4303464ebd5Sriastradh            }
4313464ebd5Sriastradh         }
4323464ebd5Sriastradh         break;
4333464ebd5Sriastradh      case OPCODE_ARL:
4343464ebd5Sriastradh         {
4353464ebd5Sriastradh            GLfloat t[4];
4363464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, t);
4377ec681f3Smrg            machine->AddressReg[0][0] = util_ifloor(t[0]);
4383464ebd5Sriastradh            if (DEBUG_PROG) {
4393464ebd5Sriastradh               printf("ARL %d\n", machine->AddressReg[0][0]);
4403464ebd5Sriastradh            }
4413464ebd5Sriastradh         }
4423464ebd5Sriastradh         break;
4433464ebd5Sriastradh      case OPCODE_BGNLOOP:
4443464ebd5Sriastradh         /* no-op */
44501e04c3fSmrg         assert(program->arb.Instructions[inst->BranchTarget].Opcode
4463464ebd5Sriastradh                == OPCODE_ENDLOOP);
4473464ebd5Sriastradh         break;
4483464ebd5Sriastradh      case OPCODE_ENDLOOP:
4493464ebd5Sriastradh         /* subtract 1 here since pc is incremented by for(pc) loop */
45001e04c3fSmrg         assert(program->arb.Instructions[inst->BranchTarget].Opcode
4513464ebd5Sriastradh                == OPCODE_BGNLOOP);
4523464ebd5Sriastradh         pc = inst->BranchTarget - 1;   /* go to matching BNGLOOP */
4533464ebd5Sriastradh         break;
4543464ebd5Sriastradh      case OPCODE_BGNSUB:      /* begin subroutine */
4553464ebd5Sriastradh         break;
4563464ebd5Sriastradh      case OPCODE_ENDSUB:      /* end subroutine */
4573464ebd5Sriastradh         break;
4583464ebd5Sriastradh      case OPCODE_BRK:         /* break out of loop (conditional) */
45901e04c3fSmrg         assert(program->arb.Instructions[inst->BranchTarget].Opcode
4603464ebd5Sriastradh                == OPCODE_ENDLOOP);
46101e04c3fSmrg         /* break out of loop */
46201e04c3fSmrg         /* pc++ at end of for-loop will put us after the ENDLOOP inst */
46301e04c3fSmrg         pc = inst->BranchTarget;
4643464ebd5Sriastradh         break;
4653464ebd5Sriastradh      case OPCODE_CONT:        /* continue loop (conditional) */
46601e04c3fSmrg         assert(program->arb.Instructions[inst->BranchTarget].Opcode
4673464ebd5Sriastradh                == OPCODE_ENDLOOP);
46801e04c3fSmrg         /* continue at ENDLOOP */
46901e04c3fSmrg         /* Subtract 1 here since we'll do pc++ at end of for-loop */
47001e04c3fSmrg         pc = inst->BranchTarget - 1;
4713464ebd5Sriastradh         break;
4723464ebd5Sriastradh      case OPCODE_CAL:         /* Call subroutine (conditional) */
47301e04c3fSmrg         /* call the subroutine */
47401e04c3fSmrg         if (machine->StackDepth >= MAX_PROGRAM_CALL_DEPTH) {
47501e04c3fSmrg            return GL_TRUE;  /* Per GL_NV_vertex_program2 spec */
4763464ebd5Sriastradh         }
47701e04c3fSmrg         machine->CallStack[machine->StackDepth++] = pc + 1; /* next inst */
47801e04c3fSmrg         /* Subtract 1 here since we'll do pc++ at end of for-loop */
47901e04c3fSmrg         pc = inst->BranchTarget - 1;
4803464ebd5Sriastradh         break;
4813464ebd5Sriastradh      case OPCODE_CMP:
4823464ebd5Sriastradh         {
4833464ebd5Sriastradh            GLfloat a[4], b[4], c[4], result[4];
4843464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
4853464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[1], machine, b);
4863464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[2], machine, c);
4873464ebd5Sriastradh            result[0] = a[0] < 0.0F ? b[0] : c[0];
4883464ebd5Sriastradh            result[1] = a[1] < 0.0F ? b[1] : c[1];
4893464ebd5Sriastradh            result[2] = a[2] < 0.0F ? b[2] : c[2];
4903464ebd5Sriastradh            result[3] = a[3] < 0.0F ? b[3] : c[3];
4913464ebd5Sriastradh            store_vector4(inst, machine, result);
4923464ebd5Sriastradh            if (DEBUG_PROG) {
4933464ebd5Sriastradh               printf("CMP (%g %g %g %g) = (%g %g %g %g) < 0 ? (%g %g %g %g) : (%g %g %g %g)\n",
4943464ebd5Sriastradh                      result[0], result[1], result[2], result[3],
4953464ebd5Sriastradh                      a[0], a[1], a[2], a[3],
4963464ebd5Sriastradh                      b[0], b[1], b[2], b[3],
4973464ebd5Sriastradh                      c[0], c[1], c[2], c[3]);
4983464ebd5Sriastradh            }
4993464ebd5Sriastradh         }
5003464ebd5Sriastradh         break;
5013464ebd5Sriastradh      case OPCODE_COS:
5023464ebd5Sriastradh         {
5033464ebd5Sriastradh            GLfloat a[4], result[4];
5043464ebd5Sriastradh            fetch_vector1(&inst->SrcReg[0], machine, a);
5053464ebd5Sriastradh            result[0] = result[1] = result[2] = result[3]
50601e04c3fSmrg               = cosf(a[0]);
5073464ebd5Sriastradh            store_vector4(inst, machine, result);
5083464ebd5Sriastradh         }
5093464ebd5Sriastradh         break;
5103464ebd5Sriastradh      case OPCODE_DDX:         /* Partial derivative with respect to X */
5113464ebd5Sriastradh         {
5123464ebd5Sriastradh            GLfloat result[4];
51301e04c3fSmrg            fetch_vector4_deriv(&inst->SrcReg[0], machine, 'X', result);
5143464ebd5Sriastradh            store_vector4(inst, machine, result);
5153464ebd5Sriastradh         }
5163464ebd5Sriastradh         break;
5173464ebd5Sriastradh      case OPCODE_DDY:         /* Partial derivative with respect to Y */
5183464ebd5Sriastradh         {
5193464ebd5Sriastradh            GLfloat result[4];
52001e04c3fSmrg            fetch_vector4_deriv(&inst->SrcReg[0], machine, 'Y', result);
5213464ebd5Sriastradh            store_vector4(inst, machine, result);
5223464ebd5Sriastradh         }
5233464ebd5Sriastradh         break;
5243464ebd5Sriastradh      case OPCODE_DP2:
5253464ebd5Sriastradh         {
5263464ebd5Sriastradh            GLfloat a[4], b[4], result[4];
5273464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
5283464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[1], machine, b);
5293464ebd5Sriastradh            result[0] = result[1] = result[2] = result[3] = DOT2(a, b);
5303464ebd5Sriastradh            store_vector4(inst, machine, result);
5313464ebd5Sriastradh            if (DEBUG_PROG) {
5323464ebd5Sriastradh               printf("DP2 %g = (%g %g) . (%g %g)\n",
5333464ebd5Sriastradh                      result[0], a[0], a[1], b[0], b[1]);
5343464ebd5Sriastradh            }
5353464ebd5Sriastradh         }
5363464ebd5Sriastradh         break;
5373464ebd5Sriastradh      case OPCODE_DP3:
5383464ebd5Sriastradh         {
5393464ebd5Sriastradh            GLfloat a[4], b[4], result[4];
5403464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
5413464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[1], machine, b);
5423464ebd5Sriastradh            result[0] = result[1] = result[2] = result[3] = DOT3(a, b);
5433464ebd5Sriastradh            store_vector4(inst, machine, result);
5443464ebd5Sriastradh            if (DEBUG_PROG) {
5453464ebd5Sriastradh               printf("DP3 %g = (%g %g %g) . (%g %g %g)\n",
5463464ebd5Sriastradh                      result[0], a[0], a[1], a[2], b[0], b[1], b[2]);
5473464ebd5Sriastradh            }
5483464ebd5Sriastradh         }
5493464ebd5Sriastradh         break;
5503464ebd5Sriastradh      case OPCODE_DP4:
5513464ebd5Sriastradh         {
5523464ebd5Sriastradh            GLfloat a[4], b[4], result[4];
5533464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
5543464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[1], machine, b);
5553464ebd5Sriastradh            result[0] = result[1] = result[2] = result[3] = DOT4(a, b);
5563464ebd5Sriastradh            store_vector4(inst, machine, result);
5573464ebd5Sriastradh            if (DEBUG_PROG) {
5583464ebd5Sriastradh               printf("DP4 %g = (%g, %g %g %g) . (%g, %g %g %g)\n",
5593464ebd5Sriastradh                      result[0], a[0], a[1], a[2], a[3],
5603464ebd5Sriastradh                      b[0], b[1], b[2], b[3]);
5613464ebd5Sriastradh            }
5623464ebd5Sriastradh         }
5633464ebd5Sriastradh         break;
5643464ebd5Sriastradh      case OPCODE_DPH:
5653464ebd5Sriastradh         {
5663464ebd5Sriastradh            GLfloat a[4], b[4], result[4];
5673464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
5683464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[1], machine, b);
5693464ebd5Sriastradh            result[0] = result[1] = result[2] = result[3] = DOT3(a, b) + b[3];
5703464ebd5Sriastradh            store_vector4(inst, machine, result);
5713464ebd5Sriastradh         }
5723464ebd5Sriastradh         break;
5733464ebd5Sriastradh      case OPCODE_DST:         /* Distance vector */
5743464ebd5Sriastradh         {
5753464ebd5Sriastradh            GLfloat a[4], b[4], result[4];
5763464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
5773464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[1], machine, b);
5783464ebd5Sriastradh            result[0] = 1.0F;
5793464ebd5Sriastradh            result[1] = a[1] * b[1];
5803464ebd5Sriastradh            result[2] = a[2];
5813464ebd5Sriastradh            result[3] = b[3];
5823464ebd5Sriastradh            store_vector4(inst, machine, result);
5833464ebd5Sriastradh         }
5843464ebd5Sriastradh         break;
5853464ebd5Sriastradh      case OPCODE_EXP:
5863464ebd5Sriastradh         {
5873464ebd5Sriastradh            GLfloat t[4], q[4], floor_t0;
5883464ebd5Sriastradh            fetch_vector1(&inst->SrcReg[0], machine, t);
58901e04c3fSmrg            floor_t0 = floorf(t[0]);
5903464ebd5Sriastradh            if (floor_t0 > FLT_MAX_EXP) {
5913464ebd5Sriastradh               SET_POS_INFINITY(q[0]);
5923464ebd5Sriastradh               SET_POS_INFINITY(q[2]);
5933464ebd5Sriastradh            }
5943464ebd5Sriastradh            else if (floor_t0 < FLT_MIN_EXP) {
5953464ebd5Sriastradh               q[0] = 0.0F;
5963464ebd5Sriastradh               q[2] = 0.0F;
5973464ebd5Sriastradh            }
5983464ebd5Sriastradh            else {
59901e04c3fSmrg               q[0] = ldexpf(1.0, (int) floor_t0);
6003464ebd5Sriastradh               /* Note: GL_NV_vertex_program expects
6013464ebd5Sriastradh                * result.z = result.x * APPX(result.y)
6023464ebd5Sriastradh                * We do what the ARB extension says.
6033464ebd5Sriastradh                */
60401e04c3fSmrg               q[2] = exp2f(t[0]);
6053464ebd5Sriastradh            }
6063464ebd5Sriastradh            q[1] = t[0] - floor_t0;
6073464ebd5Sriastradh            q[3] = 1.0F;
6083464ebd5Sriastradh            store_vector4( inst, machine, q );
6093464ebd5Sriastradh         }
6103464ebd5Sriastradh         break;
6113464ebd5Sriastradh      case OPCODE_EX2:         /* Exponential base 2 */
6123464ebd5Sriastradh         {
6133464ebd5Sriastradh            GLfloat a[4], result[4], val;
6143464ebd5Sriastradh            fetch_vector1(&inst->SrcReg[0], machine, a);
61501e04c3fSmrg            val = exp2f(a[0]);
6163464ebd5Sriastradh            /*
6177ec681f3Smrg            if (util_is_inf_or_nan(val))
6183464ebd5Sriastradh               val = 1.0e10;
6193464ebd5Sriastradh            */
6203464ebd5Sriastradh            result[0] = result[1] = result[2] = result[3] = val;
6213464ebd5Sriastradh            store_vector4(inst, machine, result);
6223464ebd5Sriastradh         }
6233464ebd5Sriastradh         break;
6243464ebd5Sriastradh      case OPCODE_FLR:
6253464ebd5Sriastradh         {
6263464ebd5Sriastradh            GLfloat a[4], result[4];
6273464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
62801e04c3fSmrg            result[0] = floorf(a[0]);
62901e04c3fSmrg            result[1] = floorf(a[1]);
63001e04c3fSmrg            result[2] = floorf(a[2]);
63101e04c3fSmrg            result[3] = floorf(a[3]);
6323464ebd5Sriastradh            store_vector4(inst, machine, result);
6333464ebd5Sriastradh         }
6343464ebd5Sriastradh         break;
6353464ebd5Sriastradh      case OPCODE_FRC:
6363464ebd5Sriastradh         {
6373464ebd5Sriastradh            GLfloat a[4], result[4];
6383464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
63901e04c3fSmrg            result[0] = a[0] - floorf(a[0]);
64001e04c3fSmrg            result[1] = a[1] - floorf(a[1]);
64101e04c3fSmrg            result[2] = a[2] - floorf(a[2]);
64201e04c3fSmrg            result[3] = a[3] - floorf(a[3]);
6433464ebd5Sriastradh            store_vector4(inst, machine, result);
6443464ebd5Sriastradh         }
6453464ebd5Sriastradh         break;
6463464ebd5Sriastradh      case OPCODE_IF:
6473464ebd5Sriastradh         {
6483464ebd5Sriastradh            GLboolean cond;
64901e04c3fSmrg            assert(program->arb.Instructions[inst->BranchTarget].Opcode
6503464ebd5Sriastradh                   == OPCODE_ELSE ||
65101e04c3fSmrg                   program->arb.Instructions[inst->BranchTarget].Opcode
6523464ebd5Sriastradh                   == OPCODE_ENDIF);
6533464ebd5Sriastradh            /* eval condition */
65401e04c3fSmrg            GLfloat a[4];
65501e04c3fSmrg            fetch_vector1(&inst->SrcReg[0], machine, a);
65601e04c3fSmrg            cond = (a[0] != 0.0F);
6573464ebd5Sriastradh            if (DEBUG_PROG) {
6583464ebd5Sriastradh               printf("IF: %d\n", cond);
6593464ebd5Sriastradh            }
6603464ebd5Sriastradh            /* do if/else */
6613464ebd5Sriastradh            if (cond) {
6623464ebd5Sriastradh               /* do if-clause (just continue execution) */
6633464ebd5Sriastradh            }
6643464ebd5Sriastradh            else {
6653464ebd5Sriastradh               /* go to the instruction after ELSE or ENDIF */
6663464ebd5Sriastradh               assert(inst->BranchTarget >= 0);
6673464ebd5Sriastradh               pc = inst->BranchTarget;
6683464ebd5Sriastradh            }
6693464ebd5Sriastradh         }
6703464ebd5Sriastradh         break;
6713464ebd5Sriastradh      case OPCODE_ELSE:
6723464ebd5Sriastradh         /* goto ENDIF */
67301e04c3fSmrg         assert(program->arb.Instructions[inst->BranchTarget].Opcode
6743464ebd5Sriastradh                == OPCODE_ENDIF);
6753464ebd5Sriastradh         assert(inst->BranchTarget >= 0);
6763464ebd5Sriastradh         pc = inst->BranchTarget;
6773464ebd5Sriastradh         break;
6783464ebd5Sriastradh      case OPCODE_ENDIF:
6793464ebd5Sriastradh         /* nothing */
6803464ebd5Sriastradh         break;
6813464ebd5Sriastradh      case OPCODE_KIL:         /* ARB_f_p only */
6823464ebd5Sriastradh         {
6833464ebd5Sriastradh            GLfloat a[4];
6843464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
6853464ebd5Sriastradh            if (DEBUG_PROG) {
6863464ebd5Sriastradh               printf("KIL if (%g %g %g %g) <= 0.0\n",
6873464ebd5Sriastradh                      a[0], a[1], a[2], a[3]);
6883464ebd5Sriastradh            }
6893464ebd5Sriastradh
6903464ebd5Sriastradh            if (a[0] < 0.0F || a[1] < 0.0F || a[2] < 0.0F || a[3] < 0.0F) {
6913464ebd5Sriastradh               return GL_FALSE;
6923464ebd5Sriastradh            }
6933464ebd5Sriastradh         }
6943464ebd5Sriastradh         break;
6953464ebd5Sriastradh      case OPCODE_LG2:         /* log base 2 */
6963464ebd5Sriastradh         {
6973464ebd5Sriastradh            GLfloat a[4], result[4], val;
6983464ebd5Sriastradh            fetch_vector1(&inst->SrcReg[0], machine, a);
6993464ebd5Sriastradh	    /* The fast LOG2 macro doesn't meet the precision requirements.
7003464ebd5Sriastradh	     */
7013464ebd5Sriastradh            if (a[0] == 0.0F) {
7023464ebd5Sriastradh               val = -FLT_MAX;
7033464ebd5Sriastradh            }
7043464ebd5Sriastradh            else {
70501e04c3fSmrg               val = logf(a[0]) * 1.442695F;
7063464ebd5Sriastradh            }
7073464ebd5Sriastradh            result[0] = result[1] = result[2] = result[3] = val;
7083464ebd5Sriastradh            store_vector4(inst, machine, result);
7093464ebd5Sriastradh         }
7103464ebd5Sriastradh         break;
7113464ebd5Sriastradh      case OPCODE_LIT:
7123464ebd5Sriastradh         {
7133464ebd5Sriastradh            const GLfloat epsilon = 1.0F / 256.0F;      /* from NV VP spec */
7143464ebd5Sriastradh            GLfloat a[4], result[4];
7153464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
7163464ebd5Sriastradh            a[0] = MAX2(a[0], 0.0F);
7173464ebd5Sriastradh            a[1] = MAX2(a[1], 0.0F);
7183464ebd5Sriastradh            /* XXX ARB version clamps a[3], NV version doesn't */
7193464ebd5Sriastradh            a[3] = CLAMP(a[3], -(128.0F - epsilon), (128.0F - epsilon));
7203464ebd5Sriastradh            result[0] = 1.0F;
7213464ebd5Sriastradh            result[1] = a[0];
7223464ebd5Sriastradh            /* XXX we could probably just use pow() here */
7233464ebd5Sriastradh            if (a[0] > 0.0F) {
72401e04c3fSmrg               if (a[1] == 0.0F && a[3] == 0.0F)
7253464ebd5Sriastradh                  result[2] = 1.0F;
7263464ebd5Sriastradh               else
72701e04c3fSmrg                  result[2] = powf(a[1], a[3]);
7283464ebd5Sriastradh            }
7293464ebd5Sriastradh            else {
7303464ebd5Sriastradh               result[2] = 0.0F;
7313464ebd5Sriastradh            }
7323464ebd5Sriastradh            result[3] = 1.0F;
7333464ebd5Sriastradh            store_vector4(inst, machine, result);
7343464ebd5Sriastradh            if (DEBUG_PROG) {
7353464ebd5Sriastradh               printf("LIT (%g %g %g %g) : (%g %g %g %g)\n",
7363464ebd5Sriastradh                      result[0], result[1], result[2], result[3],
7373464ebd5Sriastradh                      a[0], a[1], a[2], a[3]);
7383464ebd5Sriastradh            }
7393464ebd5Sriastradh         }
7403464ebd5Sriastradh         break;
7413464ebd5Sriastradh      case OPCODE_LOG:
7423464ebd5Sriastradh         {
7433464ebd5Sriastradh            GLfloat t[4], q[4], abs_t0;
7443464ebd5Sriastradh            fetch_vector1(&inst->SrcReg[0], machine, t);
74501e04c3fSmrg            abs_t0 = fabsf(t[0]);
7463464ebd5Sriastradh            if (abs_t0 != 0.0F) {
7477ec681f3Smrg               if (util_is_inf_or_nan(abs_t0))
7483464ebd5Sriastradh               {
7493464ebd5Sriastradh                  SET_POS_INFINITY(q[0]);
7503464ebd5Sriastradh                  q[1] = 1.0F;
7513464ebd5Sriastradh                  SET_POS_INFINITY(q[2]);
7523464ebd5Sriastradh               }
7533464ebd5Sriastradh               else {
7543464ebd5Sriastradh                  int exponent;
75501e04c3fSmrg                  GLfloat mantissa = frexpf(t[0], &exponent);
7563464ebd5Sriastradh                  q[0] = (GLfloat) (exponent - 1);
75701e04c3fSmrg                  q[1] = 2.0F * mantissa; /* map [.5, 1) -> [1, 2) */
7583464ebd5Sriastradh
7593464ebd5Sriastradh		  /* The fast LOG2 macro doesn't meet the precision
7603464ebd5Sriastradh		   * requirements.
7613464ebd5Sriastradh		   */
76201e04c3fSmrg                  q[2] = logf(t[0]) * 1.442695F;
7633464ebd5Sriastradh               }
7643464ebd5Sriastradh            }
7653464ebd5Sriastradh            else {
7663464ebd5Sriastradh               SET_NEG_INFINITY(q[0]);
7673464ebd5Sriastradh               q[1] = 1.0F;
7683464ebd5Sriastradh               SET_NEG_INFINITY(q[2]);
7693464ebd5Sriastradh            }
7703464ebd5Sriastradh            q[3] = 1.0;
7713464ebd5Sriastradh            store_vector4(inst, machine, q);
7723464ebd5Sriastradh         }
7733464ebd5Sriastradh         break;
7743464ebd5Sriastradh      case OPCODE_LRP:
7753464ebd5Sriastradh         {
7763464ebd5Sriastradh            GLfloat a[4], b[4], c[4], result[4];
7773464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
7783464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[1], machine, b);
7793464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[2], machine, c);
7803464ebd5Sriastradh            result[0] = a[0] * b[0] + (1.0F - a[0]) * c[0];
7813464ebd5Sriastradh            result[1] = a[1] * b[1] + (1.0F - a[1]) * c[1];
7823464ebd5Sriastradh            result[2] = a[2] * b[2] + (1.0F - a[2]) * c[2];
7833464ebd5Sriastradh            result[3] = a[3] * b[3] + (1.0F - a[3]) * c[3];
7843464ebd5Sriastradh            store_vector4(inst, machine, result);
7853464ebd5Sriastradh            if (DEBUG_PROG) {
7863464ebd5Sriastradh               printf("LRP (%g %g %g %g) = (%g %g %g %g), "
7873464ebd5Sriastradh                      "(%g %g %g %g), (%g %g %g %g)\n",
7883464ebd5Sriastradh                      result[0], result[1], result[2], result[3],
7893464ebd5Sriastradh                      a[0], a[1], a[2], a[3],
7903464ebd5Sriastradh                      b[0], b[1], b[2], b[3], c[0], c[1], c[2], c[3]);
7913464ebd5Sriastradh            }
7923464ebd5Sriastradh         }
7933464ebd5Sriastradh         break;
7943464ebd5Sriastradh      case OPCODE_MAD:
7953464ebd5Sriastradh         {
7963464ebd5Sriastradh            GLfloat a[4], b[4], c[4], result[4];
7973464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
7983464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[1], machine, b);
7993464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[2], machine, c);
8003464ebd5Sriastradh            result[0] = a[0] * b[0] + c[0];
8013464ebd5Sriastradh            result[1] = a[1] * b[1] + c[1];
8023464ebd5Sriastradh            result[2] = a[2] * b[2] + c[2];
8033464ebd5Sriastradh            result[3] = a[3] * b[3] + c[3];
8043464ebd5Sriastradh            store_vector4(inst, machine, result);
8053464ebd5Sriastradh            if (DEBUG_PROG) {
8063464ebd5Sriastradh               printf("MAD (%g %g %g %g) = (%g %g %g %g) * "
8073464ebd5Sriastradh                      "(%g %g %g %g) + (%g %g %g %g)\n",
8083464ebd5Sriastradh                      result[0], result[1], result[2], result[3],
8093464ebd5Sriastradh                      a[0], a[1], a[2], a[3],
8103464ebd5Sriastradh                      b[0], b[1], b[2], b[3], c[0], c[1], c[2], c[3]);
8113464ebd5Sriastradh            }
8123464ebd5Sriastradh         }
8133464ebd5Sriastradh         break;
8143464ebd5Sriastradh      case OPCODE_MAX:
8153464ebd5Sriastradh         {
8163464ebd5Sriastradh            GLfloat a[4], b[4], result[4];
8173464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
8183464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[1], machine, b);
8193464ebd5Sriastradh            result[0] = MAX2(a[0], b[0]);
8203464ebd5Sriastradh            result[1] = MAX2(a[1], b[1]);
8213464ebd5Sriastradh            result[2] = MAX2(a[2], b[2]);
8223464ebd5Sriastradh            result[3] = MAX2(a[3], b[3]);
8233464ebd5Sriastradh            store_vector4(inst, machine, result);
8243464ebd5Sriastradh            if (DEBUG_PROG) {
8253464ebd5Sriastradh               printf("MAX (%g %g %g %g) = (%g %g %g %g), (%g %g %g %g)\n",
8263464ebd5Sriastradh                      result[0], result[1], result[2], result[3],
8273464ebd5Sriastradh                      a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]);
8283464ebd5Sriastradh            }
8293464ebd5Sriastradh         }
8303464ebd5Sriastradh         break;
8313464ebd5Sriastradh      case OPCODE_MIN:
8323464ebd5Sriastradh         {
8333464ebd5Sriastradh            GLfloat a[4], b[4], result[4];
8343464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
8353464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[1], machine, b);
8363464ebd5Sriastradh            result[0] = MIN2(a[0], b[0]);
8373464ebd5Sriastradh            result[1] = MIN2(a[1], b[1]);
8383464ebd5Sriastradh            result[2] = MIN2(a[2], b[2]);
8393464ebd5Sriastradh            result[3] = MIN2(a[3], b[3]);
8403464ebd5Sriastradh            store_vector4(inst, machine, result);
8413464ebd5Sriastradh         }
8423464ebd5Sriastradh         break;
8433464ebd5Sriastradh      case OPCODE_MOV:
8443464ebd5Sriastradh         {
8453464ebd5Sriastradh            GLfloat result[4];
8463464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, result);
8473464ebd5Sriastradh            store_vector4(inst, machine, result);
8483464ebd5Sriastradh            if (DEBUG_PROG) {
8493464ebd5Sriastradh               printf("MOV (%g %g %g %g)\n",
8503464ebd5Sriastradh                      result[0], result[1], result[2], result[3]);
8513464ebd5Sriastradh            }
8523464ebd5Sriastradh         }
8533464ebd5Sriastradh         break;
8543464ebd5Sriastradh      case OPCODE_MUL:
8553464ebd5Sriastradh         {
8563464ebd5Sriastradh            GLfloat a[4], b[4], result[4];
8573464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
8583464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[1], machine, b);
8593464ebd5Sriastradh            result[0] = a[0] * b[0];
8603464ebd5Sriastradh            result[1] = a[1] * b[1];
8613464ebd5Sriastradh            result[2] = a[2] * b[2];
8623464ebd5Sriastradh            result[3] = a[3] * b[3];
8633464ebd5Sriastradh            store_vector4(inst, machine, result);
8643464ebd5Sriastradh            if (DEBUG_PROG) {
8653464ebd5Sriastradh               printf("MUL (%g %g %g %g) = (%g %g %g %g) * (%g %g %g %g)\n",
8663464ebd5Sriastradh                      result[0], result[1], result[2], result[3],
8673464ebd5Sriastradh                      a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]);
8683464ebd5Sriastradh            }
8693464ebd5Sriastradh         }
8703464ebd5Sriastradh         break;
8713464ebd5Sriastradh      case OPCODE_NOISE1:
8723464ebd5Sriastradh         {
8733464ebd5Sriastradh            GLfloat a[4], result[4];
8743464ebd5Sriastradh            fetch_vector1(&inst->SrcReg[0], machine, a);
8753464ebd5Sriastradh            result[0] =
8763464ebd5Sriastradh               result[1] =
8773464ebd5Sriastradh               result[2] =
8783464ebd5Sriastradh               result[3] = _mesa_noise1(a[0]);
8793464ebd5Sriastradh            store_vector4(inst, machine, result);
8803464ebd5Sriastradh         }
8813464ebd5Sriastradh         break;
8823464ebd5Sriastradh      case OPCODE_NOISE2:
8833464ebd5Sriastradh         {
8843464ebd5Sriastradh            GLfloat a[4], result[4];
8853464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
8863464ebd5Sriastradh            result[0] =
8873464ebd5Sriastradh               result[1] =
8883464ebd5Sriastradh               result[2] = result[3] = _mesa_noise2(a[0], a[1]);
8893464ebd5Sriastradh            store_vector4(inst, machine, result);
8903464ebd5Sriastradh         }
8913464ebd5Sriastradh         break;
8923464ebd5Sriastradh      case OPCODE_NOISE3:
8933464ebd5Sriastradh         {
8943464ebd5Sriastradh            GLfloat a[4], result[4];
8953464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
8963464ebd5Sriastradh            result[0] =
8973464ebd5Sriastradh               result[1] =
8983464ebd5Sriastradh               result[2] =
8993464ebd5Sriastradh               result[3] = _mesa_noise3(a[0], a[1], a[2]);
9003464ebd5Sriastradh            store_vector4(inst, machine, result);
9013464ebd5Sriastradh         }
9023464ebd5Sriastradh         break;
9033464ebd5Sriastradh      case OPCODE_NOISE4:
9043464ebd5Sriastradh         {
9053464ebd5Sriastradh            GLfloat a[4], result[4];
9063464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
9073464ebd5Sriastradh            result[0] =
9083464ebd5Sriastradh               result[1] =
9093464ebd5Sriastradh               result[2] =
9103464ebd5Sriastradh               result[3] = _mesa_noise4(a[0], a[1], a[2], a[3]);
9113464ebd5Sriastradh            store_vector4(inst, machine, result);
9123464ebd5Sriastradh         }
9133464ebd5Sriastradh         break;
9143464ebd5Sriastradh      case OPCODE_NOP:
9153464ebd5Sriastradh         break;
9163464ebd5Sriastradh      case OPCODE_POW:
9173464ebd5Sriastradh         {
9183464ebd5Sriastradh            GLfloat a[4], b[4], result[4];
9193464ebd5Sriastradh            fetch_vector1(&inst->SrcReg[0], machine, a);
9203464ebd5Sriastradh            fetch_vector1(&inst->SrcReg[1], machine, b);
9213464ebd5Sriastradh            result[0] = result[1] = result[2] = result[3]
92201e04c3fSmrg               = powf(a[0], b[0]);
9233464ebd5Sriastradh            store_vector4(inst, machine, result);
9243464ebd5Sriastradh         }
9253464ebd5Sriastradh         break;
9263464ebd5Sriastradh
9273464ebd5Sriastradh      case OPCODE_RCP:
9283464ebd5Sriastradh         {
9293464ebd5Sriastradh            GLfloat a[4], result[4];
9303464ebd5Sriastradh            fetch_vector1(&inst->SrcReg[0], machine, a);
9313464ebd5Sriastradh            if (DEBUG_PROG) {
9323464ebd5Sriastradh               if (a[0] == 0)
9333464ebd5Sriastradh                  printf("RCP(0)\n");
9347ec681f3Smrg               else if (util_is_inf_or_nan(a[0]))
9353464ebd5Sriastradh                  printf("RCP(inf)\n");
9363464ebd5Sriastradh            }
9373464ebd5Sriastradh            result[0] = result[1] = result[2] = result[3] = 1.0F / a[0];
9383464ebd5Sriastradh            store_vector4(inst, machine, result);
9393464ebd5Sriastradh         }
9403464ebd5Sriastradh         break;
9413464ebd5Sriastradh      case OPCODE_RET:         /* return from subroutine (conditional) */
94201e04c3fSmrg         if (machine->StackDepth == 0) {
94301e04c3fSmrg            return GL_TRUE;  /* Per GL_NV_vertex_program2 spec */
9443464ebd5Sriastradh         }
94501e04c3fSmrg         /* subtract one because of pc++ in the for loop */
94601e04c3fSmrg         pc = machine->CallStack[--machine->StackDepth] - 1;
9473464ebd5Sriastradh         break;
9483464ebd5Sriastradh      case OPCODE_RSQ:         /* 1 / sqrt() */
9493464ebd5Sriastradh         {
9503464ebd5Sriastradh            GLfloat a[4], result[4];
9513464ebd5Sriastradh            fetch_vector1(&inst->SrcReg[0], machine, a);
95201e04c3fSmrg            a[0] = fabsf(a[0]);
95301e04c3fSmrg            result[0] = result[1] = result[2] = result[3] = 1.0f / sqrtf(a[0]);
9543464ebd5Sriastradh            store_vector4(inst, machine, result);
9553464ebd5Sriastradh            if (DEBUG_PROG) {
9563464ebd5Sriastradh               printf("RSQ %g = 1/sqrt(|%g|)\n", result[0], a[0]);
9573464ebd5Sriastradh            }
9583464ebd5Sriastradh         }
9593464ebd5Sriastradh         break;
9603464ebd5Sriastradh      case OPCODE_SCS:         /* sine and cos */
9613464ebd5Sriastradh         {
9623464ebd5Sriastradh            GLfloat a[4], result[4];
9633464ebd5Sriastradh            fetch_vector1(&inst->SrcReg[0], machine, a);
96401e04c3fSmrg            result[0] = cosf(a[0]);
96501e04c3fSmrg            result[1] = sinf(a[0]);
96601e04c3fSmrg            result[2] = 0.0F;    /* undefined! */
96701e04c3fSmrg            result[3] = 0.0F;    /* undefined! */
9683464ebd5Sriastradh            store_vector4(inst, machine, result);
9693464ebd5Sriastradh         }
9703464ebd5Sriastradh         break;
9713464ebd5Sriastradh      case OPCODE_SGE:         /* set on greater or equal */
9723464ebd5Sriastradh         {
9733464ebd5Sriastradh            GLfloat a[4], b[4], result[4];
9743464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
9753464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[1], machine, b);
9763464ebd5Sriastradh            result[0] = (a[0] >= b[0]) ? 1.0F : 0.0F;
9773464ebd5Sriastradh            result[1] = (a[1] >= b[1]) ? 1.0F : 0.0F;
9783464ebd5Sriastradh            result[2] = (a[2] >= b[2]) ? 1.0F : 0.0F;
9793464ebd5Sriastradh            result[3] = (a[3] >= b[3]) ? 1.0F : 0.0F;
9803464ebd5Sriastradh            store_vector4(inst, machine, result);
9813464ebd5Sriastradh            if (DEBUG_PROG) {
9823464ebd5Sriastradh               printf("SGE (%g %g %g %g) = (%g %g %g %g) >= (%g %g %g %g)\n",
9833464ebd5Sriastradh                      result[0], result[1], result[2], result[3],
9843464ebd5Sriastradh                      a[0], a[1], a[2], a[3],
9853464ebd5Sriastradh                      b[0], b[1], b[2], b[3]);
9863464ebd5Sriastradh            }
9873464ebd5Sriastradh         }
9883464ebd5Sriastradh         break;
9893464ebd5Sriastradh      case OPCODE_SIN:
9903464ebd5Sriastradh         {
9913464ebd5Sriastradh            GLfloat a[4], result[4];
9923464ebd5Sriastradh            fetch_vector1(&inst->SrcReg[0], machine, a);
9933464ebd5Sriastradh            result[0] = result[1] = result[2] = result[3]
99401e04c3fSmrg               = sinf(a[0]);
9953464ebd5Sriastradh            store_vector4(inst, machine, result);
9963464ebd5Sriastradh         }
9973464ebd5Sriastradh         break;
9983464ebd5Sriastradh      case OPCODE_SLT:         /* set on less */
9993464ebd5Sriastradh         {
10003464ebd5Sriastradh            GLfloat a[4], b[4], result[4];
10013464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
10023464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[1], machine, b);
10033464ebd5Sriastradh            result[0] = (a[0] < b[0]) ? 1.0F : 0.0F;
10043464ebd5Sriastradh            result[1] = (a[1] < b[1]) ? 1.0F : 0.0F;
10053464ebd5Sriastradh            result[2] = (a[2] < b[2]) ? 1.0F : 0.0F;
10063464ebd5Sriastradh            result[3] = (a[3] < b[3]) ? 1.0F : 0.0F;
10073464ebd5Sriastradh            store_vector4(inst, machine, result);
10083464ebd5Sriastradh            if (DEBUG_PROG) {
10093464ebd5Sriastradh               printf("SLT (%g %g %g %g) = (%g %g %g %g) < (%g %g %g %g)\n",
10103464ebd5Sriastradh                      result[0], result[1], result[2], result[3],
10113464ebd5Sriastradh                      a[0], a[1], a[2], a[3],
10123464ebd5Sriastradh                      b[0], b[1], b[2], b[3]);
10133464ebd5Sriastradh            }
10143464ebd5Sriastradh         }
10153464ebd5Sriastradh         break;
10163464ebd5Sriastradh      case OPCODE_SSG:         /* set sign (-1, 0 or +1) */
10173464ebd5Sriastradh         {
10183464ebd5Sriastradh            GLfloat a[4], result[4];
10193464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
10203464ebd5Sriastradh            result[0] = (GLfloat) ((a[0] > 0.0F) - (a[0] < 0.0F));
10213464ebd5Sriastradh            result[1] = (GLfloat) ((a[1] > 0.0F) - (a[1] < 0.0F));
10223464ebd5Sriastradh            result[2] = (GLfloat) ((a[2] > 0.0F) - (a[2] < 0.0F));
10233464ebd5Sriastradh            result[3] = (GLfloat) ((a[3] > 0.0F) - (a[3] < 0.0F));
10243464ebd5Sriastradh            store_vector4(inst, machine, result);
10253464ebd5Sriastradh         }
10263464ebd5Sriastradh         break;
10273464ebd5Sriastradh      case OPCODE_SUB:
10283464ebd5Sriastradh         {
10293464ebd5Sriastradh            GLfloat a[4], b[4], result[4];
10303464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
10313464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[1], machine, b);
10323464ebd5Sriastradh            result[0] = a[0] - b[0];
10333464ebd5Sriastradh            result[1] = a[1] - b[1];
10343464ebd5Sriastradh            result[2] = a[2] - b[2];
10353464ebd5Sriastradh            result[3] = a[3] - b[3];
10363464ebd5Sriastradh            store_vector4(inst, machine, result);
10373464ebd5Sriastradh            if (DEBUG_PROG) {
10383464ebd5Sriastradh               printf("SUB (%g %g %g %g) = (%g %g %g %g) - (%g %g %g %g)\n",
10393464ebd5Sriastradh                      result[0], result[1], result[2], result[3],
10403464ebd5Sriastradh                      a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]);
10413464ebd5Sriastradh            }
10423464ebd5Sriastradh         }
10433464ebd5Sriastradh         break;
10443464ebd5Sriastradh      case OPCODE_SWZ:         /* extended swizzle */
10453464ebd5Sriastradh         {
10463464ebd5Sriastradh            const struct prog_src_register *source = &inst->SrcReg[0];
10473464ebd5Sriastradh            const GLfloat *src = get_src_register_pointer(source, machine);
10483464ebd5Sriastradh            GLfloat result[4];
10493464ebd5Sriastradh            GLuint i;
10503464ebd5Sriastradh            for (i = 0; i < 4; i++) {
10513464ebd5Sriastradh               const GLuint swz = GET_SWZ(source->Swizzle, i);
10523464ebd5Sriastradh               if (swz == SWIZZLE_ZERO)
10533464ebd5Sriastradh                  result[i] = 0.0;
10543464ebd5Sriastradh               else if (swz == SWIZZLE_ONE)
10553464ebd5Sriastradh                  result[i] = 1.0;
10563464ebd5Sriastradh               else {
105701e04c3fSmrg                  assert(swz <= 3);
10583464ebd5Sriastradh                  result[i] = src[swz];
10593464ebd5Sriastradh               }
10603464ebd5Sriastradh               if (source->Negate & (1 << i))
10613464ebd5Sriastradh                  result[i] = -result[i];
10623464ebd5Sriastradh            }
10633464ebd5Sriastradh            store_vector4(inst, machine, result);
10643464ebd5Sriastradh         }
10653464ebd5Sriastradh         break;
10663464ebd5Sriastradh      case OPCODE_TEX:         /* Both ARB and NV frag prog */
10673464ebd5Sriastradh         /* Simple texel lookup */
10683464ebd5Sriastradh         {
10693464ebd5Sriastradh            GLfloat texcoord[4], color[4];
10703464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, texcoord);
10713464ebd5Sriastradh
1072af69d88dSmrg            /* For TEX, texcoord.Q should not be used and its value should not
1073af69d88dSmrg             * matter (at most, we pass coord.xyz to texture3D() in GLSL).
1074af69d88dSmrg             * Set Q=1 so that FetchTexelDeriv() doesn't get a garbage value
1075af69d88dSmrg             * which is effectively what happens when the texcoord swizzle
1076af69d88dSmrg             * is .xyzz
1077af69d88dSmrg             */
1078af69d88dSmrg            texcoord[3] = 1.0f;
1079af69d88dSmrg
10803464ebd5Sriastradh            fetch_texel(ctx, machine, inst, texcoord, 0.0, color);
10813464ebd5Sriastradh
10823464ebd5Sriastradh            if (DEBUG_PROG) {
10833464ebd5Sriastradh               printf("TEX (%g, %g, %g, %g) = texture[%d][%g, %g, %g, %g]\n",
10843464ebd5Sriastradh                      color[0], color[1], color[2], color[3],
10853464ebd5Sriastradh                      inst->TexSrcUnit,
10863464ebd5Sriastradh                      texcoord[0], texcoord[1], texcoord[2], texcoord[3]);
10873464ebd5Sriastradh            }
10883464ebd5Sriastradh            store_vector4(inst, machine, color);
10893464ebd5Sriastradh         }
10903464ebd5Sriastradh         break;
10913464ebd5Sriastradh      case OPCODE_TXB:         /* GL_ARB_fragment_program only */
10923464ebd5Sriastradh         /* Texel lookup with LOD bias */
10933464ebd5Sriastradh         {
10943464ebd5Sriastradh            GLfloat texcoord[4], color[4], lodBias;
10953464ebd5Sriastradh
10963464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, texcoord);
10973464ebd5Sriastradh
10983464ebd5Sriastradh            /* texcoord[3] is the bias to add to lambda */
10993464ebd5Sriastradh            lodBias = texcoord[3];
11003464ebd5Sriastradh
11013464ebd5Sriastradh            fetch_texel(ctx, machine, inst, texcoord, lodBias, color);
11023464ebd5Sriastradh
11033464ebd5Sriastradh            if (DEBUG_PROG) {
11043464ebd5Sriastradh               printf("TXB (%g, %g, %g, %g) = texture[%d][%g %g %g %g]"
11053464ebd5Sriastradh                      "  bias %g\n",
11063464ebd5Sriastradh                      color[0], color[1], color[2], color[3],
11073464ebd5Sriastradh                      inst->TexSrcUnit,
11083464ebd5Sriastradh                      texcoord[0],
11093464ebd5Sriastradh                      texcoord[1],
11103464ebd5Sriastradh                      texcoord[2],
11113464ebd5Sriastradh                      texcoord[3],
11123464ebd5Sriastradh                      lodBias);
11133464ebd5Sriastradh            }
11143464ebd5Sriastradh
11153464ebd5Sriastradh            store_vector4(inst, machine, color);
11163464ebd5Sriastradh         }
11173464ebd5Sriastradh         break;
111801e04c3fSmrg      case OPCODE_TXD:
11193464ebd5Sriastradh         /* Texture lookup w/ partial derivatives for LOD */
11203464ebd5Sriastradh         {
11213464ebd5Sriastradh            GLfloat texcoord[4], dtdx[4], dtdy[4], color[4];
11223464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, texcoord);
11233464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[1], machine, dtdx);
11243464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[2], machine, dtdy);
11253464ebd5Sriastradh            machine->FetchTexelDeriv(ctx, texcoord, dtdx, dtdy,
11263464ebd5Sriastradh                                     0.0, /* lodBias */
11273464ebd5Sriastradh                                     inst->TexSrcUnit, color);
11283464ebd5Sriastradh            store_vector4(inst, machine, color);
11293464ebd5Sriastradh         }
11303464ebd5Sriastradh         break;
11313464ebd5Sriastradh      case OPCODE_TXL:
11323464ebd5Sriastradh         /* Texel lookup with explicit LOD */
11333464ebd5Sriastradh         {
11343464ebd5Sriastradh            GLfloat texcoord[4], color[4], lod;
11353464ebd5Sriastradh
11363464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, texcoord);
11373464ebd5Sriastradh
11383464ebd5Sriastradh            /* texcoord[3] is the LOD */
11393464ebd5Sriastradh            lod = texcoord[3];
11403464ebd5Sriastradh
11413464ebd5Sriastradh	    machine->FetchTexelLod(ctx, texcoord, lod,
11423464ebd5Sriastradh				   machine->Samplers[inst->TexSrcUnit], color);
11433464ebd5Sriastradh
11443464ebd5Sriastradh            store_vector4(inst, machine, color);
11453464ebd5Sriastradh         }
11463464ebd5Sriastradh         break;
11473464ebd5Sriastradh      case OPCODE_TXP:         /* GL_ARB_fragment_program only */
11483464ebd5Sriastradh         /* Texture lookup w/ projective divide */
11493464ebd5Sriastradh         {
11503464ebd5Sriastradh            GLfloat texcoord[4], color[4];
11513464ebd5Sriastradh
11523464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, texcoord);
11533464ebd5Sriastradh            /* Not so sure about this test - if texcoord[3] is
115401e04c3fSmrg             * zero, we'd probably be fine except for an assert in
11553464ebd5Sriastradh             * IROUND_POS() which gets triggered by the inf values created.
11563464ebd5Sriastradh             */
115701e04c3fSmrg            if (texcoord[3] != 0.0F) {
11583464ebd5Sriastradh               texcoord[0] /= texcoord[3];
11593464ebd5Sriastradh               texcoord[1] /= texcoord[3];
11603464ebd5Sriastradh               texcoord[2] /= texcoord[3];
11613464ebd5Sriastradh            }
11623464ebd5Sriastradh
11633464ebd5Sriastradh            fetch_texel(ctx, machine, inst, texcoord, 0.0, color);
11643464ebd5Sriastradh
11653464ebd5Sriastradh            store_vector4(inst, machine, color);
11663464ebd5Sriastradh         }
11673464ebd5Sriastradh         break;
11683464ebd5Sriastradh      case OPCODE_TRUNC:       /* truncate toward zero */
11693464ebd5Sriastradh         {
11703464ebd5Sriastradh            GLfloat a[4], result[4];
11713464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
11723464ebd5Sriastradh            result[0] = (GLfloat) (GLint) a[0];
11733464ebd5Sriastradh            result[1] = (GLfloat) (GLint) a[1];
11743464ebd5Sriastradh            result[2] = (GLfloat) (GLint) a[2];
11753464ebd5Sriastradh            result[3] = (GLfloat) (GLint) a[3];
11763464ebd5Sriastradh            store_vector4(inst, machine, result);
11773464ebd5Sriastradh         }
11783464ebd5Sriastradh         break;
11793464ebd5Sriastradh      case OPCODE_XPD:         /* cross product */
11803464ebd5Sriastradh         {
11813464ebd5Sriastradh            GLfloat a[4], b[4], result[4];
11823464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[0], machine, a);
11833464ebd5Sriastradh            fetch_vector4(&inst->SrcReg[1], machine, b);
11843464ebd5Sriastradh            result[0] = a[1] * b[2] - a[2] * b[1];
11853464ebd5Sriastradh            result[1] = a[2] * b[0] - a[0] * b[2];
11863464ebd5Sriastradh            result[2] = a[0] * b[1] - a[1] * b[0];
11873464ebd5Sriastradh            result[3] = 1.0;
11883464ebd5Sriastradh            store_vector4(inst, machine, result);
11893464ebd5Sriastradh            if (DEBUG_PROG) {
11903464ebd5Sriastradh               printf("XPD (%g %g %g %g) = (%g %g %g) X (%g %g %g)\n",
11913464ebd5Sriastradh                      result[0], result[1], result[2], result[3],
11923464ebd5Sriastradh                      a[0], a[1], a[2], b[0], b[1], b[2]);
11933464ebd5Sriastradh            }
11943464ebd5Sriastradh         }
11953464ebd5Sriastradh         break;
11963464ebd5Sriastradh      case OPCODE_END:
11973464ebd5Sriastradh         return GL_TRUE;
11983464ebd5Sriastradh      default:
11993464ebd5Sriastradh         _mesa_problem(ctx, "Bad opcode %d in _mesa_execute_program",
12003464ebd5Sriastradh                       inst->Opcode);
12013464ebd5Sriastradh         return GL_TRUE;        /* return value doesn't matter */
12023464ebd5Sriastradh      }
12033464ebd5Sriastradh
12043464ebd5Sriastradh      numExec++;
12053464ebd5Sriastradh      if (numExec > maxExec) {
12063464ebd5Sriastradh	 static GLboolean reported = GL_FALSE;
12073464ebd5Sriastradh	 if (!reported) {
12083464ebd5Sriastradh	    _mesa_problem(ctx, "Infinite loop detected in fragment program");
12093464ebd5Sriastradh	    reported = GL_TRUE;
12103464ebd5Sriastradh	 }
12113464ebd5Sriastradh         return GL_TRUE;
12123464ebd5Sriastradh      }
12133464ebd5Sriastradh
12143464ebd5Sriastradh   } /* for pc */
12153464ebd5Sriastradh
12163464ebd5Sriastradh   return GL_TRUE;
12173464ebd5Sriastradh}
1218