#include "glheader.h"
#include "context.h"
#include "imports.h"
#include "macros.h"
#include "mtypes.h"
#include "vpexec.h"
#include "mmath.h"
#include "math/m_matrix.h"
void
_mesa_init_vp_registers(GLcontext *ctx)
{
struct vp_machine *machine = &(ctx->VertexProgram.Machine);
GLuint i;
MEMCPY(machine->Registers[VP_INPUT_REG_START],
ctx->Current.Attrib,
16 * 4 * sizeof(GLfloat));
for (i = VP_OUTPUT_REG_START; i <= VP_OUTPUT_REG_END; i++) {
machine->Registers[i][0] = 0.0F;
machine->Registers[i][1] = 0.0F;
machine->Registers[i][2] = 0.0F;
machine->Registers[i][3] = 1.0F;
}
for (i = VP_TEMP_REG_START; i <= VP_TEMP_REG_END; i++) {
machine->Registers[i][0] = 0.0F;
machine->Registers[i][1] = 0.0F;
machine->Registers[i][2] = 0.0F;
machine->Registers[i][3] = 1.0F;
}
}
static void
load_matrix(GLfloat registers[][4], GLuint pos, const GLfloat mat[16])
{
GLuint i;
pos += VP_PROG_REG_START;
for (i = 0; i < 4; i++) {
registers[pos + i][0] = mat[0 + i];
registers[pos + i][1] = mat[4 + i];
registers[pos + i][2] = mat[8 + i];
registers[pos + i][3] = mat[12 + i];
}
}
static void
load_transpose_matrix(GLfloat registers[][4], GLuint pos,
const GLfloat mat[16])
{
pos += VP_PROG_REG_START;
MEMCPY(registers[pos], mat, 16 * sizeof(GLfloat));
}
void
_mesa_init_tracked_matrices(GLcontext *ctx)
{
GLuint i;
for (i = 0; i < VP_NUM_PROG_REGS / 4; i++) {
GLmatrix *mat;
if (ctx->VertexProgram.TrackMatrix[i] == GL_MODELVIEW) {
mat = ctx->ModelviewMatrixStack.Top;
}
else if (ctx->VertexProgram.TrackMatrix[i] == GL_PROJECTION) {
mat = ctx->ProjectionMatrixStack.Top;
}
else if (ctx->VertexProgram.TrackMatrix[i] == GL_TEXTURE) {
mat = ctx->TextureMatrixStack[ctx->Texture.CurrentUnit].Top;
}
else if (ctx->VertexProgram.TrackMatrix[i] == GL_COLOR) {
mat = ctx->ColorMatrixStack.Top;
}
else if (ctx->VertexProgram.TrackMatrix[i]==GL_MODELVIEW_PROJECTION_NV) {
mat = &ctx->_ModelProjectMatrix;
}
else if (ctx->VertexProgram.TrackMatrix[i] >= GL_MATRIX0_NV &&
ctx->VertexProgram.TrackMatrix[i] <= GL_MATRIX7_NV) {
GLuint n = ctx->VertexProgram.TrackMatrix[i] - GL_MATRIX0_NV;
ASSERT(n < MAX_PROGRAM_MATRICES);
mat = ctx->ProgramMatrixStack[n].Top;
}
else {
assert(ctx->VertexProgram.TrackMatrix[i] == GL_NONE);
continue;
}
if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_IDENTITY_NV) {
load_matrix(ctx->VertexProgram.Machine.Registers, i*4, mat->m);
}
else if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_INVERSE_NV) {
_math_matrix_analyse(mat);
assert((mat->flags & MAT_DIRTY_INVERSE) == 0);
load_matrix(ctx->VertexProgram.Machine.Registers, i*4, mat->inv);
}
else if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_TRANSPOSE_NV) {
load_transpose_matrix(ctx->VertexProgram.Machine.Registers, i*4, mat->m);
}
else {
assert(ctx->VertexProgram.TrackMatrixTransform[i]
== GL_INVERSE_TRANSPOSE_NV);
_math_matrix_analyse(mat);
assert((mat->flags & MAT_DIRTY_INVERSE) == 0);
load_transpose_matrix(ctx->VertexProgram.Machine.Registers,
i*4, mat->inv);
}
}
}
void
_mesa_dump_vp_machine( const struct vp_machine *machine )
{
int i;
_mesa_printf("VertexIn:\n");
for (i = 0; i < VP_NUM_INPUT_REGS; i++) {
_mesa_printf("%d: %f %f %f %f ", i,
machine->Registers[i + VP_INPUT_REG_START][0],
machine->Registers[i + VP_INPUT_REG_START][1],
machine->Registers[i + VP_INPUT_REG_START][2],
machine->Registers[i + VP_INPUT_REG_START][3]);
}
_mesa_printf("\n");
_mesa_printf("VertexOut:\n");
for (i = 0; i < VP_NUM_OUTPUT_REGS; i++) {
_mesa_printf("%d: %f %f %f %f ", i,
machine->Registers[i + VP_OUTPUT_REG_START][0],
machine->Registers[i + VP_OUTPUT_REG_START][1],
machine->Registers[i + VP_OUTPUT_REG_START][2],
machine->Registers[i + VP_OUTPUT_REG_START][3]);
}
_mesa_printf("\n");
_mesa_printf("Registers:\n");
for (i = 0; i < VP_NUM_TEMP_REGS; i++) {
_mesa_printf("%d: %f %f %f %f ", i,
machine->Registers[i + VP_TEMP_REG_START][0],
machine->Registers[i + VP_TEMP_REG_START][1],
machine->Registers[i + VP_TEMP_REG_START][2],
machine->Registers[i + VP_TEMP_REG_START][3]);
}
_mesa_printf("\n");
_mesa_printf("Parameters:\n");
for (i = 0; i < VP_NUM_PROG_REGS; i++) {
_mesa_printf("%d: %f %f %f %f ", i,
machine->Registers[i + VP_PROG_REG_START][0],
machine->Registers[i + VP_PROG_REG_START][1],
machine->Registers[i + VP_PROG_REG_START][2],
machine->Registers[i + VP_PROG_REG_START][3]);
}
_mesa_printf("\n");
}
static void
fetch_vector4( const struct vp_src_register *source,
const struct vp_machine *machine,
GLfloat result[4] )
{
static const GLfloat zero[4] = { 0, 0, 0, 0 };
const GLfloat *src;
if (source->RelAddr) {
const GLint reg = source->Register + machine->AddressReg;
if (reg < 0 || reg > VP_NUM_PROG_REGS)
src = zero;
else
src = machine->Registers[VP_PROG_REG_START + reg];
}
else {
src = machine->Registers[source->Register];
}
if (source->Negate) {
result[0] = -src[source->Swizzle[0]];
result[1] = -src[source->Swizzle[1]];
result[2] = -src[source->Swizzle[2]];
result[3] = -src[source->Swizzle[3]];
}
else {
result[0] = src[source->Swizzle[0]];
result[1] = src[source->Swizzle[1]];
result[2] = src[source->Swizzle[2]];
result[3] = src[source->Swizzle[3]];
}
}
static void
fetch_vector1( const struct vp_src_register *source,
const struct vp_machine *machine,
GLfloat result[4] )
{
static const GLfloat zero[4] = { 0, 0, 0, 0 };
const GLfloat *src;
if (source->RelAddr) {
const GLint reg = source->Register + machine->AddressReg;
if (reg < 0 || reg > VP_NUM_PROG_REGS)
src = zero;
else
src = machine->Registers[VP_PROG_REG_START + reg];
}
else {
src = machine->Registers[source->Register];
}
if (source->Negate) {
result[0] = -src[source->Swizzle[0]];
}
else {
result[0] = src[source->Swizzle[0]];
}
}
static void
store_vector4( const struct vp_dst_register *dest, struct vp_machine *machine,
const GLfloat value[4] )
{
GLfloat *dst = machine->Registers[dest->Register];
if (dest->WriteMask[0])
dst[0] = value[0];
if (dest->WriteMask[1])
dst[1] = value[1];
if (dest->WriteMask[2])
dst[2] = value[2];
if (dest->WriteMask[3])
dst[3] = value[3];
}
#ifdef USE_IEEE
#define SET_POS_INFINITY(x) ( *((GLuint *) &x) = 0x7F800000 )
#define SET_NEG_INFINITY(x) ( *((GLuint *) &x) = 0xFF800000 )
#elif defined(VMS)
#define SET_POS_INFINITY(x) x = __MAXFLOAT
#define SET_NEG_INFINITY(x) x = -__MAXFLOAT
#else
#define SET_POS_INFINITY(x) x = (GLfloat) HUGE_VAL
#define SET_NEG_INFINITY(x) x = (GLfloat) -HUGE_VAL
#endif
#define SET_FLOAT_BITS(x, bits) ((fi_type *) &(x))->i = bits
void
_mesa_exec_program(GLcontext *ctx, const struct vp_program *program)
{
struct vp_machine *machine = &ctx->VertexProgram.Machine;
const struct vp_instruction *inst;
for (inst = program->Instructions; inst->Opcode !=END; inst++) {
switch (inst->Opcode) {
case MOV:
{
GLfloat t[4];
fetch_vector4( &inst->SrcReg[0], machine, t );
store_vector4( &inst->DstReg, machine, t );
}
break;
case LIT:
{
const GLfloat epsilon = 1.0e-5F;
GLfloat t[4], lit[4];
fetch_vector4( &inst->SrcReg[0], machine, t );
if (t[3] < -(128.0F - epsilon))
t[3] = - (128.0F - epsilon);
else if (t[3] > 128.0F - epsilon)
t[3] = 128.0F - epsilon;
if (t[0] < 0.0)
t[0] = 0.0;
if (t[1] < 0.0)
t[1] = 0.0;
lit[0] = 1.0;
lit[1] = t[0];
lit[2] = (t[0] > 0.0) ? (GLfloat) exp(t[3] * log(t[1])) : 0.0F;
lit[3] = 1.0;
store_vector4( &inst->DstReg, machine, lit );
}
break;
case RCP:
{
GLfloat t[4];
fetch_vector1( &inst->SrcReg[0], machine, t );
if (t[0] != 1.0F)
t[0] = 1.0F / t[0];
t[1] = t[2] = t[3] = t[0];
store_vector4( &inst->DstReg, machine, t );
}
break;
case RSQ:
{
GLfloat t[4];
fetch_vector1( &inst->SrcReg[0], machine, t );
t[0] = (float) (1.0 / sqrt(fabs(t[0])));
t[1] = t[2] = t[3] = t[0];
store_vector4( &inst->DstReg, machine, t );
}
break;
case EXP:
{
GLfloat t[4], q[4], floor_t0;
fetch_vector1( &inst->SrcReg[0], machine, t );
floor_t0 = (float) floor(t[0]);
if (floor_t0 > FLT_MAX_EXP) {
SET_POS_INFINITY(q[0]);
SET_POS_INFINITY(q[2]);
}
else if (floor_t0 < FLT_MIN_EXP) {
q[0] = 0.0F;
q[2] = 0.0F;
}
else {
#ifdef USE_IEEE
GLint ii = (GLint) floor_t0;
ii = (ii < 23) + 0x3f800000;
SET_FLOAT_BITS(q[0], ii);
q[0] = *((GLfloat *) &ii);
#else
q[0] = (GLfloat) pow(2.0, floor_t0);
#endif
q[2] = (GLfloat) (q[0] * LOG2(q[1]));
}
q[1] = t[0] - floor_t0;
q[3] = 1.0F;
store_vector4( &inst->DstReg, machine, q );
}
break;
case LOG:
{
GLfloat t[4], q[4], abs_t0;
fetch_vector1( &inst->SrcReg[0], machine, t );
abs_t0 = (GLfloat) fabs(t[0]);
if (abs_t0 != 0.0F) {
#ifdef VMS
if (abs_t0 == __MAXFLOAT) {
#else
if (IS_INF_OR_NAN(abs_t0)) {
#endif
SET_POS_INFINITY(q[0]);
q[1] = 1.0F;
SET_POS_INFINITY(q[2]);
}
else {
int exponent;
double mantissa = frexp(t[0], &exponent);
q[0] = (GLfloat) (exponent - 1);
q[1] = (GLfloat) (2.0 * mantissa);
q[2] = (GLfloat) (q[0] + LOG2(q[1]));
}
}
else {
SET_NEG_INFINITY(q[0]);
q[1] = 1.0F;
SET_NEG_INFINITY(q[2]);
}
q[3] = 1.0;
store_vector4( &inst->DstReg, machine, q );
}
break;
case MUL:
{
GLfloat t[4], u[4], prod[4];
fetch_vector4( &inst->SrcReg[0], machine, t );
fetch_vector4( &inst->SrcReg[1], machine, u );
prod[0] = t[0] * u[0];
prod[1] = t[1] * u[1];
prod[2] = t[2] * u[2];
prod[3] = t[3] * u[3];
store_vector4( &inst->DstReg, machine, prod );
}
break;
case ADD:
{
GLfloat t[4], u[4], sum[4];
fetch_vector4( &inst->SrcReg[0], machine, t );
fetch_vector4( &inst->SrcReg[1], machine, u );
sum[0] = t[0] + u[0];
sum[1] = t[1] + u[1];
sum[2] = t[2] + u[2];
sum[3] = t[3] + u[3];
store_vector4( &inst->DstReg, machine, sum );
}
break;
case DP3:
{
GLfloat t[4], u[4], dot[4];
fetch_vector4( &inst->SrcReg[0], machine, t );
fetch_vector4( &inst->SrcReg[1], machine, u );
dot[0] = t[0] * u[0] + t[1] * u[1] + t[2] * u[2];
dot[1] = dot[2] = dot[3] = dot[0];
store_vector4( &inst->DstReg, machine, dot );
}
break;
case DP4:
{
GLfloat t[4], u[4], dot[4];
fetch_vector4( &inst->SrcReg[0], machine, t );
fetch_vector4( &inst->SrcReg[1], machine, u );
dot[0] = t[0] * u[0] + t[1] * u[1] + t[2] * u[2] + t[3] * u[3];
dot[1] = dot[2] = dot[3] = dot[0];
store_vector4( &inst->DstReg, machine, dot );
}
break;
case DST:
{
GLfloat t[4], u[4], dst[4];
fetch_vector4( &inst->SrcReg[0], machine, t );
fetch_vector4( &inst->SrcReg[1], machine, u );
dst[0] = 1.0F;
dst[1] = t[1] * u[1];
dst[2] = t[2];
dst[3] = u[3];
store_vector4( &inst->DstReg, machine, dst );
}
break;
case MIN:
{
GLfloat t[4], u[4], min[4];
fetch_vector4( &inst->SrcReg[0], machine, t );
fetch_vector4( &inst->SrcReg[1], machine, u );
min[0] = (t[0] < u[0]) ? t[0] : u[0];
min[1] = (t[1] < u[1]) ? t[1] : u[1];
min[2] = (t[2] < u[2]) ? t[2] : u[2];
min[3] = (t[3] < u[3]) ? t[3] : u[3];
store_vector4( &inst->DstReg, machine, min );
}
break;
case MAX:
{
GLfloat t[4], u[4], max[4];
fetch_vector4( &inst->SrcReg[0], machine, t );
fetch_vector4( &inst->SrcReg[1], machine, u );
max[0] = (t[0] > u[0]) ? t[0] : u[0];
max[1] = (t[1] > u[1]) ? t[1] : u[1];
max[2] = (t[2] > u[2]) ? t[2] : u[2];
max[3] = (t[3] > u[3]) ? t[3] : u[3];
store_vector4( &inst->DstReg, machine, max );
}
break;
case SLT:
{
GLfloat t[4], u[4], slt[4];
fetch_vector4( &inst->SrcReg[0], machine, t );
fetch_vector4( &inst->SrcReg[1], machine, u );
slt[0] = (t[0] < u[0]) ? 1.0F : 0.0F;
slt[1] = (t[1] < u[1]) ? 1.0F : 0.0F;
slt[2] = (t[2] < u[2]) ? 1.0F : 0.0F;
slt[3] = (t[3] < u[3]) ? 1.0F : 0.0F;
store_vector4( &inst->DstReg, machine, slt );
}
break;
case SGE:
{
GLfloat t[4], u[4], sge[4];
fetch_vector4( &inst->SrcReg[0], machine, t );
fetch_vector4( &inst->SrcReg[1], machine, u );
sge[0] = (t[0] >= u[0]) ? 1.0F : 0.0F;
sge[1] = (t[1] >= u[1]) ? 1.0F : 0.0F;
sge[2] = (t[2] >= u[2]) ? 1.0F : 0.0F;
sge[3] = (t[3] >= u[3]) ? 1.0F : 0.0F;
store_vector4( &inst->DstReg, machine, sge );
}
break;
case MAD:
{
GLfloat t[4], u[4], v[4], sum[4];
fetch_vector4( &inst->SrcReg[0], machine, t );
fetch_vector4( &inst->SrcReg[1], machine, u );
fetch_vector4( &inst->SrcReg[2], machine, v );
sum[0] = t[0] * u[0] + v[0];
sum[1] = t[1] * u[1] + v[1];
sum[2] = t[2] * u[2] + v[2];
sum[3] = t[3] * u[3] + v[3];
store_vector4( &inst->DstReg, machine, sum );
}
break;
case ARL:
{
GLfloat t[4];
fetch_vector4( &inst->SrcReg[0], machine, t );
machine->AddressReg = (GLint) floor(t[0]);
}
break;
case DPH:
{
GLfloat t[4], u[4], dot[4];
fetch_vector4( &inst->SrcReg[0], machine, t );
fetch_vector4( &inst->SrcReg[1], machine, u );
dot[0] = t[0] * u[0] + t[1] * u[1] + t[2] * u[2] + u[3];
dot[1] = dot[2] = dot[3] = dot[0];
store_vector4( &inst->DstReg, machine, dot );
}
break;
case RCC:
{
GLfloat t[4], u;
fetch_vector1( &inst->SrcReg[0], machine, t );
if (t[0] == 1.0F)
u = 1.0F;
else
u = 1.0F / t[0];
if (u > 0.0F) {
if (u > 1.884467e+019F) {
u = 1.884467e+019F;
}
else if (u < 5.42101e-020F) {
u = 5.42101e-020F;
}
}
else {
if (u < -1.884467e+019F) {
u = -1.884467e+019F;
}
else if (u > -5.42101e-020F) {
u = -5.42101e-020F;
}
}
t[0] = t[1] = t[2] = t[3] = u;
store_vector4( &inst->DstReg, machine, t );
}
break;
case SUB:
{
GLfloat t[4], u[4], sum[4];
fetch_vector4( &inst->SrcReg[0], machine, t );
fetch_vector4( &inst->SrcReg[1], machine, u );
sum[0] = t[0] - u[0];
sum[1] = t[1] - u[1];
sum[2] = t[2] - u[2];
sum[3] = t[3] - u[3];
store_vector4( &inst->DstReg, machine, sum );
}
break;
case ABS:
{
GLfloat t[4];
fetch_vector4( &inst->SrcReg[0], machine, t );
if (t[0] < 0.0) t[0] = -t[0];
if (t[1] < 0.0) t[1] = -t[1];
if (t[2] < 0.0) t[2] = -t[2];
if (t[3] < 0.0) t[3] = -t[3];
store_vector4( &inst->DstReg, machine, t );
}
break;
case END:
return;
default:
_mesa_problem(ctx, "Bad VP Opcode in _mesa_exec_program");
return;
}
}
}