/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
Doom 3 Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 Source Code. If not, see .
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include
#include
#include "sys/platform.h"
#include "idlib/math/Simd_AltiVec.h"
// Doom3 SIMD Library version 0.5
// Patrick Flanagan (pflanagan@apple.com)
// Sanjay Patel (spatel@apple.com)
// Architecture & Performance Group, Apple Computer
//===============================================================
//
// AltiVec implementation of idSIMDProcessor
//
//===============================================================
#if defined(MACOS_X) && defined(__GNUC__) && defined(__ALTIVEC__)
#ifdef PPC_INTRINSICS
// for square root estimate instruction
#include
#endif
// Data struct sizes
#ifndef DRAWVERT_PADDED
// 60 bytes, 15 floats at 4 bytes each
#define DRAWVERT_OFFSET 15
#else
// 64 bytes, 16 floats
#define DRAWVERT_OFFSET 16
#endif
// 16 bytes each, 4 floats
#define PLANE_OFFSET 4
// 16 bytes each, 4 floats
#define IDVEC4_OFFSET 4
// Alignment tests
#define IS_16BYTE_ALIGNED( x ) ( ( (unsigned int)&x & 0x0F ) == 0 )
#define NOT_16BYTE_ALIGNED( x ) ( ( (unsigned int)&x & 0x0F) != 0 )
// Aligned storing floats
#define ALIGNED_STORE2( ADDR, V0, V1 ) \
vec_st( V0, 0, ADDR ); \
vec_st( V1, 16, ADDR )
#define ALIGNED_STORE3( ADDR, V0, V1, V2 ) \
vec_st( V0, 0, ADDR ); \
vec_st( V1, 16, ADDR ); \
vec_st( V2, 32, ADDR )
#define ALIGNED_STORE4( ADDR, V0, V1, V2, V3 ) \
vec_st( V0, 0, ADDR ); \
vec_st( V1, 16, ADDR ); \
vec_st( V2, 32, ADDR ); \
vec_st( V3, 48, ADDR )
#define ALIGNED_STORE6( ADDR, V0, V1, V2, V3, V4, V5 ) \
vec_st( V0, 0, ADDR ); \
vec_st( V1, 16, ADDR ); \
vec_st( V2, 32, ADDR ); \
vec_st( V3, 48, ADDR ); \
vec_st( V4, 64, ADDR ); \
vec_st( V5, 80, ADDR )
#define ALIGNED_STORE8( ADDR, V0, V1, V2, V3, V4, V5, V6, V7 ) \
vec_st( V0, 0, ADDR ); \
vec_st( V1, 16, ADDR ); \
vec_st( V2, 32, ADDR ); \
vec_st( V3, 48, ADDR ); \
vec_st( V4, 64, ADDR ); \
vec_st( V5, 80, ADDR ); \
vec_st( V6, 96, ADDR ); \
vec_st( V7, 112, ADDR )
// Unaligned storing floats. These assume that we can trash the input
#define UNALIGNED_STORE1( ADDR, V0 ) { \
/* use store element */ \
vector unsigned char ULStoreMacroPerm = vec_lvsr( 0, ADDR ); \
V0 = vec_perm( V0, V0, ULStoreMacroPerm ); \
vec_ste( V0, 0, ADDR ); \
vec_ste( V0, 4, ADDR ); \
vec_ste( V0, 8, ADDR ); \
vec_ste( V0, 12, ADDR ); \
}
#define UNALIGNED_STORE2( ADDR, V0, V1 ) { \
/* load up the values that are there now */ \
vector float ULStoreMacro1 = vec_ld( 0, ADDR ); \
vector float ULStoreMacro2 = vec_ld( 31, ADDR ); \
/* generate permute vector and mask */ \
vector unsigned char ULStoreMacroPerm = vec_sub( vec_lvsr( 15, ADDR ), (vector unsigned char)(1) ); \
vector unsigned int ULStoreMacroMask = vec_perm( (vector unsigned int)(0), (vector unsigned int)(-1), ULStoreMacroPerm ); \
/* right rotate input data */ \
V0 = vec_perm( V0, V0, ULStoreMacroPerm ); \
V1 = vec_perm( V1, V1, ULStoreMacroPerm ); \
/* setup the output vectors */ \
vector float ULStoreVal1, ULStoreVal2, ULStoreVal3; \
ULStoreVal1 = vec_sel( ULStoreMacro1, V0, ULStoreMacroMask ); \
ULStoreVal2 = vec_sel( V0, V1, ULStoreMacroMask ); \
ULStoreVal3 = vec_sel( V1, ULStoreMacro2, ULStoreMacroMask ); \
/* store results */ \
vec_st( ULStoreVal1, 0, ADDR ); \
vec_st( ULStoreVal2, 15, ADDR ); \
vec_st( ULStoreVal3, 31, ADDR ); }
#define UNALIGNED_STORE3( ADDR, V0, V1, V2 ) { \
/* load up the values that are there now */ \
vector float ULStoreMacro1 = vec_ld( 0, ADDR ); \
vector float ULStoreMacro2 = vec_ld( 47, ADDR ); \
/* generate permute vector and mask */ \
vector unsigned char ULStoreMacroPerm = vec_sub( vec_lvsr( 15, ADDR ), (vector unsigned char)(1) ); \
vector unsigned int ULStoreMacroMask = vec_perm( (vector unsigned int)(0), (vector unsigned int)(-1), ULStoreMacroPerm ); \
/* right rotate input data */ \
V0 = vec_perm( V0, V0, ULStoreMacroPerm ); \
V1 = vec_perm( V1, V1, ULStoreMacroPerm ); \
V2 = vec_perm( V2, V2, ULStoreMacroPerm ); \
/* setup the output vectors */ \
vector float ULStoreVal1, ULStoreVal2, ULStoreVal3, ULStoreVal4; \
ULStoreVal1 = vec_sel( ULStoreMacro1, V0, ULStoreMacroMask ); \
ULStoreVal2 = vec_sel( V0, V1, ULStoreMacroMask ); \
ULStoreVal3 = vec_sel( V1, V2, ULStoreMacroMask ); \
ULStoreVal4 = vec_sel( V2, ULStoreMacro2, ULStoreMacroMask ); \
/* store results */ \
vec_st( ULStoreVal1, 0, ADDR ); \
vec_st( ULStoreVal2, 15, ADDR ); \
vec_st( ULStoreVal3, 31, ADDR ); \
vec_st( ULStoreVal4, 47, ADDR ); }
#define UNALIGNED_STORE4( ADDR, V0, V1, V2, V3 ) { \
/* load up the values that are there now */ \
vector float ULStoreMacro1 = vec_ld( 0, ADDR ); \
vector float ULStoreMacro2 = vec_ld( 63, ADDR ); \
/* generate permute vector and mask */ \
vector unsigned char ULStoreMacroPerm = vec_sub( vec_lvsr( 15, ADDR ), (vector unsigned char)(1) ); \
vector unsigned int ULStoreMacroMask = vec_perm( (vector unsigned int)(0), (vector unsigned int)(-1), ULStoreMacroPerm ); \
/* right rotate input data */ \
V0 = vec_perm( V0, V0, ULStoreMacroPerm ); \
V1 = vec_perm( V1, V1, ULStoreMacroPerm ); \
V2 = vec_perm( V2, V2, ULStoreMacroPerm ); \
V3 = vec_perm( V3, V3, ULStoreMacroPerm ); \
/* setup the output vectors */ \
vector float ULStoreVal1, ULStoreVal2, ULStoreVal3, ULStoreVal4, ULStoreVal5; \
ULStoreVal1 = vec_sel( ULStoreMacro1, V0, ULStoreMacroMask ); \
ULStoreVal2 = vec_sel( V0, V1, ULStoreMacroMask ); \
ULStoreVal3 = vec_sel( V1, V2, ULStoreMacroMask ); \
ULStoreVal4 = vec_sel( V2, V3, ULStoreMacroMask ); \
ULStoreVal5 = vec_sel( V3, ULStoreMacro2, ULStoreMacroMask ); \
/* store results */ \
vec_st( ULStoreVal1, 0, ADDR ); \
vec_st( ULStoreVal2, 15, ADDR ); \
vec_st( ULStoreVal3, 31, ADDR ); \
vec_st( ULStoreVal4, 47, ADDR ); \
vec_st( ULStoreVal5, 63, ADDR ); }
#define UNALIGNED_STORE6( ADDR, V0, V1, V2, V3, V4, V5 ) { \
/* load up the values that are there now */ \
vector float ULStoreMacro1 = vec_ld( 0, ADDR ); \
vector float ULStoreMacro2 = vec_ld( 95, ADDR ); \
/* generate permute vector and mask */ \
vector unsigned char ULStoreMacroPerm = vec_sub( vec_lvsr( 15, ADDR ), (vector unsigned char)(1) ); \
vector unsigned int ULStoreMacroMask = vec_perm( (vector unsigned int)(0), (vector unsigned int)(-1), ULStoreMacroPerm ); \
/* right rotate input data */ \
V0 = vec_perm( V0, V0, ULStoreMacroPerm ); \
V1 = vec_perm( V1, V1, ULStoreMacroPerm ); \
V2 = vec_perm( V2, V2, ULStoreMacroPerm ); \
V3 = vec_perm( V3, V3, ULStoreMacroPerm ); \
V4 = vec_perm( V4, V4, ULStoreMacroPerm ); \
V5 = vec_perm( V5, V5, ULStoreMacroPerm ); \
/* setup the output vectors */ \
vector float ULStoreVal1, ULStoreVal2, ULStoreVal3, ULStoreVal4, ULStoreVal5, ULStoreVal6, ULStoreVal7; \
ULStoreVal1 = vec_sel( ULStoreMacro1, V0, ULStoreMacroMask ); \
ULStoreVal2 = vec_sel( V0, V1, ULStoreMacroMask ); \
ULStoreVal3 = vec_sel( V1, V2, ULStoreMacroMask ); \
ULStoreVal4 = vec_sel( V2, V3, ULStoreMacroMask ); \
ULStoreVal5 = vec_sel( V3, V4, ULStoreMacroMask ); \
ULStoreVal6 = vec_sel( V4, V5, ULStoreMacroMask ); \
ULStoreVal7 = vec_sel( V5, ULStoreMacro2, ULStoreMacroMask ); \
/* store results */ \
vec_st( ULStoreVal1, 0, ADDR ); \
vec_st( ULStoreVal2, 15, ADDR ); \
vec_st( ULStoreVal3, 31, ADDR ); \
vec_st( ULStoreVal4, 47, ADDR ); \
vec_st( ULStoreVal5, 63, ADDR ); \
vec_st( ULStoreVal6, 79, ADDR ); \
vec_st( ULStoreVal7, 95, ADDR ); }
#define UNALIGNED_STORE9( ADDR, V0, V1, V2, V3, V4, V5, V6, V7, V8 ) { \
/* load up the values that are there now */ \
vector float ULStoreMacro1 = vec_ld( 0, ADDR ); \
vector float ULStoreMacro2 = vec_ld( 143, ADDR ); \
/* generate permute vector and mask */ \
vector unsigned char ULStoreMacroPerm = vec_sub( vec_lvsr( 15, ADDR ), (vector unsigned char)(1) ); \
vector unsigned int ULStoreMacroMask = vec_perm( (vector unsigned int)(0), (vector unsigned int)(-1), ULStoreMacroPerm ); \
/* right rotate input data */ \
V0 = vec_perm( V0, V0, ULStoreMacroPerm ); \
V1 = vec_perm( V1, V1, ULStoreMacroPerm ); \
V2 = vec_perm( V2, V2, ULStoreMacroPerm ); \
V3 = vec_perm( V3, V3, ULStoreMacroPerm ); \
V4 = vec_perm( V4, V4, ULStoreMacroPerm ); \
V5 = vec_perm( V5, V5, ULStoreMacroPerm ); \
V6 = vec_perm( V6, V6, ULStoreMacroPerm ); \
V7 = vec_perm( V7, V7, ULStoreMacroPerm ); \
V8 = vec_perm( V8, V8, ULStoreMacroPerm ); \
/* setup the output vectors */ \
vector float ULStoreVal1, ULStoreVal2, ULStoreVal3, ULStoreVal4, ULStoreVal5, ULStoreVal6, ULStoreVal7; \
vector float ULStoreVal8, ULStoreVal9, ULStoreVal10; \
ULStoreVal1 = vec_sel( ULStoreMacro1, V0, ULStoreMacroMask ); \
ULStoreVal2 = vec_sel( V0, V1, ULStoreMacroMask ); \
ULStoreVal3 = vec_sel( V1, V2, ULStoreMacroMask ); \
ULStoreVal4 = vec_sel( V2, V3, ULStoreMacroMask ); \
ULStoreVal5 = vec_sel( V3, V4, ULStoreMacroMask ); \
ULStoreVal6 = vec_sel( V4, V5, ULStoreMacroMask ); \
ULStoreVal7 = vec_sel( V5, V6, ULStoreMacroMask ); \
ULStoreVal8 = vec_sel( V6, V7, ULStoreMacroMask ); \
ULStoreVal9 = vec_sel( V7, V8, ULStoreMacroMask ); \
ULStoreVal10 = vec_sel( V8, ULStoreMacro2, ULStoreMacroMask ); \
/* store results */ \
vec_st( ULStoreVal1, 0, ADDR ); \
vec_st( ULStoreVal2, 15, ADDR ); \
vec_st( ULStoreVal3, 31, ADDR ); \
vec_st( ULStoreVal4, 47, ADDR ); \
vec_st( ULStoreVal5, 63, ADDR ); \
vec_st( ULStoreVal6, 79, ADDR ); \
vec_st( ULStoreVal7, 95, ADDR ); \
vec_st( ULStoreVal8, 111, ADDR ); \
vec_st( ULStoreVal9, 127, ADDR ); \
vec_st( ULStoreVal10, 143, ADDR ); }
/*
============
idSIMD_AltiVec::GetName
============
*/
const char *idSIMD_AltiVec::GetName( void ) const {
return "AltiVec";
}
/*
Helper Functions
*/
#if 0
// Prints the values of a vector, useful for debugging but
// should never be called in real code
inline void debugPrintVector( vector float v, char *msg ) {
printf("%s -- %vf\n", msg, v );
}
inline void debugPrintVector( vector unsigned int v, char *msg ) {
printf("%s -- %vd\n", msg, v );
}
inline void debugPrintVector( vector bool int v, char *msg ) {
printf("%s -- %vi\n", msg, v );
}
inline void debugPrintVector( vector unsigned char v, char *msg ) {
printf("%s -- %vuc\n", msg, v );
}
inline void debugPrintVector( vector unsigned short v, char *msg ) {
printf("%s -- %vs\n", msg, v );
}
#endif
/*
===============
Reciprocal
For each element in vector:
n = 1 / n
===============
*/
// Use Newton-Raphson to calculate reciprocal of a vector
inline vector float Reciprocal( vector float v ) {
//Get the reciprocal estimate
vector float estimate = vec_re( v );
//One round of Newton-Raphson refinement
return vec_madd( vec_nmsub( estimate, v, (vector float) (1.0) ), estimate, estimate );
}
/*
===============
ReciprocalSquareRoot
For each element in vector:
n = 1 / sqrt(n)
===============
*/
// Reciprocal square root estimate of a vector
inline vector float ReciprocalSquareRoot( vector float v ) {
//Get the square root reciprocal estimate
vector float zero = (vector float)(0);
vector float oneHalf = (vector float)(0.5);
vector float one = (vector float)(1.0);
vector float estimate = vec_rsqrte( vec_max( v, (vector float)(FLT_MIN) ) );
//One round of Newton-Raphson refinement
vector float estimateSquared = vec_madd( estimate, estimate, zero );
vector float halfEstimate = vec_madd( estimate, oneHalf, zero );
return vec_madd( vec_nmsub( v, estimateSquared, one ), halfEstimate, estimate );
}
/*
===============
Divide
For each element in vectors:
n = a / b
===============
*/
// Use reciprocal estimate and multiply to divide a vector
inline vector float Divide( vector float a, vector float b ) {
return vec_madd( a, Reciprocal( b ), (vector float)(0) );
}
/*
===============
loadSplatUnalignedScalar
For each element in vector:
n = s
===============
*/
inline vector float loadSplatUnalignedScalar( const float *s ) {
vector unsigned char splatMap = vec_lvsl( 0, s );
vector float v = vec_ld( 0, s );
splatMap = (vector unsigned char) vec_splat( (vector float) splatMap, 0 );
return vec_perm( v, v, splatMap );
}
/*
===============
VectorATan16
For each element in vector:
n = idMath::ATan16( x, y )
===============
*/
// calculates arc tangent of a vector with 16 bits of precision, based on atan16 in idMath
inline vector float VectorATan16( vector float x, vector float y ) {
vector float xDivY = Divide( x, y );
vector float yDivX = Divide( y, x );
vector float zeroVector = (vector float)(0);
vector bool int vecCmp = vec_cmpgt( vec_abs( y ), vec_abs( x ) );
vector float vecA = vec_sel( yDivX, xDivY, vecCmp );
vector bool int vecCmp2 = vec_cmplt( vecA, zeroVector );
vector float vecS = vec_madd( vecA, vecA, (vector float)(0) );
// do calculation for S
vector float vecWork1 = vec_madd( (vector float)(0.0028662257f), vecS, (vector float)(-0.0161657367f) );
vecWork1 = vec_madd( vecWork1, vecS, (vector float)(0.0429096138f) );
vecWork1 = vec_madd( vecWork1, vecS, (vector float)(-0.0752896400f) );
vecWork1 = vec_madd( vecWork1, vecS, (vector float)(0.1065626393f) );
vecWork1 = vec_madd( vecWork1, vecS, (vector float)(-0.1420889944f) );
vecWork1 = vec_madd( vecWork1, vecS, (vector float)(0.1999355085f) );
vecWork1 = vec_madd( vecWork1, vecS, (vector float)(-0.3333314528f) );
vecWork1 = vec_madd( vecWork1, vecS, (vector float)(1) );
// get the regular S value
vecS = vec_madd( vecWork1, vecA, (vector float)(0) );
// calculate what to return if y > x
vector float negSPlusHalfPI = vec_madd( vecS, (vector float)(-1), (vector float)(0.5f * 3.14159265358979323846f) );
vector float negSMinusHalfPI = vec_madd( vecS, (vector float)(-1), (vector float)(-0.5f * 3.14159265358979323846f) );
vector float modRet = vec_sel( negSPlusHalfPI, negSMinusHalfPI, vecCmp2 );
return vec_sel( modRet, vecS, vecCmp );
}
/*
===============
VectorSin16
For each element in vector:
n = idMath::Sin16( v )
===============
*/
inline vector float VectorSin16( vector float v ) {
vector float zero = (vector float)(0);
#if 0
// load up half PI and use it to calculate the rest of the values. This is
// sometimes cheaper than loading them from memory
vector float halfPI = (vector float) ( 0.5f * 3.14159265358979323846f );
vector float PI = vec_add( halfPI, halfPI );
vector float oneandhalfPI = vec_add( PI, halfPI );
vector float twoPI = vec_add( oneandhalfPI, halfPI );
#else
vector float halfPI = (vector float) ( 0.5f * 3.14159265358979323846f );
vector float PI = (vector float)(3.14159265358979323846f);
vector float oneandhalfPI = (vector float)(3.14159265358979323846f + ( 0.5f * 3.14159265358979323846f ) );
vector float twoPI = (vector float)( 2.0f * 3.14159265358979323846f);
#endif
vector bool int vecCmp1, vecCmp2, vecCmp3, vecCmp4;
vector float vecMod;
vector float vecResult;
// fix the range if needbe
vecMod = vec_floor( Divide( v, twoPI ) );
vecResult = vec_nmsub( vecMod, twoPI, v );
vector float vecPIminusA = vec_sub( PI, vecResult );
vector float vecAminus2PI = vec_sub( vecResult, twoPI );
vecCmp1 = vec_cmplt( vecResult, PI );
vecCmp2 = vec_cmpgt( vecResult, halfPI );
// these are the ones where a > PI + HALF_PI so set a = a - TWO_PI
vecCmp3 = vec_cmpgt( vecResult, oneandhalfPI );
// we also want to set a = PI - a everywhere that !(a < PI) and !(a > PI + HALF_PI)
vecCmp4 = vec_and( vec_xor( vecCmp3, (vector bool int)(1) ), vec_xor( vecCmp1, (vector bool int)(1) ) ); // everywhere that both of those are false
// these are ones where a < PI and a > HALF_PI so we set a = PI - a
vecCmp1 = vec_and( vecCmp1, vecCmp2 );
vecCmp1 = vec_or( vecCmp1, vecCmp4 );
// put the correct values into place
vecResult = vec_sel( vecResult, vecPIminusA, vecCmp1 );
vecResult = vec_sel( vecResult, vecAminus2PI, vecCmp3 );
// calculate answer
vector float vecASquared = vec_madd( vecResult, vecResult, zero );
vector float vecEst = vec_madd( (vector float)(-2.39e-08f), vecASquared, (vector float)(2.7526e-06f) );
vecEst = vec_madd( vecEst, vecASquared, (vector float)(-1.98409e-04f) );
vecEst = vec_madd( vecEst, vecASquared, (vector float)(8.3333315e-03f) );
vecEst = vec_madd( vecEst, vecASquared, (vector float)(-1.666666664e-01f) );
vecEst = vec_madd( vecEst, vecASquared, (vector float)(1.0f) );
return vec_madd( vecResult, vecEst, zero );
}
/*
===============
vecSplatWithRunTime
For each element in vector:
n = v(i)
===============
*/
// splats an element across a vector using a runtime variable
inline vector float vecSplatWithRunTime( vector float v, int i ) {
vector unsigned char rotate = vec_lvsl( i * sizeof( float ), (int*) 0L );
v = vec_perm( v, v, rotate );
return vec_splat( v, 0 );
}
/*
===============
FastScalarInvSqrt
n = 1 / sqrt( f )
===============
*/
inline float FastScalarInvSqrt( float f ) {
#ifdef PPC_INTRINSICS
float estimate;
const float kSmallestFloat = FLT_MIN;
//Calculate a 5 bit starting estimate for the reciprocal sqrt
estimate = __frsqrte ( f + kSmallestFloat );
//if you require less precision, you may reduce the number of loop iterations.
// This will do 2 rounds of NR
estimate = estimate + 0.5f * estimate * ( 1.0f - f * estimate * estimate );
estimate = estimate + 0.5f * estimate * ( 1.0f - f * estimate * estimate );
return estimate;
#else
return idMath::InvSqrt( f );
#endif
}
/*
===============
FastScalarInvSqrt_x3
arg1 = 1 / sqrt( arg1 )
arg2 = 1 / sqrt( arg2 )
arg3 = 1 / sqrt( arg3 )
===============
*/
inline void FastScalarInvSqrt_x3( float *arg1, float *arg2, float *arg3 ) {
#ifdef PPC_INTRINSICS
register float estimate1, estimate2, estimate3;
const float kSmallestFloat = FLT_MIN;
//Calculate a 5 bit starting estimate for the reciprocal sqrt of each
estimate1 = __frsqrte ( *arg1 + kSmallestFloat );
estimate2 = __frsqrte ( *arg2 + kSmallestFloat );
estimate3 = __frsqrte ( *arg3 + kSmallestFloat );
// two rounds newton-raphson
estimate1 = estimate1 + 0.5f * estimate1 * ( 1.0f - *arg1 * estimate1 * estimate1 );
estimate2 = estimate2 + 0.5f * estimate2 * ( 1.0f - *arg2 * estimate2 * estimate2 );
estimate3 = estimate3 + 0.5f * estimate3 * ( 1.0f - *arg3 * estimate3 * estimate3 );
estimate1 = estimate1 + 0.5f * estimate1 * ( 1.0f - *arg1 * estimate1 * estimate1 );
estimate2 = estimate2 + 0.5f * estimate2 * ( 1.0f - *arg2 * estimate2 * estimate2 );
estimate3 = estimate3 + 0.5f * estimate3 * ( 1.0f - *arg3 * estimate3 * estimate3 );
*arg1 = estimate1;
*arg2 = estimate2;
*arg3 = estimate3;
#else
*arg1 = idMath::InvSqrt( *arg1 );
*arg2 = idMath::InvSqrt( *arg2 );
*arg3 = idMath::InvSqrt( *arg3 );
#endif
}
/*
===============
FastScalarInvSqrt_x6
arg1 = 1 / sqrt( arg1 )
arg2 = 1 / sqrt( arg2 )
arg3 = 1 / sqrt( arg3 )
arg4 = 1 / sqrt( arg4 )
arg5 = 1 / sqrt( arg5 )
arg6 = 1 / sqrt( arg6 )
On a G5, you've got 2 pipeline stages to fill. (2 FPU's with 6 stages each)
===============
*/
inline void FastScalarInvSqrt_x6( float *arg1, float *arg2, float *arg3, float *arg4, float *arg5, float *arg6 ) {
#ifdef PPC_INTRINSICS
register float estimate1, estimate2, estimate3, estimate4, estimate5, estimate6;
const float kSmallestFloat = FLT_MIN;
//Calculate a 5 bit starting estimate for the reciprocal sqrt of each
estimate1 = __frsqrte ( *arg1 + kSmallestFloat );
estimate2 = __frsqrte ( *arg2 + kSmallestFloat );
estimate3 = __frsqrte ( *arg3 + kSmallestFloat );
estimate4 = __frsqrte ( *arg4 + kSmallestFloat );
estimate5 = __frsqrte ( *arg5 + kSmallestFloat );
estimate6 = __frsqrte ( *arg6 + kSmallestFloat );
// two rounds newton-raphson
estimate1 = estimate1 + 0.5f * estimate1 * ( 1.0f - *arg1 * estimate1 * estimate1 );
estimate2 = estimate2 + 0.5f * estimate2 * ( 1.0f - *arg2 * estimate2 * estimate2 );
estimate3 = estimate3 + 0.5f * estimate3 * ( 1.0f - *arg3 * estimate3 * estimate3 );
estimate4 = estimate4 + 0.5f * estimate4 * ( 1.0f - *arg4 * estimate4 * estimate4 );
estimate5 = estimate5 + 0.5f * estimate5 * ( 1.0f - *arg5 * estimate5 * estimate5 );
estimate6 = estimate6 + 0.5f * estimate6 * ( 1.0f - *arg6 * estimate6 * estimate6 );
estimate1 = estimate1 + 0.5f * estimate1 * ( 1.0f - *arg1 * estimate1 * estimate1 );
estimate2 = estimate2 + 0.5f * estimate2 * ( 1.0f - *arg2 * estimate2 * estimate2 );
estimate3 = estimate3 + 0.5f * estimate3 * ( 1.0f - *arg3 * estimate3 * estimate3 );
estimate4 = estimate4 + 0.5f * estimate4 * ( 1.0f - *arg4 * estimate4 * estimate4 );
estimate5 = estimate5 + 0.5f * estimate5 * ( 1.0f - *arg5 * estimate5 * estimate5 );
estimate6 = estimate6 + 0.5f * estimate6 * ( 1.0f - *arg6 * estimate6 * estimate6 );
*arg1 = estimate1;
*arg2 = estimate2;
*arg3 = estimate3;
*arg4 = estimate4;
*arg5 = estimate5;
*arg6 = estimate6;
#else
*arg1 = idMath::InvSqrt( *arg1 );
*arg2 = idMath::InvSqrt( *arg2 );
*arg3 = idMath::InvSqrt( *arg3 );
*arg4 = idMath::InvSqrt( *arg4 );
*arg5 = idMath::InvSqrt( *arg5 );
*arg6 = idMath::InvSqrt( *arg6 );
#endif
}
// End Helper Functions
#ifdef ENABLE_SIMPLE_MATH
/*
============
idSIMD_AltiVec::Add
dst[i] = constant + src[i];
============
*/
void VPCALL idSIMD_AltiVec::Add( float *dst, const float constant, const float *src, const int count ) {
vector float v0, v1, v2, v3;
vector float v0_low, v0_hi, v1_hi;
vector unsigned char permVec;
vector float constVec;
int i;
// handle unaligned cases at beginning
for ( i = 0; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count ); i++ ) {
dst[i] = constant + src[i];
}
//splat constant into a vector
constVec = loadSplatUnalignedScalar( &constant );
//calculate permute and do first load
permVec = vec_add( vec_lvsl( -1, (int*) &src[i] ), (vector unsigned char)(1) );
v1_hi = vec_ld( 0, &src[i] );
//vectorize!
for ( ; i+7 < count; i += 8 ) {
//load source
v0_low = v1_hi;
v0_hi = vec_ld( 15, &src[i] );
v1_hi = vec_ld( 31, &src[i] );
v0 = vec_perm( v0_low, v0_hi, permVec );
v1 = vec_perm( v0_hi, v1_hi, permVec );
v2 = vec_add( v0, constVec );
v3 = vec_add( v1, constVec );
// store results
ALIGNED_STORE2( &dst[i], v2, v3 );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] = constant + src[i];
}
}
/*
============
idSIMD_AltiVec::Add
dst[i] = src0[i] + src1[i];
============
*/
void VPCALL idSIMD_AltiVec::Add( float *dst, const float *src0, const float *src1, const int count ) {
register vector float v0, v1, v2, v3, v4, v5;
//src0
register vector float v0_low, v0_hi, v2_low, v2_hi;
//src1
register vector float v1_low, v1_hi, v3_low, v3_hi;
//permute vectors
register vector unsigned char permVec1, permVec2;
vector unsigned char oneCharVector = (vector unsigned char)(1);
int i;
//unaligned at start
for ( i = 0 ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count ); i++ ) {
dst[i] = src0[i] + src1[i];
}
//calculate permute and do loads
permVec1 = vec_add( vec_lvsl( -1, (int*) &src0[i] ), oneCharVector );
permVec2 = vec_add( vec_lvsl( -1, (int*) &src1[i] ), oneCharVector );
v2_hi = vec_ld( 0, &src0[i] );
v3_hi = vec_ld( 0, &src1[i] );
//vectorize!
for ( ; i+7 < count; i += 8 ) {
//load source
v0_low = v2_hi;
v0_hi = vec_ld( 15, &src0[i] );
v2_low = v0_hi;
v2_hi = vec_ld( 31, &src0[i] );
v1_low = v3_hi;
v1_hi = vec_ld( 15, &src1[i] );
v3_low = v1_hi;
v3_hi = vec_ld( 31, &src1[i] );
v0 = vec_perm( v0_low, v0_hi, permVec1 );
v1 = vec_perm( v1_low, v1_hi, permVec2 );
v2 = vec_perm( v2_low, v2_hi, permVec1 );
v3 = vec_perm( v3_low, v3_hi, permVec2 );
v4 = vec_add( v0, v1 );
v5 = vec_add( v2, v3 );
ALIGNED_STORE2( &dst[i], v4, v5 );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] = src0[i] + src1[i];
}
}
/*
============
idSIMD_AltiVec::Sub
dst[i] = constant - src[i];
============
*/
void VPCALL idSIMD_AltiVec::Sub( float *dst, const float constant, const float *src, const int count ) {
register vector float v0, v1, v2, v3;
register vector float v0_low, v0_hi, v1_low, v1_hi;
register vector unsigned char permVec;
register vector float constVec;
vector unsigned char oneCharVector = (vector unsigned char)(1);
int i;
//handle unaligned at start
for ( i = 0 ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count ); i++ ) {
dst[i] = constant - src[i];
}
//splat constant into a vector
constVec = loadSplatUnalignedScalar( &constant );
//calculate permute vector and do first load
permVec = vec_add( vec_lvsl( -1, (int*) &src[i] ), oneCharVector );
v1_hi = vec_ld( 0, &src[i] );
//vectorize!
for ( ; i+7 < count; i += 8 ) {
//load source
v0_low = v1_hi;
v0_hi = vec_ld( 15, &src[i] );
v1_low = v0_hi;
v1_hi = vec_ld( 31, &src[i] );
v0 = vec_perm( v0_low, v0_hi, permVec );
v1 = vec_perm( v1_low, v1_hi, permVec );
v2 = vec_sub( constVec, v0 );
v3 = vec_sub( constVec, v1 );
ALIGNED_STORE2( &dst[i], v2, v3 );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] = constant - src[i];
}
}
/*
============
idSIMD_AltiVec::Sub
dst[i] = src0[i] - src1[i];
============
*/
void VPCALL idSIMD_AltiVec::Sub( float *dst, const float *src0, const float *src1, const int count ) {
register vector float v0, v1, v2, v3, v4, v5;
//src0
register vector float v0_low, v0_hi, v2_low, v2_hi;
//src1
register vector float v1_low, v1_hi, v3_low, v3_hi;
register vector unsigned char permVec1, permVec2;
vector unsigned char oneCharVector = (vector unsigned char)(1);
int i;
//handle unaligned at start
for ( i = 0 ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count ); i++ ) {
dst[i] = src0[i] - src1[i];
}
//calculate permute and do first loads
permVec1 = vec_add( vec_lvsl( -1, (int*) &src0[i] ), oneCharVector );
permVec2 = vec_add( vec_lvsl( -1, (int*) &src1[i] ), oneCharVector );
v2_hi = vec_ld( 0, &src0[i] );
v3_hi = vec_ld( 0, &src1[i] );
//vectorize!
for ( ; i+7 < count; i += 8 ) {
//load source
v0_low = v2_hi;
v0_hi = vec_ld( 15, &src0[i] );
v2_low = v0_hi;
v2_hi = vec_ld( 31, &src0[i] );
v1_low = v3_hi;
v1_hi = vec_ld( 15, &src1[i] );
v3_low = v1_hi;
v3_hi = vec_ld( 31, &src1[i] );
v0 = vec_perm( v0_low, v0_hi, permVec1 );
v1 = vec_perm( v1_low, v1_hi, permVec2 );
v2 = vec_perm( v2_low, v2_hi, permVec1 );
v3 = vec_perm( v3_low, v3_hi, permVec2 );
v4 = vec_sub( v0, v1 );
v5 = vec_sub( v2, v3 );
ALIGNED_STORE2( &dst[i], v4, v5 );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] = src0[i] - src1[i];
}
}
/*
============
idSIMD_AltiVec::Mul
dst[i] = constant * src[i];
============
*/
void VPCALL idSIMD_AltiVec::Mul( float *dst, const float constant, const float *src, const int count) {
register vector float v0, v0_low, v0_hi, v1_low, v1_hi, v1, v2, v3;
register vector float constVec;
register vector unsigned char permVec;
vector unsigned char oneCharVector = (vector unsigned char)(1);
register vector float zeroVector = (vector float)(0.0);
int i;
// handle unaligned data at start
for ( i = 0 ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count );i++ ) {
dst[i] = constant * src[i];
}
//splat constant into a vector
constVec = loadSplatUnalignedScalar( &constant );
permVec = vec_add( vec_lvsl( -1, (int*) &src[i] ), oneCharVector );
v1_hi = vec_ld( 0, &src[i] );
//vectorize!
for ( ; i+7 < count; i += 8 ) {
//load source
v0_low = v1_hi;
v0_hi = vec_ld( 15, &src[i] );
v1_low = v0_hi;
v1_hi = vec_ld( 31, &src[i] );
v0 = vec_perm( v0_low, v0_hi, permVec );
v1 = vec_perm( v1_low, v1_hi, permVec );
v2 = vec_madd( constVec, v0, zeroVector );
v3 = vec_madd( constVec, v1, zeroVector );
ALIGNED_STORE2( &dst[i], v2, v3 );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] = constant * src[i];
}
}
/*
============
idSIMD_AltiVec::Mul
dst[i] = src0[i] * src1[i];
============
*/
void VPCALL idSIMD_AltiVec::Mul( float *dst, const float *src0, const float *src1, const int count ) {
register vector float v0, v1, v2, v3, v4, v5;
//src0
register vector float v0_low, v0_hi, v2_low, v2_hi;
//src1
register vector float v1_low, v1_hi, v3_low, v3_hi;
//permute vectors
register vector unsigned char permVec1, permVec2;
register vector float constVec = (vector float)(0.0);
vector unsigned char oneCharVector = (vector unsigned char)(1);
int i;
//handle unaligned at start
for ( i = 0; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count );i++ ) {
dst[i] = src0[i] * src1[i];
}
//calculate permute and do loads
permVec1 = vec_add( vec_lvsl( -1, (int*) &src0[i] ), oneCharVector );
permVec2 = vec_add( vec_lvsl( -1, (int*) &src1[i] ), oneCharVector );
v2_hi = vec_ld( 0, &src0[i] );
v3_hi = vec_ld( 0, &src1[i] );
//vectorize!
for ( ; i+7 < count; i += 8 ) {
//load source
v0_low = v2_hi;
v0_hi = vec_ld( 15, &src0[i] );
v2_low = v0_hi;
v2_hi = vec_ld( 31, &src0[i] );
v1_low = v3_hi;
v1_hi = vec_ld( 15, &src1[i] );
v3_low = v1_hi;
v3_hi = vec_ld( 31, &src1[i] );
v0 = vec_perm( v0_low, v0_hi, permVec1 );
v1 = vec_perm( v1_low, v1_hi, permVec2 );
v2 = vec_perm( v2_low, v2_hi, permVec1 );
v3 = vec_perm( v3_low, v3_hi, permVec2 );
//no such thing as regular multiply so we do
//multiply then add zero
v4 = vec_madd( v0, v1, constVec );
v5 = vec_madd( v2, v3, constVec );
ALIGNED_STORE2( &dst[i], v4, v5 );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] = src0[i] * src1[i];
}
}
/*
============
idSIMD_AltiVec::Div
dst[i] = constant / divisor[i];
============
*/
void VPCALL idSIMD_AltiVec::Div( float *dst, const float constant, const float *divisor, const int count ) {
register vector float v0, v1, v2, v3;
register vector float v0_low, v0_hi, v1_low, v1_hi;
register vector unsigned char permVec;
register vector float constVec;
vector unsigned char oneCharVector = (vector unsigned char)(1);
int i;
//handle unaligned at start
for ( i = 0 ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count );i++ ) {
dst[i] = constant / divisor[i];
}
//splat constant into a vector
constVec = loadSplatUnalignedScalar( &constant );
//calculate permute and do first loads
permVec = vec_add( vec_lvsl( -1, (int*) &divisor[i] ), oneCharVector );
v1_hi = vec_ld( 0, &divisor[i] );
//vectorize!
for ( ; i+7 < count; i += 8 ) {
//load source
v0_low = v1_hi;
v0_hi = vec_ld( 15, &divisor[i] );
v1_low = v0_hi;
v1_hi = vec_ld( 31, &divisor[i] );
v0 = vec_perm( v0_low, v0_hi, permVec );
v1 = vec_perm( v1_low, v1_hi, permVec );
v2 = Divide( constVec, v0 );
v3 = Divide( constVec, v1 );
ALIGNED_STORE2( &dst[i], v2, v3 );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] = constant / divisor[i];
}
}
/*
============
idSIMD_AltiVec::Div
dst[i] = src0[i] / src1[i];
============
*/
void VPCALL idSIMD_AltiVec::Div( float *dst, const float *src0, const float *src1, const int count ) {
register vector float v0, v1, v2, v3, v4, v5;
//src0
register vector float v0_low, v0_hi, v2_low, v2_hi;
//src1
register vector float v1_low, v1_hi, v3_low, v3_hi;
//permute vectors
register vector unsigned char permVec1, permVec2;
vector unsigned char oneCharVector = (vector unsigned char)(1);
int i;
//handle unaligned at start
for ( i = 0; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count );i++ ) {
dst[i] = src0[i] / src1[i];
}
//calculate permute and do loads
permVec1 = vec_add( vec_lvsl( -1, (int*) &src0[i] ), oneCharVector );
permVec2 = vec_add( vec_lvsl( -1, (int*) &src1[i] ), oneCharVector );
v2_hi = vec_ld( 0, &src0[i] );
v3_hi = vec_ld( 0, &src1[i] );
//vectorize!
for ( ; i+7 < count; i += 8 ) {
//load source
v0_low = v2_hi;
v0_hi = vec_ld( 15, &src0[i] );
v2_low = v0_hi;
v2_hi = vec_ld( 31, &src0[i] );
v1_low = v3_hi;
v1_hi = vec_ld( 15, &src1[i] );
v3_low = v1_hi;
v3_hi = vec_ld( 31, &src1[i] );
v0 = vec_perm( v0_low, v0_hi, permVec1 );
v1 = vec_perm( v1_low, v1_hi, permVec2 );
v2 = vec_perm( v2_low, v2_hi, permVec1 );
v3 = vec_perm( v3_low, v3_hi, permVec2 );
v4 = Divide( v0, v1 );
v5 = Divide( v2, v3 );
ALIGNED_STORE2( &dst[i], v4, v5 );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] = src0[i] / src1[i];
}
}
/*
============
idSIMD_AltiVec::MulAdd
dst[i] += constant * src[i];
============
*/
void VPCALL idSIMD_AltiVec::MulAdd( float *dst, const float constant, const float *src, const int count ) {
register vector float v0, v1, v2, v3, v4, v5;
register vector float constVec;
//src
register vector float v0_low, v0_hi, v2_low, v2_hi;
//permute vectors
register vector unsigned char permVec1;
vector unsigned char oneCharVector = (vector unsigned char)(1);
int i;
//handle unaligned at start
for ( i = 0 ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count );i++ ) {
dst[i] += constant * src[i];
}
//splat constant into a vector
constVec = loadSplatUnalignedScalar( &constant );
//calculate permute and do loads
permVec1 = vec_add( vec_lvsl( -1, (int*) &src[i] ), oneCharVector );
v2_hi = vec_ld( 0, &src[i] );
//vectorize!
for ( ; i+7 < count; i += 8 ) {
v0_low = v2_hi;
v0_hi = vec_ld( 15, &src[i] );
v2_low = v0_hi;
v2_hi = vec_ld( 31, &src[i] );
v0 = vec_perm( v0_low, v0_hi, permVec1 );
v2 = vec_perm( v2_low, v2_hi, permVec1 );
// at this point, dst is known to be aligned
v1 = vec_ld( 0, &dst[i] );
v3 = vec_ld( 16, &dst[i] );
v4 = vec_madd( constVec, v0, v1 );
v5 = vec_madd( constVec, v2, v3 );
ALIGNED_STORE2( &dst[i], v4, v5 );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] += constant * src[i];
}
}
/*
============
idSIMD_AltiVec::MulAdd
dst[i] += src0[i] * src1[i];
============
*/
void VPCALL idSIMD_AltiVec::MulAdd( float *dst, const float *src0, const float *src1, const int count ) {
register vector float v0, v1, v2, v3, v4, v5, v6, v7;
//src0
register vector float v0_low, v0_hi, v2_low, v2_hi;
//src1
register vector float v1_low, v1_hi, v3_low, v3_hi;
//permute vectors
register vector unsigned char permVec1, permVec2;
vector unsigned char oneCharVector = (vector unsigned char)(1);
int i;
//unaligned at start
for ( i = 0 ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count );i++ ) {
dst[i] += src0[i] * src1[i];
}
//calculate permute and do loads
permVec1 = vec_add( vec_lvsl( -1, (int*) &src0[i] ), oneCharVector );
permVec2 = vec_add( vec_lvsl( -1, (int*) &src1[i] ), oneCharVector );
v2_hi = vec_ld( 0, &src0[i] );
v3_hi = vec_ld( 0, &src1[i] );
//vectorize!
for ( ; i+7 < count; i += 8 ) {
// load sources
v0_low = v2_hi;
v0_hi = vec_ld( 15, &src0[i] );
v2_low = v0_hi;
v2_hi = vec_ld( 31, &src0[i] );
v1_low = v3_hi;
v1_hi = vec_ld( 15, &src1[i] );
v3_low = v1_hi;
v3_hi = vec_ld( 31, &src1[i] );
v0 = vec_perm( v0_low, v0_hi, permVec1 );
v1 = vec_perm( v1_low, v1_hi, permVec2 );
v2 = vec_perm( v2_low, v2_hi, permVec1 );
v3 = vec_perm( v3_low, v3_hi, permVec2 );
//we know dst is aligned because we handled unaligned cases
//up front
v4 = vec_ld( 0, &dst[i] );
v5 = vec_ld( 16, &dst[i] );
v6 = vec_madd( v0, v1, v4 );
v7 = vec_madd( v2, v3, v5 );
ALIGNED_STORE2( &dst[i], v6, v7 );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] += src0[i] * src1[i];
}
}
/*
============
idSIMD_AltiVec::MulSub
dst[i] -= constant * src[i];
============
*/
void VPCALL idSIMD_AltiVec::MulSub( float *dst, const float constant, const float *src, const int count ) {
register vector float v0, v1, v2, v3, v4, v5;
register vector float constVec;
//src
register vector float v0_low, v0_hi, v2_low, v2_hi;
//permute vectors
register vector unsigned char permVec1;
vector unsigned char oneCharVector = (vector unsigned char)(1);
int i;
//handle unaligned at start
for ( i = 0 ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count );i++ ) {
dst[i] -= constant * src[i];
}
//splat constant into a vector
constVec = loadSplatUnalignedScalar( &constant );
//calculate permute and do loads
permVec1 = vec_add( vec_lvsl( -1, (int*) &src[i] ), oneCharVector );
v2_hi = vec_ld( 0, &src[i] );
//vectorize!
for ( ; i+7 < count; i += 8 ) {
v0_low = v2_hi;
v0_hi = vec_ld( 15, &src[i] );
v2_low = v0_hi;
v2_hi = vec_ld( 31, &src[i] );
v0 = vec_perm( v0_low, v0_hi, permVec1 );
v2 = vec_perm( v2_low, v2_hi, permVec1 );
//we know dst will be aligned here because we already handled the preceeding
//unaligned cases
v1 = vec_ld( 0, &dst[i] );
v3 = vec_ld( 16, &dst[i] );
v4 = vec_nmsub( v0, constVec, v1 );
v5 = vec_nmsub( v2, constVec, v3 );
ALIGNED_STORE2( &dst[i], v4, v5 );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] -= constant * src[i];
}
}
/*
============
idSIMD_AltiVec::MulSub
dst[i] -= src0[i] * src1[i];
============
*/
void VPCALL idSIMD_AltiVec::MulSub( float *dst, const float *src0, const float *src1, const int count ) {
register vector float v0, v1, v2, v3, v4, v5, v6, v7;
//src0
register vector float v0_low, v0_hi, v2_low, v2_hi;
//src1
register vector float v1_low, v1_hi, v3_low, v3_hi;
//permute vectors
register vector unsigned char permVec1, permVec2;
vector unsigned char oneCharVector = (vector unsigned char)(1);
int i;
//unaligned at start
for ( i = 0 ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count );i++ ) {
dst[i] -= src0[i] * src1[i];
}
//calculate permute and do loads
permVec1 = vec_add( vec_lvsl( -1, (int*) &src0[i] ), oneCharVector );
permVec2 = vec_add( vec_lvsl( -1, (int*) &src1[i] ), oneCharVector );
v2_hi = vec_ld( 0, &src0[i] );
v3_hi = vec_ld( 0, &src1[i] );
//vectorize!
for ( ; i+7 < count; i += 8 ) {
// load sources
v0_low = v2_hi;
v0_hi = vec_ld( 15, &src0[i] );
v2_low = v0_hi;
v2_hi = vec_ld( 31, &src0[i] );
v1_low = v3_hi;
v1_hi = vec_ld( 15, &src1[i] );
v3_low = v1_hi;
v3_hi = vec_ld( 31, &src1[i] );
v0 = vec_perm( v0_low, v0_hi, permVec1 );
v1 = vec_perm( v1_low, v1_hi, permVec2 );
v2 = vec_perm( v2_low, v2_hi, permVec1 );
v3 = vec_perm( v3_low, v3_hi, permVec2 );
//we know dst is aligned because we handled unaligned cases
//up front
v4 = vec_ld( 0, &dst[i] );
v5 = vec_ld( 16, &dst[i] );
v6 = vec_nmsub( v0, v1, v4 );
v7 = vec_nmsub( v2, v3, v5 );
ALIGNED_STORE2( &dst[i], v6, v7 );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] -= src0[i] * src1[i];
}
}
#endif /* ENABLE_SIMPLE_MATH */
#ifdef ENABLE_DOT
/*
============
idSIMD_AltiVec::Dot
dst[i] = constant * src[i];
============
*/
void VPCALL idSIMD_AltiVec::Dot( float *dst, const idVec3 &constant, const idVec3 *src, const int count ) {
register vector float vecLd1, vecLd2, vecLd3, vecLd4, vecLd5, vecLd6;
register vector float vecX, vecY, vecZ;
vector float vecX2, vecY2, vecZ2;
const float *addr = src[0].ToFloatPtr();
float tempVal[4];
float constVal[4];
register vector float zeroVector = (vector float)(0.0);
register vector float vecConstX, vecConstY, vecConstZ;
// permute vectors
register vector unsigned char permX1 = (vector unsigned char)(0,1,2,3,12,13,14,15,24,25,26,27,28,29,30,31); //last 4 bytes are junk
register vector unsigned char permX2 = (vector unsigned char)(0,1,2,3,4,5,6,7,8,9,10,11,20,21,22,23);
register vector unsigned char permY1 = (vector unsigned char)(4,5,6,7,16,17,18,19,28,29,30,31,0,1,2,3); //last 4 bytes are junk
register vector unsigned char permY2 = (vector unsigned char)(0,1,2,3,4,5,6,7,8,9,10,11,24,25,26,27);
register vector unsigned char permZ1 = (vector unsigned char)(8,9,10,11,20,21,22,23,0,1,2,3,4,5,6,7); //last 8 bytes are junk
register vector unsigned char permZ2 = (vector unsigned char)(0,1,2,3,4,5,6,7,16,17,18,19,28,29,30,31);
int i;
// for scalar cleanup, if necessary
constVal[0] = constant[0];
constVal[1] = constant[1];
constVal[2] = constant[2];
constVal[3] = 0;
vector unsigned char constPerm = vec_lvsl( 0, constant.ToFloatPtr() );
vecLd1 = vec_ld( 0, constant.ToFloatPtr() );
vecLd2 = vec_ld( 11, constant.ToFloatPtr() );
vecLd1 = vec_perm( vecLd1, vecLd2, constPerm );
// populate const vectors
vecConstX = vec_splat( vecLd1, 0 );
vecConstY = vec_splat( vecLd1, 1 );
vecConstZ = vec_splat( vecLd1, 2 );
vector unsigned char permVec = vec_add( vec_lvsl( -1, addr ), (vector unsigned char)(1) );
vector float vecOld = vec_ld( 0, addr );
// handle unaligned case at beginning
for ( i = 0 ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count ); i++ ) {
dst[i] = constant * src[i];
}
for ( ; i + 7 < count; i += 8 ) {
float *vecPtr = (float*)( addr + (i*3) );
vector float v0, v1, v2, v3, v4, v5;
v0 = vecOld; //vec_ld( 0, vecPtr );
v1 = vec_ld( 15, vecPtr );
v2 = vec_ld( 31, vecPtr );
v3 = vec_ld( 47, vecPtr );
v4 = vec_ld( 63, vecPtr );
v5 = vec_ld( 79, vecPtr );
vecOld = vec_ld( 95, vecPtr );
vecLd1 = vec_perm( v0, v1, permVec );
vecLd2 = vec_perm( v1, v2, permVec );
vecLd3 = vec_perm( v2, v3, permVec );
vecLd4 = vec_perm( v3, v4, permVec );
vecLd5 = vec_perm( v4, v5, permVec );
vecLd6 = vec_perm( v5, vecOld, permVec );
// permute into X Y Z vectors
vecX = vec_perm( vecLd1, vecLd2, permX1 );
vecY = vec_perm( vecLd1, vecLd2, permY1 );
vecZ = vec_perm( vecLd1, vecLd2, permZ1 );
vecX = vec_perm( vecX, vecLd3, permX2 );
vecY = vec_perm( vecY, vecLd3, permY2 );
vecZ = vec_perm( vecZ, vecLd3, permZ2 );
vecX2 = vec_perm( vecLd4, vecLd5, permX1 );
vecY2 = vec_perm( vecLd4, vecLd5, permY1 );
vecZ2 = vec_perm( vecLd4, vecLd5, permZ1 );
vecX2 = vec_perm( vecX2, vecLd6, permX2 );
vecY2 = vec_perm( vecY2, vecLd6, permY2 );
vecZ2 = vec_perm( vecZ2, vecLd6, permZ2 );
// do multiply
vecX = vec_madd( vecX, vecConstX, zeroVector );
vecY = vec_madd( vecY, vecConstY, vecX );
vecZ = vec_madd( vecZ, vecConstZ, vecY );
vecX2 = vec_madd( vecX2, vecConstX, zeroVector );
vecY2 = vec_madd( vecY2, vecConstY, vecX2 );
vecZ2 = vec_madd( vecZ2, vecConstZ, vecY2 );
// store out results
ALIGNED_STORE2( &dst[i], vecZ, vecZ2 );
}
//cleanup
for ( ; i < count; i++ ) {
// look up whats at the address we want, cast it as float pointer, then
// dereference that pointer
tempVal[0] = *( addr + (i*3) + 0 );
tempVal[1] = *( addr + (i*3) + 1 );
tempVal[2] = *( addr + (i*3) + 2 );
dst[i] = constVal[0] * tempVal[0] + constVal[1] * tempVal[1] + constVal[2] * tempVal[2];
}
}
/*
============
idSIMD_AltiVec::Dot
dst[i] = constant * src[i].Normal() + src[i][3];
============
*/
void VPCALL idSIMD_AltiVec::Dot( float *dst, const idVec3 &constant, const idPlane *src, const int count ) {
//#define OPER(X) dst[(X)] = constant * src[(X)].Normal() + src[(X)][3];
assert( sizeof(idPlane) == PLANE_OFFSET * sizeof(float) );
int i;
float constVal[4];
float srcVal[3];
float srcI3;
float tempVal;
vector float vecPlaneLd1, vecPlaneLd2, vecPlaneLd3, vecPlaneLd4;
vector float vecPlaneLd5, vecPlaneLd6, vecPlaneLd7, vecPlaneLd8;
vector float vecX, vecY, vecZ, vecI3;
vector float vecX2, vecY2, vecZ2, vecI32;
vector float vecConstX, vecConstY, vecConstZ;
constVal[0] = constant[0];
constVal[1] = constant[1];
constVal[2] = constant[2];
constVal[3] = 1;
vector unsigned char constPerm = vec_lvsl( 0, constant.ToFloatPtr() );
vector float v0 = vec_ld( 0, constant.ToFloatPtr() );
vector float v1 = vec_ld( 11, constant.ToFloatPtr() );
vector float vecConst = vec_perm( v0, v1, constPerm );
vecConstX = vec_splat( vecConst, 0 );
vecConstY = vec_splat( vecConst, 1 );
vecConstZ = vec_splat( vecConst, 2 );
// handle unaligned case at beginning
for ( i = 0 ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count ); i++ ) {
dst[i] = constant * src[i].Normal() + src[i][3];
}
const float *addr = src[i].ToFloatPtr();
vector unsigned char permVec = vec_add( vec_lvsl( -1, addr ), (vector unsigned char)(1) );
vector float vecOld = vec_ld( 0, addr );
for ( ; i + 7 < count; i += 8 ) {
float *planePtr = (float*)( addr + (i*PLANE_OFFSET) );
vector float v0, v1, v2, v3, v4, v5, v6, v7;
v0 = vecOld; //vec_ld( 0, planePtr );
v1 = vec_ld( 15, planePtr );
v2 = vec_ld( 31, planePtr );
v3 = vec_ld( 47, planePtr );
v4 = vec_ld( 63, planePtr );
v5 = vec_ld( 79, planePtr );
v6 = vec_ld( 95, planePtr );
v7 = vec_ld( 111, planePtr );
vecOld = vec_ld( 127, planePtr );
vecPlaneLd1 = vec_perm( v0, v1, permVec );
vecPlaneLd2 = vec_perm( v1, v2, permVec );
vecPlaneLd3 = vec_perm( v2, v3, permVec );
vecPlaneLd4 = vec_perm( v3, v4, permVec );
vecPlaneLd5 = vec_perm( v4, v5, permVec );
vecPlaneLd6 = vec_perm( v5, v6, permVec );
vecPlaneLd7 = vec_perm( v6, v7, permVec );
vecPlaneLd8 = vec_perm( v7, vecOld, permVec );
// permute into X Y Z vectors, since this is square its basically
// a matrix transpose
v0 = vec_mergeh( vecPlaneLd1, vecPlaneLd3 );
v1 = vec_mergeh( vecPlaneLd2, vecPlaneLd4 );
v2 = vec_mergel( vecPlaneLd1, vecPlaneLd3 );
v3 = vec_mergel( vecPlaneLd2, vecPlaneLd4 );
vecX = vec_mergeh( v0, v1 );
vecY = vec_mergel( v0, v1 );
vecZ = vec_mergeh( v2, v3 );
vecI3 = vec_mergel( v2, v3 );
v4 = vec_mergeh( vecPlaneLd5, vecPlaneLd7 );
v5 = vec_mergeh( vecPlaneLd6, vecPlaneLd8 );
v6 = vec_mergel( vecPlaneLd5, vecPlaneLd7 );
v7 = vec_mergel( vecPlaneLd6, vecPlaneLd8 );
vecX2 = vec_mergeh( v4, v5 );
vecY2 = vec_mergel( v4, v5 );
vecZ2 = vec_mergeh( v6, v7 );
vecI32 = vec_mergel( v6, v7 );
// do calculation
v6 = vec_madd( vecZ, vecConstZ, vecI3 );
v5 = vec_madd( vecY, vecConstY, v6 );
v4 = vec_madd( vecX, vecConstX, v5 );
v0 = vec_madd( vecZ2, vecConstZ, vecI32 );
v1 = vec_madd( vecY2, vecConstY, v0 );
v2 = vec_madd( vecX2, vecConstX, v1 );
// store results
ALIGNED_STORE2( &dst[i], v4, v2 );
}
// cleanup
for ( ; i < count; i++ ) {
// populate srcVal with src X Y Z
srcVal[0] = *(addr + (i*PLANE_OFFSET) + 0 );
srcVal[1] = *(addr + (i*PLANE_OFFSET) + 1 );
srcVal[2] = *(addr + (i*PLANE_OFFSET) + 2 );
// put src[i][3] into srcI3
srcI3 = *(addr + (i*PLANE_OFFSET) + 3 );
tempVal = constVal[0] * srcVal[0] + constVal[1] * srcVal[1] + constVal[2] * srcVal[2];
dst[i] = tempVal + srcI3;
}
}
#ifndef DRAWVERT_PADDED
/*
============
idSIMD_AltiVec::Dot
dst[i] = constant * src[i].xyz;
============
*/
void VPCALL idSIMD_AltiVec::Dot( float *dst, const idVec3 &constant, const idDrawVert *src, const int count ) {
//#define OPER(X) dst[(X)] = constant * src[(X)].xyz;
// idDrawVert size is 60 bytes
assert( sizeof(idDrawVert) == DRAWVERT_OFFSET * sizeof( float ) );
register vector float v0, v1, v2, v3, v4, v5, v6, v7;
int i;
register vector float vecConstX, vecConstY, vecConstZ;
register vector float vecSrcX1, vecSrcY1, vecSrcZ1;
register vector float zeroVector = (vector float)(0.0);
vector unsigned char vertPerm1, vertPerm2, vertPerm3, vertPerm4;
vector unsigned char constPerm = vec_lvsl( 0, constant.ToFloatPtr() );
v0 = vec_ld( 0, constant.ToFloatPtr() );
v1 = vec_ld( 11, constant.ToFloatPtr() );
v0 = vec_perm( v0, v1, constPerm );
// permute into constant vectors
vecConstX = vec_splat( v0, 0 );
vecConstY = vec_splat( v0, 1 );
vecConstZ = vec_splat( v0, 2 );
// handle unaligned case at beginning
for ( i = 0 ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count ); i++ ) {
dst[i] = constant * src[i].xyz;
}
// every fourth one will have the same alignment. Make sure we've got enough here
if ( i+3 < count ) {
vertPerm1 = vec_add( vec_lvsl( -1, (float*) src[i].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vertPerm2 = vec_add( vec_lvsl( -1, (float*) src[i+1].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vertPerm3 = vec_add( vec_lvsl( -1, (float*) src[i+2].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vertPerm4 = vec_add( vec_lvsl( -1, (float*) src[i+3].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
}
for ( ; i+3 < count; i += 4 ) {
const float *vertPtr = src[i].xyz.ToFloatPtr();
const float *vertPtr2 = src[i+1].xyz.ToFloatPtr();
const float *vertPtr3 = src[i+2].xyz.ToFloatPtr();
const float *vertPtr4 = src[i+3].xyz.ToFloatPtr();
v0 = vec_ld( 0, vertPtr );
v1 = vec_ld( 11, vertPtr );
v2 = vec_ld( 0, vertPtr2 );
v3 = vec_ld( 11, vertPtr2 );
v4 = vec_ld( 0, vertPtr3 );
v5 = vec_ld( 11, vertPtr3 );
v6 = vec_ld( 0, vertPtr4 );
v7 = vec_ld( 11, vertPtr4 );
v0 = vec_perm( v0, v1, vertPerm1 );
v2 = vec_perm( v2, v3, vertPerm2 );
v4 = vec_perm( v4, v5, vertPerm3 );
v6 = vec_perm( v6, v7, vertPerm4 );
// transpose into X Y Z vectors
v1 = vec_mergeh( v0, v4 );
v3 = vec_mergeh( v2, v6 );
v5 = vec_mergel( v0, v4 );
v7 = vec_mergel( v2, v6 );
vecSrcX1 = vec_mergeh( v1, v3 );
vecSrcY1 = vec_mergel( v1, v3 );
vecSrcZ1 = vec_mergeh( v5, v7 );
// now calculate dot product
vecSrcX1 = vec_madd( vecSrcX1, vecConstX, zeroVector );
vecSrcY1 = vec_madd( vecSrcY1, vecConstY, vecSrcX1 );
vecSrcZ1 = vec_madd( vecSrcZ1, vecConstZ, vecSrcY1 );
// store results
vec_st( vecSrcZ1, 0, &dst[i] );
}
for ( ; i < count; i++ ) {
dst[i] = constant * src[i].xyz;
}
}
#else
/*
============
idSIMD_AltiVec::Dot
dst[i] = constant * src[i].xyz;
============
*/
void VPCALL idSIMD_AltiVec::Dot( float *dst, const idVec3 &constant, const idDrawVert *src, const int count ) {
//#define OPER(X) dst[(X)] = constant * src[(X)].xyz;
// idDrawVert size is 64 bytes
assert( sizeof(idDrawVert) == DRAWVERT_OFFSET * sizeof( float ) );
register vector float v0, v1, v2, v3, v4, v5, v6, v7;
int i;
register vector float vecConstX, vecConstY, vecConstZ;
register vector float vecSrcX1, vecSrcY1, vecSrcZ1;
register vector float zeroVector = (vector float)(0.0);
vector unsigned char vertPerm1, vertPerm2, vertPerm3, vertPerm4;
vector unsigned char constPerm = vec_lvsl( 0, constant.ToFloatPtr() );
v0 = vec_ld( 0, constant.ToFloatPtr() );
v1 = vec_ld( 11, constant.ToFloatPtr() );
v0 = vec_perm( v0, v1, constPerm );
// permute into constant vectors
vecConstX = vec_splat( v0, 0 );
vecConstY = vec_splat( v0, 1 );
vecConstZ = vec_splat( v0, 2 );
// handle unaligned case at beginning
for ( i = 0 ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count ); i++ ) {
dst[i] = constant * src[i].xyz;
}
for ( ; i+3 < count; i += 4 ) {
const float *vertPtr = src[i].xyz.ToFloatPtr();
const float *vertPtr2 = src[i+1].xyz.ToFloatPtr();
const float *vertPtr3 = src[i+2].xyz.ToFloatPtr();
const float *vertPtr4 = src[i+3].xyz.ToFloatPtr();
v0 = vec_ld( 0, vertPtr );
v2 = vec_ld( 0, vertPtr2 );
v4 = vec_ld( 0, vertPtr3 );
v6 = vec_ld( 0, vertPtr4 );
// transpose into X Y Z vectors
v1 = vec_mergeh( v0, v4 );
v3 = vec_mergeh( v2, v6 );
v5 = vec_mergel( v0, v4 );
v7 = vec_mergel( v2, v6 );
vecSrcX1 = vec_mergeh( v1, v3 );
vecSrcY1 = vec_mergel( v1, v3 );
vecSrcZ1 = vec_mergeh( v5, v7 );
// now calculate dot product
vecSrcX1 = vec_madd( vecSrcX1, vecConstX, zeroVector );
vecSrcY1 = vec_madd( vecSrcY1, vecConstY, vecSrcX1 );
vecSrcZ1 = vec_madd( vecSrcZ1, vecConstZ, vecSrcY1 );
// store results
vec_st( vecSrcZ1, 0, &dst[i] );
}
for ( ; i < count; i++ ) {
dst[i] = constant * src[i].xyz;
}
}
#endif /* DRAWVERT_PADDED */
/*
============
idSIMD_AltiVec::Dot
dst[i] = constant.Normal() * src[i] + constant[3];
============
*/
void VPCALL idSIMD_AltiVec::Dot( float *dst, const idPlane &constant, const idVec3 *src, const int count ) {
//#define OPER(X) dst[(X)] = constant.Normal() * src[(X)] + constant[3];
register vector float vecLd1, vecLd2, vecLd3, vecLd4, vecLd5, vecLd6;
register vector float vecX, vecY, vecZ, vecX2, vecY2, vecZ2;
register vector float zeroVector = (vector float)(0.0);
register vector float vecConstX, vecConstY, vecConstZ;
register vector float vecConst3;
idVec3 constNormal = constant.Normal();
float const3 = constant[3];
// permute vectors
register vector unsigned char permX1 = (vector unsigned char)(0,1,2,3,12,13,14,15,24,25,26,27,28,29,30,31); //last 4 bytes are junk
register vector unsigned char permX2 = (vector unsigned char)(0,1,2,3,4,5,6,7,8,9,10,11,20,21,22,23);
register vector unsigned char permY1 = (vector unsigned char)(4,5,6,7,16,17,18,19,28,29,30,31,0,1,2,3); //last 4 bytes are junk
register vector unsigned char permY2 = (vector unsigned char)(0,1,2,3,4,5,6,7,8,9,10,11,24,25,26,27);
register vector unsigned char permZ1 = (vector unsigned char)(8,9,10,11,20,21,22,23,0,1,2,3,4,5,6,7); //last 8 bytes are junk
register vector unsigned char permZ2 = (vector unsigned char)(0,1,2,3,4,5,6,7,16,17,18,19,28,29,30,31);
int i;
vector unsigned char constPerm = vec_lvsl( 0, constant.ToFloatPtr() );
vecLd1 = vec_ld( 0, constant.ToFloatPtr() );
vecLd2 = vec_ld( 15, constant.ToFloatPtr() );
vecLd1 = vec_perm( vecLd1, vecLd2, constPerm );
// populate const vec
vecConstX = vec_splat( vecLd1, 0 );
vecConstY = vec_splat( vecLd1, 1 );
vecConstZ = vec_splat( vecLd1, 2 );
// put constant to add in vector
vecConst3 = loadSplatUnalignedScalar( &const3 );
// handle unaligned case at beginning
for ( i = 0 ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count ); i++ ) {
dst[i] = constant.Normal() * src[i] + constant[3];
}
const float *addr = src[i].ToFloatPtr();
vector unsigned char permVec = vec_add( vec_lvsl( -1, addr ), (vector unsigned char)(1) );
vector float vecOld = vec_ld( 0, addr );
for ( ; i+7 < count; i += 8 ) {
float *vecPtr = (float*)( addr + (i*3) );
vector float v0, v1, v2, v3, v4, v5;
v0 = vecOld; //vec_ld( 0, vecPtr );
v1 = vec_ld( 15, vecPtr );
v2 = vec_ld( 31, vecPtr );
v3 = vec_ld( 47, vecPtr );
v4 = vec_ld( 63, vecPtr );
v5 = vec_ld( 79, vecPtr );
vecOld = vec_ld( 95, vecPtr );
vecLd1 = vec_perm( v0, v1, permVec );
vecLd2 = vec_perm( v1, v2, permVec );
vecLd3 = vec_perm( v2, v3, permVec );
vecLd4 = vec_perm( v3, v4, permVec );
vecLd5 = vec_perm( v4, v5, permVec );
vecLd6 = vec_perm( v5, vecOld, permVec );
// permute into X Y Z vectors
vecX = vec_perm( vecLd1, vecLd2, permX1 );
vecY = vec_perm( vecLd1, vecLd2, permY1 );
vecZ = vec_perm( vecLd1, vecLd2, permZ1 );
vecX = vec_perm( vecX, vecLd3, permX2 );
vecY = vec_perm( vecY, vecLd3, permY2 );
vecZ = vec_perm( vecZ, vecLd3, permZ2 );
vecX2 = vec_perm( vecLd4, vecLd5, permX1 );
vecY2 = vec_perm( vecLd4, vecLd5, permY1 );
vecZ2 = vec_perm( vecLd4, vecLd5, permZ1 );
vecX2 = vec_perm( vecX2, vecLd6, permX2 );
vecY2 = vec_perm( vecY2, vecLd6, permY2 );
vecZ2 = vec_perm( vecZ2, vecLd6, permZ2 );
// calculate dot product
vecX = vec_madd( vecX, vecConstX, zeroVector );
vecY = vec_madd( vecY, vecConstY, vecX );
vecZ = vec_madd( vecZ, vecConstZ, vecY );
vecX2 = vec_madd( vecX2, vecConstX, zeroVector );
vecY2 = vec_madd( vecY2, vecConstY, vecX2 );
vecZ2 = vec_madd( vecZ2, vecConstZ, vecY2 );
// add in constant[3]
vecZ = vec_add( vecZ, vecConst3 );
vecZ2 = vec_add( vecZ2, vecConst3 );
// store out results
ALIGNED_STORE2( &dst[i], vecZ, vecZ2 );
}
//cleanup
for ( ; i < count; i++ ) {
dst[i] = constNormal * src[i] + const3;
}
}
/*
============
idSIMD_AltiVec::Dot
dst[i] = constant.Normal() * src[i].Normal() + constant[3] * src[i][3];
============
*/
void VPCALL idSIMD_AltiVec::Dot( float *dst, const idPlane &constant, const idPlane *src, const int count ) {
//#define OPER(X) dst[(X)] = constant.Normal() * src[(X)].Normal() + constant[3] * src[(X)][3];
// check plane size
assert( sizeof(idPlane) == PLANE_OFFSET * sizeof(float) );
float constVal[4];
float srcVal[4];
int i;
const float *constPtr = constant.ToFloatPtr();
register vector float vecX, vecY, vecZ, vecI3;
register vector float vecX2, vecY2, vecZ2, vecI32;
vector float vecPlaneLd1, vecPlaneLd2, vecPlaneLd3, vecPlaneLd4;
vector float vecPlaneLd5, vecPlaneLd6, vecPlaneLd7, vecPlaneLd8;
register vector float zeroVector = (vector float)(0.0);
register vector float vecConstX, vecConstY, vecConstZ, vecConstI3;
constVal[0] = *(constPtr);
constVal[1] = *(constPtr+1);
constVal[2] = *(constPtr+2);
constVal[3] = *(constPtr+3);
// populate const vector
vector unsigned char constPerm = vec_lvsl( 0, constant.ToFloatPtr() );
vector float v0 = vec_ld( 0, constant.ToFloatPtr() );
vector float v1 = vec_ld( 15, constant.ToFloatPtr() );
vector float vecConst = vec_perm( v0, v1, constPerm );
vecConstX = vec_splat( vecConst, 0 );
vecConstY = vec_splat( vecConst, 1 );
vecConstZ = vec_splat( vecConst, 2 );
vecConstI3 = vec_splat( vecConst, 3 );
// handle unaligned case at beginning
for ( i = 0 ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count ); i++ ) {
dst[i] = constant.Normal() * src[i].Normal() + constant[3] * src[i][3];
}
const float *srcPtr = src[i].ToFloatPtr();
vector unsigned char permVec = vec_add( vec_lvsl( -1, srcPtr ), (vector unsigned char)(1) );
vector float vecOld = vec_ld( 0, srcPtr );
for ( ; i+7 < count; i += 8 ) {
float *planePtr = (float*)( srcPtr + (i*PLANE_OFFSET) );
vector float v0, v1, v2, v3, v4, v5, v6, v7;
v0 = vecOld; // vec_ld( 0, planePtr );
v1 = vec_ld( 15, planePtr );
v2 = vec_ld( 31, planePtr );
v3 = vec_ld( 47, planePtr );
v4 = vec_ld( 63, planePtr );
v5 = vec_ld( 79, planePtr );
v6 = vec_ld( 95, planePtr );
v7 = vec_ld( 111, planePtr );
vecOld = vec_ld( 127, planePtr );
vecPlaneLd1 = vec_perm( v0, v1, permVec );
vecPlaneLd2 = vec_perm( v1, v2, permVec );
vecPlaneLd3 = vec_perm( v2, v3, permVec );
vecPlaneLd4 = vec_perm( v3, v4, permVec );
vecPlaneLd5 = vec_perm( v4, v5, permVec );
vecPlaneLd6 = vec_perm( v5, v6, permVec );
vecPlaneLd7 = vec_perm( v6, v7, permVec );
vecPlaneLd8 = vec_perm( v7, vecOld, permVec );
// permute into X Y Z vectors, since this is square its basically
// a matrix transpose
v0 = vec_mergeh( vecPlaneLd1, vecPlaneLd3 );
v1 = vec_mergeh( vecPlaneLd2, vecPlaneLd4 );
v2 = vec_mergel( vecPlaneLd1, vecPlaneLd3 );
v3 = vec_mergel( vecPlaneLd2, vecPlaneLd4 );
vecX = vec_mergeh( v0, v1 );
vecY = vec_mergel( v0, v1 );
vecZ = vec_mergeh( v2, v3 );
vecI3 = vec_mergel( v2, v3 );
v4 = vec_mergeh( vecPlaneLd5, vecPlaneLd7 );
v5 = vec_mergeh( vecPlaneLd6, vecPlaneLd8 );
v6 = vec_mergel( vecPlaneLd5, vecPlaneLd7 );
v7 = vec_mergel( vecPlaneLd6, vecPlaneLd8 );
vecX2 = vec_mergeh( v4, v5 );
vecY2 = vec_mergel( v4, v5 );
vecZ2 = vec_mergeh( v6, v7 );
vecI32 = vec_mergel( v6, v7 );
// do calculation
v4 = vec_madd( vecConstX, vecX, zeroVector );
v5 = vec_madd( vecConstY, vecY, v4 );
v6 = vec_madd( vecConstZ, vecZ, v5 );
v7 = vec_madd( vecConstI3, vecI3, v6 );
v0 = vec_madd( vecConstX, vecX2, zeroVector );
v1 = vec_madd( vecConstY, vecY2, v0 );
v2 = vec_madd( vecConstZ, vecZ2, v1 );
v3 = vec_madd( vecConstI3, vecI32, v2 );
//store result
ALIGNED_STORE2( &dst[i], v7, v3 );
}
// cleanup
for ( ; i < count; i++ ) {
//dst[i] = constant.Normal() * src[i].Normal() + constant[3] * src[i][3];
srcVal[0] = *(srcPtr + (i*PLANE_OFFSET) + 0 );
srcVal[1] = *(srcPtr + (i*PLANE_OFFSET) + 1 );
srcVal[2] = *(srcPtr + (i*PLANE_OFFSET) + 2 );
srcVal[3] = *(srcPtr + (i*PLANE_OFFSET) + 3 );
dst[i] = srcVal[0] * constVal[0] + srcVal[1] * constVal[1] + srcVal[2] * constVal[2] + constVal[3] * srcVal[3];
}
}
#ifndef DRAWVERT_PADDED
/*
============
idSIMD_AltiVec::Dot
dst[i] = constant.Normal() * src[i].xyz + constant[3];
============
*/
void VPCALL idSIMD_AltiVec::Dot( float *dst, const idPlane &constant, const idDrawVert *src, const int count ) {
//#define OPER(X) dst[(X)] = constant.Normal() * src[(X)].xyz + constant[3];
// idDrawVert size is 60 bytes
assert( sizeof(idDrawVert) == DRAWVERT_OFFSET * sizeof( float ) );
int i;
const float *constPtr = constant.ToFloatPtr();
const float *srcPtr = src[0].xyz.ToFloatPtr();
register vector float v0, v1, v2, v3, v4, v5, v6, v7;
register vector float vecConstX, vecConstY, vecConstZ, vecConstI3;
register vector float vecSrcX1, vecSrcY1, vecSrcZ1;
register vector float vecDest1;
register vector float zeroVector = (vector float)(0.0);
vector unsigned char vertPerm1, vertPerm2, vertPerm3, vertPerm4;
float constVal[4];
float srcVal[3];
constVal[0] = *(constPtr+0);
constVal[1] = *(constPtr+1);
constVal[2] = *(constPtr+2);
constVal[3] = *(constPtr+3);
// populate const vec
vector unsigned char constPerm = vec_lvsl( 0, constant.ToFloatPtr() );
v0 = vec_ld( 0, constant.ToFloatPtr() );
v1 = vec_ld( 15, constant.ToFloatPtr() );
v0 = vec_perm( v0, v1, constPerm );
vecConstX = vec_splat( v0, 0 );
vecConstY = vec_splat( v0, 1 );
vecConstZ = vec_splat( v0, 2 );
vecConstI3 = vec_splat( v0, 3 );
// handle unaligned case at beginning
for ( i = 0 ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count ); i++ ) {
dst[i] = constant.Normal() * src[i].xyz + constant[3];
}
// every fourth one will have the same alignment, so can store these. Make sure we
// have enough so we don't run off the end of the array
if ( i+3 < count ) {
vertPerm1 = vec_add( vec_lvsl( -1, (float*) src[i].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vertPerm2 = vec_add( vec_lvsl( -1, (float*) src[i+1].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vertPerm3 = vec_add( vec_lvsl( -1, (float*) src[i+2].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vertPerm4 = vec_add( vec_lvsl( -1, (float*) src[i+3].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
}
for ( ; i+3 < count; i+=4 ) {
const float *vertPtr = src[i].xyz.ToFloatPtr();
const float *vertPtr2 = src[i+1].xyz.ToFloatPtr();
const float *vertPtr3 = src[i+2].xyz.ToFloatPtr();
const float *vertPtr4 = src[i+3].xyz.ToFloatPtr();
v0 = vec_ld( 0, vertPtr );
v1 = vec_ld( 11, vertPtr );
v2 = vec_ld( 0, vertPtr2 );
v3 = vec_ld( 11, vertPtr2 );
v4 = vec_ld( 0, vertPtr3 );
v5 = vec_ld( 11, vertPtr3 );
v6 = vec_ld( 0, vertPtr4 );
v7 = vec_ld( 11, vertPtr4 );
v0 = vec_perm( v0, v1, vertPerm1 );
v2 = vec_perm( v2, v3, vertPerm2 );
v4 = vec_perm( v4, v5, vertPerm3 );
v6 = vec_perm( v6, v7, vertPerm4 );
// transpose into X Y Z vectors
v1 = vec_mergeh( v0, v4 );
v3 = vec_mergeh( v2, v6 );
v5 = vec_mergel( v0, v4 );
v7 = vec_mergel( v2, v6 );
vecSrcX1 = vec_mergeh( v1, v3 );
vecSrcY1 = vec_mergel( v1, v3 );
vecSrcZ1 = vec_mergeh( v5, v7 );
// now calculate dot product
vecSrcX1 = vec_madd( vecSrcX1, vecConstX, zeroVector );
vecSrcY1 = vec_madd( vecSrcY1, vecConstY, vecSrcX1 );
vecSrcZ1 = vec_madd( vecSrcZ1, vecConstZ, vecSrcY1 );
vecDest1 = vec_add( vecSrcZ1, vecConstI3 );
// store results
vec_st( vecDest1, 0, &dst[i] );
}
// cleanup
for ( ; i < count; i++ ) {
srcVal[0] = *(srcPtr + (i*DRAWVERT_OFFSET) + 0 );
srcVal[1] = *(srcPtr + (i*DRAWVERT_OFFSET) + 1 );
srcVal[2] = *(srcPtr + (i*DRAWVERT_OFFSET) + 2 );
// dst[i] = constant.Normal() * src[i].xyz + constant[3];
dst[i] = constVal[0] * srcVal[0] + constVal[1] * srcVal[1] + constVal[2] * srcVal[2];
dst[i] += constVal[3];
}
}
#else
/*
============
idSIMD_AltiVec::Dot
dst[i] = constant.Normal() * src[i].xyz + constant[3];
============
*/
void VPCALL idSIMD_AltiVec::Dot( float *dst, const idPlane &constant, const idDrawVert *src, const int count ) {
//#define OPER(X) dst[(X)] = constant.Normal() * src[(X)].xyz + constant[3];
// idDrawVert size is 60 bytes
assert( sizeof(idDrawVert) == DRAWVERT_OFFSET * sizeof( float ) );
int i;
const float *constPtr = constant.ToFloatPtr();
const float *srcPtr = src[0].xyz.ToFloatPtr();
register vector float v0, v1, v2, v3, v4, v5, v6, v7;
register vector float vecConstX, vecConstY, vecConstZ, vecConstI3;
register vector float vecSrcX1, vecSrcY1, vecSrcZ1;
register vector float vecDest1;
register vector float zeroVector = (vector float)(0.0);
vector unsigned char vertPerm1, vertPerm2, vertPerm3, vertPerm4;
float constVal[4];
float srcVal[3];
constVal[0] = *(constPtr+0);
constVal[1] = *(constPtr+1);
constVal[2] = *(constPtr+2);
constVal[3] = *(constPtr+3);
// populate const vec
vector unsigned char constPerm = vec_lvsl( 0, constant.ToFloatPtr() );
v0 = vec_ld( 0, constant.ToFloatPtr() );
v1 = vec_ld( 15, constant.ToFloatPtr() );
v0 = vec_perm( v0, v1, constPerm );
vecConstX = vec_splat( v0, 0 );
vecConstY = vec_splat( v0, 1 );
vecConstZ = vec_splat( v0, 2 );
vecConstI3 = vec_splat( v0, 3 );
// handle unaligned case at beginning
for ( i = 0 ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count ); i++ ) {
dst[i] = constant.Normal() * src[i].xyz + constant[3];
}
for ( ; i+3 < count; i+=4 ) {
const float *vertPtr = src[i].xyz.ToFloatPtr();
const float *vertPtr2 = src[i+1].xyz.ToFloatPtr();
const float *vertPtr3 = src[i+2].xyz.ToFloatPtr();
const float *vertPtr4 = src[i+3].xyz.ToFloatPtr();
v0 = vec_ld( 0, vertPtr );
v2 = vec_ld( 0, vertPtr2 );
v4 = vec_ld( 0, vertPtr3 );
v6 = vec_ld( 0, vertPtr4 );
// transpose into X Y Z vectors
v1 = vec_mergeh( v0, v4 );
v3 = vec_mergeh( v2, v6 );
v5 = vec_mergel( v0, v4 );
v7 = vec_mergel( v2, v6 );
vecSrcX1 = vec_mergeh( v1, v3 );
vecSrcY1 = vec_mergel( v1, v3 );
vecSrcZ1 = vec_mergeh( v5, v7 );
// now calculate dot product
vecSrcX1 = vec_madd( vecSrcX1, vecConstX, zeroVector );
vecSrcY1 = vec_madd( vecSrcY1, vecConstY, vecSrcX1 );
vecSrcZ1 = vec_madd( vecSrcZ1, vecConstZ, vecSrcY1 );
vecDest1 = vec_add( vecSrcZ1, vecConstI3 );
// store results
vec_st( vecDest1, 0, &dst[i] );
}
// cleanup
for ( ; i < count; i++ ) {
srcVal[0] = *(srcPtr + (i*DRAWVERT_OFFSET) + 0 );
srcVal[1] = *(srcPtr + (i*DRAWVERT_OFFSET) + 1 );
srcVal[2] = *(srcPtr + (i*DRAWVERT_OFFSET) + 2 );
// dst[i] = constant.Normal() * src[i].xyz + constant[3];
dst[i] = constVal[0] * srcVal[0] + constVal[1] * srcVal[1] + constVal[2] * srcVal[2];
dst[i] += constVal[3];
}
}
#endif /* DRAWVERT_PADDED */
/*
============
idSIMD_AltiVec::Dot
dst[i] = src0[i] * src1[i];
============
*/
void VPCALL idSIMD_AltiVec::Dot( float *dst, const idVec3 *src0, const idVec3 *src1, const int count ) {
//#define OPER(X) dst[(X)] = src0[(X)] * src1[(X)];
int i;
float src0Val[3];
float src1Val[3];
register vector float vecLd1, vecLd2, vecLd3, vecLd4, vecLd5, vecLd6;
vector float vecLd7, vecLd8, vecLd9, vecLd10, vecLd11, vecLd12;
register vector float vecX0, vecY0, vecZ0, vecX1, vecY1, vecZ1;
register vector float vecX02, vecY02, vecZ02, vecX12, vecY12, vecZ12;
register vector float zeroVector = (vector float)(0.0);
// permute vectors
register vector unsigned char permX1 = (vector unsigned char)(0,1,2,3,12,13,14,15,24,25,26,27,28,29,30,31); //last 4 bytes are junk
register vector unsigned char permX2 = (vector unsigned char)(0,1,2,3,4,5,6,7,8,9,10,11,20,21,22,23);
register vector unsigned char permY1 = (vector unsigned char)(4,5,6,7,16,17,18,19,28,29,30,31,0,1,2,3); //last 4 bytes are junk
register vector unsigned char permY2 = (vector unsigned char)(0,1,2,3,4,5,6,7,8,9,10,11,24,25,26,27);
register vector unsigned char permZ1 = (vector unsigned char)(8,9,10,11,20,21,22,23,0,1,2,3,4,5,6,7); //last 8 bytes are junk
register vector unsigned char permZ2 = (vector unsigned char)(0,1,2,3,4,5,6,7,16,17,18,19,28,29,30,31);
// handle unaligned case at beginning
for ( i = 0 ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count ); i++ ) {
dst[i] = src0[i] * src1[i];
}
const float *src0Ptr = src0[i].ToFloatPtr();
const float *src1Ptr = src1[i].ToFloatPtr();
vector unsigned char permVec1 = vec_add( vec_lvsl( -1, src0Ptr ), (vector unsigned char)(1) );
vector unsigned char permVec2 = vec_add( vec_lvsl( -1, src1Ptr ), (vector unsigned char)(1) );
vector float vecOld0 = vec_ld( 0, src0Ptr );
vector float vecOld1 = vec_ld( 0, src1Ptr );
for ( i = 0; i+7 < count; i += 8 ) {
float *s0Ptr = (float*)( src0Ptr + (i*3) );
float *s1Ptr = (float*)( src1Ptr + (i*3) );
vector float v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11;
v0 = vecOld0;
v1 = vec_ld( 15, s0Ptr );
v2 = vec_ld( 31, s0Ptr );
v3 = vec_ld( 47, s0Ptr );
v4 = vec_ld( 63, s0Ptr );
v5 = vec_ld( 79, s0Ptr );
vecOld0 = vec_ld( 95, s0Ptr );
v6 = vecOld1;
v7 = vec_ld( 15, s1Ptr );
v8 = vec_ld( 31, s1Ptr );
v9 = vec_ld( 47, s1Ptr );
v10 = vec_ld( 63, s1Ptr );
v11 = vec_ld( 79, s1Ptr );
vecOld1 = vec_ld( 95, s1Ptr );
vecLd1 = vec_perm( v0, v1, permVec1 );
vecLd2 = vec_perm( v1, v2, permVec1 );
vecLd3 = vec_perm( v2, v3, permVec1 );
vecLd4 = vec_perm( v3, v4, permVec1 );
vecLd5 = vec_perm( v4, v5, permVec1 );
vecLd6 = vec_perm( v5, vecOld0, permVec1 );
vecLd7 = vec_perm( v6, v7, permVec2 );
vecLd8 = vec_perm( v7, v8, permVec2 );
vecLd9 = vec_perm( v8, v9, permVec2 );
vecLd10 = vec_perm( v9, v10, permVec2 );
vecLd11 = vec_perm( v10, v11, permVec2 );
vecLd12 = vec_perm( v11, vecOld1, permVec2 );
// permute into X Y Z vectors
vecX0 = vec_perm( vecLd1, vecLd2, permX1 );
vecY0 = vec_perm( vecLd1, vecLd2, permY1 );
vecZ0 = vec_perm( vecLd1, vecLd2, permZ1 );
vecX0 = vec_perm( vecX0, vecLd3, permX2 );
vecY0 = vec_perm( vecY0, vecLd3, permY2 );
vecZ0 = vec_perm( vecZ0, vecLd3, permZ2 );
vecX02 = vec_perm( vecLd4, vecLd5, permX1 );
vecY02 = vec_perm( vecLd4, vecLd5, permY1 );
vecZ02 = vec_perm( vecLd4, vecLd5, permZ1 );
vecX02 = vec_perm( vecX02, vecLd6, permX2 );
vecY02 = vec_perm( vecY02, vecLd6, permY2 );
vecZ02 = vec_perm( vecZ02, vecLd6, permZ2 );
vecX1 = vec_perm( vecLd7, vecLd8, permX1 );
vecY1 = vec_perm( vecLd7, vecLd8, permY1 );
vecZ1 = vec_perm( vecLd7, vecLd8, permZ1 );
vecX1 = vec_perm( vecX1, vecLd9, permX2 );
vecY1 = vec_perm( vecY1, vecLd9, permY2 );
vecZ1 = vec_perm( vecZ1, vecLd9, permZ2 );
vecX12 = vec_perm( vecLd10, vecLd11, permX1 );
vecY12 = vec_perm( vecLd10, vecLd11, permY1 );
vecZ12 = vec_perm( vecLd10, vecLd11, permZ1 );
vecX12 = vec_perm( vecX12, vecLd12, permX2 );
vecY12 = vec_perm( vecY12, vecLd12, permY2 );
vecZ12 = vec_perm( vecZ12, vecLd12, permZ2 );
// do multiply
vecX0 = vec_madd( vecX0, vecX1, zeroVector );
vecY0 = vec_madd( vecY0, vecY1, vecX0 );
vecZ0 = vec_madd( vecZ0, vecZ1, vecY0 );
vecX02 = vec_madd( vecX02, vecX12, zeroVector );
vecY02 = vec_madd( vecY02, vecY12, vecX02 );
vecZ02 = vec_madd( vecZ02, vecZ12, vecY02 );
// store out results
ALIGNED_STORE2( &dst[i], vecZ0, vecZ02 );
}
// cleanup
for ( ; i < count; i++ ) {
// dst[i] = src0[i] * src1[i];
src0Val[0] = *( src0Ptr + (i*3) + 0 );
src0Val[1] = *( src0Ptr + (i*3) + 1 );
src0Val[2] = *( src0Ptr + (i*3) + 2 );
src1Val[0] = *( src1Ptr + (i*3) + 0 );
src1Val[1] = *( src1Ptr + (i*3) + 1 );
src1Val[2] = *( src1Ptr + (i*3) + 2 );
dst[i] = src0Val[0] * src1Val[0] + src0Val[1] * src1Val[1] + src0Val[2] * src1Val[2];
}
}
/*
============
idSIMD_AltiVec::Dot
dot = src1[0] * src2[0] + src1[1] * src2[1] + src1[2] * src2[2] + ...
============
*/
void VPCALL idSIMD_AltiVec::Dot( float &dot, const float *src1, const float *src2, const int count ) {
dot = 0.0f;
register vector float v0, v1, v2, v3;
register vector float zeroVector;
register vector float runningTotal1, runningTotal2;
//src0
register vector float v0_low, v0_hi, v2_low, v2_hi;
//src1
register vector float v1_low, v1_hi, v3_low, v3_hi;
//permute vectors
register vector unsigned char permVec1, permVec2;
vector unsigned char oneCharVector = (vector unsigned char)(1);
int i = 0;
runningTotal1 = (vector float)(0.0);
runningTotal2 = (vector float)(0.0);
zeroVector = (vector float)(0.0);
if ( count >= 8 ) {
//calculate permute and do loads
permVec1 = vec_add( vec_lvsl( -1, (int*) &src1[i] ), oneCharVector );
permVec2 = vec_add( vec_lvsl( -1, (int*) &src2[i] ), oneCharVector );
v2_hi = vec_ld( 0, &src1[i] );
v3_hi = vec_ld( 0, &src2[i] );
//vectorize!
for ( ; i+7 < count; i += 8 ) {
//load sources
v0_low = v2_hi;
v0_hi = vec_ld( 15, &src1[i] );
v2_low = v0_hi;
v2_hi = vec_ld( 31, &src1[i] );
v1_low = v3_hi;
v1_hi = vec_ld( 15, &src2[i] );
v3_low = v1_hi;
v3_hi = vec_ld( 31, &src2[i] );
v0 = vec_perm( v0_low, v0_hi, permVec1 );
v1 = vec_perm( v1_low, v1_hi, permVec2 );
v2 = vec_perm( v2_low, v2_hi, permVec1 );
v3 = vec_perm( v3_low, v3_hi, permVec2 );
//multiply together and keep running sum
runningTotal1 = vec_madd( v0, v1, runningTotal1 );
runningTotal2 = vec_madd( v2, v3, runningTotal2 );
}
runningTotal1 = vec_add( runningTotal1, runningTotal2 );
// sum accross vector
v0 = vec_add( runningTotal1, vec_sld( runningTotal1, runningTotal1, 8 ) );
v1 = vec_add( v0, vec_sld( v0, v0, 4 ) );
runningTotal1 = vec_splat( v1, 0 );
vec_ste( runningTotal1, 0, &dot );
}
//handle cleanup. when profiling the game, we found that most of the counts to this function were small, so it
// spends a lot of time in this scalar code. It's already really really fast (eg 1 TB tick) for scalar code for
// counts less than 50, so not much point in trying to get vector code in on the action
for ( ; i < count ; i++ ) {
dot += src1[i] * src2[i];
}
}
#endif /* ENABLE_DOT */
#ifdef ENABLE_COMPARES
/*
============
idSIMD_AltiVec::CmpGT
dst[i] = src0[i] > constant;
============
*/
void VPCALL idSIMD_AltiVec::CmpGT( byte *dst, const float *src0, const float constant, const int count ) {
//#define OPER(X) dst[(X)] = src0[(X)] > constant;
register vector float v0, v1, v2, v3;
register vector bool int vr1, vr2, vr3, vr4;
register vector bool short vs1, vs2;
register vector float v0_low, v0_hi, v1_low, v1_hi, v2_low, v2_hi, v3_low, v3_hi;
register vector unsigned char vc1;
register vector bool char vbc1;
register vector float constVec;
register vector unsigned char oneVector = (vector unsigned char)(1);
register vector unsigned char permVec;
int i;
//handle unaligned at start
for ( i = 0 ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count );i++ ) {
dst[i] = src0[i] > constant;
}
//splat constant into a vector
constVec = loadSplatUnalignedScalar( &constant );
//calculate permute and do loads
permVec = vec_add( vec_lvsl( -1, (int*) &src0[i] ), oneVector );
v3_hi = vec_ld( 0, &src0[i] );
//vectorize!
for ( ; i+15 < count; i += 16 ) {
// load values
v0_low = v3_hi;
v0_hi = vec_ld( 15, &src0[i] );
v1_low = v0_hi;
v1_hi = vec_ld( 31, &src0[i] );
v2_low = v1_hi;
v2_hi = vec_ld( 47, &src0[i] );
v3_low = v2_hi;
v3_hi = vec_ld( 63, &src0[i] );
//permute into the vectors we want
v0 = vec_perm( v0_low, v0_hi, permVec );
v1 = vec_perm( v1_low, v1_hi, permVec );
v2 = vec_perm( v2_low, v2_hi, permVec );
v3 = vec_perm( v3_low, v3_hi, permVec );
//do comparison
vr1 = vec_cmpgt( v0, constVec );
vr2 = vec_cmpgt( v1, constVec );
vr3 = vec_cmpgt( v2, constVec );
vr4 = vec_cmpgt( v3, constVec );
// pack results into shorts
vs1 = vec_pack(vr1, vr2);
vs2 = vec_pack(vr3, vr4);
// pack results into byte
vbc1 = vec_pack(vs1, vs2);
//AND with 1 to get true=1 not true=255
vc1 = vec_and( vbc1, oneVector );
//store results
vec_st( vc1, 0, &dst[i] );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] = src0[i] > constant;
}
}
/*
============
idSIMD_AltiVec::CmpGT
dst[i] |= ( src0[i] > constant ) << bitNum;
============
*/
void VPCALL idSIMD_AltiVec::CmpGT( byte *dst, const byte bitNum, const float *src0, const float constant, const int count ) {
//#define OPER(X) dst[(X)] |= ( src0[(X)] > constant ) << bitNum;
// Temp vector registers
register vector bool int vtbi0, vtbi1, vtbi2, vtbi3;
register vector bool short vtbs0, vtbs1;
register vector bool char vtbc0;
register vector unsigned char vtuc0;
register vector unsigned char permVec, permVec2;
// dest vectors
register vector unsigned char vd;
// bitNum vectors
register vector unsigned char bitNumVec;
// src0 vectors
register vector float vs0, vs1, vs2, vs3;
register vector float vs0_low, vs0_hi, vs1_low, vs1_hi, vs2_low, vs2_hi, vs3_low, vs3_hi;
// constant vector
register vector float constVec;
// all one's
register vector unsigned char oneVector = (vector unsigned char)(1);
int i = 0;
//handle unaligned at start
for ( i = 0 ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count );i++ ) {
dst[i] |= ( src0[i] > constant ) << bitNum;
}
//splat constant into a vector
constVec = loadSplatUnalignedScalar( &constant );
//bitNum is unaligned.
permVec2 = vec_lvsl( 0, &bitNum );
vtuc0 = vec_ld( 0, &bitNum );
bitNumVec = vec_perm( vtuc0, vtuc0, permVec2 );
bitNumVec = vec_splat( bitNumVec, 0 );
//calculate permute and do loads
permVec = vec_add( vec_lvsl( -1, (int*) &src0[i] ), oneVector );
vs3_hi = vec_ld( 0, &src0[i] );
//vectorize!
for ( ; i+15 < count; i += 16 ) {
//load sources (floats)
vs0_low = vs3_hi;
vs0_hi = vec_ld( 15, &src0[i] );
vs1_low = vs0_hi;
vs1_hi = vec_ld( 31, &src0[i] );
vs2_low = vs1_hi;
vs2_hi = vec_ld( 47, &src0[i] );
vs3_low = vs2_hi;
vs3_hi = vec_ld( 63, &src0[i] );
//permute into the vectors we want
vs0 = vec_perm( vs0_low, vs0_hi, permVec );
vs1 = vec_perm( vs1_low, vs1_hi, permVec );
vs2 = vec_perm( vs2_low, vs2_hi, permVec );
vs3 = vec_perm( vs3_low, vs3_hi, permVec );
//load dest (bytes) as unsigned char
vd = vec_ld( 0, &dst[i] );
// do comparison and get bool int result
vtbi0 = vec_cmpgt( vs0, constVec );
vtbi1 = vec_cmpgt( vs1, constVec );
vtbi2 = vec_cmpgt( vs2, constVec );
vtbi3 = vec_cmpgt( vs3, constVec );
// pack results into shorts
vtbs0 = vec_pack(vtbi0, vtbi1);
vtbs1 = vec_pack(vtbi2, vtbi3);
// pack results into byte
vtbc0 = vec_pack(vtbs0, vtbs1);
//and with 1 to get true=1 instead of true=255
vtuc0 = vec_and(vtbc0, oneVector);
vtuc0 = vec_sl(vtuc0, bitNumVec );
//or with original
vd = vec_or( vd, vtuc0 );
vec_st( vd, 0, &dst[i] );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] |= ( src0[i] > constant ) << bitNum;
}
}
/*
============
idSIMD_AltiVec::CmpGE
dst[i] = src0[i] >= constant;
============
*/
void VPCALL idSIMD_AltiVec::CmpGE( byte *dst, const float *src0, const float constant, const int count ) {
register vector float v0, v1, v2, v3;
register vector bool int vr1, vr2, vr3, vr4;
register vector bool short vs1, vs2;
register vector float v0_low, v0_hi, v1_low, v1_hi, v2_low, v2_hi, v3_low, v3_hi;
register vector unsigned char vc1;
register vector bool char vbc1;
register vector float constVec;
register vector unsigned char oneVector = (vector unsigned char)(1);
register vector unsigned char permVec;
int i = 0;
//handle unaligned at start
for ( ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count );i++ ) {
dst[i] = src0[i] >= constant;
}
//splat constant into a vector
constVec = loadSplatUnalignedScalar( &constant );
//calculate permute and do loads
permVec = vec_add( vec_lvsl( -1, (int*) &src0[i] ), oneVector );
v3_hi = vec_ld( 0, &src0[i] );
//vectorize!
for ( ; i+15 < count; i += 16 ) {
// load values
v0_low = v3_hi;
v0_hi = vec_ld( 15, &src0[i] );
v1_low = v0_hi;
v1_hi = vec_ld( 31, &src0[i] );
v2_low = v1_hi;
v2_hi = vec_ld( 47, &src0[i] );
v3_low = v2_hi;
v3_hi = vec_ld( 63, &src0[i] );
//permute into the vectors we want
v0 = vec_perm( v0_low, v0_hi, permVec );
v1 = vec_perm( v1_low, v1_hi, permVec );
v2 = vec_perm( v2_low, v2_hi, permVec );
v3 = vec_perm( v3_low, v3_hi, permVec );
//do comparison
vr1 = vec_cmpge( v0, constVec );
vr2 = vec_cmpge( v1, constVec );
vr3 = vec_cmpge( v2, constVec );
vr4 = vec_cmpge( v3, constVec );
// pack results into shorts
vs1 = vec_pack(vr1, vr2);
vs2 = vec_pack(vr3, vr4);
// pack results into byte
vbc1 = vec_pack(vs1, vs2);
//AND with 1 to get true=1 not true=255
vc1 = vec_and( vbc1, oneVector );
//store results
vec_st( vc1, 0, &dst[i] );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] = src0[i] >= constant;
}
}
/*
============
idSIMD_AltiVec::CmpGE
dst[i] |= ( src0[i] >= constant ) << bitNum;
============
*/
void VPCALL idSIMD_AltiVec::CmpGE( byte *dst, const byte bitNum, const float *src0, const float constant, const int count ) {
register vector bool int vtbi0, vtbi1, vtbi2, vtbi3;
register vector bool short vtbs0, vtbs1;
register vector bool char vtbc0;
register vector unsigned char vtuc0;
register vector unsigned char permVec, permVec2;
// dest vectors
register vector unsigned char vd;
// bitNum vectors
register vector unsigned char bitNumVec;
// src0 vectors
register vector float vs0, vs1, vs2, vs3;
register vector float vs0_low, vs0_hi, vs1_low, vs1_hi, vs2_low, vs2_hi, vs3_low, vs3_hi;
// constant vector
register vector float constVec;
// all one's
register vector unsigned char oneVector = (vector unsigned char)(1);
int i = 0;
//handle unaligned at start
for ( ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count );i++ ) {
dst[i] |= ( src0[i] >= constant ) << bitNum;
}
//splat constant into a vector
constVec = loadSplatUnalignedScalar( &constant );
//bitNum is unaligned.
permVec2 = vec_lvsl( 0, &bitNum );
vtuc0 = vec_ld( 0, &bitNum );
bitNumVec = vec_perm( vtuc0, vtuc0, permVec2 );
bitNumVec = vec_splat( bitNumVec, 0 );
//calculate permute and do loads
permVec = vec_add( vec_lvsl( -1, (int*) &src0[i] ), oneVector );
vs3_hi = vec_ld( 0, &src0[i] );
//vectorize!
for ( ; i+15 < count; i += 16 ) {
//load sources (floats)
vs0_low = vs3_hi;
vs0_hi = vec_ld( 15, &src0[i] );
vs1_low = vs0_hi;
vs1_hi = vec_ld( 31, &src0[i] );
vs2_low = vs1_hi;
vs2_hi = vec_ld( 47, &src0[i] );
vs3_low = vs2_hi;
vs3_hi = vec_ld( 63, &src0[i] );
//permute into the vectors we want
vs0 = vec_perm( vs0_low, vs0_hi, permVec );
vs1 = vec_perm( vs1_low, vs1_hi, permVec );
vs2 = vec_perm( vs2_low, vs2_hi, permVec );
vs3 = vec_perm( vs3_low, vs3_hi, permVec );
//load dest (bytes) as unsigned char
vd = vec_ld( 0, &dst[i] );
// do comparison and get bool int result
vtbi0 = vec_cmpge( vs0, constVec );
vtbi1 = vec_cmpge( vs1, constVec );
vtbi2 = vec_cmpge( vs2, constVec );
vtbi3 = vec_cmpge( vs3, constVec );
// pack results into shorts
vtbs0 = vec_pack(vtbi0, vtbi1);
vtbs1 = vec_pack(vtbi2, vtbi3);
// pack results into byte
vtbc0 = vec_pack(vtbs0, vtbs1);
//and with 1L to get true=1 instead of true=255
vtuc0 = vec_and(vtbc0, oneVector);
vtuc0 = vec_sl(vtuc0, bitNumVec );
//or with original
vd = vec_or( vd, vtuc0 );
vec_st( vd, 0, &dst[i] );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] |= ( src0[i] >= constant ) << bitNum;
}
}
/*
============
idSIMD_AltiVec::CmpLT
dst[i] = src0[i] < constant;
============
*/
void VPCALL idSIMD_AltiVec::CmpLT( byte *dst, const float *src0, const float constant, const int count ) {
//#define OPER(X) dst[(X)] = src0[(X)] < constant;
register vector float v0, v1, v2, v3;
register vector bool int vr1, vr2, vr3, vr4;
register vector bool short vs1, vs2;
register vector float v0_low, v0_hi, v1_low, v1_hi, v2_low, v2_hi, v3_low, v3_hi;
register vector unsigned char vc1;
register vector bool char vbc1;
register vector float constVec;
register vector unsigned char oneVector = (vector unsigned char)(1);
register vector unsigned char permVec;
int i = 0;
//handle unaligned at start
for ( ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count );i++ ) {
dst[i] = src0[i] < constant;
}
//splat constant into a vector
constVec = loadSplatUnalignedScalar( &constant );
//calculate permute and do loads
permVec = vec_add( vec_lvsl( -1, (int*) &src0[i] ), oneVector );
v3_hi = vec_ld( 0, &src0[i] );
//vectorize!
for ( ; i+15 < count; i += 16 ) {
// load values
v0_low = v3_hi;
v0_hi = vec_ld( 15, &src0[i] );
v1_low = v0_hi;
v1_hi = vec_ld( 31, &src0[i] );
v2_low = v1_hi;
v2_hi = vec_ld( 47, &src0[i] );
v3_low = v2_hi;
v3_hi = vec_ld( 63, &src0[i] );
//permute into the vectors we want
v0 = vec_perm( v0_low, v0_hi, permVec );
v1 = vec_perm( v1_low, v1_hi, permVec );
v2 = vec_perm( v2_low, v2_hi, permVec );
v3 = vec_perm( v3_low, v3_hi, permVec );
//do comparison
vr1 = vec_cmplt( v0, constVec );
vr2 = vec_cmplt( v1, constVec );
vr3 = vec_cmplt( v2, constVec );
vr4 = vec_cmplt( v3, constVec );
// pack results into shorts
vs1 = vec_pack(vr1, vr2);
vs2 = vec_pack(vr3, vr4);
// pack results into byte
vbc1 = vec_pack(vs1, vs2);
//AND with 1 to get true=1 not true=255
vc1 = vec_and( vbc1, oneVector );
//store results
vec_st( vc1, 0, &dst[i] );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] = src0[i] < constant;
}
}
/*
============
idSIMD_AltiVec::CmpLT
dst[i] |= ( src0[i] < constant ) << bitNum;
============
*/
void VPCALL idSIMD_AltiVec::CmpLT( byte *dst, const byte bitNum, const float *src0, const float constant, const int count ) {
//#define OPER(X) dst[(X)] |= ( src0[(X)] < constant ) << bitNum;
register vector bool int vtbi0, vtbi1, vtbi2, vtbi3;
register vector bool short vtbs0, vtbs1;
register vector bool char vtbc0;
register vector unsigned char vtuc0;
register vector unsigned char permVec, permVec2;
// dest vectors
register vector unsigned char vd;
// bitNum vectors
register vector unsigned char bitNumVec;
// src0 vectors
register vector float vs0, vs1, vs2, vs3;
register vector float vs0_low, vs0_hi, vs1_low, vs1_hi, vs2_low, vs2_hi, vs3_low, vs3_hi;
// constant vector
register vector float constVec;
// all one's
register vector unsigned char oneVector = (vector unsigned char)(1);
int i = 0;
//handle unaligned at start
for ( i = 0 ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count );i++ ) {
dst[i] |= ( src0[i] < constant ) << bitNum;
}
//splat constant into a vector
constVec = loadSplatUnalignedScalar( &constant );
//bitNum is unaligned.
permVec2 = vec_lvsl( 0, &bitNum );
vtuc0 = vec_ld( 0, &bitNum );
bitNumVec = vec_perm( vtuc0, vtuc0, permVec2 );
bitNumVec = vec_splat( bitNumVec, 0 );
//calculate permute and do loads
permVec = vec_add( vec_lvsl( -1, (int*) &src0[i] ), oneVector );
vs3_hi = vec_ld( 0, &src0[i] );
//vectorize!
for ( ; i+15 < count; i += 16 ) {
//load sources (floats)
vs0_low = vs3_hi;
vs0_hi = vec_ld( 15, &src0[i] );
vs1_low = vs0_hi;
vs1_hi = vec_ld( 31, &src0[i] );
vs2_low = vs1_hi;
vs2_hi = vec_ld( 47, &src0[i] );
vs3_low = vs2_hi;
vs3_hi = vec_ld( 63, &src0[i] );
//permute into the vectors we want
vs0 = vec_perm( vs0_low, vs0_hi, permVec );
vs1 = vec_perm( vs1_low, vs1_hi, permVec );
vs2 = vec_perm( vs2_low, vs2_hi, permVec );
vs3 = vec_perm( vs3_low, vs3_hi, permVec );
//load dest (bytes) as unsigned char
vd = vec_ld( 0, &dst[i] );
// do comparison and get bool int result
vtbi0 = vec_cmplt( vs0, constVec );
vtbi1 = vec_cmplt( vs1, constVec );
vtbi2 = vec_cmplt( vs2, constVec );
vtbi3 = vec_cmplt( vs3, constVec );
// pack results into shorts
vtbs0 = vec_pack(vtbi0, vtbi1);
vtbs1 = vec_pack(vtbi2, vtbi3);
// pack results into byte
vtbc0 = vec_pack(vtbs0, vtbs1);
//and with 1L to get true=1 instead of true=255
vtuc0 = vec_and(vtbc0, oneVector);
vtuc0 = vec_sl(vtuc0, bitNumVec );
//or with original
vd = vec_or( vd, vtuc0 );
vec_st( vd, 0, &dst[i] );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] |= ( src0[i] < constant ) << bitNum;
}
}
//#endif
/*
============
idSIMD_AltiVec::CmpLE
dst[i] = src0[i] <= constant;
============
*/
void VPCALL idSIMD_AltiVec::CmpLE( byte *dst, const float *src0, const float constant, const int count ) {
//#define OPER(X) dst[(X)] = src0[(X)] <= constant;
register vector float v0, v1, v2, v3;
register vector bool int vr1, vr2, vr3, vr4;
register vector bool short vs1, vs2;
register vector float v0_low, v0_hi, v1_low, v1_hi, v2_low, v2_hi, v3_low, v3_hi;
register vector unsigned char vc1;
register vector bool char vbc1;
register vector float constVec;
register vector unsigned char oneVector = (vector unsigned char)(1);
register vector unsigned char permVec;
int i = 0;
//handle unaligned at start
for ( ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count );i++ ) {
dst[i] = src0[i] <= constant;
}
//splat constant into a vector
constVec = loadSplatUnalignedScalar( &constant );
//calculate permute and do loads
permVec = vec_add( vec_lvsl( -1, (int*) &src0[i] ), oneVector );
v3_hi = vec_ld( 0, &src0[i] );
//vectorize!
for ( ; i+15 < count; i += 16 ) {
// load values
v0_low = v3_hi;
v0_hi = vec_ld( 15, &src0[i] );
v1_low = v0_hi;
v1_hi = vec_ld( 31, &src0[i] );
v2_low = v1_hi;
v2_hi = vec_ld( 47, &src0[i] );
v3_low = v2_hi;
v3_hi = vec_ld( 63, &src0[i] );
//permute into the vectors we want
v0 = vec_perm( v0_low, v0_hi, permVec );
v1 = vec_perm( v1_low, v1_hi, permVec );
v2 = vec_perm( v2_low, v2_hi, permVec );
v3 = vec_perm( v3_low, v3_hi, permVec );
//do comparison
vr1 = vec_cmple( v0, constVec );
vr2 = vec_cmple( v1, constVec );
vr3 = vec_cmple( v2, constVec );
vr4 = vec_cmple( v3, constVec );
// pack results into shorts
vs1 = vec_pack(vr1, vr2);
vs2 = vec_pack(vr3, vr4);
// pack results into byte
vbc1 = vec_pack(vs1, vs2);
//AND with 1 to get true=1 not true=255
vc1 = vec_and( vbc1, oneVector );
//store results
vec_st( vc1, 0, &dst[i] );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] = src0[i] <= constant;
}
}
/*
============
idSIMD_AltiVec::CmpLE
dst[i] |= ( src0[i] <= constant ) << bitNum;
============
*/
void VPCALL idSIMD_AltiVec::CmpLE( byte *dst, const byte bitNum, const float *src0, const float constant, const int count ) {
//#define OPER(X) dst[(X)] |= ( src0[(X)] <= constant ) << bitNum;
register vector bool int vtbi0, vtbi1, vtbi2, vtbi3;
register vector bool short vtbs0, vtbs1;
register vector bool char vtbc0;
register vector unsigned char vtuc0;
register vector unsigned char permVec, permVec2;
// dest vectors
register vector unsigned char vd;
// bitNum vectors
register vector unsigned char bitNumVec;
// src0 vectors
register vector float vs0, vs1, vs2, vs3;
register vector float vs0_low, vs0_hi, vs1_low, vs1_hi, vs2_low, vs2_hi, vs3_low, vs3_hi;
// constant vector
register vector float constVec;
// all one's
register vector unsigned char oneVector = (vector unsigned char)(1);
int i = 0;
//handle unaligned at start
for ( ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count );i++ ) {
dst[i] |= ( src0[i] <= constant ) << bitNum;
}
//splat constant into a vector
constVec = loadSplatUnalignedScalar( &constant );
//bitNum is unaligned.
permVec2 = vec_lvsl( 0, &bitNum );
vtuc0 = vec_ld( 0, &bitNum );
bitNumVec = vec_perm( vtuc0, vtuc0, permVec2 );
bitNumVec = vec_splat( bitNumVec, 0 );
//calculate permute and do loads
permVec = vec_add( vec_lvsl( -1, (int*) &src0[i] ), oneVector );
vs3_hi = vec_ld( 0, &src0[i] );
//vectorize!
for ( ; i+15 < count; i += 16 ) {
//load sources (floats)
vs0_low = vs3_hi;
vs0_hi = vec_ld( 15, &src0[i] );
vs1_low = vs0_hi;
vs1_hi = vec_ld( 31, &src0[i] );
vs2_low = vs1_hi;
vs2_hi = vec_ld( 47, &src0[i] );
vs3_low = vs2_hi;
vs3_hi = vec_ld( 63, &src0[i] );
//permute into the vectors we want
vs0 = vec_perm( vs0_low, vs0_hi, permVec );
vs1 = vec_perm( vs1_low, vs1_hi, permVec );
vs2 = vec_perm( vs2_low, vs2_hi, permVec );
vs3 = vec_perm( vs3_low, vs3_hi, permVec );
//load dest (bytes) as unsigned char
vd = vec_ld( 0, &dst[i] );
// do comparison and get bool int result
vtbi0 = vec_cmple( vs0, constVec );
vtbi1 = vec_cmple( vs1, constVec );
vtbi2 = vec_cmple( vs2, constVec );
vtbi3 = vec_cmple( vs3, constVec );
// pack results into shorts
vtbs0 = vec_pack(vtbi0, vtbi1);
vtbs1 = vec_pack(vtbi2, vtbi3);
// pack results into byte
vtbc0 = vec_pack(vtbs0, vtbs1);
//and with 1L to get true=1 instead of true=255
vtuc0 = vec_and(vtbc0, oneVector);
vtuc0 = vec_sl(vtuc0, bitNumVec );
//or with original
vd = vec_or( vd, vtuc0 );
vec_st( vd, 0, &dst[i] );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] |= ( src0[i] <= constant ) << bitNum;
}
}
#endif /* ENABLE_COMPARES */
#ifdef ENABLE_MINMAX
/*
============
idSIMD_AltiVec::MinMax
============
*/
void VPCALL idSIMD_AltiVec::MinMax( float &min, float &max, const float *src, const int count ) {
min = idMath::INFINITY; max = -idMath::INFINITY;
//#define OPER(X) if ( src[(X)] < min ) {min = src[(X)];} if ( src[(X)] > max ) {max = src[(X)];}
register vector float v0, v1, v2, v3;
register vector float maxVec, minVec, tempMin, tempMax;
register vector unsigned char permVec;
register vector float v0_low, v0_hi, v1_low, v1_hi;
vector unsigned char oneCharVector = (vector unsigned char)(1);
int i = 0;
if ( count >= 4 ) {
//calculate permute and do first load to
//get a starting point for min and max
permVec = vec_add( vec_lvsl( -1, (int*) &src[0] ), oneCharVector );
v1_hi = vec_ld( 0, &src[0] );
maxVec = loadSplatUnalignedScalar( &max );
minVec = loadSplatUnalignedScalar( &min );
//vectorize!
for ( ; i+7 < count; i += 8 ) {
//load sources
v0_low = v1_hi;
v0_hi = vec_ld( 15, &src[i] );
v1_low = v0_hi;
v1_hi = vec_ld( 31, &src[i] );
v0 = vec_perm( v0_low, v0_hi, permVec );
v1 = vec_perm( v1_low, v1_hi, permVec );
// minimum
v2 = vec_min( v0, v1 );
minVec = vec_min( minVec, v2 );
// maximum
v3 = vec_max( v0, v1 );
maxVec = vec_max( maxVec, v3 );
}
//minVec and maxVec hold the min/max elements from the array, but now
//we need to figure out which particular element it is
tempMin = minVec;
tempMax = maxVec;
// rotate vector around and compare to itself to find the real min/max
tempMin = vec_min( tempMin, vec_sld( tempMin, tempMin, 8 ) );
tempMax = vec_max( tempMax, vec_sld( tempMax, tempMax, 8 ) );
tempMin = vec_min( tempMin, vec_sld( tempMin, tempMin, 4 ) );
tempMax = vec_max( tempMax, vec_sld( tempMax, tempMax, 4 ) );
minVec = vec_splat( tempMin, 0 );
maxVec = vec_splat( tempMax, 0 );
vec_ste( minVec, 0, &min );
vec_ste( maxVec, 0, &max );
}
//cleanup
for ( ; i < count; i++ ) {
if ( src[i] < min ) {
min = src[i];
}
if ( src[i] > max ) {
max = src[i];
}
}
}
/*
============
idSIMD_AltiVec::MinMax
============
*/
void VPCALL idSIMD_AltiVec::MinMax( idVec2 &min, idVec2 &max, const idVec2 *src, const int count ) {
min[0] = min[1] = idMath::INFINITY; max[0] = max[1] = -idMath::INFINITY;
//#define OPER(X) const idVec2 &v = src[(X)]; if ( v[0] < min[0] ) { min[0] = v[0]; } if ( v[0] > max[0] ) { max[0] = v[0]; } if ( v[1] < min[1] ) { min[1] = v[1]; } if ( v[1] > max[1] ) { max[1] = v[1]; }
idVec2 v;
int i = 0;
int j;
const float *srcPtr = src[0].ToFloatPtr();
register vector float vecLd1, vecLd2, vecLd3, vecLd4;
register vector float vecMin, vecMax;
register vector float v0, v1, v2, v3;
if ( count > 4 ) {
vecMin = (vector float)(FLT_MAX);
vecMax = (vector float)(FLT_MIN);
vector unsigned char permVec = vec_add( vec_lvsl( -1, srcPtr ), (vector unsigned char)(1) );
vector float vecOld = vec_ld( 0, srcPtr );
for ( i = 0, j = 0; i+7 < count; i += 8, j += 4) {
// load data
float *vecPtr = (float*)( srcPtr + (j*4) );
vector float v0, v1, v2, v3;
v0 = vecOld;
v1 = vec_ld( 15, vecPtr );
v2 = vec_ld( 31, vecPtr );
v3 = vec_ld( 47, vecPtr );
vecOld = vec_ld( 63, vecPtr );
vecLd1 = vec_perm( v0, v1, permVec );
vecLd2 = vec_perm( v1, v2, permVec );
vecLd3 = vec_perm( v2, v3, permVec );
vecLd4 = vec_perm( v3, vecOld, permVec );
// each of these vectors contains 2 elements
// looks like | X Y X Y | X Y X Y
v0 = vec_min( vecLd1, vecLd2 );
v1 = vec_min( vecLd3, vecLd4 );
v0 = vec_min( v0, v1 );
v2 = vec_max( vecLd1, vecLd2 );
v3 = vec_max( vecLd3, vecLd4 );
v2 = vec_max( v2, v3 );
// since its always X Y X Y we don't have to re-merge each time. we can wait
// until the end
vecMin = vec_min( v0, vecMin );
vecMax = vec_max( v2, vecMax );
}
vecMin = vec_min( vecMin, vec_sld( vecMin, vecMin, 8 ) );
vecMax = vec_max( vecMax, vec_sld( vecMax, vecMax, 8 ) );
v0 = vec_splat( vecMin, 0 );
v1 = vec_splat( vecMin, 1 );
v2 = vec_splat( vecMax, 0 );
v3 = vec_splat( vecMax, 1 );
vec_ste( v0, 0, &min[0] );
vec_ste( v1, 0, &min[1] );
vec_ste( v2, 0, &max[0] );
vec_ste( v3, 0, &max[1] );
}
// cleanup
for ( ; i < count; i++ ) {
v = src[i];
if ( v[0] < min[0] ) {
min[0] = v[0];
}
if ( v[0] > max[0] ) {
max[0] = v[0];
}
if ( v[1] < min[1] ) {
min[1] = v[1];
}
if ( v[1] > max[1] ) {
max[1] = v[1];
}
}
}
/*
============
idSIMD_AltiVec::MinMax
============
*/
void VPCALL idSIMD_AltiVec::MinMax( idVec3 &min, idVec3 &max, const idVec3 *src, const int count ) {
min[0] = min[1] = min[2] = idMath::INFINITY; max[0] = max[1] = max[2] = -idMath::INFINITY;
//#define OPER(X) const idVec3 &v = src[(X)]; if ( v[0] < min[0] ) { min[0] = v[0]; } if ( v[0] > max[0] ) { max[0] = v[0]; } if ( v[1] < min[1] ) { min[1] = v[1]; } if ( v[1] > max[1] ) { max[1] = v[1]; } if ( v[2] < min[2] ) { min[2] = v[2]; } if ( v[2] > max[2] ) { max[2] = v[2]; }
int i = 0;
const float *srcPtr = src[0].ToFloatPtr();
idVec3 v;
register vector float vecLd1, vecLd2, vecLd3;
register vector float vecMin, vecMax;
register vector float vecSrc1, vecSrc2, vecSrc3, vecSrc4;
register vector float vecMin1, vecMin2, vecMax1, vecMax2;
if ( count >= 4 ) {
vecMin = (vector float)(FLT_MAX);
vecMax = (vector float)(FLT_MIN);
vector unsigned char permVec = vec_add( vec_lvsl( -1, srcPtr), (vector unsigned char)(1) );
vector float vecOld = vec_ld( 0, srcPtr );
// 4 elements at a time
for ( ; i+3 < count; i += 4 ) {
float *vecPtr = (float*)( srcPtr + (i*3) );
vector float v0, v1, v2;
v0 = vecOld;
v1 = vec_ld( 15, vecPtr );
v2 = vec_ld( 31, vecPtr );
vecOld = vec_ld( 47, vecPtr );
vecLd1 = vec_perm( v0, v1, permVec );
vecLd2 = vec_perm( v1, v2, permVec );
vecLd3 = vec_perm( v2, vecOld, permVec );
// put each idVec3 into its own vector as X Y Z (crap)
vecSrc1 = vecLd1;
vecSrc2 = vec_sld( vecLd1, vecLd2, 12 );
vecSrc3 = vec_sld( vecLd2, vecLd3, 8 );
vecSrc4 = vec_sld( vecLd3, vecLd3, 4 );
// do min and max
vecMin1 = vec_min( vecSrc1, vecSrc2 );
vecMin2 = vec_min( vecSrc3, vecSrc4 );
vecMin1 = vec_min( vecMin1, vecMin2 );
vecMin = vec_min( vecMin, vecMin1 );
vecMax1 = vec_max( vecSrc1, vecSrc2 );
vecMax2 = vec_max( vecSrc3, vecSrc4 );
vecMax1 = vec_max( vecMax1, vecMax2 );
vecMax = vec_max( vecMax1, vecMax );
}
// store results
vector float v0, v1, v2, v3, v4, v5;
v0 = vec_splat( vecMin, 0 );
v1 = vec_splat( vecMin, 1 );
v2 = vec_splat( vecMin, 2 );
v3 = vec_splat( vecMax, 0 );
v4 = vec_splat( vecMax, 1 );
v5 = vec_splat( vecMax, 2 );
vec_ste( v0, 0, &min[0] );
vec_ste( v1, 0, &min[1] );
vec_ste( v2, 0, &min[2] );
vec_ste( v3, 0, &max[0] );
vec_ste( v4, 0, &max[1] );
vec_ste( v5, 0, &max[2] );
}
// cleanup
for ( ; i < count; i ++ ) {
v = src[i];
if ( v[0] < min[0] ) {
min[0] = v[0];
}
if ( v[0] > max[0] ) {
max[0] = v[0];
}
if ( v[1] < min[1] ) {
min[1] = v[1];
}
if ( v[1] > max[1] ) {
max[1] = v[1];
}
if ( v[2] < min[2] ) {
min[2] = v[2];
}
if ( v[2] > max[2] ) {
max[2] = v[2];
}
}
}
#ifndef DRAWVERT_PADDED
/*
============
idSIMD_AltiVec::MinMax
============
*/
void VPCALL idSIMD_AltiVec::MinMax( idVec3 &min, idVec3 &max, const idDrawVert *src, const int count ) {
min[0] = min[1] = min[2] = idMath::INFINITY; max[0] = max[1] = max[2] = -idMath::INFINITY;
idVec3 v;
int i = 0;
register vector float vecMin, vecMax;
register vector float v0, v1, v2, v3, v4, v5, v6, v7;
register vector float vecMin1, vecMin2, vecMax1, vecMax2;
if ( count >= 4 ) {
vecMin = (vector float)(FLT_MAX);
vecMax = (vector float)(FLT_MIN);
vector unsigned char vertPerm1 = vec_add( vec_lvsl( -1, (float*) src[i].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vector unsigned char vertPerm2 = vec_add( vec_lvsl( -1, (float*) src[i+1].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vector unsigned char vertPerm3 = vec_add( vec_lvsl( -1, (float*) src[i+2].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vector unsigned char vertPerm4 = vec_add( vec_lvsl( -1, (float*) src[i+3].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
for ( ; i+3 < count; i += 4) {
const float *vertPtr = src[i].xyz.ToFloatPtr();
const float *vertPtr2 = src[i+1].xyz.ToFloatPtr();
const float *vertPtr3 = src[i+2].xyz.ToFloatPtr();
const float *vertPtr4 = src[i+3].xyz.ToFloatPtr();
v0 = vec_ld( 0, vertPtr );
v1 = vec_ld( 11, vertPtr );
v2 = vec_ld( 0, vertPtr2 );
v3 = vec_ld( 11, vertPtr2 );
v4 = vec_ld( 0, vertPtr3 );
v5 = vec_ld( 11, vertPtr3 );
v6 = vec_ld( 0, vertPtr4 );
v7 = vec_ld( 11, vertPtr4 );
v0 = vec_perm( v0, v1, vertPerm1 );
v2 = vec_perm( v2, v3, vertPerm2 );
v4 = vec_perm( v4, v5, vertPerm3 );
v6 = vec_perm( v6, v7, vertPerm4 );
vecMin1 = vec_min( v0, v2 );
vecMin2 = vec_min( v4, v6 );
vecMin1 = vec_min( vecMin1, vecMin2 );
vecMin = vec_min( vecMin, vecMin1 );
vecMax1 = vec_max( v0, v2 );
vecMax2 = vec_max( v4, v6 );
vecMax1 = vec_max( vecMax1, vecMax2 );
vecMax = vec_max( vecMax, vecMax1 );
}
// now we have min/max vectors in X Y Z form, store out
v0 = vec_splat( vecMin, 0 );
v1 = vec_splat( vecMin, 1 );
v2 = vec_splat( vecMin, 2 );
v3 = vec_splat( vecMax, 0 );
v4 = vec_splat( vecMax, 1 );
v5 = vec_splat( vecMax, 2 );
vec_ste( v0, 0, &min[0] );
vec_ste( v1, 0, &min[1] );
vec_ste( v2, 0, &min[2] );
vec_ste( v3, 0, &max[0] );
vec_ste( v4, 0, &max[1] );
vec_ste( v5, 0, &max[2] );
}
// cleanup
for ( ; i < count; i++ ) {
v = src[i].xyz;
if ( v[0] < min[0] ) {
min[0] = v[0];
}
if ( v[0] > max[0] ) {
max[0] = v[0];
}
if ( v[1] < min[1] ) {
min[1] = v[1];
}
if ( v[1] > max[1] ) {
max[1] = v[1];
}
if ( v[2] > max[2] ) {
max[2] = v[2];
}
if ( v[2] < min[2] ) {
min[2] = v[2];
}
}
}
#else
/*
============
idSIMD_AltiVec::MinMax
============
*/
void VPCALL idSIMD_AltiVec::MinMax( idVec3 &min, idVec3 &max, const idDrawVert *src, const int count ) {
min[0] = min[1] = min[2] = idMath::INFINITY; max[0] = max[1] = max[2] = -idMath::INFINITY;
idVec3 v;
int i = 0;
register vector float vecMin, vecMax;
register vector float v0, v1, v2, v3, v4, v5, v6, v7;
register vector float vecMin1, vecMin2, vecMax1, vecMax2;
if ( count >= 4 ) {
vecMin = (vector float)(FLT_MAX);
vecMax = (vector float)(FLT_MIN);
for ( ; i+3 < count; i += 4) {
const float *vertPtr = src[i].xyz.ToFloatPtr();
const float *vertPtr2 = src[i+1].xyz.ToFloatPtr();
const float *vertPtr3 = src[i+2].xyz.ToFloatPtr();
const float *vertPtr4 = src[i+3].xyz.ToFloatPtr();
v0 = vec_ld( 0, vertPtr );
v2 = vec_ld( 0, vertPtr2 );
v4 = vec_ld( 0, vertPtr3 );
v6 = vec_ld( 0, vertPtr4 );
vecMin1 = vec_min( v0, v2 );
vecMin2 = vec_min( v4, v6 );
vecMin1 = vec_min( vecMin1, vecMin2 );
vecMin = vec_min( vecMin, vecMin1 );
vecMax1 = vec_max( v0, v2 );
vecMax2 = vec_max( v4, v6 );
vecMax1 = vec_max( vecMax1, vecMax2 );
vecMax = vec_max( vecMax, vecMax1 );
}
// now we have min/max vectors in X Y Z form, store out
v0 = vec_splat( vecMin, 0 );
v1 = vec_splat( vecMin, 1 );
v2 = vec_splat( vecMin, 2 );
v3 = vec_splat( vecMax, 0 );
v4 = vec_splat( vecMax, 1 );
v5 = vec_splat( vecMax, 2 );
vec_ste( v0, 0, &min[0] );
vec_ste( v1, 0, &min[1] );
vec_ste( v2, 0, &min[2] );
vec_ste( v3, 0, &max[0] );
vec_ste( v4, 0, &max[1] );
vec_ste( v5, 0, &max[2] );
}
// cleanup
for ( ; i < count; i++ ) {
v = src[i].xyz;
if ( v[0] < min[0] ) {
min[0] = v[0];
}
if ( v[0] > max[0] ) {
max[0] = v[0];
}
if ( v[1] < min[1] ) {
min[1] = v[1];
}
if ( v[1] > max[1] ) {
max[1] = v[1];
}
if ( v[2] > max[2] ) {
max[2] = v[2];
}
if ( v[2] < min[2] ) {
min[2] = v[2];
}
}
}
#endif /* DRAWVERT_PADDED */
#ifndef DRAWVERT_PADDED
/*
============
idSIMD_AltiVec::MinMax
============
*/
void VPCALL idSIMD_AltiVec::MinMax( idVec3 &min, idVec3 &max, const idDrawVert *src, const int *indexes, const int count ) {
min[0] = min[1] = min[2] = idMath::INFINITY; max[0] = max[1] = max[2] = -idMath::INFINITY;
idVec3 v;
int i = 0;
register vector float vecMin, vecMax;
register vector float v0, v1, v2, v3, v4, v5, v6, v7;
register vector float vecMin1, vecMin2, vecMax1, vecMax2;
if ( count >= 4 ) {
vecMin = (vector float)(FLT_MAX);
vecMax = (vector float)(FLT_MIN);
vector unsigned char vertPerm1;
vector unsigned char vertPerm2;
vector unsigned char vertPerm3;
vector unsigned char vertPerm4;
for ( ; i+3 < count; i += 4) {
const float *vertPtr = src[indexes[i]].xyz.ToFloatPtr();
const float *vertPtr2 = src[indexes[i+1]].xyz.ToFloatPtr();
const float *vertPtr3 = src[indexes[i+2]].xyz.ToFloatPtr();
const float *vertPtr4 = src[indexes[i+3]].xyz.ToFloatPtr();
vertPerm1 = vec_add( vec_lvsl( -1, vertPtr ), (vector unsigned char)(1) );
vertPerm2 = vec_add( vec_lvsl( -1, vertPtr2 ), (vector unsigned char)(1) );
vertPerm3 = vec_add( vec_lvsl( -1, vertPtr3 ), (vector unsigned char)(1) );
vertPerm4 = vec_add( vec_lvsl( -1, vertPtr4 ), (vector unsigned char)(1) );
v0 = vec_ld( 0, vertPtr );
v1 = vec_ld( 15, vertPtr );
v2 = vec_ld( 0, vertPtr2 );
v3 = vec_ld( 15, vertPtr2 );
v4 = vec_ld( 0, vertPtr3 );
v5 = vec_ld( 15, vertPtr3 );
v6 = vec_ld( 0, vertPtr4 );
v7 = vec_ld( 15, vertPtr4 );
v0 = vec_perm( v0, v1, vertPerm1 );
v2 = vec_perm( v2, v3, vertPerm2 );
v4 = vec_perm( v4, v5, vertPerm3 );
v6 = vec_perm( v6, v7, vertPerm4 );
vecMin1 = vec_min( v0, v2 );
vecMin2 = vec_min( v4, v6 );
vecMin1 = vec_min( vecMin1, vecMin2 );
vecMin = vec_min( vecMin, vecMin1 );
vecMax1 = vec_max( v0, v2 );
vecMax2 = vec_max( v4, v6 );
vecMax1 = vec_max( vecMax1, vecMax2 );
vecMax = vec_max( vecMax, vecMax1 );
}
// now we have min/max vectors in X Y Z form, store out
v0 = vec_splat( vecMin, 0 );
v1 = vec_splat( vecMin, 1 );
v2 = vec_splat( vecMin, 2 );
v3 = vec_splat( vecMax, 0 );
v4 = vec_splat( vecMax, 1 );
v5 = vec_splat( vecMax, 2 );
vec_ste( v0, 0, &min[0] );
vec_ste( v1, 0, &min[1] );
vec_ste( v2, 0, &min[2] );
vec_ste( v3, 0, &max[0] );
vec_ste( v4, 0, &max[1] );
vec_ste( v5, 0, &max[2] );
}
// cleanup
for ( ; i < count; i++ ) {
v = src[indexes[i]].xyz;
if ( v[0] < min[0] ) {
min[0] = v[0];
}
if ( v[0] > max[0] ) {
max[0] = v[0];
}
if ( v[1] < min[1] ) {
min[1] = v[1];
}
if ( v[1] > max[1] ) {
max[1] = v[1];
}
if ( v[2] > max[2] ) {
max[2] = v[2];
}
if ( v[2] < min[2] ) {
min[2] = v[2];
}
}
}
#else
/*
============
idSIMD_AltiVec::MinMax
============
*/
void VPCALL idSIMD_AltiVec::MinMax( idVec3 &min, idVec3 &max, const idDrawVert *src, const int *indexes, const int count ) {
min[0] = min[1] = min[2] = idMath::INFINITY; max[0] = max[1] = max[2] = -idMath::INFINITY;
idVec3 v;
int i = 0;
register vector float vecMin, vecMax;
register vector float v0, v1, v2, v3, v4, v5, v6, v7;
register vector float vecMin1, vecMin2, vecMax1, vecMax2;
if ( count >= 4 ) {
vecMin = (vector float)(FLT_MAX);
vecMax = (vector float)(FLT_MIN);
vector unsigned char vertPerm1;
vector unsigned char vertPerm2;
vector unsigned char vertPerm3;
vector unsigned char vertPerm4;
for ( ; i+3 < count; i += 4) {
const float *vertPtr = src[indexes[i]].xyz.ToFloatPtr();
const float *vertPtr2 = src[indexes[i+1]].xyz.ToFloatPtr();
const float *vertPtr3 = src[indexes[i+2]].xyz.ToFloatPtr();
const float *vertPtr4 = src[indexes[i+3]].xyz.ToFloatPtr();
v0 = vec_ld( 0, vertPtr );
v2 = vec_ld( 0, vertPtr2 );
v4 = vec_ld( 0, vertPtr3 );
v6 = vec_ld( 0, vertPtr4 );
vecMin1 = vec_min( v0, v2 );
vecMin2 = vec_min( v4, v6 );
vecMin1 = vec_min( vecMin1, vecMin2 );
vecMin = vec_min( vecMin, vecMin1 );
vecMax1 = vec_max( v0, v2 );
vecMax2 = vec_max( v4, v6 );
vecMax1 = vec_max( vecMax1, vecMax2 );
vecMax = vec_max( vecMax, vecMax1 );
}
// now we have min/max vectors in X Y Z form, store out
v0 = vec_splat( vecMin, 0 );
v1 = vec_splat( vecMin, 1 );
v2 = vec_splat( vecMin, 2 );
v3 = vec_splat( vecMax, 0 );
v4 = vec_splat( vecMax, 1 );
v5 = vec_splat( vecMax, 2 );
vec_ste( v0, 0, &min[0] );
vec_ste( v1, 0, &min[1] );
vec_ste( v2, 0, &min[2] );
vec_ste( v3, 0, &max[0] );
vec_ste( v4, 0, &max[1] );
vec_ste( v5, 0, &max[2] );
}
// cleanup
for ( ; i < count; i++ ) {
v = src[indexes[i]].xyz;
if ( v[0] < min[0] ) {
min[0] = v[0];
}
if ( v[0] > max[0] ) {
max[0] = v[0];
}
if ( v[1] < min[1] ) {
min[1] = v[1];
}
if ( v[1] > max[1] ) {
max[1] = v[1];
}
if ( v[2] > max[2] ) {
max[2] = v[2];
}
if ( v[2] < min[2] ) {
min[2] = v[2];
}
}
}
#endif /* DRAWVERT_PADDED */
#endif /* ENABLE_MINMAX */
#ifdef ENABLE_CLAMP
/*
============
idSIMD_AltiVec::Clamp
============
*/
void VPCALL idSIMD_AltiVec::Clamp( float *dst, const float *src, const float min, const float max, const int count ) {
//#define OPER(X) dst[(X)] = src[(X)] < min ? min : src[(X)] > max ? max : src[(X)];
register vector float v0, v1, v2, v3, v4, v5;
register vector unsigned char permVec;
register vector float v0_low, v0_hi, v1_low, v1_hi;
vector unsigned char oneVector = (vector unsigned char)(1);
register vector float minVec, maxVec;
int i = 0;
//handle unaligned at start
for ( ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count ); i++ ) {
dst[i] = src[i] < min ? min : src[i] > max ? max : src[i];
}
//splat min/max into a vector
minVec = loadSplatUnalignedScalar( &min );
maxVec = loadSplatUnalignedScalar( &max );
//calculate permute and do first load
permVec = vec_add( vec_lvsl( -1, (int*) &src[i] ), oneVector );
v1_hi = vec_ld( 0, &src[i] );
//vectorize!
for ( ; i+7 < count; i += 8 ) {
//load source
v0_low = v1_hi;
v0_hi = vec_ld( 15, &src[i] );
v1_low = v0_hi;
v1_hi = vec_ld( 31, &src[i] );
v0 = vec_perm( v0_low, v0_hi, permVec );
v1 = vec_perm( v1_low, v1_hi, permVec );
//apply minimum
v2 = vec_max( v0, minVec );
v3 = vec_max( v1, minVec );
//apply maximum
v4 = vec_min( v2, maxVec );
v5 = vec_min( v3, maxVec );
ALIGNED_STORE2( &dst[i], v4, v5 );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] = src[i] < min ? min : src[i] > max ? max : src[i];
}
}
/*
============
idSIMD_AltiVec::ClampMin
============
*/
void VPCALL idSIMD_AltiVec::ClampMin( float *dst, const float *src, const float min, const int count ) {
//#define OPER(X) dst[(X)] = src[(X)] < min ? min : src[(X)];
register vector float v0, v1, v2, v3;
register vector unsigned char permVec;
register vector float v0_low, v0_hi, v1_low, v1_hi;
register vector float constVec;
vector unsigned char oneVector = (vector unsigned char)(1);
int i = 0;
//handle unaligned at start
for ( ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count ); i++ ) {
dst[i] = src[i] < min ? min : src[i];
}
//splat constant into a vector
constVec = loadSplatUnalignedScalar( &min );
//calculate permute and do first load
permVec = vec_add( vec_lvsl( -1, (int*) &src[i] ), oneVector );
v1_hi = vec_ld( 0, &src[i] );
//vectorize!
for ( ; i+7 < count; i += 8 ) {
//load source
v0_low = v1_hi;
v0_hi = vec_ld( 15, &src[i] );
v1_low = v0_hi;
v1_hi = vec_ld( 31, &src[i] );
v0 = vec_perm( v0_low, v0_hi, permVec );
v1 = vec_perm( v1_low, v1_hi, permVec );
v2 = vec_max( v0, constVec );
v3 = vec_max( v1, constVec );
ALIGNED_STORE2( &dst[i], v2, v3 );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] = src[i] < min ? min : src[i];
}
}
/*
============
idSIMD_AltiVec::ClampMax
============
*/
void VPCALL idSIMD_AltiVec::ClampMax( float *dst, const float *src, const float max, const int count ) {
//#define OPER(X) dst[(X)] = src[(X)] > max ? max : src[(X)];
register vector float v0, v1, v2, v3;
register vector unsigned char permVec;
register vector float constVec;
register vector float v0_low, v0_hi, v1_low, v1_hi;
vector unsigned char oneVector = (vector unsigned char)(1);
int i = 0;
//handle unaligned at start
for ( ; NOT_16BYTE_ALIGNED( dst[i] ) && ( i < count ); i++ ) {
dst[i] = src[i] < max ? max : src[i];
}
//splat constant into a vector
constVec = loadSplatUnalignedScalar( &max );
//calculate permute and do first load
permVec = vec_add( vec_lvsl( -1, (int*) &src[i] ), oneVector );
v1_hi = vec_ld( 0, &src[i] );
//vectorize!
for ( ; i+7 < count; i += 8 ) {
//load source
v0_low = v1_hi;
v0_hi = vec_ld( 15, &src[i] );
v1_low = v0_hi;
v1_hi = vec_ld( 31, &src[i] );
v0 = vec_perm( v0_low, v0_hi, permVec );
v1 = vec_perm( v1_low, v1_hi, permVec );
v2 = vec_min( v0, constVec );
v3 = vec_min( v1, constVec );
ALIGNED_STORE2( &dst[i], v2, v3 );
}
//handle cleanup
for ( ; i < count ; i++ ) {
dst[i] = src[i] < max ? max : src[i];
}
}
#endif /* ENABLE_CLAMP */
#ifdef ENABLE_16ROUTINES
/*
============
idSIMD_AltiVec::Zero16
============
*/
void VPCALL idSIMD_AltiVec::Zero16( float *dst, const int count ) {
memset( dst, 0, count * sizeof( float ) );
}
/*
============
idSIMD_AltiVec::Negate16
Assumptions:
dst is aligned
============
*/
void VPCALL idSIMD_AltiVec::Negate16( float *dst, const int count ) {
//#define OPER(X) ptr[(X)] ^= ( 1 << 31 ) // IEEE 32 bits float sign bit
// dst is aligned
assert( IS_16BYTE_ALIGNED( dst[0] ) );
// round count up to next 4 if needbe
int count2 = ( count + 3 ) & ~3;
int i = 0;
vector float v0, v1, v2, v3;
//know its 16-byte aligned
for ( ; i + 7 < count2; i += 8 ) {
v0 = vec_ld( 0, &dst[i] );
v1 = vec_ld( 16, &dst[i] );
v2 = vec_sub( (vector float)(0), v0 );
v3 = vec_sub( (vector float)(0), v1 );
ALIGNED_STORE2( &dst[i], v2, v3 );
}
for ( ; i < count2; i += 4 ) {
v0 = vec_ld( 0, &dst[i] );
v1 = vec_sub( (vector float)(0), v0 );
vec_st( v1, 0, &dst[i] );
}
}
/*
============
idSIMD_AltiVec::Copy16
============
*/
void VPCALL idSIMD_AltiVec::Copy16( float *dst, const float *src, const int count ) {
//#define OPER(X) dst[(X)] = src[(X)]
memcpy( dst, src, sizeof(float) * count );
}
/*
============
idSIMD_AltiVec::Add16
Assumptions:
Assumes dst, src1, src2 all start at aligned address
============
*/
void VPCALL idSIMD_AltiVec::Add16( float *dst, const float *src1, const float *src2, const int count ) {
//#define OPER(X) dst[(X)] = src1[(X)] + src2[(X)]
// dst is aligned
assert( IS_16BYTE_ALIGNED( dst[0] ) );
// src1 is aligned
assert( IS_16BYTE_ALIGNED( src1[0] ) );
// src2 is aligned
assert( IS_16BYTE_ALIGNED( src2[0] ) );
// round count up to next 4 if needbe
int count2 = ( count + 3 ) & ~3;
register vector float v0, v1, v2, v3, v4, v5;
int i = 0;
//know all data is 16-byte aligned, so vectorize!
for ( ; i+7 < count2; i += 8 ) {
//load sources
v0 = vec_ld( 0, &src1[i] );
v1 = vec_ld( 16, &src1[i] );
v2 = vec_ld( 0, &src2[i] );
v3 = vec_ld( 16, &src2[i] );
v4 = vec_add( v0, v2 );
v5 = vec_add( v1, v3 );
ALIGNED_STORE2( &dst[i], v4, v5 );
}
for ( ; i < count2; i += 4 ) {
v0 = vec_ld( 0, &src1[i] );
v1 = vec_ld( 0, &src2[i] );
v2 = vec_add( v0, v1 );
vec_st( v2, 0, &dst[i] );
}
}
/*
============
idSIMD_AltiVec::Sub16
Assumptions:
Assumes that dst, src1, and src2 all start at aligned address
============
*/
void VPCALL idSIMD_AltiVec::Sub16( float *dst, const float *src1, const float *src2, const int count ) {
//#define OPER(X) dst[(X)] = src1[(X)] - src2[(X)]
// dst is aligned
assert( IS_16BYTE_ALIGNED( dst[0] ) );
// src1 is aligned
assert( IS_16BYTE_ALIGNED( src1[0] ) );
// src2 is aligned
assert( IS_16BYTE_ALIGNED( src2[0] ) );
// round count up to next 4 if needbe
int count2 = ( count + 3 ) & ~3;
register vector float v0, v1, v2, v3, v4, v5;
int i = 0;
//know data is aligned, so vectorize!
for ( ; i+7 < count2; i += 8 ) {
//load sources
v0 = vec_ld( 0, &src1[i] );
v1 = vec_ld( 16, &src1[i] );
v2 = vec_ld( 0, &src2[i] );
v3 = vec_ld( 16, &src2[i] );
v4 = vec_sub( v0, v2 );
v5 = vec_sub( v1, v3 );
ALIGNED_STORE2( &dst[i], v4, v5 );
}
for ( ; i < count2; i += 4 ) {
v0 = vec_ld( 0, &src1[i] );
v1 = vec_ld( 0, &src2[i] );
v2 = vec_sub( v0, v1 );
vec_st( v2, 0, &dst[i] );
}
}
/*
============
idSIMD_AltiVec::Mul16
Assumptions:
Assumes that dst and src1 start at aligned address
============
*/
void VPCALL idSIMD_AltiVec::Mul16( float *dst, const float *src1, const float constant, const int count ) {
//#define OPER(X) dst[(X)] = src1[(X)] * constant
// dst is aligned
assert( IS_16BYTE_ALIGNED( dst[0] ) );
// src1 is aligned
assert( IS_16BYTE_ALIGNED( src1[0] ) );
// round count up to next 4 if needbe
int count2 = ( count + 3 ) & ~3;
register vector float v0, v1, v2, v3;
register vector float constVec;
register vector float zeroVector = (vector float)(0.0);
int i = 0;
//splat constant into a vector
constVec = loadSplatUnalignedScalar( &constant );
//know data is aligned, so vectorize!
for ( ; i+7 < count2; i += 8 ) {
//load source
v0 = vec_ld( 0, &src1[i] );
v1 = vec_ld( 16, &src1[i] );
v2 = vec_madd( constVec, v0, zeroVector );
v3 = vec_madd( constVec, v1, zeroVector );
ALIGNED_STORE2( &dst[i], v2, v3 );
}
for ( ; i < count2; i += 4 ) {
v0 = vec_ld( 0, &src1[i] );
v1 = vec_madd( constVec, v0, zeroVector );
vec_st( v1, 0, &dst[i] );
}
}
/*
============
idSIMD_AltiVec::AddAssign16
Assumptions:
Assumes that dst and src start at aligned address
============
*/
void VPCALL idSIMD_AltiVec::AddAssign16( float *dst, const float *src, const int count ) {
//#define OPER(X) dst[(X)] += src[(X)]
// dst is aligned
assert( IS_16BYTE_ALIGNED( dst[0] ) );
// src is aligned
assert( IS_16BYTE_ALIGNED( src[0] ) );
// round count up to next 4 if needbe
int count2 = ( count + 3 ) & ~3;
register vector float v0, v1, v2, v3, v4, v5;
int i = 0;
//vectorize!
for ( ; i+7 < count2; i += 8 ) {
v0 = vec_ld( 0, &src[i] );
v1 = vec_ld( 16, &src[i] );
v2 = vec_ld( 0, &dst[i] );
v3 = vec_ld( 16, &dst[i] );
v4 = vec_add( v0, v2 );
v5 = vec_add( v1, v3 );
ALIGNED_STORE2( &dst[i], v4, v5 );
}
for ( ; i < count2; i += 4 ) {
v0 = vec_ld( 0, &src[i] );
v1 = vec_ld( 0, &dst[i] );
v2 = vec_add( v0, v1 );
vec_st( v2, 0, &dst[i] );
}
}
/*
============
idSIMD_AltiVec::SubAssign16
Assumptions:
Assumes that dst and src start at aligned address
============
*/
void VPCALL idSIMD_AltiVec::SubAssign16( float *dst, const float *src, const int count ) {
//#define OPER(X) dst[(X)] -= src[(X)]
register vector float v0, v1, v2, v3, v4, v5;
int i=0;
// dst is aligned
assert( IS_16BYTE_ALIGNED( dst[0] ) );
// src is aligned
assert( IS_16BYTE_ALIGNED( src[0] ) );
// round count up to next 4 if needbe
int count2 = ( count + 3 ) & ~3;
//vectorize!
for ( ; i+7 < count2; i += 8 ) {
v0 = vec_ld( 0, &src[i] );
v1 = vec_ld( 16, &src[i] );
v2 = vec_ld( 0, &dst[i] );
v3 = vec_ld( 16, &dst[i] );
v4 = vec_sub( v2, v0 );
v5 = vec_sub( v3, v1 );
ALIGNED_STORE2( &dst[i], v4, v5 );
}
for ( ; i < count2; i += 4 ) {
v0 = vec_ld( 0, &src[i] );
v1 = vec_ld( 0, &dst[i] );
v2 = vec_sub( v1, v0 );
vec_st( v2, 0, &dst[i] );
}
}
/*
============
idSIMD_AltiVec::MulAssign16
Assumptions:
Assumes that dst starts at aligned address and count is multiple of 4
============
*/
void VPCALL idSIMD_AltiVec::MulAssign16( float *dst, const float constant, const int count ) {
//#define OPER(X) dst[(X)] *= constant
// dst is aligned
assert( IS_16BYTE_ALIGNED( dst[0] ) );
// round count up to next 4 if needbe
int count2 = ( count + 3 ) & ~3;
register vector float v0, v1, v2, v3;
register vector float constVec;
int i = 0;
register vector float zeroVector = (vector float)(0.0);
//splat constant into a vector
constVec = loadSplatUnalignedScalar( &constant );
//vectorize!
for ( ; i+7 < count2; i += 8 ) {
v0 = vec_ld( 0, &dst[i] );
v1 = vec_ld( 16, &dst[i] );
v2 = vec_madd( v0, constVec, zeroVector );
v3 = vec_madd( v1, constVec, zeroVector );
ALIGNED_STORE2( &dst[i], v2, v3 );
}
for ( ; i < count2; i += 4 ) {
v0 = vec_ld( 0, &dst[i] );
v1 = vec_madd( v0, constVec, zeroVector );
vec_st( v1, 0, &dst[i] );
}
}
#endif /* ENABLE_16ROUTINES */
#ifdef ENABLE_LOWER_TRIANGULAR
/*
============
idSIMD_AltiVec::MatX_LowerTriangularSolve
solves x in L * x = b for the first n rows of L
if skip > 0 the first skip elements of x are assumed to be valid already
L has to be a lower triangular matrix with (implicit) ones on the diagonal
x == b is allowed
============
*/
void VPCALL idSIMD_AltiVec::MatX_LowerTriangularSolve( const idMatX &L, float *x, const float *b, const int n, int skip ) {
int i, j;
const float *lptr;
const float *lptr2;
const float *lptr3;
const float *lptr4;
float sum;
float sum2;
float sum3;
float sum4;
float tempSum;
float tempSum2;
float tempSum3;
float tempSum4;
vector float vecSum1 = (vector float)(0.0);
vector float vecSum2 = (vector float)(0.0);
vector float v0, v1, v2, v3, v4, v5, v6, v7, v8, v9;
vector float zeroVector = (vector float)(0.0);
vector float vecSum3, vecSum4, vecSum5, vecSum6, vecSum7, vecSum8;
vector unsigned char vecPermX = vec_add( vec_lvsl( -1, &x[0] ), (vector unsigned char)(1) );
// unrolled this loop a bit
for ( i = skip; i+3 < n; i+=4 ) {
sum = b[i];
sum2 = b[i+1];
sum3 = b[i+2];
sum4 = b[i+3];
vecSum1 = zeroVector;
vecSum2 = zeroVector;
vecSum3 = vecSum4 = vecSum5 = vecSum6 = vecSum7 = vecSum8 = zeroVector;
lptr = L[i];
lptr2 = L[i+1];
lptr3 = L[i+2];
lptr4 = L[i+3];
vector unsigned char vecPermLptr1 = vec_add( vec_lvsl( -1, lptr ), (vector unsigned char)(1) );
vector unsigned char vecPermLptr2 = vec_add( vec_lvsl( -1, lptr2 ), (vector unsigned char)(1) );
vector unsigned char vecPermLptr3 = vec_add( vec_lvsl( -1, lptr3 ), (vector unsigned char)(1) );
vector unsigned char vecPermLptr4 = vec_add( vec_lvsl( -1, lptr4 ), (vector unsigned char)(1) );
for ( j = 0 ; j+7 < i; j+=8 ) {
v0 = vec_ld( 0, &x[j] );
v1 = vec_ld( 15, &x[j] );
vector float vecExtraX = vec_ld( 31, &x[j] );
v0 = vec_perm( v0, v1, vecPermX );
v1 = vec_perm( v1, vecExtraX, vecPermX );
v2 = vec_ld( 0, lptr + j );
v3 = vec_ld( 15, lptr + j );
vector float vecExtra1 = vec_ld( 31, lptr + j );
v2 = vec_perm( v2, v3, vecPermLptr1 );
v3 = vec_perm( v3, vecExtra1, vecPermLptr1 );
v4 = vec_ld( 0, lptr2 + j );
v5 = vec_ld( 15, lptr2 + j );
vector float vecExtra2 = vec_ld( 31, lptr2 + j );
v4 = vec_perm( v4, v5, vecPermLptr2 );
v5 = vec_perm( v5, vecExtra2, vecPermLptr2 );
v6 = vec_ld( 0, lptr3 + j );
v7 = vec_ld( 15, lptr3 + j );
vector float vecExtra3 = vec_ld( 31, lptr3 + j );
v6 = vec_perm( v6, v7, vecPermLptr3 );
v7 = vec_perm( v7, vecExtra3, vecPermLptr3 );
v8 = vec_ld( 0, lptr4 + j );
v9 = vec_ld( 15, lptr4 + j );
vector float vecExtra4 = vec_ld( 31, lptr4 + j );
v8 = vec_perm( v8, v9, vecPermLptr4 );
v9 = vec_perm( v9, vecExtra4, vecPermLptr4 );
vecSum1 = vec_madd( v2, v0, vecSum1 );
vecSum2 = vec_madd( v3, v1, vecSum2 );
vecSum3 = vec_madd( v4, v0, vecSum3 );
vecSum4 = vec_madd( v5, v1, vecSum4 );
vecSum5 = vec_madd( v6, v0, vecSum5 );
vecSum6 = vec_madd( v7, v1, vecSum6 );
vecSum7 = vec_madd( v8, v0, vecSum7 );
vecSum8 = vec_madd( v9, v1, vecSum8 );
}
// if we ran the unrolled code, we need to sum accross the vectors
// to find out how much to subtract from sum
if ( j > 0 ) {
vecSum1 = vec_add( vecSum1, vecSum2 );
vecSum3 = vec_add( vecSum3, vecSum4 );
vecSum5 = vec_add( vecSum5, vecSum6 );
vecSum7 = vec_add( vecSum7, vecSum8 );
//sum accross the vectors
vecSum1 = vec_add( vecSum1, vec_sld( vecSum1, vecSum1, 8 ) );
vecSum1 = vec_add( vecSum1, vec_sld( vecSum1, vecSum1, 4 ) );
vecSum3 = vec_add( vecSum3, vec_sld( vecSum3, vecSum3, 8 ) );
vecSum3 = vec_add( vecSum3, vec_sld( vecSum3, vecSum3, 4 ) );
vecSum5 = vec_add( vecSum5, vec_sld( vecSum5, vecSum5, 8 ) );
vecSum5 = vec_add( vecSum5, vec_sld( vecSum5, vecSum5, 4 ) );
vecSum7 = vec_add( vecSum7, vec_sld( vecSum7, vecSum7, 8 ) );
vecSum7 = vec_add( vecSum7, vec_sld( vecSum7, vecSum7, 4 ) );
//move the result to the FPU
vec_ste( vec_splat( vecSum1, 0 ), 0, &tempSum );
vec_ste( vec_splat( vecSum3, 0 ), 0, &tempSum2 );
vec_ste( vec_splat( vecSum5, 0 ), 0, &tempSum3 );
vec_ste( vec_splat( vecSum7, 0 ), 0, &tempSum4 );
sum -= tempSum;
sum2 -= tempSum2;
sum3 -= tempSum3;
sum4 -= tempSum4;
}
//cleanup
for ( ; j < i; j++ ) {
sum -= lptr[j] * x[j];
sum2 -= lptr2[j] * x[j];
sum3 -= lptr3[j] * x[j];
sum4 -= lptr4[j] * x[j];
}
// store the 4 results at a time
sum2 -= ( lptr2[i] * sum );
sum3 = sum3 - ( lptr3[i+1] * sum2 ) - ( lptr3[i] * sum );
sum4 = sum4 - ( lptr4[i+2] * sum3 ) - ( lptr4[i+1] * sum2 ) - ( lptr4[i] * sum );
x[i] = sum;
x[i+1] = sum2;
x[i+2] = sum3;
x[i+3] = sum4;
}
// cleanup
for ( ; i < n; i++ ) {
sum = b[i];
vecSum1 = zeroVector;
vecSum2 = zeroVector;
lptr = L[i];
vector unsigned char vecPermLptr = vec_add( vec_lvsl( -1, lptr ), (vector unsigned char)(1) );
for ( j = 0 ; j+7 < i; j+=8 ) {
v0 = vec_ld( 0, &x[j] );
v2 = vec_ld( 15, &x[j] );
vector float vecExtraX = vec_ld( 31, &x[j] );
v0 = vec_perm( v0, v2, vecPermX );
v2 = vec_perm( v2, vecExtraX, vecPermX );
v1 = vec_ld( 0, lptr + j );
v3 = vec_ld( 15, lptr + j );
vector float vecExtra = vec_ld( 31, lptr + j );
v1 = vec_perm( v1, v3, vecPermLptr );
v3 = vec_perm( v3, vecExtra, vecPermLptr );
vecSum1 = vec_madd( v1, v0, vecSum1 );
vecSum2 = vec_madd( v3, v2, vecSum2 );
}
// if we ran the unrolled code, we need to sum accross the vectors
// to find out how much to subtract from sum
if ( j > 0 ) {
//sum accross the vectors
vecSum1 = vec_add( vecSum1, vecSum2 );
vecSum1 = vec_add( vecSum1, vec_sld( vecSum1, vecSum1, 8 ) );
vecSum1 = vec_add( vecSum1, vec_sld( vecSum1, vecSum1, 4 ) );
//move the result to the FPU
vec_ste( vec_splat( vecSum1, 0 ), 0, &tempSum );
sum -= tempSum;
}
//cleanup
for ( ; j < i; j++ ) {
sum -= lptr[j] * x[j];
}
x[i] = sum;
}
}
/*
============
idSIMD_AltiVec::MatX_LowerTriangularSolveTranspose
solves x in L.Transpose() * x = b for the first n rows of L
L has to be a lower triangular matrix with (implicit) ones on the diagonal
x == b is allowed
============
*/
void VPCALL idSIMD_AltiVec::MatX_LowerTriangularSolveTranspose( const idMatX &L, float *x, const float *b, const int n ) {
int nc;
const float *lptr;
lptr = L.ToFloatPtr();
nc = L.GetNumColumns();
float x0, x1, x2, x3, x4, x5, x6;
// unrolled cases for n < 8
if ( n < 8 ) {
switch( n ) {
// using local variables to avoid aliasing issues
case 0:
return;
case 1:
x[0] = b[0];
return;
case 2:
x1 = b[1];
x0 = b[0] - lptr[1*nc+0] * x1;
x[1] = x1;
x[0] = x0;
return;
case 3:
x2 = b[2];
x1 = b[1] - lptr[2*nc+1] * x2;
x0 = b[0] - lptr[2*nc+0] * x2 - lptr[1*nc+0] * x1;
x[2] = x2;
x[1] = x1;
x[0] = x0;
return;
case 4:
x3 = b[3];
x2 = b[2] - lptr[3*nc+2] * x3;
x1 = b[1] - lptr[3*nc+1] * x3 - lptr[2*nc+1] * x2;
x0 = b[0] - lptr[3*nc+0] * x3 - lptr[2*nc+0] * x2 - lptr[1*nc+0] * x1;
x[3] = x3;
x[2] = x2;
x[1] = x1;
x[0] = x0;
return;
case 5:
x4 = b[4];
x3 = b[3] - lptr[4*nc+3] * x4;
x2 = b[2] - lptr[4*nc+2] * x4 - lptr[3*nc+2] * x3;
x1 = b[1] - lptr[4*nc+1] * x4 - lptr[3*nc+1] * x3 - lptr[2*nc+1] * x2;
x0 = b[0] - lptr[4*nc+0] * x4 - lptr[3*nc+0] * x3 - lptr[2*nc+0] * x2 - lptr[1*nc+0] * x1;
x[4] = x4;
x[3] = x3;
x[2] = x2;
x[1] = x1;
x[0] = x0;
return;
case 6:
x5 = b[5];
x4 = b[4] - lptr[5*nc+4] * x5;
x3 = b[3] - lptr[5*nc+3] * x5 - lptr[4*nc+3] * x4;
x2 = b[2] - lptr[5*nc+2] * x5 - lptr[4*nc+2] * x4 - lptr[3*nc+2] * x3;
x1 = b[1] - lptr[5*nc+1] * x5 - lptr[4*nc+1] * x4 - lptr[3*nc+1] * x3 - lptr[2*nc+1] * x2;
x0 = b[0] - lptr[5*nc+0] * x5 - lptr[4*nc+0] * x4 - lptr[3*nc+0] * x3 - lptr[2*nc+0] * x2 - lptr[1*nc+0] * x1;
x[5] = x5;
x[4] = x4;
x[3] = x3;
x[2] = x2;
x[1] = x1;
x[0] = x0;
return;
case 7:
x6 = b[6];
x5 = b[5] - lptr[6*nc+5] * x6;
x4 = b[4] - lptr[6*nc+4] * x6 - lptr[5*nc+4] * x5;
x3 = b[3] - lptr[6*nc+3] * x6 - lptr[5*nc+3] * x5 - lptr[4*nc+3] * x4;
x2 = b[2] - lptr[6*nc+2] * x6 - lptr[5*nc+2] * x5 - lptr[4*nc+2] * x4 - lptr[3*nc+2] * x3;
x1 = b[1] - lptr[6*nc+1] * x6 - lptr[5*nc+1] * x5 - lptr[4*nc+1] * x4 - lptr[3*nc+1] * x3 - lptr[2*nc+1] * x2;
x0 = b[0] - lptr[6*nc+0] * x6 - lptr[5*nc+0] * x5 - lptr[4*nc+0] * x4 - lptr[3*nc+0] * x3 - lptr[2*nc+0] * x2 - lptr[1*nc+0] * x1;
x[6] = x6;
x[5] = x5;
x[4] = x4;
x[3] = x3;
x[2] = x2;
x[1] = x1;
x[0] = x0;
return;
}
return;
}
int i, j;
register float s0, s1, s2, s3;
float *xptr;
lptr = L.ToFloatPtr() + n * nc + n - 4;
xptr = x + n;
// process 4 rows at a time
for ( i = n; i >= 4; i -= 4 ) {
s0 = b[i-4];
s1 = b[i-3];
s2 = b[i-2];
s3 = b[i-1];
// process 4x4 blocks
for ( j = 0; j < n-i; j += 4 ) {
s0 -= lptr[(j+0)*nc+0] * xptr[j+0];
s1 -= lptr[(j+0)*nc+1] * xptr[j+0];
s2 -= lptr[(j+0)*nc+2] * xptr[j+0];
s3 -= lptr[(j+0)*nc+3] * xptr[j+0];
s0 -= lptr[(j+1)*nc+0] * xptr[j+1];
s1 -= lptr[(j+1)*nc+1] * xptr[j+1];
s2 -= lptr[(j+1)*nc+2] * xptr[j+1];
s3 -= lptr[(j+1)*nc+3] * xptr[j+1];
s0 -= lptr[(j+2)*nc+0] * xptr[j+2];
s1 -= lptr[(j+2)*nc+1] * xptr[j+2];
s2 -= lptr[(j+2)*nc+2] * xptr[j+2];
s3 -= lptr[(j+2)*nc+3] * xptr[j+2];
s0 -= lptr[(j+3)*nc+0] * xptr[j+3];
s1 -= lptr[(j+3)*nc+1] * xptr[j+3];
s2 -= lptr[(j+3)*nc+2] * xptr[j+3];
s3 -= lptr[(j+3)*nc+3] * xptr[j+3];
}
// process left over of the 4 rows
s0 -= lptr[0-1*nc] * s3;
s1 -= lptr[1-1*nc] * s3;
s2 -= lptr[2-1*nc] * s3;
s0 -= lptr[0-2*nc] * s2;
s1 -= lptr[1-2*nc] * s2;
s0 -= lptr[0-3*nc] * s1;
// store result
xptr[-4] = s0;
xptr[-3] = s1;
xptr[-2] = s2;
xptr[-1] = s3;
// update pointers for next four rows
lptr -= 4 + 4 * nc;
xptr -= 4;
}
// process left over rows
for ( i--; i >= 0; i-- ) {
s0 = b[i];
lptr = L[0] + i;
for ( j = i + 1; j < n; j++ ) {
s0 -= lptr[j*nc] * x[j];
}
x[i] = s0;
}
}
/*
============
idSIMD_AltiVec::MatX_LDLTFactor
============
*/
bool VPCALL idSIMD_AltiVec::MatX_LDLTFactor( idMatX &mat, idVecX &invDiag, const int n ) {
int i, j, k, nc;
float *v, *diag, *mptr;
float s0, s1, s2, s3, sum, d;
float s0_2, s1_2, s2_2, s3_2, sum_2;
float *mptr2;
v = (float *) _alloca16( n * sizeof( float ) );
diag = (float *) _alloca16( n * sizeof( float ) );
nc = mat.GetNumColumns();
if ( n <= 0 ) {
return true;
}
mptr = mat[0];
sum = mptr[0];
if ( sum == 0.0f ) {
return false;
}
diag[0] = sum;
invDiag[0] = d = 1.0f / sum;
if ( n <= 1 ) {
return true;
}
mptr = mat[0];
for ( j = 1; j < n; j++ ) {
mptr[j*nc+0] = ( mptr[j*nc+0] ) * d;
}
mptr = mat[1];
v[0] = diag[0] * mptr[0]; s0 = v[0] * mptr[0];
sum = mptr[1] - s0;
if ( sum == 0.0f ) {
return false;
}
mat[1][1] = sum;
diag[1] = sum;
invDiag[1] = d = 1.0f / sum;
if ( n <= 2 ) {
return true;
}
mptr = mat[0];
for ( j = 2; j < n; j++ ) {
mptr[j*nc+1] = ( mptr[j*nc+1] - v[0] * mptr[j*nc+0] ) * d;
}
mptr = mat[2];
v[0] = diag[0] * mptr[0]; s0 = v[0] * mptr[0];
v[1] = diag[1] * mptr[1]; s1 = v[1] * mptr[1];
sum = mptr[2] - s0 - s1;
if ( sum == 0.0f ) {
return false;
}
mat[2][2] = sum;
diag[2] = sum;
invDiag[2] = d = 1.0f / sum;
if ( n <= 3 ) {
return true;
}
mptr = mat[0];
for ( j = 3; j < n; j++ ) {
mptr[j*nc+2] = ( mptr[j*nc+2] - v[0] * mptr[j*nc+0] - v[1] * mptr[j*nc+1] ) * d;
}
mptr = mat[3];
v[0] = diag[0] * mptr[0]; s0 = v[0] * mptr[0];
v[1] = diag[1] * mptr[1]; s1 = v[1] * mptr[1];
v[2] = diag[2] * mptr[2]; s2 = v[2] * mptr[2];
sum = mptr[3] - s0 - s1 - s2;
if ( sum == 0.0f ) {
return false;
}
mat[3][3] = sum;
diag[3] = sum;
invDiag[3] = d = 1.0f / sum;
if ( n <= 4 ) {
return true;
}
mptr = mat[0];
for ( j = 4; j < n; j++ ) {
mptr[j*nc+3] = ( mptr[j*nc+3] - v[0] * mptr[j*nc+0] - v[1] * mptr[j*nc+1] - v[2] * mptr[j*nc+2] ) * d;
}
for ( i = 4; i < n; i++ ) {
mptr = mat[i];
v[0] = diag[0] * mptr[0]; s0 = v[0] * mptr[0];
v[1] = diag[1] * mptr[1]; s1 = v[1] * mptr[1];
v[2] = diag[2] * mptr[2]; s2 = v[2] * mptr[2];
v[3] = diag[3] * mptr[3]; s3 = v[3] * mptr[3];
for ( k = 4; k < i-3; k += 4 ) {
v[k+0] = diag[k+0] * mptr[k+0]; s0 += v[k+0] * mptr[k+0];
v[k+1] = diag[k+1] * mptr[k+1]; s1 += v[k+1] * mptr[k+1];
v[k+2] = diag[k+2] * mptr[k+2]; s2 += v[k+2] * mptr[k+2];
v[k+3] = diag[k+3] * mptr[k+3]; s3 += v[k+3] * mptr[k+3];
}
switch( i - k ) {
case 3: v[k+2] = diag[k+2] * mptr[k+2]; s0 += v[k+2] * mptr[k+2];
case 2: v[k+1] = diag[k+1] * mptr[k+1]; s1 += v[k+1] * mptr[k+1];
case 1: v[k+0] = diag[k+0] * mptr[k+0]; s2 += v[k+0] * mptr[k+0];
}
sum = s3;
sum += s2;
sum += s1;
sum += s0;
sum = mptr[i] - sum;
if ( sum == 0.0f ) {
return false;
}
mat[i][i] = sum;
diag[i] = sum;
invDiag[i] = d = 1.0f / sum;
if ( i + 1 >= n ) {
return true;
}
// unrolling madness!
mptr = mat[i+1];
mptr2 = mat[i+1] + nc;
for ( j = i+1; j+1 < n; j+=2 ) {
s0 = mptr[0] * v[0];
s1 = mptr[1] * v[1];
s2 = mptr[2] * v[2];
s3 = mptr[3] * v[3];
s0_2 = mptr2[0] * v[0];
s1_2 = mptr2[1] * v[1];
s2_2 = mptr2[2] * v[2];
s3_2 = mptr2[3] * v[3];
for ( k = 4; k < i-7; k += 8 ) {
s0 += mptr[k+0] * v[k+0];
s1 += mptr[k+1] * v[k+1];
s2 += mptr[k+2] * v[k+2];
s3 += mptr[k+3] * v[k+3];
s0 += mptr[k+4] * v[k+4];
s1 += mptr[k+5] * v[k+5];
s2 += mptr[k+6] * v[k+6];
s3 += mptr[k+7] * v[k+7];
s0_2 += mptr2[k+0] * v[k+0];
s1_2 += mptr2[k+1] * v[k+1];
s2_2 += mptr2[k+2] * v[k+2];
s3_2 += mptr2[k+3] * v[k+3];
s0_2 += mptr2[k+4] * v[k+4];
s1_2 += mptr2[k+5] * v[k+5];
s2_2 += mptr2[k+6] * v[k+6];
s3_2 += mptr2[k+7] * v[k+7];
}
switch( i - k ) {
case 7: s0 += mptr[k+6] * v[k+6]; s0_2 += mptr2[k+6] * v[k+6];
case 6: s1 += mptr[k+5] * v[k+5]; s1_2 += mptr2[k+5] * v[k+5];
case 5: s2 += mptr[k+4] * v[k+4]; s2_2 += mptr2[k+4] * v[k+4];
case 4: s3 += mptr[k+3] * v[k+3]; s3_2 += mptr2[k+3] * v[k+3];
case 3: s0 += mptr[k+2] * v[k+2]; s0_2 += mptr2[k+2] * v[k+2];
case 2: s1 += mptr[k+1] * v[k+1]; s1_2 += mptr2[k+1] * v[k+1];
case 1: s2 += mptr[k+0] * v[k+0]; s2_2 += mptr2[k+0] * v[k+0];
}
// disassociate these adds
s3 += s2;
s1 += s0;
sum = s1 + s3;
s3_2 += s2_2;
s1_2 += s0_2;
sum_2 = s1_2 + s3_2;
mptr[i] = ( mptr[i] - sum ) * d;
mptr2[i] = ( mptr2[i] - sum_2 ) * d;
mptr += nc*2;
mptr2 += nc*2;
}
// cleanup
for ( ; j < n; j++ ) {
s0 = mptr[0] * v[0];
s1 = mptr[1] * v[1];
s2 = mptr[2] * v[2];
s3 = mptr[3] * v[3];
for ( k = 4; k < i-7; k += 8 ) {
s0 += mptr[k+0] * v[k+0];
s1 += mptr[k+1] * v[k+1];
s2 += mptr[k+2] * v[k+2];
s3 += mptr[k+3] * v[k+3];
s0 += mptr[k+4] * v[k+4];
s1 += mptr[k+5] * v[k+5];
s2 += mptr[k+6] * v[k+6];
s3 += mptr[k+7] * v[k+7];
}
switch( i - k ) {
case 7: s0 += mptr[k+6] * v[k+6];
case 6: s1 += mptr[k+5] * v[k+5];
case 5: s2 += mptr[k+4] * v[k+4];
case 4: s3 += mptr[k+3] * v[k+3];
case 3: s0 += mptr[k+2] * v[k+2];
case 2: s1 += mptr[k+1] * v[k+1];
case 1: s2 += mptr[k+0] * v[k+0];
}
// disassociate these adds
s3 += s2;
s1 += s0;
sum = s1 + s3;
mptr[i] = ( mptr[i] - sum ) * d;
mptr += nc;
}
}
return true;
}
#endif /* ENABLE_LOWER_TRIANGULAR */
#ifdef LIVE_VICARIOUSLY
/*
============
idSIMD_AltiVec::BlendJoints
============
*/
void VPCALL idSIMD_AltiVec::BlendJoints( idJointQuat *joints, const idJointQuat *blendJoints, const float lerp, const int *index, const int numJoints ) {
int i;
// since lerp is a constant, we can special case the two cases if they're true
if ( lerp <= 0.0f ) {
// this sets joints back to joints. No sense in doing no work, so just return
return;
}
if ( lerp >= 1.0f ) {
// this copies each q from blendJoints to joints and copies each t from blendJoints to joints
memcpy( joints[0].q.ToFloatPtr(), blendJoints[0].q.ToFloatPtr(), sizeof(idJointQuat) * numJoints );
return;
}
vector float vecLerp = loadSplatUnalignedScalar( &lerp );
vector float zeroVector = (vector float)(0);
for ( i = 0; i+3 < numJoints; i+=4 ) {
int j = index[i];
int j2 = index[i+1];
int j3 = index[i+2];
int j4 = index[i+3];
// slerp
const float *jointPtr = joints[j].q.ToFloatPtr();
const float *blendPtr = blendJoints[j].q.ToFloatPtr();
const float *jointPtr2 = joints[j2].q.ToFloatPtr();
const float *blendPtr2 = blendJoints[j2].q.ToFloatPtr();
const float *jointPtr3 = joints[j3].q.ToFloatPtr();
const float *blendPtr3 = blendJoints[j3].q.ToFloatPtr();
const float *jointPtr4 = joints[j4].q.ToFloatPtr();
const float *blendPtr4 = blendJoints[j4].q.ToFloatPtr();
vector unsigned char permVec = vec_add( vec_lvsl( -1, jointPtr ), (vector unsigned char)(1) );
vector unsigned char permVec2 = vec_add( vec_lvsl( -1, jointPtr2 ), (vector unsigned char)(1) );
vector unsigned char permVec3 = vec_add( vec_lvsl( -1, jointPtr3 ), (vector unsigned char)(1) );
vector unsigned char permVec4 = vec_add( vec_lvsl( -1, jointPtr4 ), (vector unsigned char)(1) );
vector unsigned char permVec5 = vec_add( vec_lvsl( -1, blendPtr ), (vector unsigned char)(1) );
vector unsigned char permVec6 = vec_add( vec_lvsl( -1, blendPtr2 ), (vector unsigned char)(1) );
vector unsigned char permVec7 = vec_add( vec_lvsl( -1, blendPtr3 ), (vector unsigned char)(1) );
vector unsigned char permVec8 = vec_add( vec_lvsl( -1, blendPtr4 ), (vector unsigned char)(1) );
vector float v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11;
vector float v12, v13, v14, v15, v16;
vector float vecFromX, vecFromY, vecFromZ, vecFromW;
vector float vecToX, vecToY, vecToZ, vecToW;
// load up the the idJointQuats from joints
v0 = vec_ld( 0, jointPtr );
v1 = vec_ld( 15, jointPtr );
v2 = vec_perm( v0, v1, permVec );
v3 = vec_ld( 0, jointPtr2 );
v4 = vec_ld( 15, jointPtr2 );
v5 = vec_perm( v3, v4, permVec2 );
v6 = vec_ld( 0, jointPtr3 );
v7 = vec_ld( 15, jointPtr3 );
v8 = vec_perm( v6, v7, permVec3 );
v9 = vec_ld( 0, jointPtr4 );
v10 = vec_ld( 15, jointPtr4 );
v11 = vec_perm( v9, v10, permVec4 );
// planarizing, so put each x y z w into its own vector
v0 = vec_mergeh( v2, v8 );
v1 = vec_mergeh( v5, v11 );
v3 = vec_mergel( v2, v8 );
v4 = vec_mergel( v5, v11 );
vecFromX = vec_mergeh( v0, v1 );
vecFromY = vec_mergel( v0, v1 );
vecFromZ = vec_mergeh( v3, v4 );
vecFromW = vec_mergel( v3, v4 );
// load up idJointQuats from blendJoints
v5 = vec_ld( 0, blendPtr );
v6 = vec_ld( 15, blendPtr );
v7 = vec_perm( v5, v6, permVec5 );
v8 = vec_ld( 0, blendPtr2 );
v9 = vec_ld( 15, blendPtr2 );
v10 = vec_perm( v8, v9, permVec6 );
v11 = vec_ld( 0, blendPtr3 );
v12 = vec_ld( 15, blendPtr3 );
v13 = vec_perm( v11, v12, permVec7 );
v14 = vec_ld( 0, blendPtr4 );
v15 = vec_ld( 15, blendPtr4 );
v16 = vec_perm( v14, v15, permVec8 );
// put these into their own vectors too
v5 = vec_mergeh( v7, v13 );
v6 = vec_mergeh( v10, v16 );
v8 = vec_mergel( v7, v13 );
v9 = vec_mergel( v10, v16 );
vecToX = vec_mergeh( v5, v6 );
vecToY = vec_mergel( v5, v6 );
vecToZ = vec_mergeh( v8, v9 );
vecToW = vec_mergel( v8, v9 );
// calculate cosom
vector float vecCosom = vec_madd( vecFromX, vecToX, (vector float)(0) );
vecCosom = vec_madd( vecFromY, vecToY, vecCosom );
vecCosom = vec_madd( vecFromZ, vecToZ, vecCosom );
vecCosom = vec_madd( vecFromW, vecToW, vecCosom );
// if cosom is < 0, negate it and set temp to negated elements in to. otherwise, set temp to
// to
vector bool int vecCmp, vecCmp2;
vecCmp = vec_cmplt( vecCosom, zeroVector );
// negate if needed
vecToX = vec_sel( vecToX, vec_madd( vecToX, (vector float)(-1), zeroVector ), vecCmp );
vecToY = vec_sel( vecToY, vec_madd( vecToY, (vector float)(-1), zeroVector ), vecCmp );
vecToZ = vec_sel( vecToZ, vec_madd( vecToZ, (vector float)(-1), zeroVector ), vecCmp );
vecToW = vec_sel( vecToW, vec_madd( vecToW, (vector float)(-1), zeroVector ), vecCmp );
vecCosom = vec_sel( vecCosom, vec_madd( vecCosom, (vector float)(-1), zeroVector ), vecCmp );
// check if we need to calculate scale
vecCmp2 = vec_cmpgt( vec_sub( (vector float)(1), vecCosom ), (vector float)(1e-6f) );
vector float vecScale0 = vec_sub( (vector float)(1), vecLerp );
vector float vecScale1 = vec_splat( vecLerp, 0 );
vector float vecWork1 = vec_sub( (vector float)(1), vec_madd( vecCosom, vecCosom, zeroVector ) );
vector float vecWork2 = ReciprocalSquareRoot( vecWork1 );
vector float vecWork3 = VectorATan16( vec_madd( vecWork1, vecWork2, zeroVector ), vecCosom );
vecWork1 = vec_madd( VectorSin16( vec_madd( vecScale0, vecWork3, zeroVector ) ), vecWork2, zeroVector );
vecWork2 = vec_madd( VectorSin16( vec_madd( vecLerp, vecWork3, zeroVector ) ), vecWork2, zeroVector );
// see which ones we have to insert into our scale0 and scale1 vectors
vecScale0 = vec_sel( vecScale0, vecWork1, vecCmp2 );
vecScale1 = vec_sel( vecScale1, vecWork2, vecCmp2 );
// multiply each element by the scale
vecFromX = vec_madd( vecFromX, vecScale0, zeroVector );
vecFromY = vec_madd( vecFromY, vecScale0, zeroVector );
vecFromZ = vec_madd( vecFromZ, vecScale0, zeroVector );
vecFromW = vec_madd( vecFromW, vecScale0, zeroVector );
// multiply temp by scale and add to result
vecFromX = vec_madd( vecToX, vecScale1, vecFromX );
vecFromY = vec_madd( vecToY, vecScale1, vecFromY );
vecFromZ = vec_madd( vecToZ, vecScale1, vecFromZ );
vecFromW = vec_madd( vecToW, vecScale1, vecFromW );
// do a transform again to get the results back to vectors we can store out
v5 = vec_mergeh( vecFromX, vecFromZ );
v6 = vec_mergeh( vecFromY, vecFromW );
v8 = vec_mergel( vecFromX, vecFromZ );
v9 = vec_mergel( vecFromY, vecFromW );
vecToX = vec_mergeh( v5, v6 );
vecToY = vec_mergel( v5, v6 );
vecToZ = vec_mergeh( v8, v9 );
vecToW = vec_mergel( v8, v9 );
vector unsigned char storePerm1 = vec_lvsr( 0, jointPtr );
vector unsigned char storePerm2 = vec_lvsr( 0, jointPtr2 );
vector unsigned char storePerm3 = vec_lvsr( 0, jointPtr3 );
vector unsigned char storePerm4 = vec_lvsr( 0, jointPtr4 );
// right rotate the input data
vecToX = vec_perm( vecToX, vecToX, storePerm1 );
vecToY = vec_perm( vecToY, vecToY, storePerm2 );
vecToZ = vec_perm( vecToZ, vecToZ, storePerm3 );
vecToW = vec_perm( vecToW, vecToW, storePerm4 );
vec_ste( vecToX, 0, (float*) jointPtr );
vec_ste( vecToX, 4, (float*) jointPtr );
vec_ste( vecToX, 8, (float*) jointPtr );
vec_ste( vecToX, 12, (float*) jointPtr );
vec_ste( vecToY, 0, (float*) jointPtr2 );
vec_ste( vecToY, 4, (float*) jointPtr2 );
vec_ste( vecToY, 8, (float*) jointPtr2 );
vec_ste( vecToY, 12, (float*) jointPtr2 );
vec_ste( vecToZ, 0, (float*) jointPtr3 );
vec_ste( vecToZ, 4, (float*) jointPtr3 );
vec_ste( vecToZ, 8, (float*) jointPtr3 );
vec_ste( vecToZ, 12, (float*) jointPtr3 );
vec_ste( vecToW, 0, (float*) jointPtr4 );
vec_ste( vecToW, 4, (float*) jointPtr4 );
vec_ste( vecToW, 8, (float*) jointPtr4 );
vec_ste( vecToW, 12, (float*) jointPtr4 );
// lerp is v1 + l * ( v2 - v1 );
// the idVec3 T is going to be 12 bytes after the Q, so we can do this without calling ToFloatPtr() again. since its
float *jointVecPtr = (float*)( jointPtr + 4 );
float *jointVecPtr2 = (float*)( jointPtr2 + 4 );
float *jointVecPtr3 = (float*)( jointPtr3 + 4 );
float *jointVecPtr4 = (float*)( jointPtr4 + 4 );
v0 = vec_ld( 0, jointVecPtr );
v1 = vec_ld( 11, jointVecPtr );
vector float vecLd1 = vec_perm( v0, v1, vec_add( vec_lvsl( -1, jointVecPtr ), (vector unsigned char)(1) ) );
v2 = vec_ld( 0, jointVecPtr2 );
v3 = vec_ld( 11, jointVecPtr2 );
vector float vecLd2 = vec_perm( v2, v3, vec_add( vec_lvsl( -1, jointVecPtr2 ), (vector unsigned char)(1) ) );
v4 = vec_ld( 0, jointVecPtr3 );
v5 = vec_ld( 11, jointVecPtr3 );
vector float vecLd3 = vec_perm( v4, v5, vec_add( vec_lvsl( -1, jointVecPtr3 ), (vector unsigned char)(1) ) );
v6 = vec_ld( 0, jointVecPtr4 );
v7 = vec_ld( 11, jointVecPtr4 );
vector float vecLd4 = vec_perm( v6, v7, vec_add( vec_lvsl( -1, jointVecPtr4 ), (vector unsigned char)(1) ) );
vector float vecVecX, vecVecY, vecVecZ;
vecVecX = vecVecY = vecVecZ = zeroVector;
// planarize
v0 = vec_mergeh( vecLd1, vecLd3 );
v1 = vec_mergeh( vecLd2, vecLd4 );
v3 = vec_mergel( vecLd1, vecLd3 );
v4 = vec_mergel( vecLd2, vecLd4 );
vecVecX = vec_mergeh( v0, v1 );
vecVecY = vec_mergel( v0, v1 );
vecVecZ = vec_mergeh( v3, v4 );
// load blend joint idvec3's
float *blendVecPtr = (float*)( blendPtr + 4 );
float *blendVecPtr2 =(float*)( blendPtr2 + 4 );
float *blendVecPtr3 = (float*)( blendPtr3 + 4 );
float *blendVecPtr4 = (float*)( blendPtr4 + 4 );
v0 = vec_ld( 0, blendVecPtr );
v1 = vec_ld( 11, blendVecPtr );
vector float vecLd5 = vec_perm( v0, v1, vec_add( vec_lvsl( -1, blendVecPtr ), (vector unsigned char)(1) ) );
v2 = vec_ld( 0, blendVecPtr2 );
v3 = vec_ld( 11, blendVecPtr2 );
vector float vecLd6 = vec_perm( v2, v3, vec_add( vec_lvsl( -1, blendVecPtr2 ), (vector unsigned char)(1) ) );
v4 = vec_ld( 0, blendVecPtr3 );
v5 = vec_ld( 11, blendVecPtr3 );
vector float vecLd7 = vec_perm( v4, v5, vec_add( vec_lvsl( -1, blendVecPtr3 ), (vector unsigned char)(1) ) );
v6 = vec_ld( 0, blendVecPtr4 );
v7 = vec_ld( 11, blendVecPtr4 );
vector float vecLd8 = vec_perm( v6, v7, vec_add( vec_lvsl( -1, blendVecPtr4 ), (vector unsigned char)(1) ) );
vector float vecBlendX, vecBlendY, vecBlendZ;
vecBlendX = vecBlendY = vecBlendZ = zeroVector;
// planarize
v0 = vec_mergeh( vecLd5, vecLd7 );
v1 = vec_mergeh( vecLd6, vecLd8 );
v3 = vec_mergel( vecLd5, vecLd7 );
v4 = vec_mergel( vecLd6, vecLd8 );
vecBlendX = vec_mergeh( v0, v1 );
vecBlendY = vec_mergel( v0, v1 );
vecBlendZ = vec_mergeh( v3, v4 );
// do subtraction
vecWork1 = vec_sub( vecBlendX, vecVecX );
vecWork2 = vec_sub( vecBlendY, vecVecY );
vecWork3 = vec_sub( vecBlendZ, vecVecZ );
// multiply by lerp and add to v1
vecVecX = vec_madd( vecWork1, vecLerp, vecVecX );
vecVecY = vec_madd( vecWork2, vecLerp, vecVecY );
vecVecZ = vec_madd( vecWork3, vecLerp, vecVecZ );
// put it back in original form
v0 = vec_mergeh( vecVecX, vecVecZ );
v1 = vec_mergeh( vecVecY, zeroVector );
v3 = vec_mergel( vecVecX, vecVecZ );
v4 = vec_mergel( vecVecY, zeroVector );
// generate vectors to store
vecWork1 = vec_mergeh( v0, v1 );
vecWork2 = vec_mergel( v0, v1 );
vecWork3 = vec_mergeh( v3, v4 );
vector float vecWork4 = vec_mergel( v3, v4 );
// store the T values
storePerm1 = vec_lvsr( 0, jointVecPtr );
storePerm2 = vec_lvsr( 0, jointVecPtr2 );
storePerm3 = vec_lvsr( 0, jointVecPtr3 );
storePerm4 = vec_lvsr( 0, jointVecPtr4 );
// right rotate the input data
vecWork1 = vec_perm( vecWork1, vecWork1, storePerm1 );
vecWork2 = vec_perm( vecWork2, vecWork2, storePerm2 );
vecWork3 = vec_perm( vecWork3, vecWork3, storePerm3 );
vecWork4 = vec_perm( vecWork4, vecWork4, storePerm4 );
vec_ste( vecWork1, 0, (float*) jointVecPtr );
vec_ste( vecWork1, 4, (float*) jointVecPtr );
vec_ste( vecWork1, 8, (float*) jointVecPtr );
vec_ste( vecWork2, 0, (float*) jointVecPtr2 );
vec_ste( vecWork2, 4, (float*) jointVecPtr2 );
vec_ste( vecWork2, 8, (float*) jointVecPtr2 );
vec_ste( vecWork3, 0, (float*) jointVecPtr3 );
vec_ste( vecWork3, 4, (float*) jointVecPtr3 );
vec_ste( vecWork3, 8, (float*) jointVecPtr3 );
vec_ste( vecWork4, 0, (float*) jointVecPtr4 );
vec_ste( vecWork4, 4, (float*) jointVecPtr4 );
vec_ste( vecWork4, 8, (float*) jointVecPtr4 );
}
// cleanup
for ( ; i < numJoints; i++ ) {
int j = index[i];
joints[j].q.Slerp( joints[j].q, blendJoints[j].q, lerp );
joints[j].t.Lerp( joints[j].t, blendJoints[j].t, lerp );
}
}
/*
============
idSIMD_AltiVec::ConvertJointQuatsToJointMats
============
*/
// SSE doesn't vectorize this, and I don't think we should either. Its mainly just copying data, there's very little math involved and
// it's not easily parallelizable
void VPCALL idSIMD_AltiVec::ConvertJointQuatsToJointMats( idJointMat *jointMats, const idJointQuat *jointQuats, const int numJoints ) {
for ( int i = 0; i < numJoints; i++ ) {
const float *q = jointQuats[i].q.ToFloatPtr();
float *m = jointMats[i].ToFloatPtr();
m[0*4+3] = q[4];
m[1*4+3] = q[5];
m[2*4+3] = q[6];
float x2 = q[0] + q[0];
float y2 = q[1] + q[1];
float z2 = q[2] + q[2];
{
float xx = q[0] * x2;
float yy = q[1] * y2;
float zz = q[2] * z2;
m[0*4+0] = 1.0f - yy - zz;
m[1*4+1] = 1.0f - xx - zz;
m[2*4+2] = 1.0f - xx - yy;
}
{
float yz = q[1] * z2;
float wx = q[3] * x2;
m[2*4+1] = yz - wx;
m[1*4+2] = yz + wx;
}
{
float xy = q[0] * y2;
float wz = q[3] * z2;
m[1*4+0] = xy - wz;
m[0*4+1] = xy + wz;
}
{
float xz = q[0] * z2;
float wy = q[3] * y2;
m[0*4+2] = xz - wy;
m[2*4+0] = xz + wy;
}
}
}
/*
============
idSIMD_AltiVec::ConvertJointMatsToJointQuats
============
*/
void VPCALL idSIMD_AltiVec::ConvertJointMatsToJointQuats( idJointQuat *jointQuats, const idJointMat *jointMats, const int numJoints ) {
int index;
// Since we use very little of the data we have to pull in for the altivec version, we end up with
// a lot of wasted math. Rather than try to force it to use altivec, I wrote an optimized version
// of InvSqrt for the G5, and made it use that instead. With only this change, we get a little
// bigger than 50% speedup, which is not too shabby. Should really replace idMath::InvSqrt with
// my function so everyone can benefit on G5.
for ( index = 0; index < numJoints; index++ ) {
idJointQuat jq;
float trace;
float s;
float t;
int i;
int j;
int k;
static int next[3] = { 1, 2, 0 };
float *mat = (float*)( jointMats[index].ToFloatPtr() );
trace = mat[0 * 4 + 0] + mat[1 * 4 + 1] + mat[2 * 4 + 2];
if ( trace > 0.0f ) {
t = trace + 1.0f;
//s = idMath::InvSqrt( t ) * 0.5f;
s = FastScalarInvSqrt( t ) * 0.5f;
jq.q[3] = s * t;
jq.q[0] = ( mat[1 * 4 + 2] - mat[2 * 4 + 1] ) * s;
jq.q[1] = ( mat[2 * 4 + 0] - mat[0 * 4 + 2] ) * s;
jq.q[2] = ( mat[0 * 4 + 1] - mat[1 * 4 + 0] ) * s;
} else {
i = 0;
if ( mat[1 * 4 + 1] > mat[0 * 4 + 0] ) {
i = 1;
}
if ( mat[2 * 4 + 2] > mat[i * 4 + i] ) {
i = 2;
}
j = next[i];
k = next[j];
t = ( mat[i * 4 + i] - ( mat[j * 4 + j] + mat[k * 4 + k] ) ) + 1.0f;
//s = idMath::InvSqrt( t ) * 0.5f;
s = FastScalarInvSqrt( t ) * 0.5f;
jq.q[i] = s * t;
jq.q[3] = ( mat[j * 4 + k] - mat[k * 4 + j] ) * s;
jq.q[j] = ( mat[i * 4 + j] + mat[j * 4 + i] ) * s;
jq.q[k] = ( mat[i * 4 + k] + mat[k * 4 + i] ) * s;
}
jq.t[0] = mat[0 * 4 + 3];
jq.t[1] = mat[1 * 4 + 3];
jq.t[2] = mat[2 * 4 + 3];
jointQuats[index] = jq;
}
}
/*
============
idSIMD_AltiVec::TransformJoints
============
*/
void VPCALL idSIMD_AltiVec::TransformJoints( idJointMat *jointMats, const int *parents, const int firstJoint, const int lastJoint ) {
int i;
#if 0
for( i = firstJoint; i <= lastJoint; i++ ) {
assert( parents[i] < i );
jointMats[i] *= jointMats[parents[i]];
}
#else
// I don't think you can unroll this since the next iteration of the loop might depending on the previous iteration, depending
// on what the parents array looks like. This is true in the test code.
for ( i = firstJoint; i <= lastJoint; i++ ) {
assert( parents[i] < i );
float *jointPtr = jointMats[i].ToFloatPtr();
float *parentPtr = jointMats[parents[i]].ToFloatPtr();
vector unsigned char permVec = vec_add( vec_lvsl( -1, jointPtr ), (vector unsigned char)(1) );
vector unsigned char permVec2 = vec_add( vec_lvsl( -1, parentPtr ), (vector unsigned char)(1) );
vector float v0, v1, v2, v3, v4, v5, v6, v7;
// we need to load up 12 float elements that make up the Mat
v0 = vec_ld( 0, jointPtr );
v1 = vec_ld( 15, jointPtr );
v2 = vec_ld( 31, jointPtr );
v3 = vec_ld( 47, jointPtr );
// load parents
v4 = vec_ld( 0, parentPtr );
v5 = vec_ld( 15, parentPtr );
v6 = vec_ld( 31, parentPtr );
v7 = vec_ld( 47, parentPtr );
// permute into vectors
vector float vecJointMat1 = vec_perm( v0, v1, permVec );
vector float vecJointMat2 = vec_perm( v1, v2, permVec );
vector float vecJointMat3 = vec_perm( v2, v3, permVec );
vector float vecParentMat1 = vec_perm( v4, v5, permVec2 );
vector float vecParentMat2 = vec_perm( v5, v6, permVec2 );
vector float vecParentMat3 = vec_perm( v6, v7, permVec2 );
vector float zero = (vector float)(0);
vector float C1, C2, C3;
// matrix multiply
C1 = vec_madd( vecJointMat1, vec_splat( vecParentMat1, 0 ), zero ); // m(0 to 3) * a(0)
C2 = vec_madd( vecJointMat1, vec_splat( vecParentMat2, 0 ), zero ); // m(4 to 7) * a(4)
C3 = vec_madd( vecJointMat1, vec_splat( vecParentMat3, 0 ), zero ); // m(8 to 11) * a(8)
C1 = vec_madd( vecJointMat2, vec_splat( vecParentMat1, 1 ), C1 ); // add in m(4 to 7) * a(1)
C2 = vec_madd( vecJointMat2, vec_splat( vecParentMat2, 1 ), C2 ); // add in m(4 to 7) * a(5)
C3 = vec_madd( vecJointMat2, vec_splat( vecParentMat3, 1 ), C3 ); // add in m(4 to 7) * a(9)
C1 = vec_madd( vecJointMat3, vec_splat( vecParentMat1, 2 ), C1 );
C2 = vec_madd( vecJointMat3, vec_splat( vecParentMat2, 2 ), C2 );
C3 = vec_madd( vecJointMat3, vec_splat( vecParentMat3, 2 ), C3 );
// do the addition at the end
vector unsigned char permZeroAndLast = (vector unsigned char)(0,1,2,3,4,5,6,7,8,9,10,11,28,29,30,31);
C1 = vec_add( C1, vec_perm( zero, vecParentMat1, permZeroAndLast ) );
C2 = vec_add( C2, vec_perm( zero, vecParentMat2, permZeroAndLast ) );
C3 = vec_add( C3, vec_perm( zero, vecParentMat3, permZeroAndLast ) );
// store results
UNALIGNED_STORE3( (float*) jointPtr, C1, C2, C3 );
}
#endif
}
/*
============
idSIMD_AltiVec::UntransformJoints
============
*/
void VPCALL idSIMD_AltiVec::UntransformJoints( idJointMat *jointMats, const int *parents, const int firstJoint, const int lastJoint ) {
int i;
#if 0
for( i = lastJoint; i >= firstJoint; i-- ) {
assert( parents[i] < i );
jointMats[i] /= jointMats[parents[i]];
}
#else
// I don't think you can unroll this since the next iteration of the loop might depending on the previous iteration, depending
// on what the parents array looks like. This is true in the test code.
for ( i = lastJoint; i >= firstJoint; i-- ) {
assert( parents[i] < i );
float *jointPtr = jointMats[i].ToFloatPtr();
float *parentPtr = jointMats[parents[i]].ToFloatPtr();
vector unsigned char permVec = vec_add( vec_lvsl( -1, jointPtr ), (vector unsigned char)(1) );
vector unsigned char permVec2 = vec_add( vec_lvsl( -1, parentPtr ), (vector unsigned char)(1) );
vector float v0, v1, v2, v3, v4, v5, v6, v7;
// we need to load up 12 float elements that make up the Mat
v0 = vec_ld( 0, jointPtr );
v1 = vec_ld( 15, jointPtr );
v2 = vec_ld( 31, jointPtr );
v3 = vec_ld( 47, jointPtr );
// load parents
v4 = vec_ld( 0, parentPtr );
v5 = vec_ld( 15, parentPtr );
v6 = vec_ld( 31, parentPtr );
v7 = vec_ld( 47, parentPtr );
// permute into vectors
vector float vecJointMat1 = vec_perm( v0, v1, permVec );
vector float vecJointMat2 = vec_perm( v1, v2, permVec );
vector float vecJointMat3 = vec_perm( v2, v3, permVec );
vector float vecParentMat1 = vec_perm( v4, v5, permVec2 );
vector float vecParentMat2 = vec_perm( v5, v6, permVec2 );
vector float vecParentMat3 = vec_perm( v6, v7, permVec2 );
vector float zero = (vector float)(0);
vector float C1, C2, C3;
// do subtraction at the beginning
vector unsigned char permZeroAndLast = (vector unsigned char)(0,1,2,3,4,5,6,7,8,9,10,11,28,29,30,31);
vecJointMat1 = vec_sub( vecJointMat1, vec_perm( zero, vecParentMat1, permZeroAndLast ) );
vecJointMat2 = vec_sub( vecJointMat2, vec_perm( zero, vecParentMat2, permZeroAndLast ) );
vecJointMat3 = vec_sub( vecJointMat3, vec_perm( zero, vecParentMat3, permZeroAndLast ) );
// matrix multiply
C1 = vec_madd( vecJointMat1, vec_splat( vecParentMat1, 0 ), zero );
C2 = vec_madd( vecJointMat1, vec_splat( vecParentMat1, 1 ), zero );
C3 = vec_madd( vecJointMat1, vec_splat( vecParentMat1, 2 ), zero );
C1 = vec_madd( vecJointMat2, vec_splat( vecParentMat2, 0 ), C1 );
C2 = vec_madd( vecJointMat2, vec_splat( vecParentMat2, 1 ), C2 );
C3 = vec_madd( vecJointMat2, vec_splat( vecParentMat2, 2 ), C3 );
C1 = vec_madd( vecJointMat3, vec_splat( vecParentMat3, 0 ), C1 );
C2 = vec_madd( vecJointMat3, vec_splat( vecParentMat3, 1 ), C2 );
C3 = vec_madd( vecJointMat3, vec_splat( vecParentMat3, 2 ), C3 );
// store results back
vector unsigned char storePerm = vec_lvsr( 0, jointPtr );
// right rotate the input data
C1 = vec_perm( C1, C1, storePerm );
C2 = vec_perm( C2, C2, storePerm );
C3 = vec_perm( C3, C3, storePerm );
vec_ste( C1, 0, (float*) jointPtr );
vec_ste( C1, 4, (float*) jointPtr );
vec_ste( C1, 8, (float*) jointPtr );
vec_ste( C1, 12, (float*) jointPtr );
vec_ste( C2, 16, (float*) jointPtr );
vec_ste( C2, 20, (float*) jointPtr );
vec_ste( C2, 24, (float*) jointPtr );
vec_ste( C2, 28, (float*) jointPtr );
vec_ste( C3, 32, (float*) jointPtr );
vec_ste( C3, 36, (float*) jointPtr );
vec_ste( C3, 40, (float*) jointPtr );
vec_ste( C3, 44, (float*) jointPtr );
}
#endif
}
/*
============
idSIMD_AltiVec::TransformVerts
============
*/
// Here we don't have much for the vector unit to do, and the gain we get from doing the math
// in parallel is eaten by doing unaligned stores.
void VPCALL idSIMD_AltiVec::TransformVerts( idDrawVert *verts, const int numVerts, const idJointMat *joints, const idVec4 *weights, const int *index, int numWeights ) {
int i, j;
const byte *jointsPtr = (byte *)joints;
for( j = i = 0; i < numVerts; i++ ) {
idVec3 v;
float *matPtrOrig = ( *(idJointMat *)( jointsPtr + index[j*2] ) ).ToFloatPtr();
float *weightPtr = (float*) weights[j].ToFloatPtr();
v[0] = matPtrOrig[0] * weightPtr[0];
v[0] += matPtrOrig[1] * weightPtr[1];
v[0] += matPtrOrig[2] * weightPtr[2];
v[0] += matPtrOrig[3] * weightPtr[3];
v[1] = matPtrOrig[4] * weightPtr[0];
v[1] += matPtrOrig[5] * weightPtr[1];
v[1] += matPtrOrig[6] * weightPtr[2];
v[1] += matPtrOrig[7] * weightPtr[3];
v[2] = matPtrOrig[8] * weightPtr[0];
v[2] += matPtrOrig[9] * weightPtr[1];
v[2] += matPtrOrig[10] * weightPtr[2];
v[2] += matPtrOrig[11] * weightPtr[3];
while( index[j*2+1] == 0 ) {
j++;
float *matPtr = ( *(idJointMat *)( jointsPtr + index[j*2] ) ).ToFloatPtr();
weightPtr = (float*) weights[j].ToFloatPtr();
v[0] += matPtr[0] * weightPtr[0];
v[0] += matPtr[1] * weightPtr[1];
v[0] += matPtr[2] * weightPtr[2];
v[0] += matPtr[3] * weightPtr[3];
v[1] += matPtr[4] * weightPtr[0];
v[1] += matPtr[5] * weightPtr[1];
v[1] += matPtr[6] * weightPtr[2];
v[1] += matPtr[7] * weightPtr[3];
v[2] += matPtr[8] * weightPtr[0];
v[2] += matPtr[9] * weightPtr[1];
v[2] += matPtr[10] * weightPtr[2];
v[2] += matPtr[11] * weightPtr[3];
}
j++;
verts[i].xyz = v;
}
}
#endif /* LIVE_VICARIOUSLY */
#ifdef ENABLE_CULL
#ifndef DRAWVERT_PADDED
/*
============
idSIMD_AltiVec::TracePointCull
============
*/
void VPCALL idSIMD_AltiVec::TracePointCull( byte *cullBits, byte &totalOr, const float radius, const idPlane *planes, const idDrawVert *verts, const int numVerts ) {
// idDrawVert size
assert( sizeof(idDrawVert) == DRAWVERT_OFFSET * sizeof(float) );
byte tOr;
tOr = 0;
// pointers
const float *planePtr = planes[0].ToFloatPtr();
vector unsigned int vecShift1 = (vector unsigned int)(0,1,2,3);
vector unsigned int vecShift2 = (vector unsigned int)(4,5,6,7);
vector unsigned int vecFlipBits = (vector unsigned int)(0x0F);
vector float vecPlane0, vecPlane1, vecPlane2, vecPlane3;
vector bool int vecCmp1, vecCmp2, vecCmp3, vecCmp4, vecCmp5, vecCmp6, vecCmp7, vecCmp8;
vector unsigned char vecPerm;
vector float v0, v1, v2, v3, v4, v5, v6, v7;
vector float zeroVector = (vector float)(0);
vector float vecRadius;
vector float vecXYZ1, vecXYZ2, vecXYZ3, vecXYZ4;
vector float vec1Sum1, vec1Sum2, vec1Sum3, vec1Sum4;
vector unsigned char vecPermLast = (vector unsigned char)(0,1,2,3,4,5,6,7,8,9,10,11,16,17,18,19);
vector unsigned char vecPermHalves = (vector unsigned char)(0,1,2,3,4,5,6,7,16,17,18,19,20,21,22,23);
vector float vecDPlusRadius1, vecDPlusRadius2, vecDPlusRadius3, vecDPlusRadius4;
vector float vecDMinusRadius1, vecDMinusRadius2, vecDMinusRadius3, vecDMinusRadius4;
vector bool int oneIntVector = (vector bool int)(1);
vector unsigned int vecBitShifted1, vecBitShifted2, vecBitShifted3, vecBitShifted4, vecBitShifted5, vecBitShifted6, vecBitShifted7, vecBitShifted8;
vector unsigned int vecTotals;
vector unsigned int tempIntSum;
vector unsigned char vertPerm1, vertPerm2, vertPerm3, vertPerm4;
vecPerm = vec_add( vec_lvsl( -1, planePtr ), (vector unsigned char)(1) );
// populate planes
v0 = vec_ld( 0, planePtr );
v1 = vec_ld( 15, planePtr );
vecPlane0 = vec_perm( v0, v1, vecPerm );
v2 = vec_ld( 0, planePtr + 4 );
v3 = vec_ld( 15, planePtr + 4 );
vecPlane1 = vec_perm( v2, v3, vecPerm );
v0 = vec_ld( 0, planePtr + 8 );
v1 = vec_ld( 15, planePtr + 8 );
vecPlane2 = vec_perm( v0, v1, vecPerm );
v2 = vec_ld( 0, planePtr + 12 );
v3 = vec_ld( 15, planePtr + 12 );
vecPlane3 = vec_perm( v2, v3, vecPerm );
// transpose
v0 = vec_mergeh( vecPlane0, vecPlane2 );
v1 = vec_mergeh( vecPlane1, vecPlane3 );
v2 = vec_mergel( vecPlane0, vecPlane2 );
v3 = vec_mergel( vecPlane1, vecPlane3 );
vecPlane0 = vec_mergeh( v0, v1 );
vecPlane1 = vec_mergel( v0, v1 );
vecPlane2 = vec_mergeh( v2, v3 );
vecPlane3 = vec_mergel( v2, v3 );
// load constants
vecRadius = loadSplatUnalignedScalar( &radius );
unsigned int cullBitVal[4];
vector unsigned char cullBitPerm = vec_lvsr( 0, &cullBitVal[0] );
int i = 0;
// every fourth one will have the same alignment. Make sure we've got enough here
if ( i+3 < numVerts ) {
vertPerm1 = vec_add( vec_lvsl( -1, (float*) verts[0].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vertPerm2 = vec_add( vec_lvsl( -1, (float*) verts[1].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vertPerm3 = vec_add( vec_lvsl( -1, (float*) verts[2].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vertPerm4 = vec_add( vec_lvsl( -1, (float*) verts[3].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
}
for ( ; i+3 < numVerts; i+=4 ) {
const float *vertPtr = verts[i].xyz.ToFloatPtr();
const float *vertPtr2 = verts[i+1].xyz.ToFloatPtr();
const float *vertPtr3 = verts[i+2].xyz.ToFloatPtr();
const float *vertPtr4 = verts[i+3].xyz.ToFloatPtr();
v0 = vec_ld( 0, vertPtr );
v1 = vec_ld( 15, vertPtr );
v2 = vec_ld( 0, vertPtr2 );
v3 = vec_ld( 15, vertPtr2 );
v4 = vec_ld( 0, vertPtr3 );
v5 = vec_ld( 15, vertPtr3 );
v6 = vec_ld( 0, vertPtr4 );
v7 = vec_ld( 15, vertPtr4 );
vecXYZ1 = vec_perm( v0, v1, vertPerm1 );
vecXYZ2 = vec_perm( v2, v3, vertPerm2 );
vecXYZ3 = vec_perm( v4, v5, vertPerm3 );
vecXYZ4 = vec_perm( v6, v7, vertPerm4 );
vec1Sum1 = vec_madd( vec_splat( vecXYZ1, 0 ), vecPlane0, zeroVector );
vec1Sum1 = vec_madd( vec_splat( vecXYZ1, 1 ), vecPlane1, vec1Sum1 );
vec1Sum1 = vec_madd( vec_splat( vecXYZ1, 2 ), vecPlane2, vec1Sum1 );
vec1Sum1 = vec_add( vec1Sum1, vecPlane3 );
vec1Sum2 = vec_madd( vec_splat( vecXYZ2, 0 ), vecPlane0, zeroVector );
vec1Sum2 = vec_madd( vec_splat( vecXYZ2, 1 ), vecPlane1, vec1Sum2 );
vec1Sum2 = vec_madd( vec_splat( vecXYZ2, 2 ), vecPlane2, vec1Sum2 );
vec1Sum2 = vec_add( vec1Sum2, vecPlane3 );
vec1Sum3 = vec_madd( vec_splat( vecXYZ3, 0 ), vecPlane0, zeroVector );
vec1Sum3 = vec_madd( vec_splat( vecXYZ3, 1 ), vecPlane1, vec1Sum3 );
vec1Sum3 = vec_madd( vec_splat( vecXYZ3, 2 ), vecPlane2, vec1Sum3 );
vec1Sum3 = vec_add( vec1Sum3, vecPlane3 );
vec1Sum4 = vec_madd( vec_splat( vecXYZ4, 0 ), vecPlane0, zeroVector );
vec1Sum4 = vec_madd( vec_splat( vecXYZ4, 1 ), vecPlane1, vec1Sum4 );
vec1Sum4 = vec_madd( vec_splat( vecXYZ4, 2 ), vecPlane2, vec1Sum4 );
vec1Sum4 = vec_add( vec1Sum4, vecPlane3 );
// vec1Sum1 now holds d0, d1, d2, d3. calculate the
// difference with +radius and -radius
vecDPlusRadius1 = vec_add( vec1Sum1, vecRadius );
vecDMinusRadius1 = vec_sub( vec1Sum1, vecRadius );
vecDPlusRadius2 = vec_add( vec1Sum2, vecRadius );
vecDMinusRadius2 = vec_sub( vec1Sum2, vecRadius );
vecDPlusRadius3 = vec_add( vec1Sum3, vecRadius );
vecDMinusRadius3 = vec_sub( vec1Sum3, vecRadius );
vecDPlusRadius4 = vec_add( vec1Sum4, vecRadius );
vecDMinusRadius4 = vec_sub( vec1Sum4, vecRadius );
// do compare
vecCmp1 = vec_cmplt( vecDPlusRadius1, zeroVector );
vecCmp2 = vec_cmplt( vecDMinusRadius1, zeroVector );
vecCmp3 = vec_cmplt( vecDPlusRadius2, zeroVector );
vecCmp4 = vec_cmplt( vecDMinusRadius2, zeroVector );
vecCmp5 = vec_cmplt( vecDPlusRadius3, zeroVector );
vecCmp6 = vec_cmplt( vecDMinusRadius3, zeroVector );
vecCmp7 = vec_cmplt( vecDPlusRadius4, zeroVector );
vecCmp8 = vec_cmplt( vecDMinusRadius4, zeroVector );
//and it with 1 so we multiply by 1 not 1111's
vecCmp1 = vec_and( vecCmp1, oneIntVector );
vecCmp2 = vec_and( vecCmp2, oneIntVector );
vecCmp3 = vec_and( vecCmp3, oneIntVector );
vecCmp4 = vec_and( vecCmp4, oneIntVector );
vecCmp5 = vec_and( vecCmp5, oneIntVector );
vecCmp6 = vec_and( vecCmp6, oneIntVector );
vecCmp7 = vec_and( vecCmp7, oneIntVector );
vecCmp8 = vec_and( vecCmp8, oneIntVector );
vecBitShifted1 = vec_sl( (vector unsigned int)vecCmp1, vecShift1 );
vecBitShifted2 = vec_sl( (vector unsigned int)vecCmp2, vecShift2 );
vecBitShifted3 = vec_sl( (vector unsigned int)vecCmp3, vecShift1 );
vecBitShifted4 = vec_sl( (vector unsigned int)vecCmp4, vecShift2 );
vecBitShifted5 = vec_sl( (vector unsigned int)vecCmp5, vecShift1 );
vecBitShifted6 = vec_sl( (vector unsigned int)vecCmp6, vecShift2 );
vecBitShifted7 = vec_sl( (vector unsigned int)vecCmp7, vecShift1 );
vecBitShifted8 = vec_sl( (vector unsigned int)vecCmp8, vecShift2 );
// OR (add) them all together
vecBitShifted1 = vec_add( vecBitShifted1, vecBitShifted2 );
vecBitShifted3 = vec_add( vecBitShifted3, vecBitShifted4 );
vecBitShifted5 = vec_add( vecBitShifted5, vecBitShifted6 );
vecBitShifted7 = vec_add( vecBitShifted7, vecBitShifted8 );
vecTotals = vec_add( vecBitShifted1, vec_sld( vecBitShifted1, vecBitShifted1, 8 ) );
vecTotals = vec_add( vecTotals, vec_sld( vecTotals, vecTotals, 4 ) );
tempIntSum = vec_add( vecBitShifted3, vec_sld( vecBitShifted3, vecBitShifted3, 8 ) );
tempIntSum = vec_add( tempIntSum, vec_sld( tempIntSum, tempIntSum, 4 ) );
vecTotals = vec_mergeh( vecTotals, tempIntSum );
tempIntSum = vec_add( vecBitShifted5, vec_sld( vecBitShifted5, vecBitShifted5, 8 ) );
tempIntSum = vec_add( tempIntSum, vec_sld( tempIntSum, tempIntSum, 4 ) );
vecTotals = vec_perm( vecTotals, tempIntSum, vecPermHalves );
tempIntSum = vec_add( vecBitShifted7, vec_sld( vecBitShifted7, vecBitShifted7, 8 ) );
tempIntSum = vec_add( tempIntSum, vec_sld( tempIntSum, tempIntSum, 4 ) );
vecTotals = vec_perm( vecTotals, tempIntSum, vecPermLast );
// store out results
vector unsigned int tempSt = vec_xor( vecTotals, vecFlipBits );
tempSt = vec_perm( tempSt, tempSt, cullBitPerm );
vec_ste( tempSt, 0, &cullBitVal[0] );
vec_ste( tempSt, 4, &cullBitVal[0] );
vec_ste( tempSt, 8, &cullBitVal[0] );
vec_ste( tempSt, 12, &cullBitVal[0] );
tOr |= cullBitVal[0];
tOr |= cullBitVal[1];
tOr |= cullBitVal[2];
tOr |= cullBitVal[3];
cullBits[i] = cullBitVal[0];
cullBits[i+1] = cullBitVal[1];
cullBits[i+2] = cullBitVal[2];
cullBits[i+3] = cullBitVal[3];
}
// cleanup
for ( ; i < numVerts; i++ ) {
byte bits;
float d0, d1, d2, d3, t;
const idVec3 &v = verts[i].xyz;
d0 = planes[0].Distance( v );
d1 = planes[1].Distance( v );
d2 = planes[2].Distance( v );
d3 = planes[3].Distance( v );
t = d0 + radius;
bits = FLOATSIGNBITSET( t ) << 0;
t = d1 + radius;
bits |= FLOATSIGNBITSET( t ) << 1;
t = d2 + radius;
bits |= FLOATSIGNBITSET( t ) << 2;
t = d3 + radius;
bits |= FLOATSIGNBITSET( t ) << 3;
t = d0 - radius;
bits |= FLOATSIGNBITSET( t ) << 4;
t = d1 - radius;
bits |= FLOATSIGNBITSET( t ) << 5;
t = d2 - radius;
bits |= FLOATSIGNBITSET( t ) << 6;
t = d3 - radius;
bits |= FLOATSIGNBITSET( t ) << 7;
bits ^= 0x0F; // flip lower four bits
tOr |= bits;
cullBits[i] = bits;
}
totalOr = tOr;
}
#else
/*
============
idSIMD_AltiVec::TracePointCull
============
*/
void VPCALL idSIMD_AltiVec::TracePointCull( byte *cullBits, byte &totalOr, const float radius, const idPlane *planes, const idDrawVert *verts, const int numVerts ) {
// idDrawVert size
assert( sizeof(idDrawVert) == DRAWVERT_OFFSET * sizeof(float) );
byte tOr;
tOr = 0;
// pointers
const float *planePtr = planes[0].ToFloatPtr();
vector unsigned int vecShift1 = (vector unsigned int)(0,1,2,3);
vector unsigned int vecShift2 = (vector unsigned int)(4,5,6,7);
vector unsigned int vecFlipBits = (vector unsigned int)(0x0F);
vector float vecPlane0, vecPlane1, vecPlane2, vecPlane3;
vector bool int vecCmp1, vecCmp2, vecCmp3, vecCmp4, vecCmp5, vecCmp6, vecCmp7, vecCmp8;
vector unsigned char vecPerm;
vector float v0, v1, v2, v3, v4, v5, v6, v7;
vector float zeroVector = (vector float)(0);
vector float vecRadius;
vector float vecXYZ1, vecXYZ2, vecXYZ3, vecXYZ4;
vector float vec1Sum1, vec1Sum2, vec1Sum3, vec1Sum4;
vector unsigned char vecPermLast = (vector unsigned char)(0,1,2,3,4,5,6,7,8,9,10,11,16,17,18,19);
vector unsigned char vecPermHalves = (vector unsigned char)(0,1,2,3,4,5,6,7,16,17,18,19,20,21,22,23);
vector float vecDPlusRadius1, vecDPlusRadius2, vecDPlusRadius3, vecDPlusRadius4;
vector float vecDMinusRadius1, vecDMinusRadius2, vecDMinusRadius3, vecDMinusRadius4;
vector bool int oneIntVector = (vector bool int)(1);
vector unsigned int vecBitShifted1, vecBitShifted2, vecBitShifted3, vecBitShifted4, vecBitShifted5, vecBitShifted6, vecBitShifted7, vecBitShifted8;
vector unsigned int vecTotals;
vector unsigned int tempIntSum;
vector unsigned char vertPerm1, vertPerm2, vertPerm3, vertPerm4;
vecPerm = vec_add( vec_lvsl( -1, planePtr ), (vector unsigned char)(1) );
// populate planes
v0 = vec_ld( 0, planePtr );
v1 = vec_ld( 15, planePtr );
vecPlane0 = vec_perm( v0, v1, vecPerm );
v2 = vec_ld( 0, planePtr + 4 );
v3 = vec_ld( 15, planePtr + 4 );
vecPlane1 = vec_perm( v2, v3, vecPerm );
v0 = vec_ld( 0, planePtr + 8 );
v1 = vec_ld( 15, planePtr + 8 );
vecPlane2 = vec_perm( v0, v1, vecPerm );
v2 = vec_ld( 0, planePtr + 12 );
v3 = vec_ld( 15, planePtr + 12 );
vecPlane3 = vec_perm( v2, v3, vecPerm );
// transpose
v0 = vec_mergeh( vecPlane0, vecPlane2 );
v1 = vec_mergeh( vecPlane1, vecPlane3 );
v2 = vec_mergel( vecPlane0, vecPlane2 );
v3 = vec_mergel( vecPlane1, vecPlane3 );
vecPlane0 = vec_mergeh( v0, v1 );
vecPlane1 = vec_mergel( v0, v1 );
vecPlane2 = vec_mergeh( v2, v3 );
vecPlane3 = vec_mergel( v2, v3 );
// load constants
vecRadius = loadSplatUnalignedScalar( &radius );
unsigned int cullBitVal[4];
vector unsigned char cullBitPerm = vec_lvsr( 0, &cullBitVal[0] );
int i = 0;
for ( ; i+3 < numVerts; i+=4 ) {
const float *vertPtr = verts[i].xyz.ToFloatPtr();
const float *vertPtr2 = verts[i+1].xyz.ToFloatPtr();
const float *vertPtr3 = verts[i+2].xyz.ToFloatPtr();
const float *vertPtr4 = verts[i+3].xyz.ToFloatPtr();
vecXYZ1 = vec_ld( 0, vertPtr );
vecXYZ2 = vec_ld( 0, vertPtr2 );
vecXYZ3 = vec_ld( 0, vertPtr3 );
vecXYZ4 = vec_ld( 0, vertPtr4 );
vec1Sum1 = vec_madd( vec_splat( vecXYZ1, 0 ), vecPlane0, zeroVector );
vec1Sum1 = vec_madd( vec_splat( vecXYZ1, 1 ), vecPlane1, vec1Sum1 );
vec1Sum1 = vec_madd( vec_splat( vecXYZ1, 2 ), vecPlane2, vec1Sum1 );
vec1Sum1 = vec_add( vec1Sum1, vecPlane3 );
vec1Sum2 = vec_madd( vec_splat( vecXYZ2, 0 ), vecPlane0, zeroVector );
vec1Sum2 = vec_madd( vec_splat( vecXYZ2, 1 ), vecPlane1, vec1Sum2 );
vec1Sum2 = vec_madd( vec_splat( vecXYZ2, 2 ), vecPlane2, vec1Sum2 );
vec1Sum2 = vec_add( vec1Sum2, vecPlane3 );
vec1Sum3 = vec_madd( vec_splat( vecXYZ3, 0 ), vecPlane0, zeroVector );
vec1Sum3 = vec_madd( vec_splat( vecXYZ3, 1 ), vecPlane1, vec1Sum3 );
vec1Sum3 = vec_madd( vec_splat( vecXYZ3, 2 ), vecPlane2, vec1Sum3 );
vec1Sum3 = vec_add( vec1Sum3, vecPlane3 );
vec1Sum4 = vec_madd( vec_splat( vecXYZ4, 0 ), vecPlane0, zeroVector );
vec1Sum4 = vec_madd( vec_splat( vecXYZ4, 1 ), vecPlane1, vec1Sum4 );
vec1Sum4 = vec_madd( vec_splat( vecXYZ4, 2 ), vecPlane2, vec1Sum4 );
vec1Sum4 = vec_add( vec1Sum4, vecPlane3 );
// vec1Sum1 now holds d0, d1, d2, d3. calculate the
// difference with +radius and -radius
vecDPlusRadius1 = vec_add( vec1Sum1, vecRadius );
vecDMinusRadius1 = vec_sub( vec1Sum1, vecRadius );
vecDPlusRadius2 = vec_add( vec1Sum2, vecRadius );
vecDMinusRadius2 = vec_sub( vec1Sum2, vecRadius );
vecDPlusRadius3 = vec_add( vec1Sum3, vecRadius );
vecDMinusRadius3 = vec_sub( vec1Sum3, vecRadius );
vecDPlusRadius4 = vec_add( vec1Sum4, vecRadius );
vecDMinusRadius4 = vec_sub( vec1Sum4, vecRadius );
// do compare
vecCmp1 = vec_cmplt( vecDPlusRadius1, zeroVector );
vecCmp2 = vec_cmplt( vecDMinusRadius1, zeroVector );
vecCmp3 = vec_cmplt( vecDPlusRadius2, zeroVector );
vecCmp4 = vec_cmplt( vecDMinusRadius2, zeroVector );
vecCmp5 = vec_cmplt( vecDPlusRadius3, zeroVector );
vecCmp6 = vec_cmplt( vecDMinusRadius3, zeroVector );
vecCmp7 = vec_cmplt( vecDPlusRadius4, zeroVector );
vecCmp8 = vec_cmplt( vecDMinusRadius4, zeroVector );
//and it with 1 so we multiply by 1 not 1111's
vecCmp1 = vec_and( vecCmp1, oneIntVector );
vecCmp2 = vec_and( vecCmp2, oneIntVector );
vecCmp3 = vec_and( vecCmp3, oneIntVector );
vecCmp4 = vec_and( vecCmp4, oneIntVector );
vecCmp5 = vec_and( vecCmp5, oneIntVector );
vecCmp6 = vec_and( vecCmp6, oneIntVector );
vecCmp7 = vec_and( vecCmp7, oneIntVector );
vecCmp8 = vec_and( vecCmp8, oneIntVector );
vecBitShifted1 = vec_sl( (vector unsigned int)vecCmp1, vecShift1 );
vecBitShifted2 = vec_sl( (vector unsigned int)vecCmp2, vecShift2 );
vecBitShifted3 = vec_sl( (vector unsigned int)vecCmp3, vecShift1 );
vecBitShifted4 = vec_sl( (vector unsigned int)vecCmp4, vecShift2 );
vecBitShifted5 = vec_sl( (vector unsigned int)vecCmp5, vecShift1 );
vecBitShifted6 = vec_sl( (vector unsigned int)vecCmp6, vecShift2 );
vecBitShifted7 = vec_sl( (vector unsigned int)vecCmp7, vecShift1 );
vecBitShifted8 = vec_sl( (vector unsigned int)vecCmp8, vecShift2 );
// OR (add) them all together
vecBitShifted1 = vec_add( vecBitShifted1, vecBitShifted2 );
vecBitShifted3 = vec_add( vecBitShifted3, vecBitShifted4 );
vecBitShifted5 = vec_add( vecBitShifted5, vecBitShifted6 );
vecBitShifted7 = vec_add( vecBitShifted7, vecBitShifted8 );
vecTotals = vec_add( vecBitShifted1, vec_sld( vecBitShifted1, vecBitShifted1, 8 ) );
vecTotals = vec_add( vecTotals, vec_sld( vecTotals, vecTotals, 4 ) );
tempIntSum = vec_add( vecBitShifted3, vec_sld( vecBitShifted3, vecBitShifted3, 8 ) );
tempIntSum = vec_add( tempIntSum, vec_sld( tempIntSum, tempIntSum, 4 ) );
vecTotals = vec_mergeh( vecTotals, tempIntSum );
tempIntSum = vec_add( vecBitShifted5, vec_sld( vecBitShifted5, vecBitShifted5, 8 ) );
tempIntSum = vec_add( tempIntSum, vec_sld( tempIntSum, tempIntSum, 4 ) );
vecTotals = vec_perm( vecTotals, tempIntSum, vecPermHalves );
tempIntSum = vec_add( vecBitShifted7, vec_sld( vecBitShifted7, vecBitShifted7, 8 ) );
tempIntSum = vec_add( tempIntSum, vec_sld( tempIntSum, tempIntSum, 4 ) );
vecTotals = vec_perm( vecTotals, tempIntSum, vecPermLast );
// store out results
vector unsigned int tempSt = vec_xor( vecTotals, vecFlipBits );
tempSt = vec_perm( tempSt, tempSt, cullBitPerm );
vec_ste( tempSt, 0, &cullBitVal[0] );
vec_ste( tempSt, 4, &cullBitVal[0] );
vec_ste( tempSt, 8, &cullBitVal[0] );
vec_ste( tempSt, 12, &cullBitVal[0] );
tOr |= cullBitVal[0];
tOr |= cullBitVal[1];
tOr |= cullBitVal[2];
tOr |= cullBitVal[3];
cullBits[i] = cullBitVal[0];
cullBits[i+1] = cullBitVal[1];
cullBits[i+2] = cullBitVal[2];
cullBits[i+3] = cullBitVal[3];
}
// cleanup
for ( ; i < numVerts; i++ ) {
byte bits;
float d0, d1, d2, d3, t;
const idVec3 &v = verts[i].xyz;
d0 = planes[0].Distance( v );
d1 = planes[1].Distance( v );
d2 = planes[2].Distance( v );
d3 = planes[3].Distance( v );
t = d0 + radius;
bits = FLOATSIGNBITSET( t ) << 0;
t = d1 + radius;
bits |= FLOATSIGNBITSET( t ) << 1;
t = d2 + radius;
bits |= FLOATSIGNBITSET( t ) << 2;
t = d3 + radius;
bits |= FLOATSIGNBITSET( t ) << 3;
t = d0 - radius;
bits |= FLOATSIGNBITSET( t ) << 4;
t = d1 - radius;
bits |= FLOATSIGNBITSET( t ) << 5;
t = d2 - radius;
bits |= FLOATSIGNBITSET( t ) << 6;
t = d3 - radius;
bits |= FLOATSIGNBITSET( t ) << 7;
bits ^= 0x0F; // flip lower four bits
tOr |= bits;
cullBits[i] = bits;
}
totalOr = tOr;
}
#endif /* DRAWVERT_PADDED */
#ifndef DRAWVERT_PADDED
/*
============
idSIMD_AltiVec::DecalPointCull
============
*/
void VPCALL idSIMD_AltiVec::DecalPointCull( byte *cullBits, const idPlane *planes, const idDrawVert *verts, const int numVerts ) {
// idDrawVert size
assert( sizeof(idDrawVert) == DRAWVERT_OFFSET * sizeof(float) );
int i;
const float *planePtr = planes[0].ToFloatPtr();
vector float vecPlane0, vecPlane1, vecPlane2, vecPlane3, vecPlane4, vecPlane5, vecPlane6, vecPlane7;
vector float zeroVector = (vector float)(0.0);
vector unsigned char vecPerm;
vector float v0, v1, v2, v3, v4, v5, v6, v7;
vecPerm = vec_add( vec_lvsl( -1, planePtr ), (vector unsigned char)(1) );
// populate planes
v0 = vec_ld( 0, planePtr );
v1 = vec_ld( 15, planePtr );
vecPlane0 = vec_perm( v0, v1, vecPerm );
v2 = vec_ld( 0, planePtr + 4 );
v3 = vec_ld( 15, planePtr + 4 );
vecPlane1 = vec_perm( v2, v3, vecPerm );
v0 = vec_ld( 0, planePtr + 8 );
v1 = vec_ld( 15, planePtr + 8 );
vecPlane2 = vec_perm( v0, v1, vecPerm );
v2 = vec_ld( 0, planePtr + 12 );
v3 = vec_ld( 15, planePtr + 12 );
vecPlane3 = vec_perm( v2, v3, vecPerm );
v0 = vec_ld( 0, planePtr + 16 );
v1 = vec_ld( 15, planePtr + 16 );
vecPlane4 = vec_perm( v0, v1, vecPerm );
v2 = vec_ld( 0, planePtr + 20 );
v3 = vec_ld( 15, planePtr + 20 );
vecPlane5 = vec_perm( v2, v3, vecPerm );
// transpose
v0 = vec_mergeh( vecPlane0, vecPlane2 );
v1 = vec_mergeh( vecPlane1, vecPlane3 );
v2 = vec_mergel( vecPlane0, vecPlane2 );
v3 = vec_mergel( vecPlane1, vecPlane3 );
vecPlane0 = vec_mergeh( v0, v1 );
vecPlane1 = vec_mergel( v0, v1 );
vecPlane2 = vec_mergeh( v2, v3 );
vecPlane3 = vec_mergel( v2, v3 );
v0 = vec_mergeh( vecPlane4, zeroVector );
v1 = vec_mergeh( vecPlane5, zeroVector );
v2 = vec_mergel( vecPlane4, zeroVector );
v3 = vec_mergel( vecPlane5, zeroVector );
vecPlane4 = vec_mergeh( v0, v1 );
vecPlane5 = vec_mergel( v0, v1 );
vecPlane6 = vec_mergeh( v2, v3 );
vecPlane7 = vec_mergel( v2, v3 );
vector float vecXYZ1, vecXYZ2, vecXYZ3, vecXYZ4;
vector bool int oneIntVector = (vector bool int)(1);
vector float vec1Sum1, vec1Sum2, vec2Sum1, vec2Sum2, vec3Sum1, vec3Sum2, vec4Sum1, vec4Sum2;
vector unsigned int vecShift1 = (vector unsigned int)(0, 1, 2, 3 );
vector unsigned int vecShift2 = (vector unsigned int)(4, 5, 0, 0 );
vector bool int vecCmp1, vecCmp2, vecCmp3, vecCmp4, vecCmp5, vecCmp6, vecCmp7, vecCmp8;
vector unsigned int vecBitShifted1, vecBitShifted2, vecBitShifted3, vecBitShifted4;
vector unsigned int vecBitShifted5, vecBitShifted6, vecBitShifted7, vecBitShifted8;
vector unsigned int vecFlipBits = (vector unsigned int)( 0x3F, 0x3F, 0x3F, 0x3F );
vector unsigned int vecR1, vecR2, vecR3, vecR4;
vector unsigned char permHalves = (vector unsigned char)(0,1,2,3,4,5,6,7,16,17,18,19,20,21,22,23);
vector unsigned char vertPerm1, vertPerm2, vertPerm3, vertPerm4;
unsigned int vBits[4];
vector unsigned char vBitPerm = vec_lvsr( 0, &vBits[4] );
i = 0;
// every fourth one will have the same alignment. Make sure we've got enough here
if ( i+3 < numVerts ) {
vertPerm1 = vec_add( vec_lvsl( -1, (float*) verts[0].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vertPerm2 = vec_add( vec_lvsl( -1, (float*) verts[1].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vertPerm3 = vec_add( vec_lvsl( -1, (float*) verts[2].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vertPerm4 = vec_add( vec_lvsl( -1, (float*) verts[3].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
}
for ( ; i+3 < numVerts; i+=4 ) {
const float *vertPtr = verts[i].xyz.ToFloatPtr();
const float *vertPtr2 = verts[i+1].xyz.ToFloatPtr();
const float *vertPtr3 = verts[i+2].xyz.ToFloatPtr();
const float *vertPtr4 = verts[i+3].xyz.ToFloatPtr();
v0 = vec_ld( 0, vertPtr );
v1 = vec_ld( 15, vertPtr );
v2 = vec_ld( 0, vertPtr2 );
v3 = vec_ld( 15, vertPtr2 );
v4 = vec_ld( 0, vertPtr3 );
v5 = vec_ld( 15, vertPtr3 );
v6 = vec_ld( 0, vertPtr4 );
v7 = vec_ld( 15, vertPtr4 );
vecXYZ1 = vec_perm( v0, v1, vertPerm1 );
vecXYZ2 = vec_perm( v2, v3, vertPerm2 );
vecXYZ3 = vec_perm( v4, v5, vertPerm3 );
vecXYZ4 = vec_perm( v6, v7, vertPerm4 );
vec1Sum1 = vec_madd( vec_splat( vecXYZ1, 0 ), vecPlane0, zeroVector );
vec1Sum1 = vec_madd( vec_splat( vecXYZ1, 1 ), vecPlane1, vec1Sum1 );
vec1Sum1 = vec_madd( vec_splat( vecXYZ1, 2 ), vecPlane2, vec1Sum1 );
vec1Sum1 = vec_add( vec1Sum1, vecPlane3 );
vec1Sum2 = vec_madd( vec_splat( vecXYZ1, 0 ), vecPlane4, zeroVector );
vec1Sum2 = vec_madd( vec_splat( vecXYZ1, 1 ), vecPlane5, vec1Sum2 );
vec1Sum2 = vec_madd( vec_splat( vecXYZ1, 2 ), vecPlane6, vec1Sum2 );
vec1Sum2 = vec_add( vec1Sum2, vecPlane7 );
vec2Sum1 = vec_madd( vec_splat( vecXYZ2, 0 ), vecPlane0, zeroVector );
vec2Sum1 = vec_madd( vec_splat( vecXYZ2, 1 ), vecPlane1, vec2Sum1 );
vec2Sum1 = vec_madd( vec_splat( vecXYZ2, 2 ), vecPlane2, vec2Sum1 );
vec2Sum1 = vec_add( vec2Sum1, vecPlane3 );
vec2Sum2 = vec_madd( vec_splat( vecXYZ2, 0 ), vecPlane4, zeroVector );
vec2Sum2 = vec_madd( vec_splat( vecXYZ2, 1 ), vecPlane5, vec2Sum2 );
vec2Sum2 = vec_madd( vec_splat( vecXYZ2, 2 ), vecPlane6, vec2Sum2 );
vec2Sum2 = vec_add( vec2Sum2, vecPlane7 );
vec3Sum1 = vec_madd( vec_splat( vecXYZ3, 0 ), vecPlane0, zeroVector );
vec3Sum1 = vec_madd( vec_splat( vecXYZ3, 1 ), vecPlane1, vec3Sum1 );
vec3Sum1 = vec_madd( vec_splat( vecXYZ3, 2 ), vecPlane2, vec3Sum1 );
vec3Sum1 = vec_add( vec3Sum1, vecPlane3 );
vec3Sum2 = vec_madd( vec_splat( vecXYZ3, 0 ), vecPlane4, zeroVector );
vec3Sum2 = vec_madd( vec_splat( vecXYZ3, 1 ), vecPlane5, vec3Sum2 );
vec3Sum2 = vec_madd( vec_splat( vecXYZ3, 2 ), vecPlane6, vec3Sum2 );
vec3Sum2 = vec_add( vec3Sum2, vecPlane7 );
vec4Sum1 = vec_madd( vec_splat( vecXYZ4, 0 ), vecPlane0, zeroVector );
vec4Sum1 = vec_madd( vec_splat( vecXYZ4, 1 ), vecPlane1, vec4Sum1 );
vec4Sum1 = vec_madd( vec_splat( vecXYZ4, 2 ), vecPlane2, vec4Sum1 );
vec4Sum1 = vec_add( vec4Sum1, vecPlane3 );
vec4Sum2 = vec_madd( vec_splat( vecXYZ4, 0 ), vecPlane4, zeroVector );
vec4Sum2 = vec_madd( vec_splat( vecXYZ4, 1 ), vecPlane5, vec4Sum2 );
vec4Sum2 = vec_madd( vec_splat( vecXYZ4, 2 ), vecPlane6, vec4Sum2 );
vec4Sum2 = vec_add( vec4Sum2, vecPlane7 );
vecCmp1 = vec_cmplt( vec1Sum1, zeroVector );
vecCmp2 = vec_cmplt( vec1Sum2, zeroVector );
vecCmp3 = vec_cmplt( vec2Sum1, zeroVector );
vecCmp4 = vec_cmplt( vec2Sum2, zeroVector );
vecCmp5 = vec_cmplt( vec3Sum1, zeroVector );
vecCmp6 = vec_cmplt( vec3Sum2, zeroVector );
vecCmp7 = vec_cmplt( vec4Sum1, zeroVector );
vecCmp8 = vec_cmplt( vec4Sum2, zeroVector );
//and it with 1 so we multiply by 1 not 1111's
vecCmp1 = vec_and( vecCmp1, oneIntVector );
vecCmp2 = vec_and( vecCmp2, oneIntVector );
vecCmp3 = vec_and( vecCmp3, oneIntVector );
vecCmp4 = vec_and( vecCmp4, oneIntVector );
vecCmp5 = vec_and( vecCmp5, oneIntVector );
vecCmp6 = vec_and( vecCmp6, oneIntVector );
vecCmp7 = vec_and( vecCmp7, oneIntVector );
vecCmp8 = vec_and( vecCmp8, oneIntVector );
vecBitShifted1 = vec_sl( (vector unsigned int)vecCmp1, vecShift1 );
vecBitShifted2 = vec_sl( (vector unsigned int)vecCmp2, vecShift2 );
vecBitShifted3 = vec_sl( (vector unsigned int)vecCmp3, vecShift1 );
vecBitShifted4 = vec_sl( (vector unsigned int)vecCmp4, vecShift2 );
vecBitShifted5 = vec_sl( (vector unsigned int)vecCmp5, vecShift1 );
vecBitShifted6 = vec_sl( (vector unsigned int)vecCmp6, vecShift2 );
vecBitShifted7 = vec_sl( (vector unsigned int)vecCmp7, vecShift1 );
vecBitShifted8 = vec_sl( (vector unsigned int)vecCmp8, vecShift2 );
//OR them all together (this is the same as adding them, since they're all only 1 bit set)
vecR1 = (vector unsigned int)(0); //zeroIntVector;
vecR1 = vec_add( vecBitShifted1, vec_sld( vecBitShifted1, vecBitShifted1, 8 ) );
vecR1 = vec_add( vecR1, vec_sld( vecR1, vecR1, 4 ) );
vecR1 = vec_add(vecR1, vecBitShifted2 );
vecR1 = vec_or( vecR1, vec_sld( vecBitShifted2, vecBitShifted2, 4 ) );
vecR2 = (vector unsigned int)(0); //zeroIntVector;
vecR2 = vec_add( vecBitShifted3, vec_sld( vecBitShifted3, vecBitShifted3, 8 ) );
vecR2 = vec_add( vecR2, vec_sld( vecR2, vecR2, 4 ) );
vecR2 = vec_add(vecR2, vecBitShifted4 );
vecR2 = vec_or( vecR2, vec_sld( vecBitShifted4, vecBitShifted4, 4 ) );
vecR3 = (vector unsigned int)(0); //zeroIntVector;
vecR3 = vec_add( vecBitShifted5, vec_sld( vecBitShifted5, vecBitShifted5, 8 ) );
vecR3 = vec_add( vecR3, vec_sld( vecR3, vecR3, 4 ) );
vecR3 = vec_add(vecR3, vecBitShifted6 );
vecR3 = vec_or( vecR3, vec_sld( vecBitShifted6, vecBitShifted6, 4 ) );
vecR4 = (vector unsigned int)(0); //zeroIntVector;
vecR4 = vec_add( vecBitShifted7, vec_sld( vecBitShifted7, vecBitShifted7, 8 ) );
vecR4 = vec_add( vecR4, vec_sld( vecR4, vecR4, 4 ) );
vecR4 = vec_add(vecR4, vecBitShifted8 );
vecR4 = vec_or( vecR4, vec_sld( vecBitShifted8, vecBitShifted8, 4 ) );
// take the first element from each vector and put them into vecR1
vecR1 = vec_mergeh( vecR1, vecR2 );
vecR3 = vec_mergeh( vecR3, vecR4 );
vecR1 = vec_perm( vecR1, vecR3, permHalves );
// XOR with 0x3F to flip lower 6 bits
vecR1 = vec_xor( vecR1, vecFlipBits );
// store out results. don't have 16 at a time so let's just
// do this and avoid alignment concerns
vecR1 = vec_perm( vecR1, vecR1, vBitPerm );
vec_ste( vecR1, 0, &vBits[0] );
vec_ste( vecR1, 4, &vBits[0] );
vec_ste( vecR1, 8, &vBits[0] );
vec_ste( vecR1, 12, &vBits[0] );
cullBits[i] = vBits[0];
cullBits[i+1] = vBits[1];
cullBits[i+2] = vBits[2];
cullBits[i+3] = vBits[3];
}
for ( ; i < numVerts; i++ ) {
byte bits;
float d0, d1, d2, d3, d4, d5;
const idVec3 &v = verts[i].xyz;
d0 = planes[0].Distance( v );
d1 = planes[1].Distance( v );
d2 = planes[2].Distance( v );
d3 = planes[3].Distance( v );
d4 = planes[4].Distance( v );
d5 = planes[5].Distance( v );
// they check if the sign bit is set by casting as long and shifting right 31 places.
bits = FLOATSIGNBITSET( d0 ) << 0;
bits |= FLOATSIGNBITSET( d1 ) << 1;
bits |= FLOATSIGNBITSET( d2 ) << 2;
bits |= FLOATSIGNBITSET( d3 ) << 3;
bits |= FLOATSIGNBITSET( d4 ) << 4;
bits |= FLOATSIGNBITSET( d5 ) << 5;
cullBits[i] = bits ^ 0x3F; // flip lower 6 bits
}
}
#else
/*
============
idSIMD_AltiVec::DecalPointCull
============
*/
void VPCALL idSIMD_AltiVec::DecalPointCull( byte *cullBits, const idPlane *planes, const idDrawVert *verts, const int numVerts ) {
// idDrawVert size
assert( sizeof(idDrawVert) == DRAWVERT_OFFSET * sizeof(float) );
int i;
const float *planePtr = planes[0].ToFloatPtr();
vector float vecPlane0, vecPlane1, vecPlane2, vecPlane3, vecPlane4, vecPlane5, vecPlane6, vecPlane7;
vector float zeroVector = (vector float)(0.0);
vector unsigned char vecPerm;
vector float v0, v1, v2, v3, v4, v5, v6, v7;
vecPerm = vec_add( vec_lvsl( -1, planePtr ), (vector unsigned char)(1) );
// populate planes
v0 = vec_ld( 0, planePtr );
v1 = vec_ld( 15, planePtr );
vecPlane0 = vec_perm( v0, v1, vecPerm );
v2 = vec_ld( 0, planePtr + 4 );
v3 = vec_ld( 15, planePtr + 4 );
vecPlane1 = vec_perm( v2, v3, vecPerm );
v0 = vec_ld( 0, planePtr + 8 );
v1 = vec_ld( 15, planePtr + 8 );
vecPlane2 = vec_perm( v0, v1, vecPerm );
v2 = vec_ld( 0, planePtr + 12 );
v3 = vec_ld( 15, planePtr + 12 );
vecPlane3 = vec_perm( v2, v3, vecPerm );
v0 = vec_ld( 0, planePtr + 16 );
v1 = vec_ld( 15, planePtr + 16 );
vecPlane4 = vec_perm( v0, v1, vecPerm );
v2 = vec_ld( 0, planePtr + 20 );
v3 = vec_ld( 15, planePtr + 20 );
vecPlane5 = vec_perm( v2, v3, vecPerm );
// transpose
v0 = vec_mergeh( vecPlane0, vecPlane2 );
v1 = vec_mergeh( vecPlane1, vecPlane3 );
v2 = vec_mergel( vecPlane0, vecPlane2 );
v3 = vec_mergel( vecPlane1, vecPlane3 );
vecPlane0 = vec_mergeh( v0, v1 );
vecPlane1 = vec_mergel( v0, v1 );
vecPlane2 = vec_mergeh( v2, v3 );
vecPlane3 = vec_mergel( v2, v3 );
v0 = vec_mergeh( vecPlane4, zeroVector );
v1 = vec_mergeh( vecPlane5, zeroVector );
v2 = vec_mergel( vecPlane4, zeroVector );
v3 = vec_mergel( vecPlane5, zeroVector );
vecPlane4 = vec_mergeh( v0, v1 );
vecPlane5 = vec_mergel( v0, v1 );
vecPlane6 = vec_mergeh( v2, v3 );
vecPlane7 = vec_mergel( v2, v3 );
vector float vecXYZ1, vecXYZ2, vecXYZ3, vecXYZ4;
vector bool int oneIntVector = (vector bool int)(1);
vector float vec1Sum1, vec1Sum2, vec2Sum1, vec2Sum2, vec3Sum1, vec3Sum2, vec4Sum1, vec4Sum2;
vector unsigned int vecShift1 = (vector unsigned int)(0, 1, 2, 3 );
vector unsigned int vecShift2 = (vector unsigned int)(4, 5, 0, 0 );
vector bool int vecCmp1, vecCmp2, vecCmp3, vecCmp4, vecCmp5, vecCmp6, vecCmp7, vecCmp8;
vector unsigned int vecBitShifted1, vecBitShifted2, vecBitShifted3, vecBitShifted4;
vector unsigned int vecBitShifted5, vecBitShifted6, vecBitShifted7, vecBitShifted8;
vector unsigned int vecFlipBits = (vector unsigned int)( 0x3F, 0x3F, 0x3F, 0x3F );
vector unsigned int vecR1, vecR2, vecR3, vecR4;
vector unsigned char permHalves = (vector unsigned char)(0,1,2,3,4,5,6,7,16,17,18,19,20,21,22,23);
vector unsigned char vertPerm1, vertPerm2, vertPerm3, vertPerm4;
unsigned int vBits[4];
vector unsigned char vBitPerm = vec_lvsr( 0, &vBits[4] );
i = 0;
for ( ; i+3 < numVerts; i+=4 ) {
const float *vertPtr = verts[i].xyz.ToFloatPtr();
const float *vertPtr2 = verts[i+1].xyz.ToFloatPtr();
const float *vertPtr3 = verts[i+2].xyz.ToFloatPtr();
const float *vertPtr4 = verts[i+3].xyz.ToFloatPtr();
v0 = vec_ld( 0, vertPtr );
v2 = vec_ld( 0, vertPtr2 );
v4 = vec_ld( 0, vertPtr3 );
v6 = vec_ld( 0, vertPtr4 );
vec1Sum1 = vec_madd( vec_splat( vecXYZ1, 0 ), vecPlane0, zeroVector );
vec1Sum1 = vec_madd( vec_splat( vecXYZ1, 1 ), vecPlane1, vec1Sum1 );
vec1Sum1 = vec_madd( vec_splat( vecXYZ1, 2 ), vecPlane2, vec1Sum1 );
vec1Sum1 = vec_add( vec1Sum1, vecPlane3 );
vec1Sum2 = vec_madd( vec_splat( vecXYZ1, 0 ), vecPlane4, zeroVector );
vec1Sum2 = vec_madd( vec_splat( vecXYZ1, 1 ), vecPlane5, vec1Sum2 );
vec1Sum2 = vec_madd( vec_splat( vecXYZ1, 2 ), vecPlane6, vec1Sum2 );
vec1Sum2 = vec_add( vec1Sum2, vecPlane7 );
vec2Sum1 = vec_madd( vec_splat( vecXYZ2, 0 ), vecPlane0, zeroVector );
vec2Sum1 = vec_madd( vec_splat( vecXYZ2, 1 ), vecPlane1, vec2Sum1 );
vec2Sum1 = vec_madd( vec_splat( vecXYZ2, 2 ), vecPlane2, vec2Sum1 );
vec2Sum1 = vec_add( vec2Sum1, vecPlane3 );
vec2Sum2 = vec_madd( vec_splat( vecXYZ2, 0 ), vecPlane4, zeroVector );
vec2Sum2 = vec_madd( vec_splat( vecXYZ2, 1 ), vecPlane5, vec2Sum2 );
vec2Sum2 = vec_madd( vec_splat( vecXYZ2, 2 ), vecPlane6, vec2Sum2 );
vec2Sum2 = vec_add( vec2Sum2, vecPlane7 );
vec3Sum1 = vec_madd( vec_splat( vecXYZ3, 0 ), vecPlane0, zeroVector );
vec3Sum1 = vec_madd( vec_splat( vecXYZ3, 1 ), vecPlane1, vec3Sum1 );
vec3Sum1 = vec_madd( vec_splat( vecXYZ3, 2 ), vecPlane2, vec3Sum1 );
vec3Sum1 = vec_add( vec3Sum1, vecPlane3 );
vec3Sum2 = vec_madd( vec_splat( vecXYZ3, 0 ), vecPlane4, zeroVector );
vec3Sum2 = vec_madd( vec_splat( vecXYZ3, 1 ), vecPlane5, vec3Sum2 );
vec3Sum2 = vec_madd( vec_splat( vecXYZ3, 2 ), vecPlane6, vec3Sum2 );
vec3Sum2 = vec_add( vec3Sum2, vecPlane7 );
vec4Sum1 = vec_madd( vec_splat( vecXYZ4, 0 ), vecPlane0, zeroVector );
vec4Sum1 = vec_madd( vec_splat( vecXYZ4, 1 ), vecPlane1, vec4Sum1 );
vec4Sum1 = vec_madd( vec_splat( vecXYZ4, 2 ), vecPlane2, vec4Sum1 );
vec4Sum1 = vec_add( vec4Sum1, vecPlane3 );
vec4Sum2 = vec_madd( vec_splat( vecXYZ4, 0 ), vecPlane4, zeroVector );
vec4Sum2 = vec_madd( vec_splat( vecXYZ4, 1 ), vecPlane5, vec4Sum2 );
vec4Sum2 = vec_madd( vec_splat( vecXYZ4, 2 ), vecPlane6, vec4Sum2 );
vec4Sum2 = vec_add( vec4Sum2, vecPlane7 );
vecCmp1 = vec_cmplt( vec1Sum1, zeroVector );
vecCmp2 = vec_cmplt( vec1Sum2, zeroVector );
vecCmp3 = vec_cmplt( vec2Sum1, zeroVector );
vecCmp4 = vec_cmplt( vec2Sum2, zeroVector );
vecCmp5 = vec_cmplt( vec3Sum1, zeroVector );
vecCmp6 = vec_cmplt( vec3Sum2, zeroVector );
vecCmp7 = vec_cmplt( vec4Sum1, zeroVector );
vecCmp8 = vec_cmplt( vec4Sum2, zeroVector );
//and it with 1 so we multiply by 1 not 1111's
vecCmp1 = vec_and( vecCmp1, oneIntVector );
vecCmp2 = vec_and( vecCmp2, oneIntVector );
vecCmp3 = vec_and( vecCmp3, oneIntVector );
vecCmp4 = vec_and( vecCmp4, oneIntVector );
vecCmp5 = vec_and( vecCmp5, oneIntVector );
vecCmp6 = vec_and( vecCmp6, oneIntVector );
vecCmp7 = vec_and( vecCmp7, oneIntVector );
vecCmp8 = vec_and( vecCmp8, oneIntVector );
vecBitShifted1 = vec_sl( (vector unsigned int)vecCmp1, vecShift1 );
vecBitShifted2 = vec_sl( (vector unsigned int)vecCmp2, vecShift2 );
vecBitShifted3 = vec_sl( (vector unsigned int)vecCmp3, vecShift1 );
vecBitShifted4 = vec_sl( (vector unsigned int)vecCmp4, vecShift2 );
vecBitShifted5 = vec_sl( (vector unsigned int)vecCmp5, vecShift1 );
vecBitShifted6 = vec_sl( (vector unsigned int)vecCmp6, vecShift2 );
vecBitShifted7 = vec_sl( (vector unsigned int)vecCmp7, vecShift1 );
vecBitShifted8 = vec_sl( (vector unsigned int)vecCmp8, vecShift2 );
//OR them all together (this is the same as adding them, since they're all only 1 bit set)
vecR1 = (vector unsigned int)(0); //zeroIntVector;
vecR1 = vec_add( vecBitShifted1, vec_sld( vecBitShifted1, vecBitShifted1, 8 ) );
vecR1 = vec_add( vecR1, vec_sld( vecR1, vecR1, 4 ) );
vecR1 = vec_add(vecR1, vecBitShifted2 );
vecR1 = vec_or( vecR1, vec_sld( vecBitShifted2, vecBitShifted2, 4 ) );
vecR2 = (vector unsigned int)(0); //zeroIntVector;
vecR2 = vec_add( vecBitShifted3, vec_sld( vecBitShifted3, vecBitShifted3, 8 ) );
vecR2 = vec_add( vecR2, vec_sld( vecR2, vecR2, 4 ) );
vecR2 = vec_add(vecR2, vecBitShifted4 );
vecR2 = vec_or( vecR2, vec_sld( vecBitShifted4, vecBitShifted4, 4 ) );
vecR3 = (vector unsigned int)(0); //zeroIntVector;
vecR3 = vec_add( vecBitShifted5, vec_sld( vecBitShifted5, vecBitShifted5, 8 ) );
vecR3 = vec_add( vecR3, vec_sld( vecR3, vecR3, 4 ) );
vecR3 = vec_add(vecR3, vecBitShifted6 );
vecR3 = vec_or( vecR3, vec_sld( vecBitShifted6, vecBitShifted6, 4 ) );
vecR4 = (vector unsigned int)(0); //zeroIntVector;
vecR4 = vec_add( vecBitShifted7, vec_sld( vecBitShifted7, vecBitShifted7, 8 ) );
vecR4 = vec_add( vecR4, vec_sld( vecR4, vecR4, 4 ) );
vecR4 = vec_add(vecR4, vecBitShifted8 );
vecR4 = vec_or( vecR4, vec_sld( vecBitShifted8, vecBitShifted8, 4 ) );
// take the first element from each vector and put them into vecR1
vecR1 = vec_mergeh( vecR1, vecR2 );
vecR3 = vec_mergeh( vecR3, vecR4 );
vecR1 = vec_perm( vecR1, vecR3, permHalves );
// XOR with 0x3F to flip lower 6 bits
vecR1 = vec_xor( vecR1, vecFlipBits );
// store out results. don't have 16 at a time so let's just
// do this and avoid alignment concerns
vecR1 = vec_perm( vecR1, vecR1, vBitPerm );
vec_ste( vecR1, 0, &vBits[0] );
vec_ste( vecR1, 4, &vBits[0] );
vec_ste( vecR1, 8, &vBits[0] );
vec_ste( vecR1, 12, &vBits[0] );
cullBits[i] = vBits[0];
cullBits[i+1] = vBits[1];
cullBits[i+2] = vBits[2];
cullBits[i+3] = vBits[3];
}
for ( ; i < numVerts; i++ ) {
byte bits;
float d0, d1, d2, d3, d4, d5;
const idVec3 &v = verts[i].xyz;
d0 = planes[0].Distance( v );
d1 = planes[1].Distance( v );
d2 = planes[2].Distance( v );
d3 = planes[3].Distance( v );
d4 = planes[4].Distance( v );
d5 = planes[5].Distance( v );
// they check if the sign bit is set by casting as long and shifting right 31 places.
bits = FLOATSIGNBITSET( d0 ) << 0;
bits |= FLOATSIGNBITSET( d1 ) << 1;
bits |= FLOATSIGNBITSET( d2 ) << 2;
bits |= FLOATSIGNBITSET( d3 ) << 3;
bits |= FLOATSIGNBITSET( d4 ) << 4;
bits |= FLOATSIGNBITSET( d5 ) << 5;
cullBits[i] = bits ^ 0x3F; // flip lower 6 bits
}
}
#endif /*DRAWVERT_PADDED */
#ifndef DRAWVERT_PADDED
/*
============
idSIMD_AltiVec::OverlayPointCull
============
*/
void VPCALL idSIMD_AltiVec::OverlayPointCull( byte *cullBits, idVec2 *texCoords, const idPlane *planes, const idDrawVert *verts, const int numVerts ) {
// idDrawVert size
assert( sizeof(idDrawVert) == DRAWVERT_OFFSET * sizeof(float) );
int i;
float p0x, p0y, p0z, p0d;
float p1x, p1y, p1z, p1d;
const float *planePtr = planes[0].ToFloatPtr();
const float *vertPtr = verts[0].xyz.ToFloatPtr();
vector float vecPlane0, vecPlane1, vecPlane2, vecPlane3;
vector float v0, v1, v2, v3, v4, v5, v6, v7;
vector unsigned char vecPerm;
vector float zeroVector = (vector float)(0);
p0x = *(planePtr + 0);
p0y = *(planePtr + 1);
p0z = *(planePtr + 2);
p0d = *(planePtr + 3);
p1x = *(planePtr + 4);
p1y = *(planePtr + 5);
p1z = *(planePtr + 6);
p1d = *(planePtr + 7);
// populate the planes
vecPerm = vec_add( vec_lvsl( -1, planePtr ), (vector unsigned char)(1) );
v0 = vec_ld( 0, planePtr );
v1 = vec_ld( 15, planePtr );
vecPlane0 = vec_perm( v0, v1, vecPerm );
v2 = vec_ld( 31, planePtr );
vecPlane1 = vec_perm( v1, v2, vecPerm );
// transpose
v0 = vec_mergeh( vecPlane0, vecPlane0 );
v1 = vec_mergeh( vecPlane1, vecPlane1 );
v2 = vec_mergel( vecPlane0, vecPlane0 );
v3 = vec_mergel( vecPlane1, vecPlane1);
vecPlane0 = vec_mergeh( v0, v1 );
vecPlane1 = vec_mergel( v0, v1 );
vecPlane2 = vec_mergeh( v2, v3 );
vecPlane3 = vec_mergel( v2, v3 );
vector float vecXYZ1, vecXYZ2, vecXYZ3, vecXYZ4;
vector float oneVector = (vector float)(1);
vector float vecSum1, vecSum2, vecSum1Inv,vecSum2Inv;
vector bool int vecCmp1, vecCmp2, vecCmp1Inv, vecCmp2Inv;
vector float negTwoVector = (vector float)(-2);
vector unsigned int vecBitShifted1, vecBitShifted2, vecBitShifted1Inv, vecBitShifted2Inv;
vector unsigned int vecShift = (vector unsigned int)( 0, 1, 0, 1 );
vector unsigned int vecShiftInv = (vector unsigned int)( 2, 3, 2, 3 );
vector unsigned char vecPermFirstThird = (vector unsigned char)(0,1,2,3,8,9,10,11,16,17,18,19,24,25,26,27);
vector bool int oneIntVector = (vector bool int)(1);
vector unsigned char vertPerm1, vertPerm2, vertPerm3, vertPerm4;
unsigned int cullBitVal[4];
vector unsigned char cullBitPerm = vec_lvsr( 0, &cullBitVal[0] );
i = 0;
// every fourth one will have the same alignment. Make sure we've got enough here
if ( i+3 < numVerts ) {
vertPerm1 = vec_add( vec_lvsl( -1, (float*) verts[0].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vertPerm2 = vec_add( vec_lvsl( -1, (float*) verts[1].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vertPerm3 = vec_add( vec_lvsl( -1, (float*) verts[2].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vertPerm4 = vec_add( vec_lvsl( -1, (float*) verts[3].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
}
for ( ; i+3 < numVerts; i+=4 ) {
const float *vertPtr = verts[i].xyz.ToFloatPtr();
const float *vertPtr2 = verts[i+1].xyz.ToFloatPtr();
const float *vertPtr3 = verts[i+2].xyz.ToFloatPtr();
const float *vertPtr4 = verts[i+3].xyz.ToFloatPtr();
v0 = vec_ld( 0, vertPtr );
v1 = vec_ld( 15, vertPtr );
v2 = vec_ld( 0, vertPtr2 );
v3 = vec_ld( 15, vertPtr2 );
v4 = vec_ld( 0, vertPtr3 );
v5 = vec_ld( 15, vertPtr3 );
v6 = vec_ld( 0, vertPtr4 );
v7 = vec_ld( 15, vertPtr4 );
vecXYZ1 = vec_perm( v0, v1, vertPerm1 );
vecXYZ2 = vec_perm( v2, v3, vertPerm2 );
vecXYZ3 = vec_perm( v4, v5, vertPerm3 );
vecXYZ4 = vec_perm( v6, v7, vertPerm4 );
// like a splat, but only doing halves
vecSum1 = vec_madd( vec_perm( vecXYZ1, vecXYZ2, (vector unsigned char)(0,1,2,3,0,1,2,3,16,17,18,19,16,17,18,19) ), vecPlane0, zeroVector );
vecSum1 = vec_madd( vec_perm( vecXYZ1, vecXYZ2, (vector unsigned char)(4,5,6,7,4,5,6,7,20,21,22,23,20,21,22,23) ) , vecPlane1, vecSum1 );
vecSum1 = vec_madd( vec_perm( vecXYZ1, vecXYZ2, (vector unsigned char)(8,9,10,11,8,9,10,11,24,25,26,27,24,25,26,27) ), vecPlane2, vecSum1 );
vecSum1 = vec_add( vecSum1, vecPlane3 );
vecSum2 = vec_madd( vec_perm( vecXYZ3, vecXYZ4, (vector unsigned char)(0,1,2,3,0,1,2,3,16,17,18,19,16,17,18,19) ), vecPlane0, zeroVector );
vecSum2 = vec_madd( vec_perm( vecXYZ3, vecXYZ4, (vector unsigned char)(4,5,6,7,4,5,6,7,20,21,22,23,20,21,22,23) ) , vecPlane1, vecSum2 );
vecSum2 = vec_madd( vec_perm( vecXYZ3, vecXYZ4, (vector unsigned char)(8,9,10,11,8,9,10,11,24,25,26,27,24,25,26,27) ), vecPlane2, vecSum2 );
vecSum2 = vec_add( vecSum2, vecPlane3 );
// store out results
UNALIGNED_STORE2( &texCoords[i][0], vecSum1, vecSum2 );
// bit manipulation
vecCmp1 = vec_cmplt( vecSum1, zeroVector );
vecCmp2 = vec_cmplt( vecSum2, zeroVector );
//and it with 1 so we multiply by 1 not 1111's
vecCmp1 = vec_and( vecCmp1, oneIntVector );
vecCmp2 = vec_and( vecCmp2, oneIntVector );
// store out and write to cullBits
// finally, a use for algebra! 1-x = x + 1 - 2x
vecSum1Inv = vec_madd( vecSum1, negTwoVector, vecSum1 );
vecSum2Inv = vec_madd( vecSum2, negTwoVector, vecSum2 );
vecSum1Inv = vec_add( vecSum1Inv, oneVector );
vecSum2Inv = vec_add( vecSum2Inv, oneVector );
// do the same comparisons for the inverted d0/d1
vecCmp1Inv = vec_cmplt( vecSum1Inv, zeroVector );
vecCmp2Inv = vec_cmplt( vecSum2Inv, zeroVector );
//and it with 1 so we multiply by 1 not 1111's
vecCmp1Inv = vec_and( vecCmp1Inv, oneIntVector );
vecCmp2Inv = vec_and( vecCmp2Inv, oneIntVector );
// shift them as needed
vecBitShifted1 = vec_sl( (vector unsigned int)vecCmp1, vecShift );
vecBitShifted2 = vec_sl( (vector unsigned int)vecCmp2, vecShift );
vecBitShifted1Inv = vec_sl( (vector unsigned int)vecCmp1Inv, vecShiftInv );
vecBitShifted2Inv = vec_sl( (vector unsigned int)vecCmp2Inv, vecShiftInv );
// OR them all together. since only 1 bit is set for each value, thats
// the same as adding them. add up d0 + d1 + d0Inv + d1Inv
vector unsigned int vecResult;
vector unsigned int vecResult2;
vector unsigned int vecResult3;
vecResult = vec_add( vecBitShifted1, vec_sld( vecBitShifted1, vecBitShifted1, 4 ) );
vecResult2 = vec_add( vecBitShifted2, vec_sld( vecBitShifted2, vecBitShifted2, 4 ) );
// vecResult now holds the values without the inverses yet, so add those
vecResult = vec_perm( vecResult, vecResult2, vecPermFirstThird );
vecResult2 = vec_add( vecBitShifted1Inv, vec_sld( vecBitShifted1Inv, vecBitShifted1Inv, 4 ) );
vecResult3 = vec_add( vecBitShifted2Inv, vec_sld( vecBitShifted2Inv, vecBitShifted2Inv, 4 ) );
vecResult2 = vec_perm( vecResult2, vecResult3, vecPermFirstThird );
vecResult = vec_add( vecResult, vecResult2 );
//store out results
vecResult = vec_perm( vecResult, vecResult, cullBitPerm );
vec_ste( vecResult, 0, &cullBitVal[0] );
vec_ste( vecResult, 4, &cullBitVal[0] );
vec_ste( vecResult, 8, &cullBitVal[0] );
vec_ste( vecResult, 12, &cullBitVal[0] );
cullBits[i] = cullBitVal[0];
cullBits[i+1] = cullBitVal[1];
cullBits[i+2] = cullBitVal[2];
cullBits[i+3] = cullBitVal[3];
}
// cleanup
for ( ; i < numVerts; i++ ) {
byte bits;
float d0, d1;
float vx, vy, vz;
vx = *( vertPtr + (i*DRAWVERT_OFFSET) + 0 );
vy = *( vertPtr + (i*DRAWVERT_OFFSET) + 1 );
vz = *( vertPtr + (i*DRAWVERT_OFFSET) + 2 );
d0 = p0x * vx + p0y * vy + p0z * vz + p0d;
d1 = p1x * vx + p1y * vy + p1z * vz + p1d;
texCoords[i][0] = d0;
texCoords[i][1] = d1;
bits = ( d0 >= 0 ) ? 0 : 1;
d0 = 1.0f - d0;
bits |= ( d1 >= 0 ) ? 0 : 1*2;
d1 = 1.0f - d1;
bits |= ( d0 >= 0 ) ? 0: 1*4;
bits |= ( d1 >= 0 ) ? 0: 1*8;
cullBits[i] = bits;
}
}
#else
/*
============
idSIMD_AltiVec::OverlayPointCull
============
*/
void VPCALL idSIMD_AltiVec::OverlayPointCull( byte *cullBits, idVec2 *texCoords, const idPlane *planes, const idDrawVert *verts, const int numVerts ) {
// idDrawVert size
assert( sizeof(idDrawVert) == DRAWVERT_OFFSET * sizeof(float) );
int i;
float p0x, p0y, p0z, p0d;
float p1x, p1y, p1z, p1d;
const float *planePtr = planes[0].ToFloatPtr();
const float *vertPtr = verts[0].xyz.ToFloatPtr();
vector float vecPlane0, vecPlane1, vecPlane2, vecPlane3;
vector float v0, v1, v2, v3, v4, v5, v6, v7;
vector unsigned char vecPerm;
vector float zeroVector = (vector float)(0);
p0x = *(planePtr + 0);
p0y = *(planePtr + 1);
p0z = *(planePtr + 2);
p0d = *(planePtr + 3);
p1x = *(planePtr + 4);
p1y = *(planePtr + 5);
p1z = *(planePtr + 6);
p1d = *(planePtr + 7);
// populate the planes
vecPerm = vec_add( vec_lvsl( -1, planePtr ), (vector unsigned char)(1) );
v0 = vec_ld( 0, planePtr );
v1 = vec_ld( 15, planePtr );
vecPlane0 = vec_perm( v0, v1, vecPerm );
v2 = vec_ld( 31, planePtr );
vecPlane1 = vec_perm( v1, v2, vecPerm );
// transpose
v0 = vec_mergeh( vecPlane0, vecPlane0 );
v1 = vec_mergeh( vecPlane1, vecPlane1 );
v2 = vec_mergel( vecPlane0, vecPlane0 );
v3 = vec_mergel( vecPlane1, vecPlane1);
vecPlane0 = vec_mergeh( v0, v1 );
vecPlane1 = vec_mergel( v0, v1 );
vecPlane2 = vec_mergeh( v2, v3 );
vecPlane3 = vec_mergel( v2, v3 );
vector float vecXYZ1, vecXYZ2, vecXYZ3, vecXYZ4;
vector float oneVector = (vector float)(1);
vector float vecSum1, vecSum2, vecSum1Inv,vecSum2Inv;
vector bool int vecCmp1, vecCmp2, vecCmp1Inv, vecCmp2Inv;
vector float negTwoVector = (vector float)(-2);
vector unsigned int vecBitShifted1, vecBitShifted2, vecBitShifted1Inv, vecBitShifted2Inv;
vector unsigned int vecShift = (vector unsigned int)( 0, 1, 0, 1 );
vector unsigned int vecShiftInv = (vector unsigned int)( 2, 3, 2, 3 );
vector unsigned char vecPermFirstThird = (vector unsigned char)(0,1,2,3,8,9,10,11,16,17,18,19,24,25,26,27);
vector bool int oneIntVector = (vector bool int)(1);
vector unsigned char vertPerm1, vertPerm2, vertPerm3, vertPerm4;
unsigned int cullBitVal[4];
vector unsigned char cullBitPerm = vec_lvsr( 0, &cullBitVal[0] );
i = 0;
for ( ; i+3 < numVerts; i+=4 ) {
const float *vertPtr = verts[i].xyz.ToFloatPtr();
const float *vertPtr2 = verts[i+1].xyz.ToFloatPtr();
const float *vertPtr3 = verts[i+2].xyz.ToFloatPtr();
const float *vertPtr4 = verts[i+3].xyz.ToFloatPtr();
vecXYZ1 = vec_ld( 0, vertPtr );
vecXYZ2 = vec_ld( 0, vertPtr2 );
vecXYZ3 = vec_ld( 0, vertPtr3 );
vecXYZ4 = vec_ld( 0, vertPtr4 );
// like a splat, but only doing halves
vecSum1 = vec_madd( vec_perm( vecXYZ1, vecXYZ2, (vector unsigned char)(0,1,2,3,0,1,2,3,16,17,18,19,16,17,18,19) ), vecPlane0, zeroVector );
vecSum1 = vec_madd( vec_perm( vecXYZ1, vecXYZ2, (vector unsigned char)(4,5,6,7,4,5,6,7,20,21,22,23,20,21,22,23) ) , vecPlane1, vecSum1 );
vecSum1 = vec_madd( vec_perm( vecXYZ1, vecXYZ2, (vector unsigned char)(8,9,10,11,8,9,10,11,24,25,26,27,24,25,26,27) ), vecPlane2, vecSum1 );
vecSum1 = vec_add( vecSum1, vecPlane3 );
vecSum2 = vec_madd( vec_perm( vecXYZ3, vecXYZ4, (vector unsigned char)(0,1,2,3,0,1,2,3,16,17,18,19,16,17,18,19) ), vecPlane0, zeroVector );
vecSum2 = vec_madd( vec_perm( vecXYZ3, vecXYZ4, (vector unsigned char)(4,5,6,7,4,5,6,7,20,21,22,23,20,21,22,23) ) , vecPlane1, vecSum2 );
vecSum2 = vec_madd( vec_perm( vecXYZ3, vecXYZ4, (vector unsigned char)(8,9,10,11,8,9,10,11,24,25,26,27,24,25,26,27) ), vecPlane2, vecSum2 );
vecSum2 = vec_add( vecSum2, vecPlane3 );
// store out results
UNALIGNED_STORE2( &texCoords[i][0], vecSum1, vecSum2 );
// bit manipulation
vecCmp1 = vec_cmplt( vecSum1, zeroVector );
vecCmp2 = vec_cmplt( vecSum2, zeroVector );
//and it with 1 so we multiply by 1 not 1111's
vecCmp1 = vec_and( vecCmp1, oneIntVector );
vecCmp2 = vec_and( vecCmp2, oneIntVector );
// store out and write to cullBits
// finally, a use for algebra! 1-x = x + 1 - 2x
vecSum1Inv = vec_madd( vecSum1, negTwoVector, vecSum1 );
vecSum2Inv = vec_madd( vecSum2, negTwoVector, vecSum2 );
vecSum1Inv = vec_add( vecSum1Inv, oneVector );
vecSum2Inv = vec_add( vecSum2Inv, oneVector );
// do the same comparisons for the inverted d0/d1
vecCmp1Inv = vec_cmplt( vecSum1Inv, zeroVector );
vecCmp2Inv = vec_cmplt( vecSum2Inv, zeroVector );
//and it with 1 so we multiply by 1 not 1111's
vecCmp1Inv = vec_and( vecCmp1Inv, oneIntVector );
vecCmp2Inv = vec_and( vecCmp2Inv, oneIntVector );
// shift them as needed
vecBitShifted1 = vec_sl( (vector unsigned int)vecCmp1, vecShift );
vecBitShifted2 = vec_sl( (vector unsigned int)vecCmp2, vecShift );
vecBitShifted1Inv = vec_sl( (vector unsigned int)vecCmp1Inv, vecShiftInv );
vecBitShifted2Inv = vec_sl( (vector unsigned int)vecCmp2Inv, vecShiftInv );
// OR them all together. since only 1 bit is set for each value, thats
// the same as adding them. add up d0 + d1 + d0Inv + d1Inv
vector unsigned int vecResult;
vector unsigned int vecResult2;
vector unsigned int vecResult3;
vecResult = vec_add( vecBitShifted1, vec_sld( vecBitShifted1, vecBitShifted1, 4 ) );
vecResult2 = vec_add( vecBitShifted2, vec_sld( vecBitShifted2, vecBitShifted2, 4 ) );
// vecResult now holds the values without the inverses yet, so add those
vecResult = vec_perm( vecResult, vecResult2, vecPermFirstThird );
vecResult2 = vec_add( vecBitShifted1Inv, vec_sld( vecBitShifted1Inv, vecBitShifted1Inv, 4 ) );
vecResult3 = vec_add( vecBitShifted2Inv, vec_sld( vecBitShifted2Inv, vecBitShifted2Inv, 4 ) );
vecResult2 = vec_perm( vecResult2, vecResult3, vecPermFirstThird );
vecResult = vec_add( vecResult, vecResult2 );
//store out results
vecResult = vec_perm( vecResult, vecResult, cullBitPerm );
vec_ste( vecResult, 0, &cullBitVal[0] );
vec_ste( vecResult, 4, &cullBitVal[0] );
vec_ste( vecResult, 8, &cullBitVal[0] );
vec_ste( vecResult, 12, &cullBitVal[0] );
cullBits[i] = cullBitVal[0];
cullBits[i+1] = cullBitVal[1];
cullBits[i+2] = cullBitVal[2];
cullBits[i+3] = cullBitVal[3];
}
// cleanup
for ( ; i < numVerts; i++ ) {
byte bits;
float d0, d1;
float vx, vy, vz;
vx = *( vertPtr + (i*DRAWVERT_OFFSET) + 0 );
vy = *( vertPtr + (i*DRAWVERT_OFFSET) + 1 );
vz = *( vertPtr + (i*DRAWVERT_OFFSET) + 2 );
d0 = p0x * vx + p0y * vy + p0z * vz + p0d;
d1 = p1x * vx + p1y * vy + p1z * vz + p1d;
texCoords[i][0] = d0;
texCoords[i][1] = d1;
bits = ( d0 >= 0 ) ? 0 : 1;
d0 = 1.0f - d0;
bits |= ( d1 >= 0 ) ? 0 : 1*2;
d1 = 1.0f - d1;
bits |= ( d0 >= 0 ) ? 0: 1*4;
bits |= ( d1 >= 0 ) ? 0: 1*8;
cullBits[i] = bits;
}
}
#endif /* DRAWVERT_PADDED */
#endif /* ENABLE_CULL */
#ifdef ENABLE_DERIVE
/*
============
idSIMD_AltiVec::DeriveTriPlanes
Derives a plane equation for each triangle.
============
*/
void VPCALL idSIMD_AltiVec::DeriveTriPlanes( idPlane *planes, const idDrawVert *verts, const int numVerts, const int *indexes, const int numIndexes ) {
// idDrawVert size
assert( sizeof(idDrawVert) == DRAWVERT_OFFSET * sizeof(float) );
// idPlane size
assert( sizeof(idPlane) == PLANE_OFFSET * sizeof(float) );
int i;
vector float vecD0, vecD1, vecD2, vecD3, vecD4, vecD5, vecD6, vecD7;
vector float vecVertA, vecVertB, vecVertC;
vector float vecVertA2, vecVertB2, vecVertC2;
vector float vecVertA3, vecVertB3, vecVertC3;
vector float vecVertA4, vecVertB4, vecVertC4;
vector float vecN, vecN2, vecN3, vecN4;
vector float vecWork1, vecWork2, vecWork3, vecWork4, vecWork5, vecWork6, vecWork7, vecWork8;
vector unsigned char vecPerm1 = (vector unsigned char)(4,5,6,7,8,9,10,11,0,1,2,3,12,13,14,15);
vector unsigned char vecPerm2 = (vector unsigned char)(8,9,10,11,0,1,2,3,4,5,6,7,12,13,14,15);
vector float vecF;
vector float vecF1, vecF2, vecF3, vecF4;
vector float zeroVector = (vector float)(0);
vector float vecNegOne = (vector float)(-1);
vector float vecSecondHalf, vecFirstHalf, vecSecondHalf2, vecFirstHalf2, vecSecondHalf3, vecFirstHalf3, vecFirstHalf4, vecSecondHalf4;
vector unsigned char vecPermA, vecPermA2, vecPermA3, vecPermA4;
vector unsigned char vecPermB, vecPermB2, vecPermB3, vecPermB4;
vector unsigned char vecPermC, vecPermC2, vecPermC3, vecPermC4;
vector unsigned char oneVector = (vector unsigned char)(1);
vector float vecLd1, vecLd2, vecLd3, vecLd4, vecLd5, vecLd6;
vector unsigned char vecPermZeroLast = (vector unsigned char)(0,1,2,3,4,5,6,7,8,9,10,11,16,17,18,19);
const float *xyzPtr = verts[0].xyz.ToFloatPtr();
float *planePtr = planes[0].ToFloatPtr();
int j;
for ( j = 0, i = 0; i+11 < numIndexes; i += 12, j += 4 ) {
#ifndef DRAWVERT_PADDED
// calculate permute vectors to load as needed. these are all
// triangle indexes and are usaully pretty close together but
// not guaranteed to be in any particular order
vecPermA = vec_add( vec_lvsl( -1, xyzPtr + ( indexes[i+0] * DRAWVERT_OFFSET ) ), oneVector );
vecPermB = vec_add( vec_lvsl( -1, xyzPtr + ( indexes[i+1] * DRAWVERT_OFFSET ) ), oneVector );
vecPermC = vec_add( vec_lvsl( -1, xyzPtr + ( indexes[i+2] * DRAWVERT_OFFSET ) ), oneVector );
vecPermA2 = vec_add( vec_lvsl( -1, xyzPtr + ( indexes[i+3] * DRAWVERT_OFFSET ) ), oneVector );
vecPermB2 = vec_add( vec_lvsl( -1, xyzPtr + ( indexes[i+4] * DRAWVERT_OFFSET ) ), oneVector );
vecPermC2 = vec_add( vec_lvsl( -1, xyzPtr + ( indexes[i+5] * DRAWVERT_OFFSET ) ), oneVector );
vecPermA3 = vec_add( vec_lvsl( -1, xyzPtr + ( indexes[i+6] * DRAWVERT_OFFSET ) ), oneVector );
vecPermB3 = vec_add( vec_lvsl( -1, xyzPtr + ( indexes[i+7] * DRAWVERT_OFFSET ) ), oneVector );
vecPermC3 = vec_add( vec_lvsl( -1, xyzPtr + ( indexes[i+8] * DRAWVERT_OFFSET ) ), oneVector );
vecPermA4 = vec_add( vec_lvsl( -1, xyzPtr + ( indexes[i+9] * DRAWVERT_OFFSET ) ), oneVector );
vecPermB4 = vec_add( vec_lvsl( -1, xyzPtr + ( indexes[i+10] * DRAWVERT_OFFSET ) ), oneVector );
vecPermC4 = vec_add( vec_lvsl( -1, xyzPtr + ( indexes[i+11] * DRAWVERT_OFFSET ) ), oneVector );
#endif
#ifndef DRAWVERT_PADDED
// load first A B C
vecLd1 = vec_ld( 0, xyzPtr + ( indexes[i+0] * DRAWVERT_OFFSET ) );
vecLd2 = vec_ld( 15, xyzPtr + ( indexes[i+0] * DRAWVERT_OFFSET ) );
vecLd3 = vec_ld( 0, xyzPtr + ( indexes[i+1] * DRAWVERT_OFFSET ) );
vecLd4 = vec_ld( 15, xyzPtr + ( indexes[i+1] * DRAWVERT_OFFSET ) );
vecLd5 = vec_ld( 0, xyzPtr + ( indexes[i+2] * DRAWVERT_OFFSET ) );
vecLd6 = vec_ld( 15, xyzPtr + ( indexes[i+2] * DRAWVERT_OFFSET ) );
vecVertA = vec_perm( vecLd1, vecLd2, vecPermA );
vecVertB = vec_perm( vecLd3, vecLd4, vecPermB );
vecVertC = vec_perm( vecLd5, vecLd6, vecPermC );
// set the last element to 0
vecVertA = vec_perm( vecVertA, zeroVector, vecPermZeroLast );
vecVertB = vec_perm( vecVertB, zeroVector, vecPermZeroLast );
vecVertC = vec_perm( vecVertC, zeroVector, vecPermZeroLast );
// load second A B C
vecLd1 = vec_ld( 0, xyzPtr + ( indexes[i+3] * DRAWVERT_OFFSET ) );
vecLd2 = vec_ld( 15, xyzPtr + ( indexes[i+3] * DRAWVERT_OFFSET ) );
vecLd3 = vec_ld( 0, xyzPtr + ( indexes[i+4] * DRAWVERT_OFFSET ) );
vecLd4 = vec_ld( 15, xyzPtr + ( indexes[i+4] * DRAWVERT_OFFSET ) );
vecLd5 = vec_ld( 0, xyzPtr + ( indexes[i+5] * DRAWVERT_OFFSET ) );
vecLd6 = vec_ld( 15, xyzPtr + ( indexes[i+5] * DRAWVERT_OFFSET ) );
vecVertA2 = vec_perm( vecLd1, vecLd2, vecPermA2 );
vecVertB2 = vec_perm( vecLd3, vecLd4, vecPermB2 );
vecVertC2 = vec_perm( vecLd5, vecLd6, vecPermC2 );
// set the last element to 0
vecVertA2 = vec_perm( vecVertA2, zeroVector, vecPermZeroLast );
vecVertB2 = vec_perm( vecVertB2, zeroVector, vecPermZeroLast );
vecVertC2 = vec_perm( vecVertC2, zeroVector, vecPermZeroLast );
// load third A B C
vecLd1 = vec_ld( 0, xyzPtr + ( indexes[i+6] * DRAWVERT_OFFSET ) );
vecLd2 = vec_ld( 15, xyzPtr + ( indexes[i+6] * DRAWVERT_OFFSET ) );
vecLd3 = vec_ld( 0, xyzPtr + ( indexes[i+7] * DRAWVERT_OFFSET ) );
vecLd4 = vec_ld( 15, xyzPtr + ( indexes[i+7] * DRAWVERT_OFFSET ) );
vecLd5 = vec_ld( 0, xyzPtr + ( indexes[i+8] * DRAWVERT_OFFSET ) );
vecLd6 = vec_ld( 15, xyzPtr + ( indexes[i+8] * DRAWVERT_OFFSET ) );
vecVertA3 = vec_perm( vecLd1, vecLd2, vecPermA3 );
vecVertB3 = vec_perm( vecLd3, vecLd4, vecPermB3 );
vecVertC3 = vec_perm( vecLd5, vecLd6, vecPermC3 );
// set the last element to 0
vecVertA2 = vec_perm( vecVertA2, zeroVector, vecPermZeroLast );
vecVertB2 = vec_perm( vecVertB2, zeroVector, vecPermZeroLast );
vecVertC2 = vec_perm( vecVertC2, zeroVector, vecPermZeroLast );
// load the fourth A B C
vecLd1 = vec_ld( 0, xyzPtr + ( indexes[i+9] * DRAWVERT_OFFSET ) );
vecLd2 = vec_ld( 15, xyzPtr + ( indexes[i+9] * DRAWVERT_OFFSET ) );
vecLd3 = vec_ld( 0, xyzPtr + ( indexes[i+10] * DRAWVERT_OFFSET ) );
vecLd4 = vec_ld( 15, xyzPtr + ( indexes[i+10] * DRAWVERT_OFFSET ) );
vecLd5 = vec_ld( 0, xyzPtr + ( indexes[i+11] * DRAWVERT_OFFSET ) );
vecLd6 = vec_ld( 15, xyzPtr + ( indexes[i+11] * DRAWVERT_OFFSET ) );
vecVertA4 = vec_perm( vecLd1, vecLd2, vecPermA4 );
vecVertB4 = vec_perm( vecLd3, vecLd4, vecPermB4 );
vecVertC4 = vec_perm( vecLd5, vecLd6, vecPermC4 );
// set the last element to 0
vecVertA4 = vec_perm( vecVertA4, zeroVector, vecPermZeroLast );
vecVertB4 = vec_perm( vecVertB4, zeroVector, vecPermZeroLast );
vecVertC4 = vec_perm( vecVertC4, zeroVector, vecPermZeroLast );
#else
// load first A B C
vecVertA = vec_ld( 0, xyzPtr + ( indexes[i+0] * DRAWVERT_OFFSET ) );
vecVertB = vec_ld( 0, xyzPtr + ( indexes[i+1] * DRAWVERT_OFFSET ) );
vecVertC = vec_ld( 0, xyzPtr + ( indexes[i+2] * DRAWVERT_OFFSET ) );
// set the last element to 0
vecVertA = vec_perm( vecVertA, zeroVector, vecPermZeroLast );
vecVertB = vec_perm( vecVertB, zeroVector, vecPermZeroLast );
vecVertC = vec_perm( vecVertC, zeroVector, vecPermZeroLast );
// load second A B C
vecVertA2 = vec_ld( 0, xyzPtr + ( indexes[i+3] * DRAWVERT_OFFSET ) );
vecVertB2 = vec_ld( 0, xyzPtr + ( indexes[i+4] * DRAWVERT_OFFSET ) );
vecVertC2 = vec_ld( 0, xyzPtr + ( indexes[i+5] * DRAWVERT_OFFSET ) );
// set the last element to 0
vecVertA2 = vec_perm( vecVertA2, zeroVector, vecPermZeroLast );
vecVertB2 = vec_perm( vecVertB2, zeroVector, vecPermZeroLast );
vecVertC2 = vec_perm( vecVertC2, zeroVector, vecPermZeroLast );
// load third A B C
vecVertA3 = vec_ld( 0, xyzPtr + ( indexes[i+6] * DRAWVERT_OFFSET ) );
vecVertB3 = vec_ld( 0, xyzPtr + ( indexes[i+7] * DRAWVERT_OFFSET ) );
vecVertC3 = vec_ld( 0, xyzPtr + ( indexes[i+8] * DRAWVERT_OFFSET ) );
// set the last element to 0
vecVertA3 = vec_perm( vecVertA3, zeroVector, vecPermZeroLast );
vecVertB3 = vec_perm( vecVertB3, zeroVector, vecPermZeroLast );
vecVertC3 = vec_perm( vecVertC3, zeroVector, vecPermZeroLast );
// load the fourth A B C
vecVertA4 = vec_ld( 0, xyzPtr + ( indexes[i+9] * DRAWVERT_OFFSET ) );
vecVertB4 = vec_ld( 0, xyzPtr + ( indexes[i+10] * DRAWVERT_OFFSET ) );
vecVertC4 = vec_ld( 0, xyzPtr + ( indexes[i+11] * DRAWVERT_OFFSET ) );
// set the last element to 0
vecVertA4 = vec_perm( vecVertA4, zeroVector, vecPermZeroLast );
vecVertB4 = vec_perm( vecVertB4, zeroVector, vecPermZeroLast );
vecVertC4 = vec_perm( vecVertC4, zeroVector, vecPermZeroLast );
#endif
// calculate d0 and d1 for each
vecD0 = vec_sub( vecVertB, vecVertA );
vecD1 = vec_sub( vecVertC, vecVertA );
vecD2 = vec_sub( vecVertB2, vecVertA2 );
vecD3 = vec_sub( vecVertC2, vecVertA2 );
vecD4 = vec_sub( vecVertB3, vecVertA3 );
vecD5 = vec_sub( vecVertC3, vecVertA3 );
vecD6 = vec_sub( vecVertB4, vecVertA4 );
vecD7 = vec_sub( vecVertC4, vecVertA4 );
vecWork1 = vec_perm( vecD0, vecD0, vecPerm1 );
vecWork2 = vec_perm( vecD1, vecD1, vecPerm2 );
vecWork3 = vec_perm( vecD2, vecD2, vecPerm1 );
vecWork4 = vec_perm( vecD3, vecD3, vecPerm2 );
vecWork5 = vec_perm( vecD4, vecD4, vecPerm1 );
vecWork6 = vec_perm( vecD5, vecD5, vecPerm2 );
vecWork7 = vec_perm( vecD6, vecD6, vecPerm1 );
vecWork8 = vec_perm( vecD7, vecD7, vecPerm2 );
vecSecondHalf = vec_madd( vecWork1, vecWork2, zeroVector );
vecSecondHalf2 = vec_madd( vecWork3, vecWork4, zeroVector );
vecSecondHalf3 = vec_madd( vecWork5, vecWork6, zeroVector );
vecSecondHalf4 = vec_madd( vecWork7, vecWork8, zeroVector );
vecWork1 = vec_perm( vecD1, vecD1, vecPerm1 );
vecWork2 = vec_perm( vecD0, vecD0, vecPerm2 );
vecWork3 = vec_perm( vecD3, vecD3, vecPerm1 );
vecWork4 = vec_perm( vecD2, vecD2, vecPerm2 );
vecWork5 = vec_perm( vecD5, vecD5, vecPerm1 );
vecWork6 = vec_perm( vecD4, vecD4, vecPerm2 );
vecWork7 = vec_perm( vecD7, vecD7, vecPerm1 );
vecWork8 = vec_perm( vecD6, vecD6, vecPerm2 );
vecFirstHalf = vec_madd( vecWork1, vecWork2, zeroVector );
vecFirstHalf2 = vec_madd( vecWork3, vecWork4, zeroVector );
vecFirstHalf3 = vec_madd( vecWork5, vecWork6, zeroVector );
vecFirstHalf4 = vec_madd( vecWork7, vecWork8, zeroVector );
vecN = vec_madd( vecSecondHalf, vecNegOne, vecFirstHalf );
vecN2 = vec_madd( vecSecondHalf2, vecNegOne, vecFirstHalf2 );
vecN3 = vec_madd( vecSecondHalf3, vecNegOne, vecFirstHalf3 );
vecN4 = vec_madd( vecSecondHalf4, vecNegOne, vecFirstHalf4 );
// transpose vecNs
vector float v0, v1, v2, v3;
v0 = vec_mergeh( vecN, vecN3 );
v1 = vec_mergeh( vecN2, vecN4 );
v2 = vec_mergel( vecN, vecN3 );
v3 = vec_mergel( vecN2, vecN4 );
vecN = vec_mergeh( v0, v1 );
vecN2 = vec_mergel( v0, v1 );
vecN3 = vec_mergeh( v2, v3 );
vecN4 = vec_mergel( v2, v3 );
vecF = vec_madd( vecN, vecN, zeroVector );
vecF = vec_madd( vecN2, vecN2, vecF );
vecF = vec_madd( vecN3, vecN3, vecF );
vecF = ReciprocalSquareRoot( vecF );
vecF1 = vec_madd( vecF, vecN, zeroVector );
vecF2 = vec_madd( vecF, vecN2, zeroVector );
vecF3 = vec_madd( vecF, vecN3, zeroVector );
vecF4 = vec_madd( vecF, vecN4, zeroVector );
vector float v8, v9, v10, v11;
v8 = vecF1;
v9 = vecF2;
v10 = vecF3;
v11 = vecF4;
// transpose vecVerts
v0 = vec_mergeh( vecVertA, vecVertA3 );
v1 = vec_mergeh( vecVertA2, vecVertA4 );
v2 = vec_mergel( vecVertA, vecVertA3 );
v3 = vec_mergel( vecVertA2, vecVertA4 );
vecVertA = vec_mergeh( v0, v1 );
vecVertA2 = vec_mergel( v0, v1 );
vecVertA3 = vec_mergeh( v2, v3 );
vecVertA4 = vec_mergel( v2, v3 );
vector float vecTotals;
vecTotals = vec_madd( vecVertA, v8, zeroVector );
vecTotals = vec_madd( vecVertA2, v9, vecTotals );
vecTotals = vec_madd( vecVertA3, v10, vecTotals );
vecTotals = vec_madd( vecVertA4, v11, vecTotals );
vecF = vec_madd( vecTotals, vecNegOne, zeroVector );
// transpose vecFs
v0 = vec_mergeh( vecF1, vecF3 );
v1 = vec_mergeh( vecF2, vecF );
v2 = vec_mergel( vecF1, vecF3 );
v3 = vec_mergel( vecF2, vecF );
vecF1 = vec_mergeh( v0, v1 );
vecF2 = vec_mergel( v0, v1 );
vecF3 = vec_mergeh( v2, v3 );
vecF4 = vec_mergel( v2, v3 );
// store results
UNALIGNED_STORE4( planePtr + ( j * PLANE_OFFSET ), vecF1, vecF2, vecF3, vecF4 );
}
// cleanup
for ( ; i < numIndexes; i += 3, j++ ) {
const idDrawVert *a, *b, *c;
float d0[3], d1[3], f;
idVec3 n;
a = verts + indexes[i + 0];
b = verts + indexes[i + 1];
c = verts + indexes[i + 2];
d0[0] = b->xyz[0] - a->xyz[0];
d0[1] = b->xyz[1] - a->xyz[1];
d0[2] = b->xyz[2] - a->xyz[2];
d1[0] = c->xyz[0] - a->xyz[0];
d1[1] = c->xyz[1] - a->xyz[1];
d1[2] = c->xyz[2] - a->xyz[2];
n[0] = d1[1] * d0[2] - d1[2] * d0[1];
n[1] = d1[2] * d0[0] - d1[0] * d0[2];
n[2] = d1[0] * d0[1] - d1[1] * d0[0];
f = FastScalarInvSqrt( n.x * n.x + n.y * n.y + n.z * n.z );
//idMath::RSqrt( n.x * n.x + n.y * n.y + n.z * n.z );
n.x *= f;
n.y *= f;
n.z *= f;
planes[j].SetNormal( n );
planes[j].FitThroughPoint( a->xyz );
}
}
/*
============
idSIMD_AltiVec::DeriveTangents
Derives the normal and orthogonal tangent vectors for the triangle vertices.
For each vertex the normal and tangent vectors are derived from all triangles
using the vertex which results in smooth tangents across the mesh.
In the process the triangle planes are calculated as well.
============
*/
void VPCALL idSIMD_AltiVec::DeriveTangents( idPlane *planes, idDrawVert *verts, const int numVerts, const int *indexes, const int numIndexes ) {
int i;
bool *used = (bool *)_alloca16( numVerts * sizeof( used[0] ) );
memset( used, 0, numVerts * sizeof( used[0] ) );
idPlane *planesPtr = planes;
for ( i = 0; i < numIndexes; i += 3 ) {
idDrawVert *a, *b, *c;
// unsigned long signBit;
float d0[5], d1[5], area;
idVec3 n, t0, t1;
float f1, f2, f3;
int v0 = indexes[i + 0];
int v1 = indexes[i + 1];
int v2 = indexes[i + 2];
a = verts + v0;
b = verts + v1;
c = verts + v2;
d0[0] = b->xyz[0] - a->xyz[0];
d0[1] = b->xyz[1] - a->xyz[1];
d0[2] = b->xyz[2] - a->xyz[2];
d0[3] = b->st[0] - a->st[0];
d0[4] = b->st[1] - a->st[1];
d1[0] = c->xyz[0] - a->xyz[0];
d1[1] = c->xyz[1] - a->xyz[1];
d1[2] = c->xyz[2] - a->xyz[2];
d1[3] = c->st[0] - a->st[0];
d1[4] = c->st[1] - a->st[1];
// normal
n[0] = d1[1] * d0[2] - d1[2] * d0[1];
n[1] = d1[2] * d0[0] - d1[0] * d0[2];
n[2] = d1[0] * d0[1] - d1[1] * d0[0];
f1 = n.x * n.x + n.y * n.y + n.z * n.z;
// area sign bit
area = d0[3] * d1[4] - d0[4] * d1[3];
// first tangent
t0[0] = d0[0] * d1[4] - d0[4] * d1[0];
t0[1] = d0[1] * d1[4] - d0[4] * d1[1];
t0[2] = d0[2] * d1[4] - d0[4] * d1[2];
f2 = t0.x * t0.x + t0.y * t0.y + t0.z * t0.z;
// second tangent
t1[0] = d0[3] * d1[0] - d0[0] * d1[3];
t1[1] = d0[3] * d1[1] - d0[1] * d1[3];
t1[2] = d0[3] * d1[2] - d0[2] * d1[3];
f3 = t1.x * t1.x + t1.y * t1.y + t1.z * t1.z;
// Behold! The power of the pipeline
FastScalarInvSqrt_x3( &f1, &f2, &f3 );
#ifdef PPC_INTRINSICS
f2 = __fsel( area, f2, -f2 );
f3 = __fsel( area, f3, -f3 );
#else
f2 = ( area < 0.0f ) ? -f2 : f2;
f3 = ( area < 0.0f ) ? -f3 : f3;
#endif
t0.x *= f2;
t0.y *= f2;
t0.z *= f2;
n.x *= f1;
n.y *= f1;
n.z *= f1;
planesPtr->SetNormal( n );
planesPtr->FitThroughPoint( a->xyz );
planesPtr++;
t1.x *= f3;
t1.y *= f3;
t1.z *= f3;
if ( used[v0] ) {
a->normal += n;
a->tangents[0] += t0;
a->tangents[1] += t1;
} else {
a->normal = n;
a->tangents[0] = t0;
a->tangents[1] = t1;
used[v0] = true;
}
if ( used[v1] ) {
b->normal += n;
b->tangents[0] += t0;
b->tangents[1] += t1;
} else {
b->normal = n;
b->tangents[0] = t0;
b->tangents[1] = t1;
used[v1] = true;
}
if ( used[v2] ) {
c->normal += n;
c->tangents[0] += t0;
c->tangents[1] += t1;
} else {
c->normal = n;
c->tangents[0] = t0;
c->tangents[1] = t1;
used[v2] = true;
}
}
}
#ifdef DERIVE_UNSMOOTH_DRAWVERT_ALIGNED
/*
============
idSIMD_AltiVec::DeriveUnsmoothedTangents
Derives the normal and orthogonal tangent vectors for the triangle vertices.
For each vertex the normal and tangent vectors are derived from a single dominant triangle.
============
*/
#define DERIVE_UNSMOOTHED_BITANGENT
void VPCALL idSIMD_AltiVec::DeriveUnsmoothedTangents( idDrawVert *verts, const dominantTri_s *dominantTris, const int numVerts ) {
int i;
// idDrawVert size
assert( sizeof(idDrawVert) == DRAWVERT_OFFSET * sizeof(float) );
// drawverts aligned
assert( IS_16BYTE_ALIGNED( verts[0] ) );
vector float vecVertA, vecVertB, vecVertC;
vector float vecVertA2, vecVertB2, vecVertC2;
vector float vecVertA3, vecVertB3, vecVertC3;
vector float vecVertA4, vecVertB4, vecVertC4;
vector float v0, v1, v2, v3, v4, v5, v6, v7, v8;
vector float vecS0, vecS1, vecS2;
vector float vecS0_2, vecS1_2, vecS2_2;
vector float vecS0_3, vecS1_3, vecS2_3;
vector float vecS0_4, vecS1_4, vecS2_4;
vector float vecD1, vecD2, vecD3, vecD4, vecD5, vecD6;
vector float vecD7, vecD8, vecD9, vecD10, vecD11, vecD12;
vector float vecT1, vecT1_2, vecT1_3, vecT1_4, vecT2, vecT2_2, vecT2_3, vecT2_4;
vector float vecWork1, vecWork2, vecWork3, vecWork4, vecWork5, vecWork6, vecWork7, vecWork8;
vector float vecN, vecN2, vecN3, vecN4;
vector unsigned char vecPermN0 = (vector unsigned char)(8,9,10,11,0,1,2,3,4,5,6,7,12,13,14,15);
vector unsigned char vecPermN1 = (vector unsigned char)(4,5,6,7,8,9,10,11,0,1,2,3,12,13,14,15);
vector unsigned char vecPermT0 = (vector unsigned char)(0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3);
vector unsigned char vecPermT1 = (vector unsigned char)(8,9,10,11,8,9,10,11,8,9,10,11,8,9,10,11);
vector float zeroVector = (vector float)(0);
vector float vecNegOne = (vector float)(-1.0);
vector float vecStore1, vecStore2, vecStore3;
vector unsigned char vecPermFirstThreeLast = (vector unsigned char)(0,1,2,3,4,5,6,7,8,9,10,11,16,17,18,19);
vector unsigned char vecPermStoreSecond = (vector unsigned char)(4,5,6,7,8,9,10,11,16,17,18,19,20,21,22,23);
vector unsigned char vecPermLeadAndThree = (vector unsigned char)(0,1,2,3,16,17,18,19,20,21,22,23,24,25,26,27);
vector unsigned char vecPermStore2 = (vector unsigned char)(4,5,6,7,8,9,10,11,24,25,26,27,28,29,30,31);
vector unsigned char vecPermStore3 = (vector unsigned char)(4,5,6,7,8,9,10,11,16,17,18,19,20,21,22,23);
vector unsigned char vecPermStore4 = (vector unsigned char)(8,9,10,11,16,17,18,19,20,21,22,23,24,25,26,27);
vector unsigned char vecPermHalves = (vector unsigned char)(0,1,2,3,4,5,6,7,16,17,18,19,20,21,22,23);
vector float vecLd1, vecLd2, vecLd3;
vector unsigned char vecPerm0, vecPerm1, vecPerm2, vecPerm3, vecPerm4;
float *normalPtr = verts[0].normal.ToFloatPtr();
float *xyzPtr = verts[0].xyz.ToFloatPtr();
vector float vecFirstHalf, vecSecondHalf;
vector float vecFirstHalf2, vecSecondHalf2;
vector float vecFirstHalf3, vecSecondHalf3;
vector float vecFirstHalf4, vecSecondHalf4;
for ( i = 0; i+3 < numVerts; i+=4 ) {
int bOffset1, bOffset2, bOffset3, bOffset4;
int cOffset1, cOffset2, cOffset3, cOffset4;
bOffset1 = dominantTris[i].v2;
cOffset1 = dominantTris[i].v3;
bOffset2 = dominantTris[i+1].v2;
cOffset2 = dominantTris[i+1].v3;
bOffset3 = dominantTris[i+2].v2;
cOffset3 = dominantTris[i+2].v3;
bOffset4 = dominantTris[i+3].v2;
cOffset4 = dominantTris[i+3].v3;
vecPerm0 = vec_lvsl( 0, xyzPtr + ( i * DRAWVERT_OFFSET ) );
v0 = vec_ld( 0, xyzPtr + (i * DRAWVERT_OFFSET ) );
v1 = vec_ld( 16, xyzPtr + (i * DRAWVERT_OFFSET ) );
vecVertA = vec_perm( v0, v1, vecPerm0 );
vecPerm1 = vec_lvsl( 0, xyzPtr + (bOffset1 * DRAWVERT_OFFSET ) );
v2 = vec_ld( 0, xyzPtr + ( bOffset1 * DRAWVERT_OFFSET ) );
v3 = vec_ld( 16, xyzPtr + ( bOffset1 * DRAWVERT_OFFSET ) );
vecVertB = vec_perm( v2, v3, vecPerm1 );
vecPerm2 = vec_lvsl( 0, xyzPtr + ( cOffset1 * DRAWVERT_OFFSET ) );
v4 = vec_ld( 0, xyzPtr + ( cOffset1 * DRAWVERT_OFFSET ) );
v5 = vec_ld( 16, xyzPtr + ( cOffset1 * DRAWVERT_OFFSET ) );
vecVertC = vec_perm( v4, v5, vecPerm2 );
// put remainder into v2
v1 = vec_perm( v1, v1, vecPerm0 );
v3 = vec_perm( v3, v3, vecPerm1 );
v5 = vec_perm( v5, v5, vecPerm2 );
v1 = vec_mergeh( v1, v5 );
v2 = vec_mergeh( v3, zeroVector );
v2 = vec_mergeh( v1, v2 );
v2 = vec_perm( v2, v2, (vector unsigned char)(4,5,6,7,0,1,2,3,8,9,10,11,0,1,2,3) );
// load second one
vecPerm0 = vec_lvsl( 0, xyzPtr + ((i+1) * DRAWVERT_OFFSET ) );
v0 = vec_ld( 0, xyzPtr + ((i+1) * DRAWVERT_OFFSET ) );
v1 = vec_ld( 16, xyzPtr + ((i+1) * DRAWVERT_OFFSET ) );
vecVertA2 = vec_perm( v0, v1, vecPerm0 );
vecPerm3 = vec_lvsl( 0, xyzPtr + (bOffset2 * DRAWVERT_OFFSET ) );
v3 = vec_ld( 0, xyzPtr + ( bOffset2 * DRAWVERT_OFFSET ) );
v4 = vec_ld( 16, xyzPtr + ( bOffset2 * DRAWVERT_OFFSET ) );
vecVertB2 = vec_perm( v3, v4, vecPerm3 );
vecPerm4 = vec_lvsl( 0, xyzPtr + ( cOffset2 * DRAWVERT_OFFSET ) );
v5 = vec_ld( 0, xyzPtr + ( cOffset2 * DRAWVERT_OFFSET ) );
v6 = vec_ld( 16, xyzPtr + ( cOffset2 * DRAWVERT_OFFSET ) );
vecVertC2 = vec_perm( v5, v6, vecPerm4 );
// put remainder into v3
v1 = vec_perm( v1, v1, vecPerm0 );
v4 = vec_perm( v4, v4, vecPerm3 );
v5 = vec_perm( v6, v6, vecPerm4 );
v1 = vec_mergeh( v1, v5 );
v3 = vec_mergeh( v4, zeroVector );
v3 = vec_mergeh( v1, v3 );
v3 = vec_perm( v3, v3, (vector unsigned char)(4,5,6,7,0,1,2,3,8,9,10,11,0,1,2,3) );
// load third one
vecPerm0 = vec_lvsl( 0, xyzPtr + ((i+2) * DRAWVERT_OFFSET ) );
v0 = vec_ld( 0, xyzPtr + ((i+2) * DRAWVERT_OFFSET ) );
v1 = vec_ld( 16, xyzPtr + ((i+2) * DRAWVERT_OFFSET ) );
vecVertA3 = vec_perm( v0, v1, vecPerm0 );
vecPerm1 = vec_lvsl( 0, xyzPtr + (bOffset3 * DRAWVERT_OFFSET ) );
v4 = vec_ld( 0, xyzPtr + ( bOffset3 * DRAWVERT_OFFSET ) );
v5 = vec_ld( 16, xyzPtr + ( bOffset3 * DRAWVERT_OFFSET ) );
vecVertB3 = vec_perm( v4, v5, vecPerm1 );
vecPerm2 = vec_lvsl( 0, xyzPtr + ( cOffset3 * DRAWVERT_OFFSET ) );
v6 = vec_ld( 0, xyzPtr + ( cOffset3 * DRAWVERT_OFFSET ) );
v7 = vec_ld( 16, xyzPtr + ( cOffset3 * DRAWVERT_OFFSET ) );
vecVertC3 = vec_perm( v6, v7, vecPerm2 );
// put remainder into v4
v1 = vec_perm( v1, v1, vecPerm0 );
v5 = vec_perm( v5, v5, vecPerm1 );
v7 = vec_perm( v7, v7, vecPerm2 );
v1 = vec_mergeh( v1, v7 );
v4 = vec_mergeh( v5, zeroVector );
v4 = vec_mergeh( v1, v4 );
v4 = vec_perm( v4, v4, (vector unsigned char)(4,5,6,7,0,1,2,3,8,9,10,11,0,1,2,3) );
// load fourth one
vecPerm0 = vec_lvsl( 0, xyzPtr + ((i+3) * DRAWVERT_OFFSET ) );
v0 = vec_ld( 0, xyzPtr + ((i+3) * DRAWVERT_OFFSET ) );
v1 = vec_ld( 16, xyzPtr + ((i+3) * DRAWVERT_OFFSET ) );
vecVertA4 = vec_perm( v0, v1, vecPerm0 );
vecPerm3 = vec_lvsl( 0, xyzPtr + (bOffset4 * DRAWVERT_OFFSET ) );
v5 = vec_ld( 0, xyzPtr + ( bOffset4 * DRAWVERT_OFFSET ) );
v6 = vec_ld( 16, xyzPtr + ( bOffset4 * DRAWVERT_OFFSET ) );
vecVertB4 = vec_perm( v5, v6, vecPerm3 );
vecPerm4 = vec_lvsl( 0, xyzPtr + ( cOffset4 * DRAWVERT_OFFSET ) );
v7 = vec_ld( 0, xyzPtr + ( cOffset4 * DRAWVERT_OFFSET ) );
v8 = vec_ld( 16, xyzPtr + ( cOffset4 * DRAWVERT_OFFSET ) );
vecVertC4 = vec_perm( v7, v8, vecPerm4 );
// put remainder into v5
v1 = vec_perm( v1, v1, vecPerm0 );
v6 = vec_perm( v6, v6, vecPerm3 );
v8 = vec_perm( v8, v8, vecPerm4 );
v1 = vec_mergeh( v1, v8 );
v5 = vec_mergeh( v6, zeroVector );
v5 = vec_mergeh( v1, v5 );
v5 = vec_perm( v5, v5, (vector unsigned char)(4,5,6,7,0,1,2,3,8,9,10,11,0,1,2,3) );
// remainder vectors look like b->st[1], a->st[1], c->st[1], a->st[1]
//vecD1 now holds d0, d1, d2, d3
vecD1 = vec_sub( vecVertB, vecVertA );
vecD4 = vec_sub( vecVertB2, vecVertA2 );
vecD7 = vec_sub( vecVertB3, vecVertA3 );
vecD10 = vec_sub( vecVertB4, vecVertA4 );
// vecD2 how holds d5, d6, d7, d8
vecD2 = vec_sub( vecVertC, vecVertA );
vecD5 = vec_sub( vecVertC2, vecVertA2 );
vecD8 = vec_sub( vecVertC3, vecVertA3 );
vecD11 = vec_sub( vecVertC4, vecVertA4 );
// vecD3 now holds d4, crap, d9, crap
vecD3 = vec_sub( v2, vec_sld( v2, v2, 4 ) );
vecD6 = vec_sub( v3, vec_sld( v3, v3, 4 ) );
vecD9 = vec_sub( v4, vec_sld( v4, v4, 4 ) );
vecD12 = vec_sub( v5, vec_sld( v5, v5, 4 ) );
// get permute vectors for loading from dt
vecPerm1 = vec_add( vec_lvsl( -1, (int*) &dominantTris[i].normalizationScale[0] ), (vector unsigned char)(1) );
vecPerm2 = vec_add( vec_lvsl( -1, (int*) &dominantTris[i+1].normalizationScale[0] ), (vector unsigned char)(1) );
vecPerm3 = vec_add( vec_lvsl( -1, (int*) &dominantTris[i+2].normalizationScale[0] ), (vector unsigned char)(1) );
vecPerm4 = vec_add( vec_lvsl( -1, (int*) &dominantTris[i+3].normalizationScale[0] ), (vector unsigned char)(1) );
// load S values from dominantTris
v0 = vec_ld( 0, &dominantTris[i].normalizationScale[0] );
v1 = vec_ld( 11, &dominantTris[i].normalizationScale[0] );
v2 = vec_ld( 0, &dominantTris[i+1].normalizationScale[0] );
v3 = vec_ld( 11, &dominantTris[i+1].normalizationScale[0] );
v4 = vec_ld( 0, &dominantTris[i+2].normalizationScale[0] );
v5 = vec_ld( 11, &dominantTris[i+2].normalizationScale[0] );
v6 = vec_ld( 0, &dominantTris[i+3].normalizationScale[0] );
v7 = vec_ld( 11, &dominantTris[i+3].normalizationScale[0] );
v0 = vec_perm( v0, v1, vecPerm1 );
v2 = vec_perm( v2, v3, vecPerm2 );
v4 = vec_perm( v4, v5, vecPerm3 );
v6 = vec_perm( v6, v7, vecPerm4 );
vecS0 = vec_splat( v0, 0 );
vecS1 = vec_splat( v0, 1 );
vecS2 = vec_splat( v0, 2 );
vecS0_2 = vec_splat( v2, 0);
vecS1_2 = vec_splat( v2, 1 );
vecS2_2 = vec_splat( v2, 2 );
vecS0_3 = vec_splat( v4, 0 );
vecS1_3 = vec_splat( v4, 1 );
vecS2_3 = vec_splat( v4, 2 );
vecS0_4 = vec_splat( v6, 0 );
vecS1_4 = vec_splat( v6, 1 );
vecS2_4 = vec_splat( v6, 2 );
// do calculation
vecWork1 = vec_perm( vecD2, vecD2, vecPermN1 );
vecWork2 = vec_perm( vecD1, vecD1, vecPermN0 );
vecWork3 = vec_perm( vecD5, vecD5, vecPermN1 );
vecWork4 = vec_perm( vecD4, vecD4, vecPermN0 );
vecWork5 = vec_perm( vecD8, vecD8, vecPermN1 );
vecWork6 = vec_perm( vecD7, vecD7, vecPermN0 );
vecWork7 = vec_perm( vecD11, vecD11, vecPermN1 );
vecWork8 = vec_perm( vecD10, vecD10, vecPermN0 );
vecFirstHalf = vec_madd( vecWork1, vecWork2, zeroVector );
vecFirstHalf2 = vec_madd( vecWork3, vecWork4, zeroVector );
vecFirstHalf3 = vec_madd( vecWork5, vecWork6, zeroVector );
vecFirstHalf4 = vec_madd( vecWork7, vecWork8, zeroVector );
vecWork1 = vec_perm( vecD2, vecD2, vecPermN0 );
vecWork2 = vec_perm( vecD1, vecD1, vecPermN1 );
vecWork3 = vec_perm( vecD5, vecD5, vecPermN0 );
vecWork4 = vec_perm( vecD4, vecD4, vecPermN1 );
vecWork5 = vec_perm( vecD8, vecD8, vecPermN0 );
vecWork6 = vec_perm( vecD7, vecD7, vecPermN1 );
vecWork7 = vec_perm( vecD11, vecD11, vecPermN0 );
vecWork8 = vec_perm( vecD10, vecD10, vecPermN1 );
vecSecondHalf = vec_nmsub( vecWork1, vecWork2, vecFirstHalf );
vecSecondHalf2 = vec_nmsub( vecWork3, vecWork4, vecFirstHalf2 );
vecSecondHalf3 = vec_nmsub( vecWork5, vecWork6, vecFirstHalf3 );
vecSecondHalf4 = vec_nmsub( vecWork7, vecWork8, vecFirstHalf4 );
// calculate N values
vecN = vec_madd( vecS2, vecSecondHalf, zeroVector );
vecN2 = vec_madd( vecS2_2, vecSecondHalf2, zeroVector );
vecN3 = vec_madd( vecS2_3, vecSecondHalf3, zeroVector );
vecN4 = vec_madd( vecS2_4, vecSecondHalf4, zeroVector );
// calculate both halves of the calculation for t
vecWork1 = vecD1;
vecWork2 = vec_perm( vecD3, vecD3, vecPermT1 );
vecWork3 = vecD4;
vecWork4 = vec_perm( vecD6, vecD6, vecPermT1 );
vecWork5 = vecD7;
vecWork6 = vec_perm( vecD9, vecD9, vecPermT1 );
vecWork7 = vecD10;
vecWork8 = vec_perm( vecD12, vecD12, vecPermT1 );
vecFirstHalf = vec_madd( vecWork1, vecWork2, zeroVector );
vecFirstHalf2 = vec_madd( vecWork3, vecWork4, zeroVector );
vecFirstHalf3 = vec_madd( vecWork5, vecWork6, zeroVector );
vecFirstHalf4 = vec_madd( vecWork7, vecWork8, zeroVector );
vecWork1 = vecD2;
vecWork2 = vec_perm( vecD3, vecD3, vecPermT0 );
vecWork3 = vecD5;
vecWork4 = vec_perm( vecD6, vecD6, vecPermT0 );
vecWork5 = vecD8;
vecWork6 = vec_perm( vecD9, vecD9, vecPermT0 );
vecWork7 = vecD11;
vecWork8 = vec_perm( vecD12, vecD12, vecPermT0 );
vecSecondHalf = vec_nmsub( vecWork1, vecWork2, vecFirstHalf );
vecSecondHalf2 = vec_nmsub( vecWork3, vecWork4, vecFirstHalf2 );
vecSecondHalf3 = vec_nmsub( vecWork5, vecWork6, vecFirstHalf3 );
vecSecondHalf4 = vec_nmsub( vecWork7, vecWork8, vecFirstHalf4 );
// calculate T values
vecT1 = vec_madd( vecS0, vecSecondHalf, zeroVector );
vecT1_2 = vec_madd( vecS0_2, vecSecondHalf2, zeroVector );
vecT1_3 = vec_madd( vecS0_3, vecSecondHalf3, zeroVector );
vecT1_4 = vec_madd( vecS0_4, vecSecondHalf4, zeroVector );
#ifndef DERIVE_UNSMOOTHED_BITANGENT
vecWork1 = vecD1;
vecWork2 = vec_perm( vecD2, vecD2, vecPermT2 );
vecWork3 = vecD4;
vecWork4 = vec_perm( vecD5, vecD5, vecPermT2 );
vecWork5 = vecD7;
vecWork6 = vec_perm( vecD8, vecD8, vecPermT2 );
vecWork7 = vecD10;
vecWork8 = vec_perm( vecD11, vecD11, vecPermT2 );
vecSecondHalf = vec_madd( vecWork1, vecWork2, zeroVector );
vecSecondHalf2 = vec_madd( vecWork3, vecWork4, zeroVector );
vecSecondHalf3 = vec_madd( vecWork5, vecWork6, zeroVector );
vecSecondHalf4 = vec_madd( vecWork7, vecWork8, zeroVector );
vecWork1 = vec_perm( vecD1, vecD1, vecPermT2 );
vecWork2 = vecD2;
vecWork3 = vec_perm( vecD4, vecD4, vecPermT2 );
vecWork4 = vecD5;
vecWork5 = vec_perm( vecD7, vecD7, vecPermT2 );
vecWork6 = vecD8;
vecWork7 = vec_perm( vecD10, vecD10, vecPermT2 );
vecWork8 = vecD11;
vecFirstHalf = vec_madd( vecWork1, vecWork2, zeroVector );
vecFirstHalf2 = vec_madd( vecWork3, vecWork4, zeroVector );
vecFirstHalf3 = vec_madd( vecWork5, vecWork6, zeroVector );
vecFirstHalf4 = vec_madd( vecWork7, vecWork8, zeroVector );
#else
vecWork1 = vec_perm( vecN, vecN, vecPermN1 );
vecWork2 = vec_perm( vecT1, vecT1, vecPermN0 );
vecWork3 = vec_perm( vecN2, vecN2, vecPermN1 );
vecWork4 = vec_perm( vecT1_2, vecT1_2, vecPermN0 );
vecWork5 = vec_perm( vecN3, vecN3, vecPermN1 );
vecWork6 = vec_perm( vecT1_3, vecT1_3, vecPermN0 );
vecWork7 = vec_perm( vecN4, vecN4, vecPermN1 );
vecWork8 = vec_perm( vecT1_4, vecT1_4, vecPermN0 );
vecSecondHalf = vec_madd( vecWork1, vecWork2, zeroVector );
vecSecondHalf2 = vec_madd( vecWork3, vecWork4, zeroVector );
vecSecondHalf3 = vec_madd( vecWork5, vecWork6, zeroVector );
vecSecondHalf4 = vec_madd( vecWork7, vecWork8, zeroVector );
vecWork1 = vec_perm( vecN, vecN, vecPermN0 );
vecWork2 = vec_perm( vecT1, vecT1, vecPermN1 );
vecWork3 = vec_perm( vecN2, vecN2, vecPermN0 );
vecWork4 = vec_perm( vecT1_2, vecT1_2, vecPermN1 );
vecWork5 = vec_perm( vecN3, vecN3, vecPermN0 );
vecWork6 = vec_perm( vecT1_3, vecT1_3, vecPermN1 );
vecWork7 = vec_perm( vecN4, vecN4, vecPermN0 );
vecWork8 = vec_perm( vecT1_4, vecT1_4, vecPermN1 );
vecFirstHalf = vec_madd( vecWork1, vecWork2, zeroVector );
vecFirstHalf2 = vec_madd( vecWork3, vecWork4, zeroVector );
vecFirstHalf3 = vec_madd( vecWork5, vecWork6, zeroVector );
vecFirstHalf4 = vec_madd( vecWork7, vecWork8, zeroVector );
#endif
// finish the calculation
vecSecondHalf = vec_madd( vecSecondHalf, vecNegOne, vecFirstHalf );
vecSecondHalf2 = vec_madd( vecSecondHalf2, vecNegOne, vecFirstHalf2 );
vecSecondHalf3 = vec_madd( vecSecondHalf3, vecNegOne, vecFirstHalf3 );
vecSecondHalf4 = vec_madd( vecSecondHalf4, vecNegOne, vecFirstHalf4 );
vecT2 = vec_madd( vecS1, vecSecondHalf, zeroVector );
vecT2_2 = vec_madd( vecS1_2, vecSecondHalf2, zeroVector );
vecT2_3 = vec_madd( vecS1_3, vecSecondHalf3, zeroVector );
vecT2_4 = vec_madd( vecS1_4, vecSecondHalf4, zeroVector );
// Store results
// read values that we need to preserve
vecLd1 = vec_ld( 0, normalPtr + ( i * DRAWVERT_OFFSET ) );
vecLd2 = vec_ld( 32, normalPtr + ( i * DRAWVERT_OFFSET ) );
//generate vectors to store
vecStore1 = vec_perm( vecLd1, vecN, vecPermLeadAndThree );
vecStore2 = vec_perm( vecT1, vecT2, vecPermFirstThreeLast );
vecStore3 = vec_perm( vecT2, vecLd2, vecPermStore2 );
// store out results
ALIGNED_STORE3( normalPtr + ( i * DRAWVERT_OFFSET ), vecStore1, vecStore2, vecStore3 );
// read values that we need to preserve
vecLd3 = vec_ld( 32, normalPtr + ( (i+1) * DRAWVERT_OFFSET ));
// generate vectors to store
vecStore1 = vec_perm( vecN2, vecT1_2, vecPermFirstThreeLast );
vecStore2 = vec_perm( vecT1_2, vecT2_2, vecPermStoreSecond );
vecStore3 = vec_perm( vecT2_2, vecLd3, (vector unsigned char)(8,9,10,11,20,21,22,23,24,25,26,27,28,29,30,31) );
// instead of doing permute, shift it where it needs to be and use vec_ste
// store out vectors
ALIGNED_STORE3( normalPtr + ((i+1) * DRAWVERT_OFFSET), vecStore1, vecStore2, vecStore3 );
// read values that we need to preserve
vecLd1 = vec_ld( 0, normalPtr + ( (i+2) * DRAWVERT_OFFSET ) );
// generate vectors to store
vecStore1 = vec_perm( vecLd1, vecN3, vecPermFirstThreeLast );
vecStore2 = vec_perm( vecN3, vecT1_3, vecPermStore3 );
vecStore3 = vec_perm( vecT1_3, vecT2_3, vecPermStore4 );
// store out vectors
ALIGNED_STORE3( normalPtr + ((i+2) * DRAWVERT_OFFSET), vecStore1, vecStore2, vecStore3 );
// read values that we need to preserve
vecLd2 = vec_ld( 0, normalPtr + ((i+3) * DRAWVERT_OFFSET ) );
vecLd3 = vec_ld( 32, normalPtr + ((i+3) * DRAWVERT_OFFSET ) );
// generate vectors to store
vecStore1 = vec_perm( vecLd2, vecN4, vecPermHalves );
vecStore2 = vec_perm( vecN4, vecT1_4, vecPermStore4 );
vecStore3 = vec_perm( vecT2_4, vecLd3, vecPermFirstThreeLast );
// store out vectors
ALIGNED_STORE3( normalPtr + ((i+3) * DRAWVERT_OFFSET ), vecStore1, vecStore2, vecStore3 );
}
// cleanup
for ( ; i < numVerts; i++ ) {
idDrawVert *a, *b, *c;
float d0, d1, d2, d3, d4;
float d5, d6, d7, d8, d9;
float s0, s1, s2;
float n0, n1, n2;
float t0, t1, t2;
float t3, t4, t5;
const dominantTri_s &dt = dominantTris[i];
a = verts + i;
b = verts + dt.v2;
c = verts + dt.v3;
d0 = b->xyz[0] - a->xyz[0];
d1 = b->xyz[1] - a->xyz[1];
d2 = b->xyz[2] - a->xyz[2];
d3 = b->st[0] - a->st[0];
d4 = b->st[1] - a->st[1];
d5 = c->xyz[0] - a->xyz[0];
d6 = c->xyz[1] - a->xyz[1];
d7 = c->xyz[2] - a->xyz[2];
d8 = c->st[0] - a->st[0];
d9 = c->st[1] - a->st[1];
s0 = dt.normalizationScale[0];
s1 = dt.normalizationScale[1];
s2 = dt.normalizationScale[2];
n0 = s2 * ( d6 * d2 - d7 * d1 );
n1 = s2 * ( d7 * d0 - d5 * d2 );
n2 = s2 * ( d5 * d1 - d6 * d0 );
t0 = s0 * ( d0 * d9 - d4 * d5 );
t1 = s0 * ( d1 * d9 - d4 * d6 );
t2 = s0 * ( d2 * d9 - d4 * d7 );
#ifndef DERIVE_UNSMOOTHED_BITANGENT
t3 = s1 * ( d3 * d5 - d0 * d8 );
t4 = s1 * ( d3 * d6 - d1 * d8 );
t5 = s1 * ( d3 * d7 - d2 * d8 );
#else
t3 = s1 * ( n2 * t1 - n1 * t2 );
t4 = s1 * ( n0 * t2 - n2 * t0 );
t5 = s1 * ( n1 * t0 - n0 * t1 );
#endif
a->normal[0] = n0;
a->normal[1] = n1;
a->normal[2] = n2;
a->tangents[0][0] = t0;
a->tangents[0][1] = t1;
a->tangents[0][2] = t2;
a->tangents[1][0] = t3;
a->tangents[1][1] = t4;
a->tangents[1][2] = t5;
}
}
#else
/*
============
idSIMD_AltiVec::DeriveUnsmoothedTangents
Derives the normal and orthogonal tangent vectors for the triangle vertices.
For each vertex the normal and tangent vectors are derived from a single dominant triangle.
============
*/
#define DERIVE_UNSMOOTHED_BITANGENT
void VPCALL idSIMD_AltiVec::DeriveUnsmoothedTangents( idDrawVert *verts, const dominantTri_s *dominantTris, const int numVerts ) {
int i;
for ( i = 0; i < numVerts; i++ ) {
idDrawVert *a, *b, *c;
float d0, d1, d2, d3, d4;
float d5, d6, d7, d8, d9;
float s0, s1, s2;
float n0, n1, n2;
float t0, t1, t2;
float t3, t4, t5;
const dominantTri_s &dt = dominantTris[i];
a = verts + i;
b = verts + dt.v2;
c = verts + dt.v3;
d0 = b->xyz[0] - a->xyz[0];
d1 = b->xyz[1] - a->xyz[1];
d2 = b->xyz[2] - a->xyz[2];
d3 = b->st[0] - a->st[0];
d4 = b->st[1] - a->st[1];
d5 = c->xyz[0] - a->xyz[0];
d6 = c->xyz[1] - a->xyz[1];
d7 = c->xyz[2] - a->xyz[2];
d8 = c->st[0] - a->st[0];
d9 = c->st[1] - a->st[1];
s0 = dt.normalizationScale[0];
s1 = dt.normalizationScale[1];
s2 = dt.normalizationScale[2];
n0 = s2 * ( d6 * d2 - d7 * d1 );
n1 = s2 * ( d7 * d0 - d5 * d2 );
n2 = s2 * ( d5 * d1 - d6 * d0 );
t0 = s0 * ( d0 * d9 - d4 * d5 );
t1 = s0 * ( d1 * d9 - d4 * d6 );
t2 = s0 * ( d2 * d9 - d4 * d7 );
#ifndef DERIVE_UNSMOOTHED_BITANGENT
t3 = s1 * ( d3 * d5 - d0 * d8 );
t4 = s1 * ( d3 * d6 - d1 * d8 );
t5 = s1 * ( d3 * d7 - d2 * d8 );
#else
t3 = s1 * ( n2 * t1 - n1 * t2 );
t4 = s1 * ( n0 * t2 - n2 * t0 );
t5 = s1 * ( n1 * t0 - n0 * t1 );
#endif
a->normal[0] = n0;
a->normal[1] = n1;
a->normal[2] = n2;
a->tangents[0][0] = t0;
a->tangents[0][1] = t1;
a->tangents[0][2] = t2;
a->tangents[1][0] = t3;
a->tangents[1][1] = t4;
a->tangents[1][2] = t5;
}
}
#endif /* DERIVE_UNSMOOTH_DRAWVERT_ALIGNED */
/*
============
idSIMD_AltiVec::NormalizeTangents
Normalizes each vertex normal and projects and normalizes the
tangent vectors onto the plane orthogonal to the vertex normal.
============
*/
void VPCALL idSIMD_AltiVec::NormalizeTangents( idDrawVert *verts, const int numVerts ) {
// idDrawVert size
assert( sizeof(idDrawVert) == DRAWVERT_OFFSET * sizeof(float) );
float *addr = verts[0].normal.ToFloatPtr();
float *tAddr = verts[0].tangents[0].ToFloatPtr();
// v0 through v3 maintain originally loaded values so we don't take
// as much hit for unaligned stores
vector float v0, v1, v2, v3;
// v5 through v8 are the "working" values of the vectors
vector float v5, v6, v7, v8;
// working values
vector float vec1T0, vec1T1, vec2T0, vec2T1, vec3T0, vec3T1, vec4T0, vec4T1;
vector float vecSum, vecTSum1, vecTSum2, tempSum, tempSum2, tempSum3;
vector float vecF, vecF2;
vector float vecTemp, vecTemp2, vecTemp3, vecTemp4;
register vector float zeroVector = (vector float)(0.0);
vector unsigned char vecPermHalves = (vector unsigned char)(0,1,2,3,4,5,6,7,16,17,18,19,20,21,22,23);
vector unsigned char vecPermLast = (vector unsigned char)(0,1,2,3,4,5,6,7,8,9,10,11,16,17,18,19);
vector unsigned char vecPermSplatFirstWithZero = (vector unsigned char)(0,1,2,3,0,1,2,3,0,1,2,3,16,17,18,19);
vector unsigned char vecPerm0, vecPerm1, vecPerm2, vecPerm3;
vector unsigned char storePerm0, storePerm1, storePerm2, storePerm3;
vector float vecTan11, vecTan12, vecTan13, vecTan21, vecTan22, vecTan23;
vector float vecTan31, vecTan32, vecTan33, vecTan41, vecTan42, vecTan43;
vector unsigned char vec1T0Perm, vec1T1Perm, vec2T0Perm, vec2T1Perm, vec3T0Perm, vec3T1Perm, vec4T0Perm, vec4T1Perm;
vector unsigned char storeT11, storeT12, storeT21, storeT22, storeT31, storeT32;
vector unsigned char storeT41, storeT42;
int i = 0;
if ( i+3 < numVerts ) {
// for loading normal from idDrawVert
vecPerm0 = vec_add( vec_lvsl( -1, addr ), (vector unsigned char)(1) );
vecPerm1 = vec_add( vec_lvsl( -1, addr + ( 1 * DRAWVERT_OFFSET ) ), (vector unsigned char)(1) );
vecPerm2 = vec_add( vec_lvsl( -1, addr + ( 2 * DRAWVERT_OFFSET ) ), (vector unsigned char)(1) );
vecPerm3 = vec_add( vec_lvsl( -1, addr + ( 3 * DRAWVERT_OFFSET ) ), (vector unsigned char)(1) );
// for loading tangents from idDrawVert
vec1T0Perm = vec_add( vec_lvsl( -1, tAddr + ( 0 * DRAWVERT_OFFSET ) ), (vector unsigned char)(1) );
vec1T1Perm = vec_add( vec_lvsl( -1, tAddr + ( 0 * DRAWVERT_OFFSET ) + 3 ), (vector unsigned char)(1) );
vec2T0Perm = vec_add( vec_lvsl( -1, tAddr + ( 1 * DRAWVERT_OFFSET ) ), (vector unsigned char)(1) );
vec2T1Perm = vec_add( vec_lvsl( -1, tAddr + ( 1 * DRAWVERT_OFFSET ) + 3 ), (vector unsigned char)(1) );
vec3T0Perm = vec_add( vec_lvsl( -1, tAddr + ( 2 * DRAWVERT_OFFSET ) ), (vector unsigned char)(1) );
vec3T1Perm = vec_add( vec_lvsl( -1, tAddr + ( 2 * DRAWVERT_OFFSET ) + 3 ), (vector unsigned char)(1) );
vec4T0Perm = vec_add( vec_lvsl( -1, tAddr + ( 3 * DRAWVERT_OFFSET ) ), (vector unsigned char)(1) );
vec4T1Perm = vec_add( vec_lvsl( -1, tAddr + ( 3 * DRAWVERT_OFFSET ) + 3 ), (vector unsigned char)(1) );
// generate permute vectors to store normals
storePerm0 = vec_lvsr( 0, addr );
storePerm1 = vec_lvsr( 0, addr + ( 1 * DRAWVERT_OFFSET ) );
storePerm2 = vec_lvsr( 0, addr + ( 2 * DRAWVERT_OFFSET ) );
storePerm3 = vec_lvsr( 0, addr + ( 3 * DRAWVERT_OFFSET ) );
// generate permute vectors to store tangents
storeT11 = vec_lvsr( 0, tAddr + ( 0 * DRAWVERT_OFFSET ) );
storeT12 = vec_lvsr( 12, tAddr + ( 0 * DRAWVERT_OFFSET ) );
storeT21 = vec_lvsr( 0, tAddr + ( 1 * DRAWVERT_OFFSET ) );
storeT22 = vec_lvsr( 12, tAddr + ( 1 * DRAWVERT_OFFSET ) );
storeT31 = vec_lvsr( 0, tAddr + ( 2 * DRAWVERT_OFFSET ) );
storeT32 = vec_lvsr( 12, tAddr + ( 2 * DRAWVERT_OFFSET ) );
storeT41 = vec_lvsr( 0, tAddr + ( 3 * DRAWVERT_OFFSET ) );
storeT42 = vec_lvsr( 12, tAddr + ( 3 * DRAWVERT_OFFSET ) );
}
for ( ; i+3 < numVerts; i+=4 ) {
// load normals
vector float vecNormal11 = vec_ld( 0, addr + ( i * DRAWVERT_OFFSET ) );
vector float vecNormal12 = vec_ld( 15, addr + ( i * DRAWVERT_OFFSET ) );
v0 = vec_perm( vecNormal11, vecNormal12, vecPerm0 );
vector float vecNormal21 = vec_ld( 0, addr + ((i+1) * DRAWVERT_OFFSET ) );
vector float vecNormal22 = vec_ld( 15, addr + ((i+1) * DRAWVERT_OFFSET ) );
v1 = vec_perm( vecNormal21, vecNormal22, vecPerm1 );
vector float vecNormal31 = vec_ld( 0, addr + ( (i+2) * DRAWVERT_OFFSET ) );
vector float vecNormal32 = vec_ld( 15, addr + ( (i+2) * DRAWVERT_OFFSET ) );
v2 = vec_perm( vecNormal31, vecNormal32, vecPerm2 );
vector float vecNormal41 = vec_ld( 0, addr + ((i+3) * DRAWVERT_OFFSET ) );
vector float vecNormal42 = vec_ld( 15, addr + ((i+3) * DRAWVERT_OFFSET ) );
v3 = vec_perm( vecNormal41, vecNormal42, vecPerm3 );
// zero out the last element of each useless vector
v0 = vec_perm( v0, zeroVector, vecPermLast );
v1 = vec_perm( v1, zeroVector, vecPermLast );
v2 = vec_perm( v2, zeroVector, vecPermLast );
v3 = vec_perm( v3, zeroVector, vecPermLast );
// got 4 vectors in v0 through v3, sum them each accross
// and put into one vector
vecTemp = vec_madd( v0, v0, zeroVector );
vecSum = vec_add( vecTemp, vec_sld( vecTemp, vecTemp, 8 ) );
vecSum = vec_add( vecSum, vec_sld( vecSum, vecSum, 4 ) );
// element 0 of vecSum now has sum of v0
vecTemp2 = vec_madd( v1, v1, zeroVector );
tempSum = vec_add( vecTemp2, vec_sld( vecTemp2, vecTemp2, 8 ) );
tempSum = vec_add( tempSum, vec_sld( tempSum, tempSum, 4 ) );
// put this into vecSum
vecSum = vec_mergeh( vecSum, tempSum );
vecTemp3 = vec_madd( v2, v2, zeroVector );
tempSum = vec_add( vecTemp3, vec_sld( vecTemp3, vecTemp3, 8 ) );
tempSum = vec_add( tempSum, vec_sld( tempSum, tempSum, 4 ) );
// put this into vecSum
vecSum = vec_perm( vecSum, tempSum, vecPermHalves );
vecTemp4 = vec_madd( v3, v3, zeroVector );
tempSum = vec_add( vecTemp4, vec_sld( vecTemp4, vecTemp4, 8 ) );
tempSum = vec_add( tempSum, vec_sld( tempSum, tempSum, 4 ) );
// put this into vecSum
vecSum = vec_perm( vecSum, tempSum, vecPermLast );
// take reciprocal square roots of these
vecF = ReciprocalSquareRoot( vecSum );
// multiply each vector by f
v5 = vec_madd( v0, vec_splat( vecF, 0 ), zeroVector );
v6 = vec_madd( v1, vec_splat( vecF, 1 ), zeroVector );
v7 = vec_madd( v2, vec_splat( vecF, 2 ), zeroVector );
v8 = vec_madd( v3, vec_splat( vecF, 3 ), zeroVector );
// load tangents as unaligned
vecTan11 = vec_ld( 0, tAddr + ( i * DRAWVERT_OFFSET ) );
vecTan12 = vec_ld( 11, tAddr + ( i * DRAWVERT_OFFSET ) );
vecTan13 = vec_ld( 23, tAddr + ( i * DRAWVERT_OFFSET ) );
vecTan21 = vec_ld( 0, tAddr + ( (i+1) * DRAWVERT_OFFSET ) );
vecTan22 = vec_ld( 11, tAddr + ( (i+1) * DRAWVERT_OFFSET ) );
vecTan23 = vec_ld( 23, tAddr + ( (i+1) * DRAWVERT_OFFSET ) );
vecTan31 = vec_ld( 0, tAddr + ( (i+2) * DRAWVERT_OFFSET ) );
vecTan32 = vec_ld( 11, tAddr + ( (i+2) * DRAWVERT_OFFSET ) );
vecTan33 = vec_ld( 23, tAddr + ( (i+2) * DRAWVERT_OFFSET ) );
vecTan41 = vec_ld( 0, tAddr + ( (i+3) * DRAWVERT_OFFSET ) );
vecTan42 = vec_ld( 11, tAddr + ( (i+3) * DRAWVERT_OFFSET ) );
vecTan43 = vec_ld( 23, tAddr + ( (i+3) * DRAWVERT_OFFSET ) );
vec1T0 = vec_perm( vecTan11, vecTan12, vec1T0Perm );
vec1T1 = vec_perm( vecTan12, vecTan13, vec1T1Perm );
vec2T0 = vec_perm( vecTan21, vecTan22, vec2T0Perm );
vec2T1 = vec_perm( vecTan22, vecTan23, vec2T1Perm );
vec3T0 = vec_perm( vecTan31, vecTan32, vec3T0Perm );
vec3T1 = vec_perm( vecTan32, vecTan33, vec3T1Perm );
vec4T0 = vec_perm( vecTan41, vecTan42, vec4T0Perm );
vec4T1 = vec_perm( vecTan42, vecTan43, vec4T1Perm );
//zero out last element of tangents
vec1T0 = vec_perm( vec1T0, zeroVector, vecPermLast );
vec1T1 = vec_perm( vec1T1, zeroVector, vecPermLast );
vec2T0 = vec_perm( vec2T0, zeroVector, vecPermLast );
vec2T1 = vec_perm( vec2T1, zeroVector, vecPermLast );
vec3T0 = vec_perm( vec3T0, zeroVector, vecPermLast );
vec3T1 = vec_perm( vec3T1, zeroVector, vecPermLast );
vec4T0 = vec_perm( vec4T0, zeroVector, vecPermLast );
vec4T1 = vec_perm( vec4T1, zeroVector, vecPermLast );
// all tangents[0]
tempSum = zeroVector;
tempSum = vec_madd( vec1T0, v5, tempSum );
//sum accross tempSum
vecTSum1 = vec_add( tempSum, vec_sld( tempSum, tempSum, 8 ) );
vecTSum1 = vec_add( vecTSum1, vec_sld( vecTSum1, vecTSum1, 4 ) );
// put tempSum splatted accross vecTSum1
vecTSum1 = vec_perm( vecTSum1, zeroVector, vecPermSplatFirstWithZero );
vecTSum1 = vec_madd( vecTSum1, v5, zeroVector );
//vec1T0 now contains what needs to be rsqrt'd and multiplied by f
vec1T0 = vec_sub( vec1T0, vecTSum1 );
tempSum = zeroVector;
tempSum = vec_madd( vec2T0, v6, tempSum );
//sum accross tempSum
vecTSum1 = vec_add( tempSum, vec_sld( tempSum, tempSum, 8 ) );
vecTSum1 = vec_add( vecTSum1, vec_sld( vecTSum1, vecTSum1, 4 ) );
vecTSum1 = vec_perm( vecTSum1, zeroVector, vecPermSplatFirstWithZero );
vecTSum1 = vec_madd( vecTSum1, v6, zeroVector );
vec2T0 = vec_sub( vec2T0, vecTSum1 );
tempSum = zeroVector;
tempSum = vec_madd( vec3T0, v7, tempSum );
//sum accross tempSum
vecTSum1 = vec_add( tempSum, vec_sld( tempSum, tempSum, 8 ) );
vecTSum1 = vec_add( vecTSum1, vec_sld( vecTSum1, vecTSum1, 4 ) );
vecTSum1 = vec_perm( vecTSum1, zeroVector, vecPermSplatFirstWithZero );
vecTSum1 = vec_madd( vecTSum1, v7, zeroVector );
vec3T0 = vec_sub( vec3T0, vecTSum1 );
tempSum = zeroVector;
tempSum = vec_madd( vec4T0, v8, tempSum );
//sum accross tempSum
vecTSum1 = vec_add( tempSum, vec_sld( tempSum, tempSum, 8 ) );
vecTSum1 = vec_add( vecTSum1, vec_sld( vecTSum1, vecTSum1, 4 ) );
vecTSum1 = vec_perm( vecTSum1, zeroVector, vecPermSplatFirstWithZero );
vecTSum1 = vec_madd( vecTSum1, v8, zeroVector );
vec4T0 = vec_sub( vec4T0, vecTSum1 );
// all tangents[1]
tempSum = zeroVector;
tempSum = vec_madd( vec1T1, v5, tempSum );
//sum accross tempSum
vecTSum1 = vec_add( tempSum, vec_sld( tempSum, tempSum, 8 ) );
vecTSum1 = vec_add( vecTSum1, vec_sld( vecTSum1, vecTSum1, 4 ) );
vecTSum1 = vec_perm( vecTSum1, zeroVector, vecPermSplatFirstWithZero );
vecTSum1 = vec_madd( vecTSum1, v5, zeroVector );
//vec1T0 now contains what needs to be rsqrt'd and multiplied by f
vec1T1 = vec_sub( vec1T1, vecTSum1 );
tempSum = zeroVector;
tempSum = vec_madd( vec2T1, v6, tempSum );
//sum accross tempSum
vecTSum1 = vec_add( tempSum, vec_sld( tempSum, tempSum, 8 ) );
vecTSum1 = vec_add( vecTSum1, vec_sld( vecTSum1, vecTSum1, 4 ) );
vecTSum1 = vec_perm( vecTSum1, zeroVector, vecPermSplatFirstWithZero );
vecTSum1 = vec_madd( vecTSum1, v6, zeroVector );
vec2T1 = vec_sub( vec2T1, vecTSum1 );
tempSum = zeroVector;
tempSum = vec_madd( vec3T1, v7, tempSum );
//sum accross tempSum
vecTSum1 = vec_add( tempSum, vec_sld( tempSum, tempSum, 8 ) );
vecTSum1 = vec_add( vecTSum1, vec_sld( vecTSum1, vecTSum1, 4 ) );
vecTSum1 = vec_perm( vecTSum1, zeroVector, vecPermSplatFirstWithZero );
vecTSum1 = vec_madd( vecTSum1, v7, zeroVector );
vec3T1 = vec_sub( vec3T1, vecTSum1 );
tempSum = zeroVector;
tempSum = vec_madd( vec4T1, v8, tempSum );
//sum accross tempSum
vecTSum1 = vec_add( tempSum, vec_sld( tempSum, tempSum, 8 ) );
vecTSum1 = vec_add( vecTSum1, vec_sld( vecTSum1, vecTSum1, 4 ) );
vecTSum1 = vec_perm( vecTSum1, zeroVector, vecPermSplatFirstWithZero );
vecTSum1 = vec_madd( vecTSum1, v8, zeroVector );
vec4T1 = vec_sub( vec4T1, vecTSum1 );
// sum accross vectors and put into one vector
vecTemp = vec_madd( vec1T0, vec1T0, zeroVector );
vecTSum1 = vec_add( vecTemp, vec_sld( vecTemp, vecTemp, 8 ) );
vecTSum1 = vec_add( vecTSum1, vec_sld( vecTSum1, vecTSum1, 4 ) );
// element 0 of vecSum now has sum of v0
vecTemp = vec_madd( vec2T0, vec2T0, zeroVector );
tempSum2 = vec_add( vecTemp, vec_sld( vecTemp, vecTemp, 8 ) );
tempSum2 = vec_add( tempSum2, vec_sld( tempSum2, tempSum2, 4 ) );
// put this into vecSum
vecTemp = vec_madd( vec3T0, vec3T0, zeroVector );
vecTSum1 = vec_mergeh( vecTSum1, tempSum2 );
tempSum2 = vec_add( vecTemp, vec_sld( vecTemp, vecTemp, 8 ) );
tempSum2 = vec_add( tempSum2, vec_sld( tempSum2, tempSum2, 4 ) );
// put this into vecSum
vecTSum1 = vec_perm( vecTSum1, tempSum2, vecPermHalves );
vecTemp = vec_madd( vec4T0, vec4T0, zeroVector );
tempSum2 = vec_add( vecTemp, vec_sld( vecTemp, vecTemp, 8 ) );
tempSum2 = vec_add( tempSum2, vec_sld( tempSum2, tempSum2, 4 ) );
// put this into vecSum
vecTSum1 = vec_perm( vecTSum1, tempSum2, vecPermLast );
vecTemp = vec_madd( vec1T1, vec1T1, zeroVector );
vecTSum2 = vec_add( vecTemp, vec_sld( vecTemp, vecTemp, 8 ) );
vecTSum2 = vec_add( vecTSum2, vec_sld( vecTSum2, vecTSum2, 4 ) );
// element 0 of vecSum now has sum of v0
vecTemp = vec_madd( vec2T1, vec2T1, zeroVector );
tempSum3 = vec_add( vecTemp, vec_sld( vecTemp, vecTemp, 8 ) );
tempSum3 = vec_add( tempSum3, vec_sld( tempSum3, tempSum3, 4 ) );
// put this into vecSum
vecTSum2 = vec_mergeh( vecTSum2, tempSum3 );
vecTemp = vec_madd( vec3T1, vec3T1, zeroVector );
tempSum3 = vec_add( vecTemp, vec_sld( vecTemp, vecTemp, 8 ) );
tempSum3 = vec_add( tempSum3, vec_sld( tempSum3, tempSum3, 4 ) );
// put this into vecSum
vecTSum2 = vec_perm( vecTSum2, tempSum3, vecPermHalves );
vecTemp = vec_madd( vec4T1, vec4T1, zeroVector );
tempSum3 = vec_add( vecTemp, vec_sld( vecTemp, vecTemp, 8 ) );
tempSum3 = vec_add( tempSum3, vec_sld( tempSum3, tempSum3, 4 ) );
// put this into vecSum
vecTSum2 = vec_perm( vecTSum2, tempSum3, vecPermLast );
// tangents[0]
vecF = ReciprocalSquareRoot( vecTSum1 );
// tangents[1]
vecF2 = ReciprocalSquareRoot( vecTSum2 );
// multiply each tangent vector by f
vec1T0 = vec_madd( vec1T0, vec_splat( vecF, 0 ), zeroVector );
vec2T0 = vec_madd( vec2T0, vec_splat( vecF, 1 ), zeroVector );
vec3T0 = vec_madd( vec3T0, vec_splat( vecF, 2 ), zeroVector );
vec4T0 = vec_madd( vec4T0, vec_splat( vecF, 3 ), zeroVector );
vec1T1 = vec_madd( vec1T1, vec_splat( vecF2, 0 ), zeroVector );
vec2T1 = vec_madd( vec2T1, vec_splat( vecF2, 1 ), zeroVector );
vec3T1 = vec_madd( vec3T1, vec_splat( vecF2, 2 ), zeroVector );
vec4T1 = vec_madd( vec4T1, vec_splat( vecF2, 3 ), zeroVector );
// rotate input data
v5 = vec_perm( v5, v5, storePerm0 );
v6 = vec_perm( v6, v6, storePerm1 );
v7 = vec_perm( v7, v7, storePerm2 );
v8 = vec_perm( v8, v8, storePerm3 );
vec_ste( v5, 0, addr + ( (i+0) * DRAWVERT_OFFSET ) );
vec_ste( v5, 4, addr + ( (i+0) * DRAWVERT_OFFSET ) );
vec_ste( v5, 8, addr + ( (i+0) * DRAWVERT_OFFSET ) );
vec_ste( v6, 0, addr + ( (i+1) * DRAWVERT_OFFSET ) );
vec_ste( v6, 4, addr + ( (i+1) * DRAWVERT_OFFSET ) );
vec_ste( v6, 8, addr + ( (i+1) * DRAWVERT_OFFSET ) );
vec_ste( v7, 0, addr + ( (i+2) * DRAWVERT_OFFSET ) );
vec_ste( v7, 4, addr + ( (i+2) * DRAWVERT_OFFSET ) );
vec_ste( v7, 8, addr + ( (i+2) * DRAWVERT_OFFSET ) );
vec_ste( v8, 0, addr + ( (i+3) * DRAWVERT_OFFSET ) );
vec_ste( v8, 4, addr + ( (i+3) * DRAWVERT_OFFSET ) );
vec_ste( v8, 8, addr + ( (i+3) * DRAWVERT_OFFSET ) );
// store tangents[0] and tangents[1]
vec1T0 = vec_perm( vec1T0, vec1T0, storeT11 );
vec1T1 = vec_perm( vec1T1, vec1T1, storeT12 );
vec_ste( vec1T0, 0, tAddr + ((i+0) * DRAWVERT_OFFSET ) );
vec_ste( vec1T0, 4, tAddr + ((i+0) * DRAWVERT_OFFSET ) );
vec_ste( vec1T0, 8, tAddr + ((i+0) * DRAWVERT_OFFSET ) );
vec_ste( vec1T1, 12, tAddr + ((i+0) * DRAWVERT_OFFSET ) );
vec_ste( vec1T1, 16, tAddr + ((i+0) * DRAWVERT_OFFSET ) );
vec_ste( vec1T1, 20, tAddr + ((i+0) * DRAWVERT_OFFSET ) );
// store second tangents[0] and tangents[1]
vec2T0 = vec_perm( vec2T0, vec2T0, storeT21 );
vec2T1 = vec_perm( vec2T1, vec2T1, storeT22 );
vec_ste( vec2T0, 0, tAddr + ((i+1) * DRAWVERT_OFFSET ) );
vec_ste( vec2T0, 4, tAddr + ((i+1) * DRAWVERT_OFFSET ) );
vec_ste( vec2T0, 8, tAddr + ((i+1) * DRAWVERT_OFFSET ) );
vec_ste( vec2T1, 12, tAddr + ((i+1) * DRAWVERT_OFFSET ) );
vec_ste( vec2T1, 16, tAddr + ((i+1) * DRAWVERT_OFFSET ) );
vec_ste( vec2T1, 20, tAddr + ((i+1) * DRAWVERT_OFFSET ) );
// store third tangents[0] and tangents[1]
vec3T0 = vec_perm( vec3T0, vec3T0, storeT31 );
vec3T1 = vec_perm( vec3T1, vec3T1, storeT32 );
vec_ste( vec3T0, 0, tAddr + ((i+2) * DRAWVERT_OFFSET ) );
vec_ste( vec3T0, 4, tAddr + ((i+2) * DRAWVERT_OFFSET ) );
vec_ste( vec3T0, 8, tAddr + ((i+2) * DRAWVERT_OFFSET ) );
vec_ste( vec3T1, 12, tAddr + ((i+2) * DRAWVERT_OFFSET ) );
vec_ste( vec3T1, 16, tAddr + ((i+2) * DRAWVERT_OFFSET ) );
vec_ste( vec3T1, 20, tAddr + ((i+2) * DRAWVERT_OFFSET ) );
// store fourth tangents[0] and tangents[1]
vec4T0 = vec_perm( vec4T0, vec4T0, storeT41 );
vec4T1 = vec_perm( vec4T1, vec4T1, storeT42 );
vec_ste( vec4T0, 0, tAddr + ((i+3) * DRAWVERT_OFFSET ) );
vec_ste( vec4T0, 4, tAddr + ((i+3) * DRAWVERT_OFFSET ) );
vec_ste( vec4T0, 8, tAddr + ((i+3) * DRAWVERT_OFFSET ) );
vec_ste( vec4T1, 12, tAddr + ((i+3) * DRAWVERT_OFFSET ) );
vec_ste( vec4T1, 16, tAddr + ((i+3) * DRAWVERT_OFFSET ) );
vec_ste( vec4T1, 20, tAddr + ((i+3) * DRAWVERT_OFFSET ) );
}
// cleanup
for ( ; i < numVerts; i++ ) {
idVec3 &v = verts[i].normal;
float f;
//f = idMath::RSqrt( v.x * v.x + v.y * v.y + v.z * v.z );
f = FastScalarInvSqrt( v.x * v.x + v.y * v.y + v.z * v.z );
v.x *= f; v.y *= f; v.z *= f;
for ( int j = 0; j < 2; j++ ) {
idVec3 &t = verts[i].tangents[j];
t -= ( t * v ) * v;
// f = idMath::RSqrt( t.x * t.x + t.y * t.y + t.z * t.z );
f = FastScalarInvSqrt( t.x * t.x + t.y * t.y + t.z * t.z );
t.x *= f; t.y *= f; t.z *= f;
}
}
}
#endif /* ENABLE_DERIVE */
#ifdef ENABLE_CREATE
/*
============
idSIMD_AltiVec::CreateTextureSpaceLightVectors
Calculates light vectors in texture space for the given triangle vertices.
For each vertex the direction towards the light origin is projected onto texture space.
The light vectors are only calculated for the vertices referenced by the indexes.
============
*/
void VPCALL idSIMD_AltiVec::CreateTextureSpaceLightVectors( idVec3 *lightVectors, const idVec3 &lightOrigin, const idDrawVert *verts, const int numVerts, const int *indexes, const int numIndexes ) {
bool *used = (bool *)_alloca16( numVerts * sizeof( used[0] ) );
memset( used, 0, numVerts * sizeof( used[0] ) );
int i;
for ( i = 0; i+7 < numIndexes; i+= 8 ) {
used[indexes[i]] = true;
used[indexes[i+1]] = true;
used[indexes[i+2]] = true;
used[indexes[i+3]] = true;
used[indexes[i+4]] = true;
used[indexes[i+5]] = true;
used[indexes[i+6]] = true;
used[indexes[i+7]] = true;
}
for ( ; i < numIndexes; i++ ) {
used[indexes[i]] = true;
}
for ( i = 0; i+1 < numVerts; i+=2 ) {
const idDrawVert *v = &verts[i];
const idDrawVert *v2 = &verts[i+1];
float x, y, z;
float x2, y2, z2;
idVec3 lightDir, lightDir2;
lightDir[0] = lightOrigin[0] - v->xyz[0];
lightDir[1] = lightOrigin[1] - v->xyz[1];
lightDir[2] = lightOrigin[2] - v->xyz[2];
lightDir2[0] = lightOrigin[0] - v2->xyz[0];
lightDir2[1] = lightOrigin[1] - v2->xyz[1];
lightDir2[2] = lightOrigin[2] - v2->xyz[2];
x = lightDir[0] * v->tangents[0][0] + lightDir[1] * v->tangents[0][1] + lightDir[2] * v->tangents[0][2];
y = lightDir[0] * v->tangents[1][0] + lightDir[1] * v->tangents[1][1] + lightDir[2] * v->tangents[1][2];
z = lightDir[0] * v->normal[0] + lightDir[1] * v->normal[1] + lightDir[2] * v->normal[2];
x2 = lightDir2[0] * v2->tangents[0][0] + lightDir2[1] * v2->tangents[0][1] + lightDir2[2] * v2->tangents[0][2];
y2 = lightDir2[0] * v2->tangents[1][0] + lightDir2[1] * v2->tangents[1][1] + lightDir2[2] * v2->tangents[1][2];
z2 = lightDir2[0] * v2->normal[0] + lightDir2[1] * v2->normal[1] + lightDir2[2] * v2->normal[2];
if ( used[i] ) {
lightVectors[i][0] = x;
lightVectors[i][1] = y;
lightVectors[i][2] = z;
}
if ( used[i+1] ) {
lightVectors[i+1][0] = x2;
lightVectors[i+1][1] = y2;
lightVectors[i+1][2] = z2;
}
}
// cleanup
for ( ; i < numVerts; i++ ) {
if ( !used[i] ) {
continue;
}
const idDrawVert *v = &verts[i];
idVec3 lightDir;
lightDir[0] = lightOrigin[0] - v->xyz[0];
lightDir[1] = lightOrigin[1] - v->xyz[1];
lightDir[2] = lightOrigin[2] - v->xyz[2];
lightVectors[i][0] = lightDir[0] * v->tangents[0][0] + lightDir[1] * v->tangents[0][1] + lightDir[2] * v->tangents[0][2];
lightVectors[i][1] = lightDir[0] * v->tangents[1][0] + lightDir[1] * v->tangents[1][1] + lightDir[2] * v->tangents[1][2];
lightVectors[i][2] = lightDir[0] * v->normal[0] + lightDir[1] * v->normal[1] + lightDir[2] * v->normal[2];
}
}
#if 1
/*
============
idSIMD_AltiVec::CreateSpecularTextureCoords
Calculates specular texture coordinates for the given triangle vertices.
For each vertex the normalized direction towards the light origin is added to the
normalized direction towards the view origin and the result is projected onto texture space.
The texture coordinates are only calculated for the vertices referenced by the indexes.
============
*/
void VPCALL idSIMD_AltiVec::CreateSpecularTextureCoords( idVec4 *texCoords, const idVec3 &lightOrigin, const idVec3 &viewOrigin, const idDrawVert *verts, const int numVerts, const int *indexes, const int numIndexes ) {
bool *used = (bool *)_alloca16( numVerts * sizeof( used[0] ) );
memset( used, 0, numVerts * sizeof( used[0] ) );
int i;
for ( i = 0; i+7 < numIndexes; i+= 8 ) {
used[indexes[i]] = true;
used[indexes[i+1]] = true;
used[indexes[i+2]] = true;
used[indexes[i+3]] = true;
used[indexes[i+4]] = true;
used[indexes[i+5]] = true;
used[indexes[i+6]] = true;
used[indexes[i+7]] = true;
}
for ( ; i < numIndexes; i++ ) {
used[indexes[i]] = true;
}
// load lightOrigin and viewOrigin into vectors
const float *lightOriginPtr = lightOrigin.ToFloatPtr();
const float *viewOriginPtr = viewOrigin.ToFloatPtr();
vector unsigned char permVec = vec_lvsl( 0, lightOriginPtr );
vector unsigned char permVec2 = vec_lvsl( 0, viewOriginPtr );
vector float v0 = vec_ld( 0, lightOriginPtr );
vector float v1 = vec_ld( 15, lightOriginPtr );
vector float v2 = vec_ld( 0, viewOriginPtr );
vector float v3 = vec_ld( 15, viewOriginPtr );
vector float vecLightOrigin = vec_perm( v0, v1, permVec );
vector float vecViewOrigin = vec_perm( v2, v3, permVec2 );
const vector float zeroVector = (vector float)(0);
int index;
for ( index = 0; index+1 < numVerts; index+=2 ) {
const float *vertPtr = verts[index].xyz.ToFloatPtr();
const float *vertPtr2 = verts[index+1].xyz.ToFloatPtr();
permVec = vec_add( vec_lvsl( -1, vertPtr ), (vector unsigned char)(1) );
permVec2 = vec_add( vec_lvsl( -1, vertPtr2 ), (vector unsigned char)(1) );
v0 = vec_ld( 0, vertPtr );
v1 = vec_ld( 15, vertPtr );
vector float v2 = vec_ld( 31, vertPtr );
vector float v3 = vec_ld( 47, vertPtr );
vector float v4 = vec_ld( 63, vertPtr );
vector float v5 = vec_ld( 0, vertPtr2 );
vector float v6 = vec_ld( 15, vertPtr2 );
vector float v7 = vec_ld( 31, vertPtr2 );
vector float v8 = vec_ld( 47, vertPtr2 );
vector float v9 = vec_ld( 63, vertPtr2 );
// figure out what values go where
vector float vecXYZ = vec_perm( v0, v1, permVec );
vector float vecNormal = vec_perm( v1, v2, permVec );
vecNormal = vec_sld( vecNormal, vecNormal, 4 );
const vector float vecTangent0 = vec_perm( v2, v3, permVec );
permVec = vec_add( permVec, (vector unsigned char)(-4) ); //shift permute right 3 elements
const vector float vecTangent1 = vec_perm( v3, v4, permVec );
vector float vecXYZ2 = vec_perm( v5, v6, permVec2 );
vector float vecNormal2 = vec_perm( v6, v7, permVec2 );
vecNormal2 = vec_sld( vecNormal2, vecNormal2, 4 );
const vector float vecTangent02 = vec_perm( v7, v8, permVec2 );
permVec2 = vec_add( permVec2, (vector unsigned char)(-4) );
const vector float vecTangent12 = vec_perm( v8, v9, permVec2 );
// calculate lightDir
vector float vecLightDir = vec_sub( vecLightOrigin, vecXYZ );
vector float vecViewDir = vec_sub( vecViewOrigin, vecXYZ );
vector float vecLightDir2 = vec_sub( vecLightOrigin, vecXYZ2 );
vector float vecViewDir2 = vec_sub( vecViewOrigin, vecXYZ2 );
// calculate distance
vector float vecTempLight = vec_madd( vecLightDir, vecLightDir, zeroVector );
vector float vecTempView = vec_madd( vecViewDir, vecViewDir, zeroVector );
vector float vecTempLight2 = vec_madd( vecLightDir2, vecLightDir2, zeroVector );
vector float vecTempView2 = vec_madd( vecViewDir2, vecViewDir2, zeroVector );
// sum accross first 3 elements of vector
vector float tempSum = vec_add( vecTempLight, vec_sld( vecTempLight, vecTempLight, 4 ) );
vecTempLight = vec_add( tempSum, vec_sld( tempSum, tempSum, 8 ) );
vector float tempSum2 = vec_add( vecTempView, vec_sld( vecTempView, vecTempView, 4 ) );
vecTempView = vec_add( tempSum2, vec_sld( tempSum2, tempSum2, 8 ) );
vector float tempSum4 = vec_add( vecTempLight2, vec_sld( vecTempLight2, vecTempLight2, 4 ) );
vecTempLight2 = vec_add( tempSum4, vec_sld( tempSum4, tempSum4, 8 ) );
vector float tempSum5 = vec_add( vecTempView2, vec_sld( vecTempView2, vecTempView2, 4 ) );
vecTempView2 = vec_add( tempSum5, vec_sld( tempSum5, tempSum5, 8 ) );
// splat sum accross the whole vector
vecTempLight = vec_splat( vecTempLight, 0 );
vecTempView = vec_splat( vecTempView, 0 );
vecTempLight2 = vec_splat( vecTempLight2, 0 );
vecTempView2 = vec_splat( vecTempView2, 0 );
vecTempLight = ReciprocalSquareRoot( vecTempLight );
vecTempView = ReciprocalSquareRoot( vecTempView );
vecTempLight2 = ReciprocalSquareRoot( vecTempLight2 );
vecTempView2 = ReciprocalSquareRoot( vecTempView2 );
// modify light and view vectors based on ilength
vecViewDir = vec_madd( vecViewDir, vecTempView, zeroVector );
vecLightDir = vec_madd( vecLightDir, vecTempLight, vecViewDir );
vecViewDir2 = vec_madd( vecViewDir2, vecTempView2, zeroVector );
vecLightDir2 = vec_madd( vecLightDir2, vecTempLight2, vecViewDir2 );
// calculate what to store in each texture coord
vector float vecTC0 = vec_madd( vecLightDir, vecTangent0, zeroVector );
vector float vecTC1 = vec_madd( vecLightDir, vecTangent1, zeroVector );
vector float vecTC2 = vec_madd( vecLightDir, vecNormal, zeroVector );
vector float vecTC3 = vec_madd( vecLightDir2, vecTangent02, zeroVector );
vector float vecTC4 = vec_madd( vecLightDir2, vecTangent12, zeroVector );
vector float vecTC5 = vec_madd( vecLightDir2, vecNormal2, zeroVector );
// sum accross first 3 elements of vector
vector float tempSum3;
tempSum = vec_add( vecTC0, vec_sld( vecTC0, vecTC0, 4 ) );
vecTC0 = vec_add( tempSum, vec_sld( vecTC0, vecTC0, 8 ) );
tempSum2 = vec_add( vecTC1, vec_sld( vecTC1, vecTC1, 4 ) );
vecTC1 = vec_add( tempSum2, vec_sld( vecTC1, vecTC1, 8 ) );
tempSum3 = vec_add( vecTC2, vec_sld( vecTC2, vecTC2, 4 ) );
vecTC2 = vec_add( tempSum3, vec_sld( vecTC2, vecTC2, 8 ) );
tempSum4 = vec_add( vecTC3, vec_sld( vecTC3, vecTC3, 4 ) );
vecTC3 = vec_add( tempSum4, vec_sld( vecTC3, vecTC3, 8 ) );
tempSum5 = vec_add( vecTC4, vec_sld( vecTC4, vecTC4, 4 ) );
vecTC4 = vec_add( tempSum5, vec_sld( vecTC4, vecTC4, 8 ) );
vector float tempSum6 = vec_add( vecTC5, vec_sld( vecTC5, vecTC5, 4 ) );
vecTC5 = vec_add( tempSum6, vec_sld( vecTC5, vecTC5, 8 ) );
vecTC0 = vec_splat( vecTC0, 0 );
vecTC1 = vec_splat( vecTC1, 0 );
vecTC2 = vec_splat( vecTC2, 0 );
vecTC3 = vec_splat( vecTC3, 0 );
vecTC4 = vec_splat( vecTC4, 0 );
vecTC5 = vec_splat( vecTC5, 0 );
if ( used[index] ) {
// store out results
vec_ste( vecTC0, 0, &texCoords[index][0] );
vec_ste( vecTC1, 0, &texCoords[index][1] );
vec_ste( vecTC2, 0, &texCoords[index][2] );
vec_ste( (vector float)(1.0), 0, &texCoords[index][3] );
}
if ( used[index+1] ) {
vec_ste( vecTC3, 0, &texCoords[index+1][0] );
vec_ste( vecTC4, 0, &texCoords[index+1][1] );
vec_ste( vecTC5, 0, &texCoords[index+1][2] );
vec_ste( (vector float)(1.0), 0, &texCoords[index+1][3] );
}
}
// cleanup
for ( ; index < numVerts; index++ ) {
if ( !used[index] ) {
continue;
}
const float *vertPtr = verts[index].xyz.ToFloatPtr();
permVec = vec_add( vec_lvsl( -1, vertPtr ), (vector unsigned char)(1) );
v0 = vec_ld( 0, vertPtr );
v1 = vec_ld( 15, vertPtr );
vector float v2 = vec_ld( 31, vertPtr );
vector float v3 = vec_ld( 47, vertPtr );
vector float v4 = vec_ld( 63, vertPtr );
// figure out what values go where
vector float vecXYZ = vec_perm( v0, v1, permVec );
vector float vecNormal = vec_perm( v1, v2, permVec );
vecNormal = vec_sld( vecNormal, vecNormal, 4 );
const vector float vecTangent0 = vec_perm( v2, v3, permVec );
permVec = vec_add( permVec, (vector unsigned char)(-4) ); //shift permute right 3 elements
const vector float vecTangent1 = vec_perm( v3, v4, permVec );
// calculate lightDir
vector float vecLightDir = vec_sub( vecLightOrigin, vecXYZ );
vector float vecViewDir = vec_sub( vecViewOrigin, vecXYZ );
// calculate distance
vector float vecTempLight = vec_madd( vecLightDir, vecLightDir, zeroVector );
vector float vecTempView = vec_madd( vecViewDir, vecViewDir, zeroVector );
// sum accross first 3 elements of vector
vector float tempSum = vec_add( vecTempLight, vec_sld( vecTempLight, vecTempLight, 4 ) );
vecTempLight = vec_add( tempSum, vec_sld( tempSum, tempSum, 8 ) );
vector float tempSum2 = vec_add( vecTempView, vec_sld( vecTempView, vecTempView, 4 ) );
vecTempView = vec_add( tempSum2, vec_sld( tempSum2, tempSum2, 8 ) );
// splat sum accross the whole vector
vecTempLight = vec_splat( vecTempLight, 0 );
vecTempView = vec_splat( vecTempView, 0 );
vecTempLight = ReciprocalSquareRoot( vecTempLight );
vecTempView = ReciprocalSquareRoot( vecTempView );
// modify light and view vectors based on ilength
vecViewDir = vec_madd( vecViewDir, vecTempView, zeroVector );
vecLightDir = vec_madd( vecLightDir, vecTempLight, vecViewDir );
// calculate what to store in each texture coord
vector float vecTC0 = vec_madd( vecLightDir, vecTangent0, zeroVector );
vector float vecTC1 = vec_madd( vecLightDir, vecTangent1, zeroVector );
vector float vecTC2 = vec_madd( vecLightDir, vecNormal, zeroVector );
// sum accross first 3 elements of vector
vector float tempSum3;
tempSum = vec_add( vecTC0, vec_sld( vecTC0, vecTC0, 4 ) );
vecTC0 = vec_add( tempSum, vec_sld( vecTC0, vecTC0, 8 ) );
tempSum2 = vec_add( vecTC1, vec_sld( vecTC1, vecTC1, 4 ) );
vecTC1 = vec_add( tempSum2, vec_sld( vecTC1, vecTC1, 8 ) );
tempSum3 = vec_add( vecTC2, vec_sld( vecTC2, vecTC2, 4 ) );
vecTC2 = vec_add( tempSum3, vec_sld( vecTC2, vecTC2, 8 ) );
vecTC0 = vec_splat( vecTC0, 0 );
vecTC1 = vec_splat( vecTC1, 0 );
vecTC2 = vec_splat( vecTC2, 0 );
// store out results
vec_ste( vecTC0, 0, &texCoords[index][0] );
vec_ste( vecTC1, 0, &texCoords[index][1] );
vec_ste( vecTC2, 0, &texCoords[index][2] );
vec_ste( (vector float)(1.0), 0, &texCoords[index][3] );
}
}
#endif /* 0 for disable spec coord */
#if 1
#ifdef VERTEXCACHE_ALIGNED
/*
============
idSIMD_AltiVec::CreateShadowCache
============
*/
int VPCALL idSIMD_AltiVec::CreateShadowCache( idVec4 *vertexCache, int *vertRemap, const idVec3 &lightOrigin, const idDrawVert *verts, const int numVerts ) {
int outVerts = 0;
int i = 0;
assert( IS_16BYTE_ALIGNED( vertexCache[0] ) );
register vector float v0, v1, v2, v3, v4, v5, v6, v7;
register vector unsigned char vecPerm, vecPerm2, vecPerm3, vecPerm4, vecPerm5;
register vector float zeroVector = (vector float)(0.0);
register vector float oneVector = (vector float)(1);
register vector unsigned char vecPermZeroLast = (vector unsigned char)(0,1,2,3,4,5,6,7,8,9,10,11,16,17,18,19);
const float *lPtr = lightOrigin.ToFloatPtr();
const float *vPtr;
const float *vPtr2;
const float *vPtr3;
const float *vPtr4;
// put values into a vector
vecPerm = vec_add( vec_lvsl( -1, lPtr ), (vector unsigned char)(1) );
v0 = vec_ld( 0, lPtr );
v1 = vec_ld( 15, lPtr );
v0 = vec_perm( v0, v1, vecPerm );
v0 = vec_perm( v0, zeroVector, vecPermZeroLast );
//v0 now contains lightOrigin[0], lightOrigin[1], lightOrigin[2], 0
for ( ; i+3 < numVerts; i+= 4 ) {
if ( ! vertRemap[i] ) {
vPtr = verts[i].xyz.ToFloatPtr();
#ifndef DRAWVERT_PADDED
vecPerm2 = vec_add( vec_lvsl( -1, vPtr ), (vector unsigned char)(1) );
v2 = vec_ld( 0, vPtr );
v3 = vec_ld( 15, vPtr );
v7 = vec_perm( v2, v3, vecPerm2 );
#else
v7 = vec_ld( 0, vPtr );
#endif
v2 = vec_perm( v7, zeroVector, vecPermZeroLast );
v3 = vec_perm( v7, oneVector, vecPermZeroLast );
v1 = vec_sub( v2, v0 );
vec_st( v3, 0, &vertexCache[outVerts][0] );
vec_st( v1, 0, &vertexCache[outVerts+1][0] );
vertRemap[i] = outVerts;
outVerts += 2;
}
if ( ! vertRemap[i+1] ) {
vPtr2 = verts[i+1].xyz.ToFloatPtr();
#ifndef DRAWVERT_PADDED
vecPerm3 = vec_add( vec_lvsl( -1, vPtr2 ), (vector unsigned char)(1) );
v4 = vec_ld( 0, vPtr2 );
v5 = vec_ld( 15, vPtr2 );
v6 = vec_perm( v4, v5, vecPerm3 );
#else
v6 = vec_ld( 0, vPtr2 );
#endif
v4 = vec_perm( v6, zeroVector, vecPermZeroLast );
v5 = vec_perm( v6, oneVector, vecPermZeroLast );
v6 = vec_sub( v4, v0 );
vec_st( v5, 0, &vertexCache[outVerts][0] );
vec_st( v6, 0, &vertexCache[outVerts+1][0] );
vertRemap[i+1] = outVerts;
outVerts += 2;
}
if ( ! vertRemap[i+2] ) {
vPtr3 = verts[i+2].xyz.ToFloatPtr();
#ifndef DRAWVERT_PADDED
vecPerm4 = vec_add( vec_lvsl( -1, vPtr3 ), (vector unsigned char)(1) );
v1 = vec_ld( 0, vPtr3 );
v2 = vec_ld( 15, vPtr3 );
v3 = vec_perm( v1, v2, vecPerm4 );
#else
v3 = vec_ld( 0, vPtr3 );
#endif
v1 = vec_perm( v3, zeroVector, vecPermZeroLast );
v2 = vec_perm( v3, oneVector, vecPermZeroLast );
v3 = vec_sub( v1, v0 );
vec_st( v2, 0, &vertexCache[outVerts][0] );
vec_st( v3, 0, &vertexCache[outVerts+1][0] );
vertRemap[i+2] = outVerts;
outVerts += 2;
}
if ( ! vertRemap[i+3] ) {
vPtr4 = verts[i+3].xyz.ToFloatPtr();
#ifndef DRAWVERT_PADDED
vecPerm5 = vec_add( vec_lvsl( -1, vPtr4 ), (vector unsigned char)(1) );
v4 = vec_ld( 0, vPtr4 );
v5 = vec_ld( 16, vPtr4 );
v6 = vec_perm( v4, v5, vecPerm5 );
#else
v6 = vec_ld( 0, vPtr4 );
#endif
v4 = vec_perm( v6, zeroVector, vecPermZeroLast );
v5 = vec_perm( v6, oneVector, vecPermZeroLast );
v6 = vec_sub( v4, v0 );
vec_st( v5, 0, &vertexCache[outVerts][0] );
vec_st( v6, 0, &vertexCache[outVerts+1][0] );
vertRemap[i+3] = outVerts;
outVerts += 2;
}
}
// cleanup
for (; i < numVerts; i++ ) {
if ( vertRemap[i] ) {
continue;
}
const float *v = verts[i].xyz.ToFloatPtr();
vertexCache[outVerts+0][0] = v[0];
vertexCache[outVerts+0][1] = v[1];
vertexCache[outVerts+0][2] = v[2];
vertexCache[outVerts+0][3] = 1.0f;
// R_SetupProjection() builds the projection matrix with a slight crunch
// for depth, which keeps this w=0 division from rasterizing right at the
// wrap around point and causing depth fighting with the rear caps
vertexCache[outVerts+1][0] = v[0] - lightOrigin[0];
vertexCache[outVerts+1][1] = v[1] - lightOrigin[1];
vertexCache[outVerts+1][2] = v[2] - lightOrigin[2];
vertexCache[outVerts+1][3] = 0.0f;
vertRemap[i] = outVerts;
outVerts += 2;
}
return outVerts;
}
#else
/*
============
idSIMD_AltiVec::CreateShadowCache
============
*/
int VPCALL idSIMD_AltiVec::CreateShadowCache( idVec4 *vertexCache, int *vertRemap, const idVec3 &lightOrigin, const idDrawVert *verts, const int numVerts ) {
int outVerts = 0;
int i = 0;
register vector float v0, v1, v2, v3, v4, v5, v6, v7;
register vector unsigned char vecPerm, vecPerm2, vecPerm3, vecPerm4, vecPerm5;
register vector float zeroVector = (vector float)(0.0);
register vector float oneVector = (vector float)(1);
register vector unsigned char vecPermZeroLast = (vector unsigned char)(0,1,2,3,4,5,6,7,8,9,10,11,16,17,18,19);
const float *lPtr = lightOrigin.ToFloatPtr();
const float *vPtr;
const float *vPtr2;
const float *vPtr3;
const float *vPtr4;
// put values into a vector
vecPerm = vec_add( vec_lvsl( -1, lPtr ), (vector unsigned char)(1) );
v0 = vec_ld( 0, lPtr );
v1 = vec_ld( 15, lPtr );
v0 = vec_perm( v0, v1, vecPerm );
v0 = vec_perm( v0, zeroVector, vecPermZeroLast );
//v0 now contains lightOrigin[0], lightOrigin[1], lightOrigin[2], 0
for ( ; i+3 < numVerts; i+= 4 ) {
if ( ! vertRemap[i] ) {
vPtr = verts[i].xyz.ToFloatPtr();
#ifndef DRAWVERT_PADDED
vecPerm2 = vec_add( vec_lvsl( -1, vPtr ), (vector unsigned char)(1) );
v2 = vec_ld( 0, vPtr );
v3 = vec_ld( 15, vPtr );
v7 = vec_perm( v2, v3, vecPerm2 );
#else
v7 = vec_ld( 0, vPtr );
#endif
v2 = vec_perm( v7, zeroVector, vecPermZeroLast );
v3 = vec_perm( v7, oneVector, vecPermZeroLast );
v1 = vec_sub( v2, v0 );
// store results
UNALIGNED_STORE2( &vertexCache[outVerts][0], v3, v1 );
vertRemap[i] = outVerts;
outVerts += 2;
}
if ( ! vertRemap[i+1] ) {
vPtr2 = verts[i+1].xyz.ToFloatPtr();
#ifndef DRAWVERT_PADDED
vecPerm3 = vec_add( vec_lvsl( -1, vPtr2 ), (vector unsigned char)(1) );
v4 = vec_ld( 0, vPtr2 );
v5 = vec_ld( 15, vPtr2 );
v6 = vec_perm( v4, v5, vecPerm3 );
#else
v6 = vec_ld( 0, vPtr2 );
#endif
v4 = vec_perm( v6, zeroVector, vecPermZeroLast );
v5 = vec_perm( v6, oneVector, vecPermZeroLast );
v6 = vec_sub( v4, v0 );
// store results
UNALIGNED_STORE2( &vertexCache[outVerts][0], v5, v6 );
vertRemap[i+1] = outVerts;
outVerts += 2;
}
if ( ! vertRemap[i+2] ) {
vPtr3 = verts[i+2].xyz.ToFloatPtr();
#ifndef DRAWVERT_PADDED
vecPerm4 = vec_add( vec_lvsl( -1, vPtr3 ), (vector unsigned char)(1) );
v1 = vec_ld( 0, vPtr3 );
v2 = vec_ld( 15, vPtr3 );
v3 = vec_perm( v1, v2, vecPerm4 );
#else
v3 = vec_ld( 0, vPtr3 );
#endif
v1 = vec_perm( v3, zeroVector, vecPermZeroLast );
v2 = vec_perm( v3, oneVector, vecPermZeroLast );
v3 = vec_sub( v1, v0 );
// store results
UNALIGNED_STORE2( &vertexCache[outVerts][0], v2, v3 );
vertRemap[i+2] = outVerts;
outVerts += 2;
}
if ( ! vertRemap[i+3] ) {
vPtr4 = verts[i+3].xyz.ToFloatPtr();
#ifndef DRAWVERT_PADDED
vecPerm5 = vec_add( vec_lvsl( -1, vPtr4 ), (vector unsigned char)(1) );
v4 = vec_ld( 0, vPtr4 );
v5 = vec_ld( 16, vPtr4 );
v6 = vec_perm( v4, v5, vecPerm5 );
#else
v6 = vec_ld( 0, vPtr4 );
#endif
v4 = vec_perm( v6, zeroVector, vecPermZeroLast );
v5 = vec_perm( v6, oneVector, vecPermZeroLast );
v6 = vec_sub( v4, v0 );
// store results
UNALIGNED_STORE2( &vertexCache[outVerts][0], v5, v6 );
vertRemap[i+3] = outVerts;
outVerts += 2;
}
}
// cleanup
for (; i < numVerts; i++ ) {
if ( vertRemap[i] ) {
continue;
}
const float *v = verts[i].xyz.ToFloatPtr();
vertexCache[outVerts+0][0] = v[0];
vertexCache[outVerts+0][1] = v[1];
vertexCache[outVerts+0][2] = v[2];
vertexCache[outVerts+0][3] = 1.0f;
// R_SetupProjection() builds the projection matrix with a slight crunch
// for depth, which keeps this w=0 division from rasterizing right at the
// wrap around point and causing depth fighting with the rear caps
vertexCache[outVerts+1][0] = v[0] - lightOrigin[0];
vertexCache[outVerts+1][1] = v[1] - lightOrigin[1];
vertexCache[outVerts+1][2] = v[2] - lightOrigin[2];
vertexCache[outVerts+1][3] = 0.0f;
vertRemap[i] = outVerts;
outVerts += 2;
}
return outVerts;
}
#endif /* VERTEXCACHE_ALIGNED */
#endif /* 0 to disable shadow cache */
#if 1
#ifdef VERTEXCACHE_ALIGNED
/*
============
idSIMD_AltiVec::CreateVertexProgramShadowCache
============
*/
int VPCALL idSIMD_AltiVec::CreateVertexProgramShadowCache( idVec4 *vertexCache, const idDrawVert *verts, const int numVerts ) {
// vertexCache aligned
assert( IS_16BYTE_ALIGNED( vertexCache[0] ) );
// idDrawVert size
assert( sizeof(idDrawVert) == DRAWVERT_OFFSET * sizeof(float) );
// idVec4 size
assert( sizeof(idVec4) == IDVEC4_OFFSET * sizeof(float) );
register vector float v0, v1, v2, v3, v4, v5, v6, v7;
register vector float zeroVector = (vector float)(0.0);
register vector float oneVector = (vector float)(1);
register vector unsigned char vecPermThreeOne = (vector unsigned char)(0,1,2,3,4,5,6,7,8,9,10,11,16,17,18,19);
vector unsigned char vertPerm1, vertPerm2, vertPerm3, vertPerm4;
int i = 0;
#ifndef DRAWVERT_PADDED
// every fourth one will have the same alignment. Make sure we've got enough here
if ( i+3 < numVerts ) {
vertPerm1 = vec_add( vec_lvsl( -1, (float*) verts[0].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vertPerm2 = vec_add( vec_lvsl( -1, (float*) verts[1].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vertPerm3 = vec_add( vec_lvsl( -1, (float*) verts[2].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vertPerm4 = vec_add( vec_lvsl( -1, (float*) verts[3].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
}
#endif
for ( ; i+3 < numVerts; i+=4 ) {
const float *vertPtr = verts[i].xyz.ToFloatPtr();
const float *vertPtr2 = verts[i+1].xyz.ToFloatPtr();
const float *vertPtr3 = verts[i+2].xyz.ToFloatPtr();
const float *vertPtr4 = verts[i+3].xyz.ToFloatPtr();
#ifndef DRAWVERT_PADDED
v0 = vec_ld( 0, vertPtr );
v1 = vec_ld( 15, vertPtr );
v2 = vec_ld( 0, vertPtr2 );
v3 = vec_ld( 15, vertPtr2 );
v4 = vec_ld( 0, vertPtr3 );
v5 = vec_ld( 15, vertPtr3 );
v6 = vec_ld( 0, vertPtr4 );
v7 = vec_ld( 15, vertPtr4 );
v0 = vec_perm( v0, v1, vertPerm1 );
v1 = vec_perm( v2, v3, vertPerm2 );
v2 = vec_perm( v4, v5, vertPerm3 );
v3 = vec_perm( v6, v7, vertPerm4 );
#else
v0 = vec_ld( 0, vertPtr );
v1 = vec_ld( 0, vertPtr2 );
v2 = vec_ld( 0, vertPtr3 );
v3 = vec_ld( 0, vertPtr4 );
#endif
v0 = vec_perm( v0, oneVector, vecPermThreeOne );
v4 = vec_perm( v0, zeroVector, vecPermThreeOne );
v1 = vec_perm( v1, oneVector, vecPermThreeOne );
v5 = vec_perm( v1, zeroVector, vecPermThreeOne );
v2 = vec_perm( v2, oneVector, vecPermThreeOne );
v6 = vec_perm( v2, zeroVector, vecPermThreeOne );
v3 = vec_perm( v3, oneVector, vecPermThreeOne );
v7 = vec_perm( v3, zeroVector, vecPermThreeOne );
// store results
ALIGNED_STORE4( &vertexCache[i*2][0], v0, v4, v1, v5 );
ALIGNED_STORE4( &vertexCache[(i+2)*2][0], v2, v6, v3, v7 );
}
// cleanup
for ( ; i < numVerts; i++ ) {
const float *v = verts[i].xyz.ToFloatPtr();
vertexCache[i*2+0][0] = v[0];
vertexCache[i*2+1][0] = v[0];
vertexCache[i*2+0][1] = v[1];
vertexCache[i*2+1][1] = v[1];
vertexCache[i*2+0][2] = v[2];
vertexCache[i*2+1][2] = v[2];
vertexCache[i*2+0][3] = 1.0f;
vertexCache[i*2+1][3] = 0.0f;
}
return numVerts * 2;
}
#else
/*
============
idSIMD_AltiVec::CreateVertexProgramShadowCache
============
*/
int VPCALL idSIMD_AltiVec::CreateVertexProgramShadowCache( idVec4 *vertexCache, const idDrawVert *verts, const int numVerts ) {
// idDrawVert size
assert( sizeof(idDrawVert) == DRAWVERT_OFFSET * sizeof(float) );
// idVec4 size
assert( sizeof(idVec4) == IDVEC4_OFFSET * sizeof(float) );
register vector float v0, v1, v2, v3, v4, v5, v6, v7;
register vector float zeroVector = (vector float)(0.0);
register vector float oneVector = (vector float)(1);
register vector unsigned char vecPermThreeOne = (vector unsigned char)(0,1,2,3,4,5,6,7,8,9,10,11,16,17,18,19);
vector unsigned char vertPerm1, vertPerm2, vertPerm3, vertPerm4;
int i = 0;
#ifndef DRAWVERT_PADDED
// every fourth one will have the same alignment. Make sure we've got enough here
if ( i+3 < numVerts ) {
vertPerm1 = vec_add( vec_lvsl( -1, (float*) verts[0].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vertPerm2 = vec_add( vec_lvsl( -1, (float*) verts[1].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vertPerm3 = vec_add( vec_lvsl( -1, (float*) verts[2].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
vertPerm4 = vec_add( vec_lvsl( -1, (float*) verts[3].xyz.ToFloatPtr() ), (vector unsigned char)(1) );
}
#endif
for ( ; i+3 < numVerts; i+=4 ) {
const float *vertPtr = verts[i].xyz.ToFloatPtr();
const float *vertPtr2 = verts[i+1].xyz.ToFloatPtr();
const float *vertPtr3 = verts[i+2].xyz.ToFloatPtr();
const float *vertPtr4 = verts[i+3].xyz.ToFloatPtr();
#ifndef DRAWVERT_PADDED
v0 = vec_ld( 0, vertPtr );
v1 = vec_ld( 15, vertPtr );
v2 = vec_ld( 0, vertPtr2 );
v3 = vec_ld( 15, vertPtr2 );
v4 = vec_ld( 0, vertPtr3 );
v5 = vec_ld( 15, vertPtr3 );
v6 = vec_ld( 0, vertPtr4 );
v7 = vec_ld( 15, vertPtr4 );
v0 = vec_perm( v0, v1, vertPerm1 );
v1 = vec_perm( v2, v3, vertPerm2 );
v2 = vec_perm( v4, v5, vertPerm3 );
v3 = vec_perm( v6, v7, vertPerm4 );
#else
v0 = vec_ld( 0, vertPtr );
v1 = vec_ld( 0, vertPtr2 );
v2 = vec_ld( 0, vertPtr3 );
v3 = vec_ld( 0, vertPtr4 );
#endif
v0 = vec_perm( v0, oneVector, vecPermThreeOne );
v4 = vec_perm( v0, zeroVector, vecPermThreeOne );
v1 = vec_perm( v1, oneVector, vecPermThreeOne );
v5 = vec_perm( v1, zeroVector, vecPermThreeOne );
v2 = vec_perm( v2, oneVector, vecPermThreeOne );
v6 = vec_perm( v2, zeroVector, vecPermThreeOne );
v3 = vec_perm( v3, oneVector, vecPermThreeOne );
v7 = vec_perm( v3, zeroVector, vecPermThreeOne );
// store results as unaligned
vector unsigned char storePerm = vec_sub( vec_lvsr( 15, &vertexCache[i*2][0] ), (vector unsigned char)(1) );
vector unsigned int mask = vec_perm( (vector unsigned int)(0), (vector unsigned int)(-1), storePerm );
vector float vc1 = vec_ld( 0, &vertexCache[i*2][0] );
vector float vc2 = vec_ld( 127, &vertexCache[i*2][0] );
// right rotate input data
v0 = vec_perm( v0, v0, storePerm );
v4 = vec_perm( v4, v4, storePerm );
v1 = vec_perm( v1, v1, storePerm );
v5 = vec_perm( v5, v5, storePerm );
v2 = vec_perm( v2, v2, storePerm );
v6 = vec_perm( v6, v6, storePerm );
v3 = vec_perm( v3, v3, storePerm );
v7 = vec_perm( v7, v7, storePerm );
vec_st( vec_sel( vc1, v0, mask ), 0 , &vertexCache[i*2][0] );
vec_st( vec_sel( v0, v4, mask ), 15 , &vertexCache[i*2][0] );
vec_st( vec_sel( v4, v1, mask ), 31 , &vertexCache[i*2][0] );
vec_st( vec_sel( v1, v5, mask ), 47 , &vertexCache[i*2][0] );
vec_st( vec_sel( v5, v2, mask ), 63 , &vertexCache[i*2][0] );
vec_st( vec_sel( v2, v6, mask ), 79 , &vertexCache[i*2][0] );
vec_st( vec_sel( v6, v3, mask ), 95 , &vertexCache[i*2][0] );
vec_st( vec_sel( v3, v7, mask ), 111 , &vertexCache[i*2][0] );
vec_st( vec_sel( v7, vc2, mask ), 127 , &vertexCache[i*2][0] );
}
// cleanup
for ( ; i < numVerts; i++ ) {
const float *v = verts[i].xyz.ToFloatPtr();
vertexCache[i*2+0][0] = v[0];
vertexCache[i*2+1][0] = v[0];
vertexCache[i*2+0][1] = v[1];
vertexCache[i*2+1][1] = v[1];
vertexCache[i*2+0][2] = v[2];
vertexCache[i*2+1][2] = v[2];
vertexCache[i*2+0][3] = 1.0f;
vertexCache[i*2+1][3] = 0.0f;
}
return numVerts * 2;
}
#endif /* VERTEXCACHE_ALIGNED */
#endif /* 0 to kill VP shader cache */
#endif /* ENABLE_CREATE */
#ifdef ENABLE_SOUND_ROUTINES
#ifdef SOUND_DEST_ALIGNED
/*
============
idSIMD_AltiVec::UpSamplePCMTo44kHz
Duplicate samples for 44kHz output.
Assumptions:
Assumes that dest starts at aligned address
============
*/
void idSIMD_AltiVec::UpSamplePCMTo44kHz( float *dest, const short *src, const int numSamples, const int kHz, const int numChannels ) {
// dest is aligned
assert( IS_16BYTE_ALIGNED( dest[0] ) );
vector signed short vs0, vs1;
register vector signed int vi0, vi1;
register vector float v0, v1, v2, v3, v4, v5, v6, v7, v8, v9;
// permute vectors
register vector unsigned char vecFirstHalf = (vector unsigned char)(0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7);
register vector unsigned char vecSecondHalf = (vector unsigned char)(8,9,10,11,12,13,14,15,8,9,10,11,12,13,14,15);
register vector unsigned char vecBottom = (vector unsigned char)(0,1,2,3,0,1,2,3,4,5,6,7,4,5,6,7);
register vector unsigned char vecTop = (vector unsigned char)(8,9,10,11,8,9,10,11,12,13,14,15,12,13,14,15);
// If this can be assumed true, we can eliminate another conditional that checks to see if we can
// load up a vector before the loop
assert( numSamples >= 12 );
if ( kHz == 11025 ) {
if ( numChannels == 1 ) {
// 8 at a time
int i = 0;
vector signed short vsOld = vec_ld( 0, &src[i] );
vector unsigned char permVec = vec_add( vec_lvsl( -1, &src[i] ), (vector unsigned char)(1) );
for ( ; i+7 < numSamples; i+= 8 ) {
// load src
vs1 = vec_ld( 15, &src[i] );
vs0 = vec_perm( vsOld, vs1, permVec );
vsOld = vs1;
// unpack shorts to ints
vi0 = vec_unpackh( vs0 );
vi1 = vec_unpackl( vs0 );
// convert ints to floats
v0 = vec_ctf( vi0, 0 );
v1 = vec_ctf( vi1, 0 );
// permute into vectors in the order to store
v2 = vec_splat( v0, 0 );
v3 = vec_splat( v0, 1 );
v4 = vec_splat( v0, 2 );
v5 = vec_splat( v0, 3 );
v6 = vec_splat( v1, 0 );
v7 = vec_splat( v1, 1 );
v8 = vec_splat( v1, 2 );
v9 = vec_splat( v1, 3 );
// store results
ALIGNED_STORE8( &dest[i*4], v2, v3, v4, v5, v6, v7, v8, v9 );
}
// cleanup
for (; i < numSamples; i++ ) {
dest[i*4+0] = dest[i*4+1] = dest[i*4+2] = dest[i*4+3] = (float) src[i+0];
}
} else {
int i = 0;
vector unsigned char permVec = vec_add( vec_lvsl( -1, &src[0] ), (vector unsigned char)(1) );
vector signed short vsOld = vec_ld( 0, &src[0] );
for ( ; i+7 < numSamples; i += 8 ) {
// load src
vs1 = vec_ld( 15, &src[i] );
vs0 = vec_perm( vsOld, vs1, permVec );
vsOld = vs1;
// unpack shorts to ints
vi0 = vec_unpackh( vs0 );
vi1 = vec_unpackl( vs0 );
// convert ints to floats
v0 = vec_ctf( vi0, 0 );
v1 = vec_ctf( vi1, 0 );
// put into vectors in order to store
v2 = vec_perm( v0, v0, vecFirstHalf );
v3 = v2;
v4 = vec_perm( v0, v0, vecSecondHalf );
v5 = v4;
v6 = vec_perm( v1, v1, vecFirstHalf );
v7 = v6;
v8 = vec_perm (v1, v1, vecSecondHalf );
v9 = v8;
// store results
ALIGNED_STORE8( &dest[i*4], v2, v3, v4, v5, v6, v7, v8, v9 );
}
for ( ; i < numSamples; i += 2 ) {
dest[i*4+0] = dest[i*4+2] = dest[i*4+4] = dest[i*4+6] = (float) src[i+0];
dest[i*4+1] = dest[i*4+3] = dest[i*4+5] = dest[i*4+7] = (float) src[i+1];
}
}
} else if ( kHz == 22050 ) {
if ( numChannels == 1 ) {
int i;
vector unsigned char permVec = vec_add( vec_lvsl( -1, &src[0] ), (vector unsigned char)(1) );
vector signed short vsOld = vec_ld( 0, &src[0] );
for ( i = 0; i+7 < numSamples; i += 8 ) {
// load src
vs1 = vec_ld( 0, &src[i] );
vs0 = vec_perm( vsOld, vs1, permVec );
vsOld = vs1;
// unpack shorts to ints
vi0 = vec_unpackh( vs0 );
vi1 = vec_unpackl( vs0 );
// convert ints to floats
v0 = vec_ctf( vi0, 0 );
v1 = vec_ctf( vi1, 0 );
// put into vectors in order to store
v2 = vec_perm( v0, v0, vecBottom );
v3 = vec_perm( v0, v0, vecTop );
v4 = vec_perm( v1, v1, vecBottom );
v5 = vec_perm (v1, v1, vecTop );
// store results
ALIGNED_STORE4( &dest[i*2], v2, v3, v4, v5 );
}
// cleanup
for ( ; i < numSamples; i++ ) {
dest[i*2+0] = dest[i*2+1] = (float) src[i+0];
}
} else {
int i;
vector unsigned char permVec = vec_add( vec_lvsl( -1, &src[0] ), (vector unsigned char)(1) );
vector signed short vsOld = vec_ld( 0, &src[0] );
for ( i = 0; i+7 < numSamples; i += 8 ) {
// load src
vs1 = vec_ld( 15, &src[i] );
vs0 = vec_perm( vsOld, vs1, permVec );
vsOld = vs1;
// unpack shorts to ints
vi0 = vec_unpackh( vs0 );
vi1 = vec_unpackl( vs0 );
// convert ints to floats
v0 = vec_ctf( vi0, 0 );
v1 = vec_ctf( vi1, 0 );
// put into vectors in order to store
v2 = vec_perm( v0, v0, vecFirstHalf );
v3 = vec_perm( v0, v0, vecSecondHalf );
v4 = vec_perm( v1, v1, vecFirstHalf );
v5 = vec_perm (v1, v1, vecSecondHalf );
// store results
ALIGNED_STORE4( &dest[i*2], v2, v3, v4, v5 );
}
// cleanup
for ( ; i < numSamples; i += 2 ) {
dest[i*2+0] = dest[i*2+2] = (float) src[i+0];
dest[i*2+1] = dest[i*2+3] = (float) src[i+1];
}
}
} else if ( kHz == 44100 ) {
int i;
vector unsigned char permVec = vec_add( vec_lvsl( -1, &src[0] ), (vector unsigned char)(1) );
vector signed short vsOld = vec_ld( 0, &src[0] );
for ( i = 0; i+7 < numSamples; i += 8 ) {
vs1 = vec_ld( 15, &src[i] );
vs0 = vec_perm( vsOld, vs1, permVec );
vsOld = vs1;
//unpack shorts to ints
vi0 = vec_unpackh( vs0 );
vi1 = vec_unpackl( vs0 );
//convert ints to floats
v0 = vec_ctf( vi0, 0 );
v1 = vec_ctf( vi1, 0 );
//store results
ALIGNED_STORE2( &dest[i], v0, v1 );
}
// cleanup
for ( ; i < numSamples; i++ ) {
dest[i] = (float) src[i];
}
} else {
assert( 0 );
}
}
#else
/*
============
idSIMD_AltiVec::UpSamplePCMTo44kHz
Duplicate samples for 44kHz output.
Assumptions:
No assumptions
============
*/
void idSIMD_AltiVec::UpSamplePCMTo44kHz( float *dest, const short *src, const int numSamples, const int kHz, const int numChannels ) {
vector signed short vs0, vs1;
register vector signed int vi0, vi1;
register vector float v0, v1, v2, v3, v4, v5, v6, v7, v8, v9;
// permute vectors
register vector unsigned char vecFirstHalf = (vector unsigned char)(0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7);
register vector unsigned char vecSecondHalf = (vector unsigned char)(8,9,10,11,12,13,14,15,8,9,10,11,12,13,14,15);
register vector unsigned char vecBottom = (vector unsigned char)(0,1,2,3,0,1,2,3,4,5,6,7,4,5,6,7);
register vector unsigned char vecTop = (vector unsigned char)(8,9,10,11,8,9,10,11,12,13,14,15,12,13,14,15);
// calculate perm vector and masks for stores
vector unsigned char storePerm = vec_sub( vec_lvsr( 15, &dest[0] ), (vector unsigned char)(1) );
// original values of dest
vector float vecDest = vec_ld( 0, &dest[0] );
vector unsigned int mask = vec_perm( (vector unsigned int)(0), (vector unsigned int)(-1), storePerm );
if ( kHz == 11025 ) {
if ( numChannels == 1 ) {
// 8 at a time
int i = 0;
vector signed short vsOld = vec_ld( 0, &src[i] );
vector unsigned char permVec = vec_add( vec_lvsl( -1, &src[i] ), (vector unsigned char)(1) );
for ( ; i+7 < numSamples; i+= 8 ) {
// load src
vs1 = vec_ld( 15, &src[i] );
vs0 = vec_perm( vsOld, vs1, permVec );
vsOld = vs1;
vector float vecDestEnd = vec_ld( 127, &dest[i*4] );
// unpack shorts to ints
vi0 = vec_unpackh( vs0 );
vi1 = vec_unpackl( vs0 );
// convert ints to floats
v0 = vec_ctf( vi0, 0 );
v1 = vec_ctf( vi1, 0 );
// permute into vectors in the order to store
v2 = vec_splat( v0, 0 );
v3 = vec_splat( v0, 1 );
v4 = vec_splat( v0, 2 );
v5 = vec_splat( v0, 3 );
v6 = vec_splat( v1, 0 );
v7 = vec_splat( v1, 1 );
v8 = vec_splat( v1, 2 );
v9 = vec_splat( v1, 3 );
v2 = vec_perm( v2, v2, storePerm );
v3 = vec_perm( v3, v3, storePerm );
v4 = vec_perm( v4, v4, storePerm );
v5 = vec_perm( v5, v5, storePerm );
v6 = vec_perm( v6, v6, storePerm );
v7 = vec_perm( v7, v7, storePerm );
v8 = vec_perm( v8, v8, storePerm );
v9 = vec_perm( v9, v9, storePerm );
// store results
vec_st( vec_sel( vecDest, v2, mask ), 0, &dest[i*4] );
vec_st( vec_sel( v2, v3, mask ), 15, &dest[i*4] );
vec_st( vec_sel( v3, v4, mask ), 31, &dest[i*4] );
vec_st( vec_sel( v4, v5, mask ), 47, &dest[i*4] );
vec_st( vec_sel( v5, v6, mask ), 63, &dest[i*4] );
vec_st( vec_sel( v6, v7, mask ), 79, &dest[i*4] );
vec_st( vec_sel( v7, v8, mask ), 95, &dest[i*4] );
vec_st( vec_sel( v8, v9, mask ), 111, &dest[i*4] );
vecDest = vec_sel( v9, vecDestEnd, mask );
vec_st( vecDest, 127, &dest[i*4] );
}
// cleanup
for (; i < numSamples; i++ ) {
dest[i*4+0] = dest[i*4+1] = dest[i*4+2] = dest[i*4+3] = (float) src[i+0];
}
} else {
int i = 0;
vector unsigned char permVec = vec_add( vec_lvsl( -1, &src[0] ), (vector unsigned char)(1) );
vector signed short vsOld = vec_ld( 0, &src[0] );
for ( ; i+7 < numSamples; i += 8 ) {
// load src
vs1 = vec_ld( 15, &src[i] );
vs0 = vec_perm( vsOld, vs1, permVec );
vsOld = vs1;
vector float vecDestEnd = vec_ld( 127, &dest[i*4] );
// unpack shorts to ints
vi0 = vec_unpackh( vs0 );
vi1 = vec_unpackl( vs0 );
// convert ints to floats
v0 = vec_ctf( vi0, 0 );
v1 = vec_ctf( vi1, 0 );
// put into vectors in order to store
v2 = vec_perm( v0, v0, vecFirstHalf );
v3 = v2;
v4 = vec_perm( v0, v0, vecSecondHalf );
v5 = v4;
v6 = vec_perm( v1, v1, vecFirstHalf );
v7 = v6;
v8 = vec_perm (v1, v1, vecSecondHalf );
v9 = v8;
v2 = vec_perm( v2, v2, storePerm );
v3 = vec_perm( v3, v3, storePerm );
v4 = vec_perm( v4, v4, storePerm );
v5 = vec_perm( v5, v5, storePerm );
v6 = vec_perm( v6, v6, storePerm );
v7 = vec_perm( v7, v7, storePerm );
v8 = vec_perm( v8, v8, storePerm );
v9 = vec_perm( v9, v9, storePerm );
// store results
vec_st( vec_sel( vecDest, v2, mask ), 0, &dest[i*4] );
vec_st( vec_sel( v2, v3, mask ), 15, &dest[i*4] );
vec_st( vec_sel( v3, v4, mask ), 31, &dest[i*4] );
vec_st( vec_sel( v4, v5, mask ), 47, &dest[i*4] );
vec_st( vec_sel( v5, v6, mask ), 63, &dest[i*4] );
vec_st( vec_sel( v6, v7, mask ), 79, &dest[i*4] );
vec_st( vec_sel( v7, v8, mask ), 95, &dest[i*4] );
vec_st( vec_sel( v8, v9, mask ), 111, &dest[i*4] );
vecDest = vec_sel( v9, vecDestEnd, mask );
vec_st( vecDest, 127, &dest[i*4] );
}
for ( ; i < numSamples; i += 2 ) {
dest[i*4+0] = dest[i*4+2] = dest[i*4+4] = dest[i*4+6] = (float) src[i+0];
dest[i*4+1] = dest[i*4+3] = dest[i*4+5] = dest[i*4+7] = (float) src[i+1];
}
}
} else if ( kHz == 22050 ) {
if ( numChannels == 1 ) {
int i;
vector unsigned char permVec = vec_add( vec_lvsl( -1, &src[0] ), (vector unsigned char)(1) );
vector signed short vsOld = vec_ld( 0, &src[0] );
for ( i = 0; i+7 < numSamples; i += 8 ) {
// load src
vs1 = vec_ld( 0, &src[i] );
vs0 = vec_perm( vsOld, vs1, permVec );
vsOld = vs1;
vector float vecDestEnd = vec_ld( 63, &dest[i*2] );
// unpack shorts to ints
vi0 = vec_unpackh( vs0 );
vi1 = vec_unpackl( vs0 );
// convert ints to floats
v0 = vec_ctf( vi0, 0 );
v1 = vec_ctf( vi1, 0 );
// put into vectors in order to store
v2 = vec_perm( v0, v0, vecBottom );
v3 = vec_perm( v0, v0, vecTop );
v4 = vec_perm( v1, v1, vecBottom );
v5 = vec_perm (v1, v1, vecTop );
v2 = vec_perm( v2, v2, storePerm );
v3 = vec_perm( v3, v3, storePerm );
v4 = vec_perm( v4, v4, storePerm );
v5 = vec_perm( v5, v5, storePerm );
// store results
vec_st( vec_sel( vecDest, v2, mask ), 0, &dest[i*2] );
vec_st( vec_sel( v2, v3, mask ), 15, &dest[i*2] );
vec_st( vec_sel( v3, v4, mask ), 31, &dest[i*2] );
vec_st( vec_sel( v4, v5, mask ), 47, &dest[i*2] );
vecDest = vec_sel( v5, vecDestEnd, mask );
vec_st( vecDest, 63, &dest[i*2] );
}
// cleanup
for ( ; i < numSamples; i++ ) {
dest[i*2+0] = dest[i*2+1] = (float) src[i+0];
}
} else {
int i;
vector unsigned char permVec = vec_add( vec_lvsl( -1, &src[0] ), (vector unsigned char)(1) );
vector signed short vsOld = vec_ld( 0, &src[0] );
for ( i = 0; i+7 < numSamples; i += 8 ) {
// load src
vs1 = vec_ld( 15, &src[i] );
vs0 = vec_perm( vsOld, vs1, permVec );
vsOld = vs1;
vector float vecDestEnd = vec_ld( 63, &dest[i*2] );
// unpack shorts to ints
vi0 = vec_unpackh( vs0 );
vi1 = vec_unpackl( vs0 );
// convert ints to floats
v0 = vec_ctf( vi0, 0 );
v1 = vec_ctf( vi1, 0 );
// put into vectors in order to store
v2 = vec_perm( v0, v0, vecFirstHalf );
v3 = vec_perm( v0, v0, vecSecondHalf );
v4 = vec_perm( v1, v1, vecFirstHalf );
v5 = vec_perm (v1, v1, vecSecondHalf );
v2 = vec_perm( v2, v2, storePerm );
v3 = vec_perm( v3, v3, storePerm );
v4 = vec_perm( v4, v4, storePerm );
v5 = vec_perm( v5, v5, storePerm );
// store results
vec_st( vec_sel( vecDest, v2, mask ), 0, &dest[i*2] );
vec_st( vec_sel( v2, v3, mask ), 15, &dest[i*2] );
vec_st( vec_sel( v3, v4, mask ), 31, &dest[i*2] );
vec_st( vec_sel( v4, v5, mask ), 47, &dest[i*2] );
vecDest = vec_sel( v5, vecDestEnd, mask );
vec_st( vecDest, 63, &dest[i*2] );
}
// cleanup
for ( ; i < numSamples; i += 2 ) {
dest[i*2+0] = dest[i*2+2] = (float) src[i+0];
dest[i*2+1] = dest[i*2+3] = (float) src[i+1];
}
}
} else if ( kHz == 44100 ) {
int i;
vector unsigned char permVec = vec_add( vec_lvsl( -1, &src[0] ), (vector unsigned char)(1) );
vector signed short vsOld = vec_ld( 0, &src[0] );
for ( i = 0; i+7 < numSamples; i += 8 ) {
//vs0 = vec_ld( 0, &src[i] );
vs1 = vec_ld( 15, &src[i] );
vs0 = vec_perm( vsOld, vs1, permVec );
vsOld = vs1;
vector float vecDestEnd = vec_ld( 31, &dest[i] );
//unpack shorts to ints
vi0 = vec_unpackh( vs0 );
vi1 = vec_unpackl( vs0 );
//convert ints to floats
v0 = vec_ctf( vi0, 0 );
v1 = vec_ctf( vi1, 0 );
v0 = vec_perm( v0, v0, storePerm );
v1 = vec_perm( v1, v1, storePerm );
// store results
vec_st( vec_sel( vecDest, v0, mask ), 0, &dest[i] );
vec_st( vec_sel( v0, v1, mask ), 15, &dest[i] );
vecDest = vec_sel( v1, vecDestEnd, mask );
vec_st( vecDest, 31, &dest[i] );
}
// cleanup
for ( ; i < numSamples; i++ ) {
dest[i] = (float) src[i];
}
} else {
assert( 0 );
}
}
#endif
#ifdef SOUND_DEST_ALIGNED
/*
============
idSIMD_AltiVec::UpSampleOGGTo44kHz
Duplicate samples for 44kHz output.
Assumptions:
Assumes that dest starts at aligned address
============
*/
void idSIMD_AltiVec::UpSampleOGGTo44kHz( float *dest, const float * const *ogg, const int numSamples, const int kHz, const int numChannels ) {
// dest is aligned
assert( IS_16BYTE_ALIGNED( dest[0] ) );
register vector float oggVec1, oggVec2, oggVec3, oggVec4, oggVec5, oggVec6, oggVec7, oggVec8;
register vector float constVec, zeroVector;
register vector float v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10;
vector unsigned char vecPerm1;
vector unsigned char vecPerm2;
vector unsigned char vecOneTwo = (vector unsigned char)(0,1,2,3,0,1,2,3,4,5,6,7,4,5,6,7);
vector unsigned char vecThreeFour = (vector unsigned char)(8,9,10,11,8,9,10,11,12,13,14,15,12,13,14,15);
vector unsigned char vecFirst = (vector unsigned char)(0,1,2,3,16,17,18,19,0,1,2,3,16,17,18,19);
vector unsigned char vecSecond = (vector unsigned char)(4,5,6,7,20,21,22,23,4,5,6,7,20,21,22,23);
vector unsigned char vecThird = (vector unsigned char)(8,9,10,11,24,25,26,27,8,9,10,11,24,25,26,27);
vector unsigned char vecFourth = (vector unsigned char)(12,13,14,15,28,29,30,31,12,13,14,15,28,29,30,31);
constVec = (vector float)(32768.0f);
zeroVector = (vector float)(0.0);
if ( kHz == 11025 ) {
if ( numChannels == 1 ) {
// calculate perm vector and do first load
vecPerm1 = vec_add( vec_lvsl( -1, (int*) &ogg[0][0] ), (vector unsigned char)(1) );
v10 = vec_ld( 0, &ogg[0][0] );
int i;
for ( i = 0; i+7 < numSamples; i += 8 ) {
// as it happens, ogg[0][i] through ogg[0][i+3] are contiguous in memory
v8 = v10;
v9 = vec_ld( 15, &ogg[0][i] );
v10 = vec_ld( 31, &ogg[0][i] );
v0 = vec_perm( v8, v9, vecPerm1 );
v1 = vec_perm( v9, v10, vecPerm1 );
// now we have the elements in a vector, we want
// to splat them each accross their own vector
oggVec1 = vec_splat( v0, 0 );
oggVec2 = vec_splat( v0, 1 );
oggVec3 = vec_splat( v0, 2 );
oggVec4 = vec_splat( v0, 3 );
oggVec5 = vec_splat( v1, 0 );
oggVec6 = vec_splat( v1, 1 );
oggVec7 = vec_splat( v1, 2 );
oggVec8 = vec_splat( v1, 3 );
v0 = vec_madd( oggVec1, constVec, zeroVector );
v1 = vec_madd( oggVec2, constVec, zeroVector );
v2 = vec_madd( oggVec3, constVec, zeroVector );
v3 = vec_madd( oggVec4, constVec, zeroVector );
v4 = vec_madd( oggVec5, constVec, zeroVector );
v5 = vec_madd( oggVec6, constVec, zeroVector );
v6 = vec_madd( oggVec7, constVec, zeroVector );
v7 = vec_madd( oggVec8, constVec, zeroVector );
//store results
ALIGNED_STORE8( &dest[i*4], v0, v1, v2, v3, v4, v5, v6, v7 );
}
//cleanup
for ( ; i < numSamples; i++ ) {
dest[i*4+0] = dest[i*4+1] = dest[i*4+2] = dest[i*4+3] = ogg[0][i] * 32768.0f;
}
} else {
// calculate perm vec for ogg
vecPerm1 = vec_add( vec_lvsl( -1, (int*) &ogg[0][0] ), (vector unsigned char)(1) );
vecPerm2 = vec_add( vec_lvsl( -1, (int*) &ogg[1][0] ), (vector unsigned char)(1) );
v7 = vec_ld( 0, &ogg[1][0] );
v9 = vec_ld( 0, &ogg[0][0] );
int i;
for ( i = 0; i+3 < numSamples >> 1; i+=4 ) { // +1 += 2
// load and splat from the array ( ogg[0][i] to ogg[0][i+3] )
v8 = v9;
v9 = vec_ld( 15, &ogg[0][i] );
v0 = vec_perm( v8, v9, vecPerm1 );
// now we have the elements in a vector, we want
// to splat them each accross their own vector
oggVec1 = vec_splat( v0, 0 );
oggVec2 = vec_splat( v0, 1 );
oggVec3 = vec_splat( v0, 2 );
oggVec4 = vec_splat( v0, 3 );
// load and splat from the array ( ogg[1][i] to ogg[1][i+3] )
v6 = v7;
v7 = vec_ld( 15, &ogg[1][i] );
v1 = vec_perm( v6, v7, vecPerm2 );
// now we have the elements in a vector, we want
// to splat them each accross their own vector
oggVec5 = vec_splat( v1, 0 );
oggVec6 = vec_splat( v1, 1 );
oggVec7 = vec_splat( v1, 2 );
oggVec8 = vec_splat( v1, 3 );
oggVec1 = vec_madd( oggVec1, constVec, zeroVector ); // ogg[0][i] * 32768
oggVec2 = vec_madd( oggVec2, constVec, zeroVector ); // ogg[0][i+1] * 32768
oggVec3 = vec_madd( oggVec3, constVec, zeroVector ); // ogg[0][i+2] * 32768
oggVec4 = vec_madd( oggVec4, constVec, zeroVector ); // ogg[0][i+3] * 32768
oggVec5 = vec_madd( oggVec5, constVec, zeroVector ); // ogg[1][i] * 32768
oggVec6 = vec_madd( oggVec6, constVec, zeroVector ); // ogg[1][i+1] * 32768
oggVec7 = vec_madd( oggVec7, constVec, zeroVector ); // ogg[1][i+2] * 32768
oggVec8 = vec_madd( oggVec8, constVec, zeroVector ); // ogg[1][i+3] * 32768
//merge generates the interleaved pattern that we want and it
//doesn't require a permute vector, so use that instead
v0 = vec_mergeh( oggVec1, oggVec5 );
v1 = vec_mergel( oggVec1, oggVec5 );
v2 = vec_mergeh( oggVec2, oggVec6 );
v3 = vec_mergel( oggVec2, oggVec6 );
v4 = vec_mergeh( oggVec3, oggVec7 );
v5 = vec_mergel( oggVec3, oggVec7 );
v6 = vec_mergeh( oggVec4, oggVec8 );
v10 = vec_mergel( oggVec4, oggVec8 );
//store results
ALIGNED_STORE8( &dest[i*8], v0, v1, v2, v3, v4, v5, v6, v10 );
}
//cleanup
for ( ; i < numSamples >> 1; i++ ) {
dest[i*8+0] = dest[i*8+2] = dest[i*8+4] = dest[i*8+6] = ogg[0][i] * 32768.0f;
dest[i*8+1] = dest[i*8+3] = dest[i*8+5] = dest[i*8+7] = ogg[1][i] * 32768.0f;
}
}
} else if ( kHz == 22050 ) {
if ( numChannels == 1 ) {
// calculate perm vector and do first load
vecPerm1 = vec_add( vec_lvsl( -1, (int*) &ogg[0][0] ), (vector unsigned char)(1) );
v10 = vec_ld( 0, &ogg[0][0] );
int i;
for ( i = 0; i+7 < numSamples; i += 8 ) {
// load values from ogg
v8 = v10;
v9 = vec_ld( 15, &ogg[0][i] );
v10 = vec_ld( 31, &ogg[0][i] );
v0 = vec_perm( v8, v9, vecPerm1 );
v1 = vec_perm( v9, v10, vecPerm1 );
// multiply
v0 = vec_madd( v0, constVec, zeroVector );
v1 = vec_madd( v1, constVec, zeroVector );
// permute into results vectors to store
v5 = vec_perm( v0, v0, vecOneTwo );
v6 = vec_perm( v0, v0, vecThreeFour);
v7 = vec_perm( v1, v1, vecOneTwo );
v8 = vec_perm( v1, v1, vecThreeFour );
//store results
ALIGNED_STORE4( &dest[i*2], v5, v6, v7, v8 );
}
// cleanup
for ( ; i < numSamples; i++ ) {
dest[i*2+0] = dest[i*2+1] = ogg[0][i] * 32768.0f;
}
} else {
// calculate perm vector and do first load
vecPerm1 = vec_add( vec_lvsl( -1, (int*) &ogg[0][0] ), (vector unsigned char)(1) );
vecPerm2 = vec_add( vec_lvsl( -1, (int*) &ogg[1][0] ), (vector unsigned char)(1) );
v7 = vec_ld( 0, &ogg[1][0] );
v9 = vec_ld( 0, &ogg[0][0] );
int i;
for ( i = 0; i+3 < numSamples >> 1; i += 4 ) {
// load ogg[0][i] to ogg[0][i+4]
v8 = v9;
v9 = vec_ld( 15, &ogg[0][i] );
v0 = vec_perm( v8, v9, vecPerm1 );
// load ogg[1][i] to ogg[1][i+3]
v6 = v7;
v7 = vec_ld( 15, &ogg[1][i] );
v1 = vec_perm( v6, v7, vecPerm2 );
// multiply
v0 = vec_madd( v0, constVec, zeroVector );
v1 = vec_madd( v1, constVec, zeroVector );
// generate result vectors to store
v2 = vec_perm( v0, v1, vecFirst );
v3 = vec_perm( v0, v1, vecSecond );
v4 = vec_perm( v0, v1, vecThird );
v5 = vec_perm( v0, v1, vecFourth );
// store results
ALIGNED_STORE4( &dest[i*4], v2, v3, v4, v5 );
}
// cleanup
for ( ; i < numSamples >> 1; i++ ) {
dest[i*4+0] = dest[i*4+2] = ogg[0][i] * 32768.0f;
dest[i*4+1] = dest[i*4+3] = ogg[1][i] * 32768.0f;
}
}
} else if ( kHz == 44100 ) {
if ( numChannels == 1 ) {
// calculate perm vector and do first load
vecPerm1 = vec_add( vec_lvsl( -1, (int*) &ogg[0][0] ), (vector unsigned char)(1) );
v9 = vec_ld( 0, &ogg[0][0] );
int i;
for ( i = 0; i+7 < numSamples; i += 8 ) {
// load values from ogg
v8 = v9;
v7 = vec_ld( 15, &ogg[0][i] );
v6 = v7;
v9 = vec_ld( 31, &ogg[0][i] );
v0 = vec_perm( v8, v7, vecPerm1 );
v1 = vec_perm( v6, v9, vecPerm1 );
// multiply
v0 = vec_madd( v0, constVec, zeroVector );
v1 = vec_madd( v1, constVec, zeroVector );
ALIGNED_STORE2( &dest[i], v0, v1 );
}
// cleanup
for ( ; i < numSamples; i++ ) {
dest[i*1+0] = ogg[0][i] * 32768.0f;
}
} else {
// calculate perm vector and do first load
vecPerm1 = vec_add( vec_lvsl( -1, (int*) &ogg[0][0] ), (vector unsigned char)(1) );
vecPerm2 = vec_add( vec_lvsl( -1, (int*) &ogg[1][0] ), (vector unsigned char)(1) );
v7 = vec_ld( 0, &ogg[1][0] );
v9 = vec_ld( 0, &ogg[0][0] );
int i;
for ( i = 0; i+3 < numSamples >> 1; i += 4 ) {
v8 = v9;
v9 = vec_ld( 15, &ogg[0][i] );
v0 = vec_perm( v8, v9, vecPerm1 );
// load ogg[1][i] to ogg[1][i+3]
v6 = v7;
v7 = vec_ld( 15, &ogg[1][i] );
v1 = vec_perm( v6, v7, vecPerm2 );
// multiply
v0 = vec_madd( v0, constVec, zeroVector );
v1 = vec_madd( v1, constVec, zeroVector );
// generate result vectors
v2 = vec_mergeh( v0, v1 );
v3 = vec_mergel( v0, v1 );
// store results
ALIGNED_STORE2( &dest[i*2], v2, v3 );
}
// cleanup
for ( ; i < numSamples >> 1; i++ ) {
dest[i*2+0] = ogg[0][i] * 32768.0f;
dest[i*2+1] = ogg[1][i] * 32768.0f;
}
}
} else {
assert( 0 );
}
}
#else
/*
============
idSIMD_AltiVec::UpSampleOGGTo44kHz
Duplicate samples for 44kHz output.
Assumptions:
No assumptions
============
*/
void idSIMD_AltiVec::UpSampleOGGTo44kHz( float *dest, const float * const *ogg, const int numSamples, const int kHz, const int numChannels ) {
register vector float oggVec1, oggVec2, oggVec3, oggVec4, oggVec5, oggVec6, oggVec7, oggVec8;
register vector float constVec, zeroVector;
register vector float v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10;
vector unsigned char vecPerm1;
vector unsigned char vecPerm2;
vector unsigned char vecOneTwo = (vector unsigned char)(0,1,2,3,0,1,2,3,4,5,6,7,4,5,6,7);
vector unsigned char vecThreeFour = (vector unsigned char)(8,9,10,11,8,9,10,11,12,13,14,15,12,13,14,15);
vector unsigned char vecFirst = (vector unsigned char)(0,1,2,3,16,17,18,19,0,1,2,3,16,17,18,19);
vector unsigned char vecSecond = (vector unsigned char)(4,5,6,7,20,21,22,23,4,5,6,7,20,21,22,23);
vector unsigned char vecThird = (vector unsigned char)(8,9,10,11,24,25,26,27,8,9,10,11,24,25,26,27);
vector unsigned char vecFourth = (vector unsigned char)(12,13,14,15,28,29,30,31,12,13,14,15,28,29,30,31);
vector unsigned char storePerm;
constVec = (vector float)(32768.0f);
zeroVector = (vector float)(0.0);
// calculate perm vector and masks for stores
storePerm = vec_sub( vec_lvsr( 15, &dest[0] ), (vector unsigned char)(1) );
// original values of dest
vector float vecDest = vec_ld( 0, &dest[0] );
vector unsigned int mask = vec_perm( (vector unsigned int)(0), (vector unsigned int)(-1), storePerm );
if ( kHz == 11025 ) {
if ( numChannels == 1 ) {
// calculate perm vector and do first load
vecPerm1 = vec_add( vec_lvsl( -1, (int*) &ogg[0][0] ), (vector unsigned char)(1) );
v10 = vec_ld( 0, &ogg[0][0] );
int i;
for ( i = 0; i+7 < numSamples; i += 8 ) {
// as it happens, ogg[0][i] through ogg[0][i+3] are contiguous in memory
v8 = v10;
v9 = vec_ld( 15, &ogg[0][i] );
v10 = vec_ld( 31, &ogg[0][i] );
vector float vecDestEnd = vec_ld( 127, &dest[i*4] );
v0 = vec_perm( v8, v9, vecPerm1 );
v1 = vec_perm( v9, v10, vecPerm1 );
// now we have the elements in a vector, we want
// to splat them each accross their own vector
oggVec1 = vec_splat( v0, 0 );
oggVec2 = vec_splat( v0, 1 );
oggVec3 = vec_splat( v0, 2 );
oggVec4 = vec_splat( v0, 3 );
oggVec5 = vec_splat( v1, 0 );
oggVec6 = vec_splat( v1, 1 );
oggVec7 = vec_splat( v1, 2 );
oggVec8 = vec_splat( v1, 3 );
v0 = vec_madd( oggVec1, constVec, zeroVector );
v1 = vec_madd( oggVec2, constVec, zeroVector );
v2 = vec_madd( oggVec3, constVec, zeroVector );
v3 = vec_madd( oggVec4, constVec, zeroVector );
v4 = vec_madd( oggVec5, constVec, zeroVector );
v5 = vec_madd( oggVec6, constVec, zeroVector );
v6 = vec_madd( oggVec7, constVec, zeroVector );
v7 = vec_madd( oggVec8, constVec, zeroVector );
// rotate input data
v0 = vec_perm( v0, v0, storePerm );
v1 = vec_perm( v1, v1, storePerm );
v2 = vec_perm( v2, v2, storePerm );
v3 = vec_perm( v3, v3, storePerm );
v4 = vec_perm( v4, v4, storePerm );
v5 = vec_perm( v5, v5, storePerm );
v6 = vec_perm( v6, v6, storePerm );
v7 = vec_perm( v7, v7, storePerm );
// store results
vec_st( vec_sel( vecDest, v0, mask ), 0, &dest[i*4] );
vec_st( vec_sel( v0, v1, mask ), 15, &dest[i*4] );
vec_st( vec_sel( v1, v2, mask ), 31, &dest[i*4] );
vec_st( vec_sel( v2, v3, mask ), 47, &dest[i*4] );
vec_st( vec_sel( v3, v4, mask ), 63, &dest[i*4] );
vec_st( vec_sel( v4, v5, mask ), 79, &dest[i*4] );
vec_st( vec_sel( v5, v6, mask ), 95, &dest[i*4] );
vec_st( vec_sel( v6, v7, mask ), 111, &dest[i*4] );
vecDest = vec_sel( v7, vecDestEnd, mask );
vec_st( vecDest, 127, &dest[i*4] );
}
//cleanup
for ( ; i < numSamples; i++ ) {
dest[i*4+0] = dest[i*4+1] = dest[i*4+2] = dest[i*4+3] = ogg[0][i] * 32768.0f;
}
} else {
// calculate perm vec for ogg
vecPerm1 = vec_add( vec_lvsl( -1, (int*) &ogg[0][0] ), (vector unsigned char)(1) );
vecPerm2 = vec_add( vec_lvsl( -1, (int*) &ogg[1][0] ), (vector unsigned char)(1) );
v7 = vec_ld( 0, &ogg[1][0] );
v9 = vec_ld( 0, &ogg[0][0] );
int i;
for ( i = 0; i+3 < numSamples >> 1; i+=4 ) { // +1 += 2
// load and splat from the array ( ogg[0][i] to ogg[0][i+3] )
v8 = v9;
v9 = vec_ld( 15, &ogg[0][i] );
vector float vecDestEnd = vec_ld( 127, &dest[i*8] );
v0 = vec_perm( v8, v9, vecPerm1 );
// now we have the elements in a vector, we want
// to splat them each accross their own vector
oggVec1 = vec_splat( v0, 0 );
oggVec2 = vec_splat( v0, 1 );
oggVec3 = vec_splat( v0, 2 );
oggVec4 = vec_splat( v0, 3 );
// load and splat from the array ( ogg[1][i] to ogg[1][i+3] )
v6 = v7;
v7 = vec_ld( 15, &ogg[1][i] );
v1 = vec_perm( v6, v7, vecPerm2 );
// now we have the elements in a vector, we want
// to splat them each accross their own vector
oggVec5 = vec_splat( v1, 0 );
oggVec6 = vec_splat( v1, 1 );
oggVec7 = vec_splat( v1, 2 );
oggVec8 = vec_splat( v1, 3 );
oggVec1 = vec_madd( oggVec1, constVec, zeroVector ); // ogg[0][i] * 32768
oggVec2 = vec_madd( oggVec2, constVec, zeroVector ); // ogg[0][i+1] * 32768
oggVec3 = vec_madd( oggVec3, constVec, zeroVector ); // ogg[0][i+2] * 32768
oggVec4 = vec_madd( oggVec4, constVec, zeroVector ); // ogg[0][i+3] * 32768
oggVec5 = vec_madd( oggVec5, constVec, zeroVector ); // ogg[1][i] * 32768
oggVec6 = vec_madd( oggVec6, constVec, zeroVector ); // ogg[1][i+1] * 32768
oggVec7 = vec_madd( oggVec7, constVec, zeroVector ); // ogg[1][i+2] * 32768
oggVec8 = vec_madd( oggVec8, constVec, zeroVector ); // ogg[1][i+3] * 32768
//merge generates the interleaved pattern that we want and it
//doesn't require a permute vector, so use that instead
v0 = vec_mergeh( oggVec1, oggVec5 );
v1 = vec_mergel( oggVec1, oggVec5 );
v2 = vec_mergeh( oggVec2, oggVec6 );
v3 = vec_mergel( oggVec2, oggVec6 );
v4 = vec_mergeh( oggVec3, oggVec7 );
v5 = vec_mergel( oggVec3, oggVec7 );
v6 = vec_mergeh( oggVec4, oggVec8 );
v10 = vec_mergel( oggVec4, oggVec8 );
// rotate input data
v0 = vec_perm( v0, v0, storePerm );
v1 = vec_perm( v1, v1, storePerm );
v2 = vec_perm( v2, v2, storePerm );
v3 = vec_perm( v3, v3, storePerm );
v4 = vec_perm( v4, v4, storePerm );
v5 = vec_perm( v5, v5, storePerm );
v6 = vec_perm( v6, v6, storePerm );
v10 = vec_perm( v10, v10, storePerm );
// store results
vec_st( vec_sel( vecDest, v0, mask ), 0, &dest[i*8] );
vec_st( vec_sel( v0, v1, mask ), 15, &dest[i*8] );
vec_st( vec_sel( v1, v2, mask ), 31, &dest[i*8] );
vec_st( vec_sel( v2, v3, mask ), 47, &dest[i*8] );
vec_st( vec_sel( v3, v4, mask ), 63, &dest[i*8] );
vec_st( vec_sel( v4, v5, mask ), 79, &dest[i*8] );
vec_st( vec_sel( v5, v6, mask ), 95, &dest[i*8] );
vec_st( vec_sel( v6, v10, mask ), 111, &dest[i*8] );
vecDest = vec_sel( v10, vecDestEnd, mask );
vec_st( vecDest, 127, &dest[i*8] );
}
//cleanup
for ( ; i < numSamples >> 1; i++ ) {
dest[i*8+0] = dest[i*8+2] = dest[i*8+4] = dest[i*8+6] = ogg[0][i] * 32768.0f;
dest[i*8+1] = dest[i*8+3] = dest[i*8+5] = dest[i*8+7] = ogg[1][i] * 32768.0f;
}
}
} else if ( kHz == 22050 ) {
if ( numChannels == 1 ) {
// calculate perm vector and do first load
vecPerm1 = vec_add( vec_lvsl( -1, (int*) &ogg[0][0] ), (vector unsigned char)(1) );
v10 = vec_ld( 0, &ogg[0][0] );
int i;
for ( i = 0; i+7 < numSamples; i += 8 ) {
// load values from ogg
v8 = v10;
v9 = vec_ld( 15, &ogg[0][i] );
v10 = vec_ld( 31, &ogg[0][i] );
vector float vecDestEnd = vec_ld( 63, &dest[i*2] );
v0 = vec_perm( v8, v9, vecPerm1 );
v1 = vec_perm( v9, v10, vecPerm1 );
// multiply
v0 = vec_madd( v0, constVec, zeroVector );
v1 = vec_madd( v1, constVec, zeroVector );
// permute into results vectors to store
v5 = vec_perm( v0, v0, vecOneTwo );
v6 = vec_perm( v0, v0, vecThreeFour);
v7 = vec_perm( v1, v1, vecOneTwo );
v8 = vec_perm( v1, v1, vecThreeFour );
// rotate input data
v5 = vec_perm( v5, v5, storePerm );
v6 = vec_perm( v6, v6, storePerm );
v7 = vec_perm( v7, v7, storePerm );
v8 = vec_perm( v8, v8, storePerm );
// store results
vec_st( vec_sel( vecDest, v5, mask ), 0, &dest[i*2] );
vec_st( vec_sel( v5, v6, mask ), 15, &dest[i*2] );
vec_st( vec_sel( v6, v7, mask ), 31, &dest[i*2] );
vec_st( vec_sel( v7, v8, mask ), 47, &dest[i*2] );
vecDest = vec_sel( v8, vecDestEnd, mask );
vec_st( vecDest, 63, &dest[i*2] );
}
// cleanup
for ( ; i < numSamples; i++ ) {
dest[i*2+0] = dest[i*2+1] = ogg[0][i] * 32768.0f;
}
} else {
// calculate perm vector and do first load
vecPerm1 = vec_add( vec_lvsl( -1, (int*) &ogg[0][0] ), (vector unsigned char)(1) );
vecPerm2 = vec_add( vec_lvsl( -1, (int*) &ogg[1][0] ), (vector unsigned char)(1) );
v7 = vec_ld( 0, &ogg[1][0] );
v9 = vec_ld( 0, &ogg[0][0] );
int i;
for ( i = 0; i+3 < numSamples >> 1; i += 4 ) {
// load ogg[0][i] to ogg[0][i+4]
v8 = v9;
v9 = vec_ld( 15, &ogg[0][i] );
vector float vecDestEnd = vec_ld( 63, &dest[i*4] );
v0 = vec_perm( v8, v9, vecPerm1 );
// load ogg[1][i] to ogg[1][i+3]
v6 = v7;
v7 = vec_ld( 15, &ogg[1][i] );
v1 = vec_perm( v6, v7, vecPerm2 );
// multiply
v0 = vec_madd( v0, constVec, zeroVector );
v1 = vec_madd( v1, constVec, zeroVector );
// generate result vectors to store
v2 = vec_perm( v0, v1, vecFirst );
v3 = vec_perm( v0, v1, vecSecond );
v4 = vec_perm( v0, v1, vecThird );
v5 = vec_perm( v0, v1, vecFourth );
// rotate input data
v2 = vec_perm( v2, v2, storePerm );
v3 = vec_perm( v3, v3, storePerm );
v4 = vec_perm( v4, v4, storePerm );
v5 = vec_perm( v5, v5, storePerm );
// store results
vec_st( vec_sel( vecDest, v2, mask ), 0, &dest[i*4] );
vec_st( vec_sel( v2, v3, mask ), 15, &dest[i*4] );
vec_st( vec_sel( v3, v4, mask ), 31, &dest[i*4] );
vec_st( vec_sel( v4, v5, mask ), 47, &dest[i*4] );
vecDest = vec_sel( v5, vecDestEnd, mask );
vec_st( vecDest, 63, &dest[i*4] );
}
// cleanup
for ( ; i < numSamples >> 1; i++ ) {
dest[i*4+0] = dest[i*4+2] = ogg[0][i] * 32768.0f;
dest[i*4+1] = dest[i*4+3] = ogg[1][i] * 32768.0f;
}
}
} else if ( kHz == 44100 ) {
if ( numChannels == 1 ) {
// calculate perm vector and do first load
vecPerm1 = vec_add( vec_lvsl( -1, (int*) &ogg[0][0] ), (vector unsigned char)(1) );
v9 = vec_ld( 0, &ogg[0][0] );
int i;
for ( i = 0; i+7 < numSamples; i += 8 ) {
// load values from ogg
v8 = v9;
v7 = vec_ld( 15, &ogg[0][i] );
v6 = v7;
v9 = vec_ld( 31, &ogg[0][i] );
vector float vecDestEnd = vec_ld( 31, &dest[i] );
v0 = vec_perm( v8, v7, vecPerm1 );
v1 = vec_perm( v6, v9, vecPerm1 );
// multiply
v0 = vec_madd( v0, constVec, zeroVector );
v1 = vec_madd( v1, constVec, zeroVector );
// rotate data
v0 = vec_perm( v0, v0, storePerm );
v1 = vec_perm( v1, v1, storePerm );
// store results
vec_st( vec_sel( vecDest, v0, mask ), 0, &dest[i] );
vec_st( vec_sel( v0, v1, mask ), 15, &dest[i] );
vecDest = vec_sel( v1, vecDestEnd, mask );
vec_st( vecDest, 31, &dest[i] );
}
// cleanup
for ( ; i < numSamples; i++ ) {
dest[i*1+0] = ogg[0][i] * 32768.0f;
}
} else {
// calculate perm vector and do first load
vecPerm1 = vec_add( vec_lvsl( -1, (int*) &ogg[0][0] ), (vector unsigned char)(1) );
vecPerm2 = vec_add( vec_lvsl( -1, (int*) &ogg[1][0] ), (vector unsigned char)(1) );
v7 = vec_ld( 0, &ogg[1][0] );
v9 = vec_ld( 0, &ogg[0][0] );
int i;
for ( i = 0; i+3 < numSamples >> 1; i += 4 ) {
v8 = v9;
v9 = vec_ld( 15, &ogg[0][i] );
v0 = vec_perm( v8, v9, vecPerm1 );
// load ogg[1][i] to ogg[1][i+3]
v6 = v7;
v7 = vec_ld( 15, &ogg[1][i] );
v1 = vec_perm( v6, v7, vecPerm2 );
// multiply
v0 = vec_madd( v0, constVec, zeroVector );
v1 = vec_madd( v1, constVec, zeroVector );
// generate result vectors
v2 = vec_mergeh( v0, v1 );
v3 = vec_mergel( v0, v1 );
// store results
UNALIGNED_STORE2( &dest[i*2], v2, v3 );
}
// cleanup
for ( ; i < numSamples >> 1; i++ ) {
dest[i*2+0] = ogg[0][i] * 32768.0f;
dest[i*2+1] = ogg[1][i] * 32768.0f;
}
}
} else {
assert( 0 );
}
}
#endif /* SOUND_DEST_ALIGNED */
#ifdef SOUND_DEST_ALIGNED
/*
============
idSIMD_AltiVec::MixSoundTwoSpeakerMono
Assumptions:
Assumes that mixBuffer starts at aligned address
============
*/
void VPCALL idSIMD_AltiVec::MixSoundTwoSpeakerMono( float *mixBuffer, const float *samples, const int numSamples, const float lastV[2], const float currentV[2] ) {
// mixBuffer is aligned
assert( IS_16BYTE_ALIGNED( mixBuffer[0] ) );
int i;
float inc[2];
float spkr[4];
register vector float vecInc;
register vector float vecSpeaker1, vecSpeaker2, vecSpeaker3, vecSpeaker4;
register vector float vecMixBuffer1, vecMixBuffer2, vecMixBuffer3, vecMixBuffer4;
register vector float vecSamplesLd1, vecSamplesLd2;
register vector float vecSamples1, vecSamples2, vecSamples3, vecSamples4;
register vector unsigned char permVec1 = (vector unsigned char)(0,1,2,3,0,1,2,3,4,5,6,7,4,5,6,7); //0,0,1,1
register vector unsigned char permVec2 = (vector unsigned char)(8,9,10,11,8,9,10,11,12,13,14,15,12,13,14,15); //2,2,3,3
register vector unsigned char permVec3 = (vector unsigned char)(16,17,18,19,16,17,18,19,20,21,22,23,20,21,22,23); //4,4,5,5
register vector unsigned char permVec4 = (vector unsigned char)(24,25,26,27,24,25,26,27,28,29,30,31,28,29,30,31); //6,6,7,7
//constants
vector float fourVec = (vector float)(4.0);
vector float zeroVec = (vector float)(0.0);
inc[0] = ( currentV[0] - lastV[0] ) / MIXBUFFER_SAMPLES;
inc[1] = ( currentV[1] - lastV[1] ) / MIXBUFFER_SAMPLES;
spkr[0] = lastV[0];
spkr[1] = lastV[1];
spkr[2] = lastV[0] + inc[0];
spkr[3] = lastV[1] + inc[1];
assert( numSamples == MIXBUFFER_SAMPLES );
inc[0] *= 2;
inc[1] *= 2;
//load data into registers
vector float v0 = loadSplatUnalignedScalar( &inc[0] );
vector float v1 = loadSplatUnalignedScalar( &inc[1] );
vecInc = vec_mergeh( v0, v1 );
vector float v2 = loadSplatUnalignedScalar( &spkr[0] );
vector float v3 = loadSplatUnalignedScalar( &spkr[1] );
vector float v4 = loadSplatUnalignedScalar( &spkr[2] );
vector float v5 = loadSplatUnalignedScalar( &spkr[3] );
// load spkr array
v0 = vec_mergeh( v2, v4 );
v1 = vec_mergeh( v3, v5 );
vecSpeaker1 = vec_mergeh( v0, v1 );
vecSpeaker2 = vec_add( vecSpeaker1, vecInc );
vecSpeaker3 = vec_add( vecSpeaker2, vecInc );
vecSpeaker4 = vec_add( vecSpeaker3, vecInc );
vecInc = vec_madd( vecInc, fourVec, zeroVec );
vector unsigned char samplesPerm = vec_add( vec_lvsl( -1, &samples[0] ), (vector unsigned char)(1) );
vector float vecSamplesLast = vec_ld( 0, &samples[0] );
//since MIXBUFFER_SAMPLES is a multiple of 8, we don't
//need a cleanup loop
for( i=0 ; i+7 < MIXBUFFER_SAMPLES; i += 8 ) {
//load samples and mix buffers
vecSamplesLd1 = vecSamplesLast; //vec_ld( 0, &samples[i] );
vecSamplesLd2 = vec_ld( 15, &samples[i] );
vecSamplesLast = vec_ld( 31, &samples[i] );
vecSamplesLd1 = vec_perm( vecSamplesLd1, vecSamplesLd2, samplesPerm );
vecSamplesLd2 = vec_perm( vecSamplesLd2, vecSamplesLast, samplesPerm );
vecMixBuffer1 = vec_ld( 0, &mixBuffer[i*2] );
vecMixBuffer2 = vec_ld( 0, &mixBuffer[i*2+4] );
vecMixBuffer3 = vec_ld( 0, &mixBuffer[i*2+8] );
vecMixBuffer4 = vec_ld( 0, &mixBuffer[i*2+12] );
vecSamples1 = vec_perm( vecSamplesLd1, vecSamplesLd2, permVec1 );
vecSamples2 = vec_perm( vecSamplesLd1, vecSamplesLd2, permVec2 );
vecSamples3 = vec_perm( vecSamplesLd1, vecSamplesLd2, permVec3 );
vecSamples4 = vec_perm( vecSamplesLd1, vecSamplesLd2, permVec4 );
vecMixBuffer1 = vec_madd( vecSamples1, vecSpeaker1, vecMixBuffer1 );
vecMixBuffer2 = vec_madd( vecSamples2, vecSpeaker2, vecMixBuffer2 );
vecMixBuffer3 = vec_madd( vecSamples3, vecSpeaker3, vecMixBuffer3 );
vecMixBuffer4 = vec_madd( vecSamples4, vecSpeaker4, vecMixBuffer4 );
// store results
ALIGNED_STORE4( &mixBuffer[i*2], vecMixBuffer1, vecMixBuffer2, vecMixBuffer3, vecMixBuffer4 );
//add for next iteration
vecSpeaker1 = vec_add( vecSpeaker1, vecInc );
vecSpeaker2 = vec_add( vecSpeaker2, vecInc );
vecSpeaker3 = vec_add( vecSpeaker3, vecInc );
vecSpeaker4 = vec_add( vecSpeaker4, vecInc );
}
}
#else
/*
============
idSIMD_AltiVec::MixSoundTwoSpeakerMono
Assumptions:
No assumptions
============
*/
void VPCALL idSIMD_AltiVec::MixSoundTwoSpeakerMono( float *mixBuffer, const float *samples, const int numSamples, const float lastV[2], const float currentV[2] ) {
int i;
float inc[2];
float spkr[4];
register vector float vecInc;
register vector float vecSpeaker1, vecSpeaker2, vecSpeaker3, vecSpeaker4;
register vector float vecMixBuffer1, vecMixBuffer2, vecMixBuffer3, vecMixBuffer4;
register vector float vecSamplesLd1, vecSamplesLd2;
register vector float vecSamples1, vecSamples2, vecSamples3, vecSamples4;
register vector unsigned char permVec1 = (vector unsigned char)(0,1,2,3,0,1,2,3,4,5,6,7,4,5,6,7); //0,0,1,1
register vector unsigned char permVec2 = (vector unsigned char)(8,9,10,11,8,9,10,11,12,13,14,15,12,13,14,15); //2,2,3,3
register vector unsigned char permVec3 = (vector unsigned char)(16,17,18,19,16,17,18,19,20,21,22,23,20,21,22,23); //4,4,5,5
register vector unsigned char permVec4 = (vector unsigned char)(24,25,26,27,24,25,26,27,28,29,30,31,28,29,30,31); //6,6,7,7
//constants
vector float fourVec = (vector float)(4.0);
vector float zeroVec = (vector float)(0.0);
inc[0] = ( currentV[0] - lastV[0] ) / MIXBUFFER_SAMPLES;
inc[1] = ( currentV[1] - lastV[1] ) / MIXBUFFER_SAMPLES;
spkr[0] = lastV[0];
spkr[1] = lastV[1];
spkr[2] = lastV[0] + inc[0];
spkr[3] = lastV[1] + inc[1];
assert( numSamples == MIXBUFFER_SAMPLES );
inc[0] *= 2;
inc[1] *= 2;
//load data into registers
vector float v0 = loadSplatUnalignedScalar( &inc[0] );
vector float v1 = loadSplatUnalignedScalar( &inc[1] );
vecInc = vec_mergeh( v0, v1 );
vector float v2 = loadSplatUnalignedScalar( &spkr[0] );
vector float v3 = loadSplatUnalignedScalar( &spkr[1] );
vector float v4 = loadSplatUnalignedScalar( &spkr[2] );
vector float v5 = loadSplatUnalignedScalar( &spkr[3] );
// load spkr array
v0 = vec_mergeh( v2, v4 );
v1 = vec_mergeh( v3, v5 );
vecSpeaker1 = vec_mergeh( v0, v1 );
vecSpeaker2 = vec_add( vecSpeaker1, vecInc );
vecSpeaker3 = vec_add( vecSpeaker2, vecInc );
vecSpeaker4 = vec_add( vecSpeaker3, vecInc );
vecInc = vec_madd( vecInc, fourVec, zeroVec );
vector unsigned char samplesPerm = vec_add( vec_lvsl( -1, &samples[0] ), (vector unsigned char)(1) );
vector unsigned char mixBufferPerm = vec_add( vec_lvsl( -1, &mixBuffer[0]), (vector unsigned char)(1) );
vector float vecSamplesLast = vec_ld( 0, &samples[0] );
vector float vecDest = vec_ld( 0, &mixBuffer[0] );
//since MIXBUFFER_SAMPLES is a multiple of 8, we don't
//need a cleanup loop
for( i=0 ; i+7 < MIXBUFFER_SAMPLES; i += 8 ) {
//load samples and mix buffers
vecSamplesLd1 = vecSamplesLast;
vecSamplesLd2 = vec_ld( 15, &samples[i] );
vecSamplesLast = vec_ld( 31, &samples[i] );
vecSamplesLd1 = vec_perm( vecSamplesLd1, vecSamplesLd2, samplesPerm );
vecSamplesLd2 = vec_perm( vecSamplesLd2, vecSamplesLast, samplesPerm );
vecMixBuffer1 = vecDest;
vecMixBuffer2 = vec_ld( 15, &mixBuffer[i*2] );
vecMixBuffer3 = vec_ld( 31, &mixBuffer[i*2] );
vecMixBuffer4 = vec_ld( 47, &mixBuffer[i*2] );
vector float vecDestEnd = vec_ld( 63, &mixBuffer[i*2] );
vecMixBuffer1 = vec_perm( vecMixBuffer1, vecMixBuffer2, mixBufferPerm );
vecMixBuffer2 = vec_perm( vecMixBuffer2, vecMixBuffer3, mixBufferPerm );
vecMixBuffer3 = vec_perm( vecMixBuffer3, vecMixBuffer4, mixBufferPerm );
vecMixBuffer4 = vec_perm( vecMixBuffer4, vecDestEnd, mixBufferPerm );
vecSamples1 = vec_perm( vecSamplesLd1, vecSamplesLd2, permVec1 );
vecSamples2 = vec_perm( vecSamplesLd1, vecSamplesLd2, permVec2 );
vecSamples3 = vec_perm( vecSamplesLd1, vecSamplesLd2, permVec3 );
vecSamples4 = vec_perm( vecSamplesLd1, vecSamplesLd2, permVec4 );
vecMixBuffer1 = vec_madd( vecSamples1, vecSpeaker1, vecMixBuffer1 );
vecMixBuffer2 = vec_madd( vecSamples2, vecSpeaker2, vecMixBuffer2 );
vecMixBuffer3 = vec_madd( vecSamples3, vecSpeaker3, vecMixBuffer3 );
vecMixBuffer4 = vec_madd( vecSamples4, vecSpeaker4, vecMixBuffer4 );
// store results
UNALIGNED_STORE4( &mixBuffer[i*2], vecMixBuffer1, vecMixBuffer2, vecMixBuffer3, vecMixBuffer4 );
//add for next iteration
vecSpeaker1 = vec_add( vecSpeaker1, vecInc );
vecSpeaker2 = vec_add( vecSpeaker2, vecInc );
vecSpeaker3 = vec_add( vecSpeaker3, vecInc );
vecSpeaker4 = vec_add( vecSpeaker4, vecInc );
}
}
#endif /* SOUND_DEST_ALIGNED */
#ifdef SOUND_DEST_ALIGNED
/*
============
idSIMD_AltiVec::MixSoundTwoSpeakerStereo
Assumptions:
Assumes that mixBuffer starts at aligned address
============
*/
void VPCALL idSIMD_AltiVec::MixSoundTwoSpeakerStereo( float *mixBuffer, const float *samples, const int numSamples, const float lastV[2], const float currentV[2] ) {
// mixBuffer is aligned
assert( IS_16BYTE_ALIGNED( mixBuffer[0] ) );
int i, k;
float inc[2];
float spkr[4];
// loading buffers
register vector float vecMixBuffer1, vecMixBuffer2, vecMixBuffer3, vecMixBuffer4;
// loading buffers
register vector float vecSamples1, vecSamples2, vecSamples3, vecSamples4;
register vector float vecSpeaker1, vecSpeaker2, vecSpeaker3, vecSpeaker4;
register vector float vecInc;
vector float fourVec = (vector float)(4.0);
vector float zeroVec = (vector float)(0.0);
assert( numSamples == MIXBUFFER_SAMPLES );
inc[0] = ( currentV[0] - lastV[0] ) / MIXBUFFER_SAMPLES;
inc[1] = ( currentV[1] - lastV[1] ) / MIXBUFFER_SAMPLES;
spkr[0] = lastV[0];
spkr[1] = lastV[1];
spkr[2] = lastV[0] + inc[0];
spkr[3] = lastV[1] + inc[1];
for ( k = 0; k < 2; k++ ) {
inc[k] *= 2;
}
// load data in vectors
vector float v0 = loadSplatUnalignedScalar( &inc[0] );
vector float v1 = loadSplatUnalignedScalar( &inc[1] );
vecInc = vec_mergeh( v0, v1 );
vector float v2 = loadSplatUnalignedScalar( &spkr[0] );
vector float v3 = loadSplatUnalignedScalar( &spkr[1] );
vector float v4 = loadSplatUnalignedScalar( &spkr[2] );
vector float v5 = loadSplatUnalignedScalar( &spkr[3] );
// load spkr array
v0 = vec_mergeh( v2, v4 );
v1 = vec_mergeh( v3, v5 );
vecSpeaker1 = vec_mergeh( v0, v1 );
vecSpeaker2 = vec_add( vecSpeaker1, vecInc );
vecSpeaker3 = vec_add( vecSpeaker2, vecInc );
vecSpeaker4 = vec_add( vecSpeaker3, vecInc );
vecInc = vec_madd( vecInc, fourVec, zeroVec );
vector unsigned char samplesPerm = vec_add( vec_lvsl( -1, &samples[0] ), (vector unsigned char)(1) );
vector float vecSamplesLast = vec_ld( 0, &samples[0] );
//since MIXBUFFER_SAMPLES is a multiple of 8, we don't
//need a cleanup loop
for( i = 0 ; i+7 < MIXBUFFER_SAMPLES; i += 8 ) {
// load mix buffers and samples
vecMixBuffer1 = vec_ld( 0, &mixBuffer[i*2] );
vecMixBuffer2 = vec_ld( 0, &mixBuffer[i*2+4] );
vecMixBuffer3 = vec_ld( 0, &mixBuffer[i*2+8] );
vecMixBuffer4 = vec_ld( 0, &mixBuffer[i*2+12] );
vecSamples1 = vecSamplesLast;
vecSamples2 = vec_ld( 15, &samples[i*2] );
vecSamples3 = vec_ld( 31, &samples[i*2] );
vecSamples4 = vec_ld( 47, &samples[i*2] );
vecSamplesLast = vec_ld( 63, &samples[i*2] );
vecSamples1 = vec_perm( vecSamples1, vecSamples2, samplesPerm );
vecSamples2 = vec_perm( vecSamples2, vecSamples3, samplesPerm );
vecSamples3 = vec_perm( vecSamples3, vecSamples4, samplesPerm );
vecSamples4 = vec_perm( vecSamples4, vecSamplesLast, samplesPerm );
vecMixBuffer1 = vec_madd( vecSamples1, vecSpeaker1, vecMixBuffer1 );
vecMixBuffer2 = vec_madd( vecSamples2, vecSpeaker2, vecMixBuffer2 );
vecMixBuffer3 = vec_madd( vecSamples3, vecSpeaker3, vecMixBuffer3 );
vecMixBuffer4 = vec_madd( vecSamples4, vecSpeaker4, vecMixBuffer4 );
vecSpeaker1 = vec_add( vecSpeaker1, vecInc );
vecSpeaker2 = vec_add( vecSpeaker2, vecInc );
vecSpeaker3 = vec_add( vecSpeaker3, vecInc );
vecSpeaker4 = vec_add( vecSpeaker4, vecInc );
//store results
ALIGNED_STORE4( &mixBuffer[i*2], vecMixBuffer1, vecMixBuffer2, vecMixBuffer3, vecMixBuffer4 );
}
}
#else
/*
============
idSIMD_AltiVec::MixSoundTwoSpeakerStereo
Assumptions:
No assumptions
============
*/
void VPCALL idSIMD_AltiVec::MixSoundTwoSpeakerStereo( float *mixBuffer, const float *samples, const int numSamples, const float lastV[2], const float currentV[2] ) {
int i, k;
float inc[2];
float spkr[4];
// loading buffers
register vector float vecMixBuffer1, vecMixBuffer2, vecMixBuffer3, vecMixBuffer4;
// loading buffers
register vector float vecSamples1, vecSamples2, vecSamples3, vecSamples4;
register vector float vecSpeaker1, vecSpeaker2, vecSpeaker3, vecSpeaker4;
register vector float vecInc;
vector float fourVec = (vector float)(4.0);
vector float zeroVec = (vector float)(0.0);
assert( numSamples == MIXBUFFER_SAMPLES );
inc[0] = ( currentV[0] - lastV[0] ) / MIXBUFFER_SAMPLES;
inc[1] = ( currentV[1] - lastV[1] ) / MIXBUFFER_SAMPLES;
spkr[0] = lastV[0];
spkr[1] = lastV[1];
spkr[2] = lastV[0] + inc[0];
spkr[3] = lastV[1] + inc[1];
for ( k = 0; k < 2; k++ ) {
inc[k] *= 2;
}
// load data in vectors
vector float v0 = loadSplatUnalignedScalar( &inc[0] );
vector float v1 = loadSplatUnalignedScalar( &inc[1] );
vecInc = vec_mergeh( v0, v1 );
vector float v2 = loadSplatUnalignedScalar( &spkr[0] );
vector float v3 = loadSplatUnalignedScalar( &spkr[1] );
vector float v4 = loadSplatUnalignedScalar( &spkr[2] );
vector float v5 = loadSplatUnalignedScalar( &spkr[3] );
// load spkr array
v0 = vec_mergeh( v2, v4 );
v1 = vec_mergeh( v3, v5 );
vecSpeaker1 = vec_mergeh( v0, v1 );
vecSpeaker2 = vec_add( vecSpeaker1, vecInc );
vecSpeaker3 = vec_add( vecSpeaker2, vecInc );
vecSpeaker4 = vec_add( vecSpeaker3, vecInc );
vecInc = vec_madd( vecInc, fourVec, zeroVec );
vector unsigned char samplesPerm = vec_add( vec_lvsl( -1, &samples[0] ), (vector unsigned char)(1) );
vector unsigned char mixBufferPerm = vec_add( vec_lvsl( -1, &mixBuffer[0] ), (vector unsigned char)(1) );
vector float vecSamplesLast = vec_ld( 0, &samples[0] );
vector float vecDest = vec_ld( 0, &mixBuffer[0] );
//since MIXBUFFER_SAMPLES is a multiple of 8, we don't
//need a cleanup loop
for( i = 0 ; i+7 < MIXBUFFER_SAMPLES; i += 8 ) {
// load mix buffers and samples
vecMixBuffer1 = vecDest;
vecMixBuffer2 = vec_ld( 15, &mixBuffer[i*2] );
vecMixBuffer3 = vec_ld( 31, &mixBuffer[i*2] );
vecMixBuffer4 = vec_ld( 47, &mixBuffer[i*2] );
vector float vecDestEnd = vec_ld( 63, &mixBuffer[i*2] );
vecMixBuffer1 = vec_perm( vecMixBuffer1, vecMixBuffer2, mixBufferPerm );
vecMixBuffer2 = vec_perm( vecMixBuffer2, vecMixBuffer3, mixBufferPerm );
vecMixBuffer3 = vec_perm( vecMixBuffer3, vecMixBuffer4, mixBufferPerm );
vecMixBuffer4 = vec_perm( vecMixBuffer4, vecDestEnd, mixBufferPerm );
vecSamples1 = vecSamplesLast;
vecSamples2 = vec_ld( 15, &samples[i*2] );
vecSamples3 = vec_ld( 31, &samples[i*2] );
vecSamples4 = vec_ld( 47, &samples[i*2] );
vecSamplesLast = vec_ld( 63, &samples[i*2] );
vecSamples1 = vec_perm( vecSamples1, vecSamples2, samplesPerm );
vecSamples2 = vec_perm( vecSamples2, vecSamples3, samplesPerm );
vecSamples3 = vec_perm( vecSamples3, vecSamples4, samplesPerm );
vecSamples4 = vec_perm( vecSamples4, vecSamplesLast, samplesPerm );
vecMixBuffer1 = vec_madd( vecSamples1, vecSpeaker1, vecMixBuffer1 );
vecMixBuffer2 = vec_madd( vecSamples2, vecSpeaker2, vecMixBuffer2 );
vecMixBuffer3 = vec_madd( vecSamples3, vecSpeaker3, vecMixBuffer3 );
vecMixBuffer4 = vec_madd( vecSamples4, vecSpeaker4, vecMixBuffer4 );
vecSpeaker1 = vec_add( vecSpeaker1, vecInc );
vecSpeaker2 = vec_add( vecSpeaker2, vecInc );
vecSpeaker3 = vec_add( vecSpeaker3, vecInc );
vecSpeaker4 = vec_add( vecSpeaker4, vecInc );
// store results
UNALIGNED_STORE4( &mixBuffer[i*2], vecMixBuffer1, vecMixBuffer2, vecMixBuffer3, vecMixBuffer4 );
}
}
#endif /* SOUND_DEST_ALIGNED */
#ifdef SOUND_DEST_ALIGNED
/*
============
idSIMD_AltiVec::MixSoundSixSpeakerMono
Assumptions:
Assumes that mixBuffer starts at aligned address
============
*/
void VPCALL idSIMD_AltiVec::MixSoundSixSpeakerMono( float *mixBuffer, const float *samples, const int numSamples, const float lastV[6], const float currentV[6] ) {
// mixBuffer is aligned
assert( IS_16BYTE_ALIGNED( mixBuffer[0] ) );
float incL[24];
float sL[24];
int i, k;
vector float vecIncl1, vecIncl2, vecIncl3, vecIncl4, vecIncl5, vecIncl6, vecIncl7;
vector float vecSL1, vecSL2, vecSL3, vecSL4, vecSL5, vecSL6, vecSL7;
vector float vecSamplesLd;
vector float vecSamples1, vecSamples2, vecSamples3, vecSamples4, vecSamples5, vecSamples6;
vector float vecMixBuffer1, vecMixBuffer2, vecMixBuffer3, vecMixBuffer4, vecMixBuffer5, vecMixBuffer6;
// permute vectors for sample
vector unsigned char samplePerm2 = (vector unsigned char)( 0,1,2,3,0,1,2,3,4,5,6,7,4,5,6,7);
vector unsigned char samplePerm5 = (vector unsigned char)( 8,9,10,11,8,9,10,11,12,13,14,15,12,13,14,15);
assert( numSamples == MIXBUFFER_SAMPLES );
assert( SPEAKER_RIGHT == 1 );
assert( SPEAKER_BACKRIGHT == 5 );
// incL array, 6 elements repeated
incL[0] = incL[6] = incL[12] = incL[18] = ( currentV[0] - lastV[0] ) / MIXBUFFER_SAMPLES;
incL[1] = incL[7] = incL[13] = incL[19] = ( currentV[1] - lastV[1] ) / MIXBUFFER_SAMPLES;
incL[2] = incL[8] = incL[14] = incL[20] = ( currentV[2] - lastV[2] ) / MIXBUFFER_SAMPLES;
incL[3] = incL[9] = incL[15] = incL[21] = ( currentV[3] - lastV[3] ) / MIXBUFFER_SAMPLES;
incL[4] = incL[10] = incL[16] = incL[22] = ( currentV[4] - lastV[4] ) / MIXBUFFER_SAMPLES;
incL[5] = incL[11] = incL[17] = incL[23] = ( currentV[5] - lastV[5] ) / MIXBUFFER_SAMPLES;
// sL array repeated
for ( k = 0; k < 6; k++ ) {
sL[k] = lastV[k];
}
for ( k = 6; k < 12; k++ ) {
sL[k] = lastV[k-6] + incL[k];
}
for ( k = 12; k < 18; k++ ) {
sL[k] = lastV[k-12] + incL[k] + incL[k];
}
for ( k = 18; k < 24; k++ ) {
sL[k] = lastV[k-18] + incL[k] + incL[k] + incL[k];
}
// multiply by 2 since doing 12 at a time
for ( k = 0; k < 24; k++ ) {
incL[k] *= 4;
}
//load the data
vector unsigned char incPerm = vec_add( vec_lvsl( -1, &incL[0] ), (vector unsigned char)(1) );
vector unsigned char slPerm = vec_add( vec_lvsl( -1, &sL[0] ), (vector unsigned char)(1) );
vecIncl1 = vec_ld( 0, &incL[0] );
vecIncl2 = vec_ld( 15, &incL[0] );
vecIncl3 = vec_ld( 31, &incL[0] );
vecIncl4 = vec_ld( 47, &incL[0] );
vecIncl5 = vec_ld( 63, &incL[0] );
vecIncl6 = vec_ld( 79, &incL[0] );
vecIncl7 = vec_ld( 95, &incL[0] );
vecIncl1 = vec_perm( vecIncl1, vecIncl2, incPerm );
vecIncl2 = vec_perm( vecIncl2, vecIncl3, incPerm );
vecIncl3 = vec_perm( vecIncl3, vecIncl4, incPerm );
vecIncl4 = vec_perm( vecIncl4, vecIncl5, incPerm );
vecIncl5 = vec_perm( vecIncl5, vecIncl6, incPerm );
vecIncl6 = vec_perm( vecIncl6, vecIncl7, incPerm );
vecSL1 = vec_ld( 0, &sL[0] );
vecSL2 = vec_ld( 15, &sL[0] );
vecSL3 = vec_ld( 31, &sL[0] );
vecSL4 = vec_ld( 47, &sL[0] );
vecSL5 = vec_ld( 63, &sL[0] );
vecSL6 = vec_ld( 79, &sL[0] );
vecSL7 = vec_ld( 95, &sL[0] );
vecSL1 = vec_perm( vecSL1, vecSL2, slPerm );
vecSL2 = vec_perm( vecSL2, vecSL3, slPerm );
vecSL3 = vec_perm( vecSL3, vecSL4, slPerm );
vecSL4 = vec_perm( vecSL4, vecSL5, slPerm );
vecSL5 = vec_perm( vecSL5, vecSL6, slPerm );
vecSL6 = vec_perm( vecSL6, vecSL7, slPerm );
vector unsigned char samplesPerm = vec_add( vec_lvsl( -1, &samples[0] ), (vector unsigned char)(1) );
vector float vecSamplesLast = vec_ld( 0, &samples[0] );
//since MIXBUFFER_SAMPLES is a multiple of 4, we don't
//need a cleanup loop
for( i = 0; i <= MIXBUFFER_SAMPLES - 4; i += 4 ) {
//load mix buffer into vectors, assume aligned
vecMixBuffer1 = vec_ld( 0, &mixBuffer[i*6] );
vecMixBuffer2 = vec_ld( 0, &mixBuffer[(i*6)+4] );
vecMixBuffer3 = vec_ld( 0, &mixBuffer[(i*6)+8] );
vecMixBuffer4 = vec_ld( 0, &mixBuffer[(i*6)+12] );
vecMixBuffer5 = vec_ld( 0, &mixBuffer[(i*6)+16] );
vecMixBuffer6 = vec_ld( 0, &mixBuffer[(i*6)+20] );
//load samples into vector
vector float vecSamplesLd2 = vec_ld( 15, &samples[i] );
vecSamplesLd = vec_perm( vecSamplesLast, vecSamplesLd2, samplesPerm );
vecSamplesLast = vecSamplesLd2;
//permute to get them ordered how we want
vecSamples1 = vec_splat( vecSamplesLd, 0 );
vecSamples2 = vec_perm( vecSamplesLd, vecSamplesLd, samplePerm2 );
vecSamples3 = vec_splat( vecSamplesLd, 1 );
vecSamples4 = vec_splat( vecSamplesLd, 2 );
vecSamples5 = vec_perm( vecSamplesLd, vecSamplesLd, samplePerm5 );
vecSamples6 = vec_splat( vecSamplesLd, 3 );
//do calculation
vecMixBuffer1 = vec_madd( vecSamples1, vecSL1, vecMixBuffer1 );
vecMixBuffer2 = vec_madd( vecSamples2, vecSL2, vecMixBuffer2 );
vecMixBuffer3 = vec_madd( vecSamples3, vecSL3, vecMixBuffer3 );
vecMixBuffer4 = vec_madd( vecSamples4, vecSL4, vecMixBuffer4 );
vecMixBuffer5 = vec_madd( vecSamples5, vecSL5, vecMixBuffer5 );
vecMixBuffer6 = vec_madd( vecSamples6, vecSL6, vecMixBuffer6 );
//store out results
ALIGNED_STORE6( &mixBuffer[i*6], vecMixBuffer1, vecMixBuffer2, vecMixBuffer3, vecMixBuffer4, vecMixBuffer5, vecMixBuffer6 );
// add for next iteration
vecSL1 = vec_add( vecSL1, vecIncl1 );
vecSL2 = vec_add( vecSL2, vecIncl2 );
vecSL3 = vec_add( vecSL3, vecIncl3 );
vecSL4 = vec_add( vecSL4, vecIncl4 );
vecSL5 = vec_add( vecSL5, vecIncl5 );
vecSL6 = vec_add( vecSL6, vecIncl6 );
}
}
#else
/*
============
idSIMD_AltiVec::MixSoundSixSpeakerMono
Assumptions:
No assumptions
============
*/
void VPCALL idSIMD_AltiVec::MixSoundSixSpeakerMono( float *mixBuffer, const float *samples, const int numSamples, const float lastV[6], const float currentV[6] ) {
float incL[24];
float sL[24];
int i, k;
vector float vecIncl1, vecIncl2, vecIncl3, vecIncl4, vecIncl5, vecIncl6, vecIncl7;
vector float vecSL1, vecSL2, vecSL3, vecSL4, vecSL5, vecSL6, vecSL7;
vector float vecSamplesLd;
vector float vecSamples1, vecSamples2, vecSamples3, vecSamples4, vecSamples5, vecSamples6;
vector float vecMixBuffer1, vecMixBuffer2, vecMixBuffer3, vecMixBuffer4, vecMixBuffer5, vecMixBuffer6;
// permute vectors for sample
register vector unsigned char samplePerm2 = (vector unsigned char)( 0,1,2,3,0,1,2,3,4,5,6,7,4,5,6,7);
register vector unsigned char samplePerm5 = (vector unsigned char)( 8,9,10,11,8,9,10,11,12,13,14,15,12,13,14,15);
assert( numSamples == MIXBUFFER_SAMPLES );
assert( SPEAKER_RIGHT == 1 );
assert( SPEAKER_BACKRIGHT == 5 );
// incL array, 6 elements repeated
incL[0] = incL[6] = incL[12] = incL[18] = ( currentV[0] - lastV[0] ) / MIXBUFFER_SAMPLES;
incL[1] = incL[7] = incL[13] = incL[19] = ( currentV[1] - lastV[1] ) / MIXBUFFER_SAMPLES;
incL[2] = incL[8] = incL[14] = incL[20] = ( currentV[2] - lastV[2] ) / MIXBUFFER_SAMPLES;
incL[3] = incL[9] = incL[15] = incL[21] = ( currentV[3] - lastV[3] ) / MIXBUFFER_SAMPLES;
incL[4] = incL[10] = incL[16] = incL[22] = ( currentV[4] - lastV[4] ) / MIXBUFFER_SAMPLES;
incL[5] = incL[11] = incL[17] = incL[23] = ( currentV[5] - lastV[5] ) / MIXBUFFER_SAMPLES;
// sL array repeated
for ( k = 0; k < 6; k++ ) {
sL[k] = lastV[k];
}
for ( k = 6; k < 12; k++ ) {
sL[k] = lastV[k-6] + incL[k];
}
for ( k = 12; k < 18; k++ ) {
sL[k] = lastV[k-12] + incL[k] + incL[k];
}
for ( k = 18; k < 24; k++ ) {
sL[k] = lastV[k-18] + incL[k] + incL[k] + incL[k];
}
// multiply by 2 since doing 12 at a time
for ( k = 0; k < 24; k++ ) {
incL[k] *= 4;
}
// load the data
vector unsigned char incPerm = vec_add( vec_lvsl( -1, &incL[0] ), (vector unsigned char)(1) );
vector unsigned char slPerm = vec_add( vec_lvsl( -1, &sL[0] ), (vector unsigned char)(1) );
vecIncl1 = vec_ld( 0, &incL[0] );
vecIncl2 = vec_ld( 15, &incL[0] );
vecIncl3 = vec_ld( 31, &incL[0] );
vecIncl4 = vec_ld( 47, &incL[0] );
vecIncl5 = vec_ld( 63, &incL[0] );
vecIncl6 = vec_ld( 79, &incL[0] );
vecIncl7 = vec_ld( 95, &incL[0] );
vecIncl1 = vec_perm( vecIncl1, vecIncl2, incPerm );
vecIncl2 = vec_perm( vecIncl2, vecIncl3, incPerm );
vecIncl3 = vec_perm( vecIncl3, vecIncl4, incPerm );
vecIncl4 = vec_perm( vecIncl4, vecIncl5, incPerm );
vecIncl5 = vec_perm( vecIncl5, vecIncl6, incPerm );
vecIncl6 = vec_perm( vecIncl6, vecIncl7, incPerm );
vecSL1 = vec_ld( 0, &sL[0] );
vecSL2 = vec_ld( 15, &sL[0] );
vecSL3 = vec_ld( 31, &sL[0] );
vecSL4 = vec_ld( 47, &sL[0] );
vecSL5 = vec_ld( 63, &sL[0] );
vecSL6 = vec_ld( 79, &sL[0] );
vecSL7 = vec_ld( 95, &sL[0] );
vecSL1 = vec_perm( vecSL1, vecSL2, slPerm );
vecSL2 = vec_perm( vecSL2, vecSL3, slPerm );
vecSL3 = vec_perm( vecSL3, vecSL4, slPerm );
vecSL4 = vec_perm( vecSL4, vecSL5, slPerm );
vecSL5 = vec_perm( vecSL5, vecSL6, slPerm );
vecSL6 = vec_perm( vecSL6, vecSL7, slPerm );
vector unsigned char samplesPerm = vec_add( vec_lvsl( -1, &samples[0] ), (vector unsigned char)(1) );
vector unsigned char mixBufferPerm = vec_add( vec_lvsl( -1, &mixBuffer[0] ), (vector unsigned char)(1) );
vector float vecSamplesLast = vec_ld( 0, &samples[0] );
vector float vecDest = vec_ld( 0, &mixBuffer[0] );
//since MIXBUFFER_SAMPLES is a multiple of 4, we don't
//need a cleanup loop
for( i = 0; i <= MIXBUFFER_SAMPLES - 4; i += 4 ) {
//load mix buffer into vectors
vecMixBuffer1 = vecDest;
vecMixBuffer2 = vec_ld( 15, &mixBuffer[i*6] );
vecMixBuffer3 = vec_ld( 31, &mixBuffer[i*6] );
vecMixBuffer4 = vec_ld( 47, &mixBuffer[i*6] );
vecMixBuffer5 = vec_ld( 63, &mixBuffer[i*6] );
vecMixBuffer6 = vec_ld( 79, &mixBuffer[i*6] );
vector float vecDestEnd = vec_ld( 95, &mixBuffer[i*6] );
vecMixBuffer1 = vec_perm( vecMixBuffer1, vecMixBuffer2, mixBufferPerm );
vecMixBuffer2 = vec_perm( vecMixBuffer2, vecMixBuffer3, mixBufferPerm );
vecMixBuffer3 = vec_perm( vecMixBuffer3, vecMixBuffer4, mixBufferPerm );
vecMixBuffer4 = vec_perm( vecMixBuffer4, vecMixBuffer5, mixBufferPerm );
vecMixBuffer5 = vec_perm( vecMixBuffer5, vecMixBuffer6, mixBufferPerm );
vecMixBuffer6 = vec_perm( vecMixBuffer6, vecDestEnd, mixBufferPerm );
//load samples into vector
vector float vecSamplesLd2 = vec_ld( 15, &samples[i] );
vecSamplesLd = vec_perm( vecSamplesLast, vecSamplesLd2, samplesPerm );
vecSamplesLast = vecSamplesLd2;
//permute to get them ordered how we want
vecSamples1 = vec_splat( vecSamplesLd, 0 );
vecSamples2 = vec_perm( vecSamplesLd, vecSamplesLd, samplePerm2 );
vecSamples3 = vec_splat( vecSamplesLd, 1 );
vecSamples4 = vec_splat( vecSamplesLd, 2 );
vecSamples5 = vec_perm( vecSamplesLd, vecSamplesLd, samplePerm5 );
vecSamples6 = vec_splat( vecSamplesLd, 3 );
//do calculation
vecMixBuffer1 = vec_madd( vecSamples1, vecSL1, vecMixBuffer1 );
vecMixBuffer2 = vec_madd( vecSamples2, vecSL2, vecMixBuffer2 );
vecMixBuffer3 = vec_madd( vecSamples3, vecSL3, vecMixBuffer3 );
vecMixBuffer4 = vec_madd( vecSamples4, vecSL4, vecMixBuffer4 );
vecMixBuffer5 = vec_madd( vecSamples5, vecSL5, vecMixBuffer5 );
vecMixBuffer6 = vec_madd( vecSamples6, vecSL6, vecMixBuffer6 );
// store results
UNALIGNED_STORE6( &mixBuffer[i*6], vecMixBuffer1, vecMixBuffer2, vecMixBuffer3, vecMixBuffer4, vecMixBuffer5, vecMixBuffer6 );
// add for next iteration
vecSL1 = vec_add( vecSL1, vecIncl1 );
vecSL2 = vec_add( vecSL2, vecIncl2 );
vecSL3 = vec_add( vecSL3, vecIncl3 );
vecSL4 = vec_add( vecSL4, vecIncl4 );
vecSL5 = vec_add( vecSL5, vecIncl5 );
vecSL6 = vec_add( vecSL6, vecIncl6 );
}
}
#endif /* SOUND_DEST_ALIGNED */
#ifdef SOUND_DEST_ALIGNED
/*
============
idSIMD_AltiVec::MixSoundSixSpeakerStereo
Assumptions:
Assumes that mixBuffer starts at aligned address
============
*/
void VPCALL idSIMD_AltiVec::MixSoundSixSpeakerStereo( float *mixBuffer, const float *samples, const int numSamples, const float lastV[6], const float currentV[6] ) {
// mixBuffer is aligned
assert( IS_16BYTE_ALIGNED( mixBuffer[0] ) );
float incL[12];
float sL[12];
int i;
vector float vecIncl1, vecIncl2, vecIncl3, vecIncl4;
vector float vecSL1, vecSL2, vecSL3, vecSL4;
vector float vecSamplesLd;
vector float vecSamples1, vecSamples2, vecSamples3;
vector float vecMixBuffer1, vecMixBuffer2, vecMixBuffer3;
// permute vectors for sample
vector unsigned char samplePerm1 = (vector unsigned char)( 0,1,2,3,4,5,6,7,0,1,2,3,0,1,2,3);
vector unsigned char samplePerm3 = (vector unsigned char)( 8,9,10,11,8,9,10,11,8,9,10,11,12,13,14,15);
assert( numSamples == MIXBUFFER_SAMPLES );
assert( SPEAKER_RIGHT == 1 );
assert( SPEAKER_BACKRIGHT == 5 );
// incL array, 6 elements repeated
incL[0] = incL[6] = ( currentV[0] - lastV[0] ) / MIXBUFFER_SAMPLES;
incL[1] = incL[7] = ( currentV[1] - lastV[1] ) / MIXBUFFER_SAMPLES;
incL[2] = incL[8] = ( currentV[2] - lastV[2] ) / MIXBUFFER_SAMPLES;
incL[3] = incL[9] = ( currentV[3] - lastV[3] ) / MIXBUFFER_SAMPLES;
incL[4] = incL[10] = ( currentV[4] - lastV[4] ) / MIXBUFFER_SAMPLES;
incL[5] = incL[11] = ( currentV[5] - lastV[5] ) / MIXBUFFER_SAMPLES;
// sL array repeated
sL[0] = lastV[0];
sL[1] = lastV[1];
sL[2] = lastV[2];
sL[3] = lastV[3];
sL[4] = lastV[4];
sL[5] = lastV[5];
sL[6] = lastV[0] + incL[0];
sL[7] = lastV[1] + incL[1];
sL[8] = lastV[2] + incL[2];
sL[9] = lastV[3] + incL[3];
sL[10] = lastV[4] + incL[4];
sL[11] = lastV[5] + incL[5];
// multiply by 2 since doing 12 at a time
incL[0] *= 2;
incL[1] *= 2;
incL[2] *= 2;
incL[3] *= 2;
incL[4] *= 2;
incL[5] *= 2;
incL[6] *= 2;
incL[7] *= 2;
incL[8] *= 2;
incL[9] *= 2;
incL[10] *= 2;
incL[11] *= 2;
//we aligned this data, so load it up
vector unsigned char incPerm = vec_add( vec_lvsl( -1, &incL[0] ), (vector unsigned char)(1) );
vector unsigned char slPerm = vec_add( vec_lvsl( -1, &sL[0] ), (vector unsigned char)(1) );
vecIncl1 = vec_ld( 0, &incL[0] );
vecIncl2 = vec_ld( 15, &incL[0] );
vecIncl3 = vec_ld( 31, &incL[0] );
vecIncl4 = vec_ld( 47, &incL[0] );
vecIncl1 = vec_perm( vecIncl1, vecIncl2, incPerm );
vecIncl2 = vec_perm( vecIncl2, vecIncl3, incPerm );
vecIncl3 = vec_perm( vecIncl3, vecIncl4, incPerm );
vecSL1 = vec_ld( 0, &sL[0] );
vecSL2 = vec_ld( 15, &sL[0] );
vecSL3 = vec_ld( 31, &sL[0] );
vecSL4 = vec_ld( 47, &sL[0] );
vecSL1 = vec_perm( vecSL1, vecSL2, slPerm );
vecSL2 = vec_perm( vecSL2, vecSL3, slPerm );
vecSL3 = vec_perm( vecSL3, vecSL4, slPerm );
vector unsigned char samplesPerm = vec_add( vec_lvsl( -1, &samples[0] ), (vector unsigned char)(1) );
vector float vecSamplesLast = vec_ld( 0, &samples[0] );
for( i = 0; i <= MIXBUFFER_SAMPLES - 2; i += 2 ) {
//load mix buffer into vectors, assume aligned
vecMixBuffer1 = vec_ld( 0, &mixBuffer[i*6] );
vecMixBuffer2 = vec_ld( 0, &mixBuffer[(i*6)+4] );
vecMixBuffer3 = vec_ld( 0, &mixBuffer[(i*6)+8] );
//load samples into vector
vector float vecSamplesLd2 = vec_ld( 15, &samples[i*2] );
vecSamplesLd = vec_perm( vecSamplesLast, vecSamplesLd2, samplesPerm );
vecSamplesLast = vecSamplesLd2;
//permute to get them ordered how we want. For the 2nd vector,
//the order happens to be the same as the order we loaded them
//in, so there's no need to permute that one
vecSamples1 = vec_perm( vecSamplesLd, vecSamplesLd, samplePerm1 );
vecSamples2 = vecSamplesLd;
vecSamples3 = vec_perm( vecSamplesLd, vecSamplesLd, samplePerm3 );
//do calculation
vecMixBuffer1 = vec_madd( vecSamples1, vecSL1, vecMixBuffer1 );
vecMixBuffer2 = vec_madd( vecSamples2, vecSL2, vecMixBuffer2 );
vecMixBuffer3 = vec_madd( vecSamples3, vecSL3, vecMixBuffer3 );
//store out results
ALIGNED_STORE3( &mixBuffer[i*6], vecMixBuffer1, vecMixBuffer2, vecMixBuffer3 );
// add for next iteration
vecSL1 = vec_add( vecSL1, vecIncl1 );
vecSL2 = vec_add( vecSL2, vecIncl2 );
vecSL3 = vec_add( vecSL3, vecIncl3 );
}
}
#else
/*
============
idSIMD_AltiVec::MixSoundSixSpeakerStereo
Assumptions:
No assumptions
============
*/
void VPCALL idSIMD_AltiVec::MixSoundSixSpeakerStereo( float *mixBuffer, const float *samples, const int numSamples, const float lastV[6], const float currentV[6] ) {
float incL[12];
float sL[12];
int i;
vector float vecIncl1, vecIncl2, vecIncl3, vecIncl4;
vector float vecSL1, vecSL2, vecSL3, vecSL4;
vector float vecSamplesLd;
vector float vecSamples1, vecSamples2, vecSamples3;
vector float vecMixBuffer1, vecMixBuffer2, vecMixBuffer3;
// permute vectors for sample
vector unsigned char samplePerm1 = (vector unsigned char)( 0,1,2,3,4,5,6,7,0,1,2,3,0,1,2,3);
vector unsigned char samplePerm3 = (vector unsigned char)( 8,9,10,11,8,9,10,11,8,9,10,11,12,13,14,15);
assert( numSamples == MIXBUFFER_SAMPLES );
assert( SPEAKER_RIGHT == 1 );
assert( SPEAKER_BACKRIGHT == 5 );
// incL array, 6 elements repeated
incL[0] = incL[6] = ( currentV[0] - lastV[0] ) / MIXBUFFER_SAMPLES;
incL[1] = incL[7] = ( currentV[1] - lastV[1] ) / MIXBUFFER_SAMPLES;
incL[2] = incL[8] = ( currentV[2] - lastV[2] ) / MIXBUFFER_SAMPLES;
incL[3] = incL[9] = ( currentV[3] - lastV[3] ) / MIXBUFFER_SAMPLES;
incL[4] = incL[10] = ( currentV[4] - lastV[4] ) / MIXBUFFER_SAMPLES;
incL[5] = incL[11] = ( currentV[5] - lastV[5] ) / MIXBUFFER_SAMPLES;
// sL array repeated
sL[0] = lastV[0];
sL[1] = lastV[1];
sL[2] = lastV[2];
sL[3] = lastV[3];
sL[4] = lastV[4];
sL[5] = lastV[5];
sL[6] = lastV[0] + incL[0];
sL[7] = lastV[1] + incL[1];
sL[8] = lastV[2] + incL[2];
sL[9] = lastV[3] + incL[3];
sL[10] = lastV[4] + incL[4];
sL[11] = lastV[5] + incL[5];
// multiply by 2 since doing 12 at a time
incL[0] *= 2;
incL[1] *= 2;
incL[2] *= 2;
incL[3] *= 2;
incL[4] *= 2;
incL[5] *= 2;
incL[6] *= 2;
incL[7] *= 2;
incL[8] *= 2;
incL[9] *= 2;
incL[10] *= 2;
incL[11] *= 2;
// load the data
vector unsigned char incPerm = vec_add( vec_lvsl( -1, &incL[0] ), (vector unsigned char)(1) );
vector unsigned char slPerm = vec_add( vec_lvsl( -1, &sL[0] ), (vector unsigned char)(1) );
vecIncl1 = vec_ld( 0, &incL[0] );
vecIncl2 = vec_ld( 15, &incL[0] );
vecIncl3 = vec_ld( 31, &incL[0] );
vecIncl4 = vec_ld( 47, &incL[0] );
vecIncl1 = vec_perm( vecIncl1, vecIncl2, incPerm );
vecIncl2 = vec_perm( vecIncl2, vecIncl3, incPerm );
vecIncl3 = vec_perm( vecIncl3, vecIncl4, incPerm );
vecSL1 = vec_ld( 0, &sL[0] );
vecSL2 = vec_ld( 15, &sL[0] );
vecSL3 = vec_ld( 31, &sL[0] );
vecSL4 = vec_ld( 47, &sL[0] );
vecSL1 = vec_perm( vecSL1, vecSL2, slPerm );
vecSL2 = vec_perm( vecSL2, vecSL3, slPerm );
vecSL3 = vec_perm( vecSL3, vecSL4, slPerm );
vector unsigned char samplesPerm = vec_add( vec_lvsl( -1, &samples[0] ), (vector unsigned char)(1) );
vector unsigned char mixBufferPerm = vec_add( vec_lvsl( -1, &mixBuffer[0] ), (vector unsigned char)(1) );
vector float vecSamplesLast = vec_ld( 0, &samples[0] );
vector float vecDest = vec_ld( 0, &mixBuffer[0] );
for( i = 0; i <= MIXBUFFER_SAMPLES - 2; i += 2 ) {
//load mix buffer into vectors
vecMixBuffer1 = vecDest;
vecMixBuffer2 = vec_ld( 15, &mixBuffer[i*6] );
vecMixBuffer3 = vec_ld( 31, &mixBuffer[i*6] );
vector float vecDestEnd = vec_ld( 47, &mixBuffer[i*6] );
vecMixBuffer1 = vec_perm( vecMixBuffer1, vecMixBuffer2, mixBufferPerm );
vecMixBuffer2 = vec_perm( vecMixBuffer2, vecMixBuffer3, mixBufferPerm );
vecMixBuffer3 = vec_perm( vecMixBuffer3, vecDestEnd, mixBufferPerm );
//load samples into vector
vector float vecSamplesLd2 = vec_ld( 15, &samples[i*2] );
vecSamplesLd = vec_perm( vecSamplesLast, vecSamplesLd2, samplesPerm );
vecSamplesLast = vecSamplesLd2;
//permute to get them ordered how we want. For the 2nd vector,
//the order happens to be the same as the order we loaded them
//in, so there's no need to permute that one
vecSamples1 = vec_perm( vecSamplesLd, vecSamplesLd, samplePerm1 );
vecSamples2 = vecSamplesLd;
vecSamples3 = vec_perm( vecSamplesLd, vecSamplesLd, samplePerm3 );
//do calculation
vecMixBuffer1 = vec_madd( vecSamples1, vecSL1, vecMixBuffer1 );
vecMixBuffer2 = vec_madd( vecSamples2, vecSL2, vecMixBuffer2 );
vecMixBuffer3 = vec_madd( vecSamples3, vecSL3, vecMixBuffer3 );
// store results
UNALIGNED_STORE3( &mixBuffer[i*6], vecMixBuffer1, vecMixBuffer2, vecMixBuffer3 );
// add for next iteration
vecSL1 = vec_add( vecSL1, vecIncl1 );
vecSL2 = vec_add( vecSL2, vecIncl2 );
vecSL3 = vec_add( vecSL3, vecIncl3 );
}
}
#endif
/*
============
idSIMD_AltiVec::MixedSoundToSamples
============
*/
void VPCALL idSIMD_AltiVec::MixedSoundToSamples( short *samples, const float *mixBuffer, const int numSamples ) {
//this is basically a clamp for sound mixing
register vector float v0, v1, v2, v3, v4, v5, v6, v7;
register vector signed int vi0, vi1, vi2, vi3;
register vector signed short vs0, vs1;
register vector float minVec, maxVec, constVec;
int i = 0;
//unaligned at start, since samples is not 16-byte aligned
for ( ; NOT_16BYTE_ALIGNED( samples[i] ) && ( i < numSamples ); i++ ) {
samples[i] = mixBuffer[i] <= -32768.0f ? -32768 : mixBuffer[i] >= 32767.0f ? 32767 : (short) mixBuffer[i];
}
constVec = (vector float)(65536.0f);
//splat min/max into a vector
minVec = (vector float)(-32768.0f);
maxVec = (vector float)(32767.0f);
vector float vecOld = vec_ld( 0, &mixBuffer[i] );
vector unsigned char permVec = vec_add( vec_lvsl( -1, &mixBuffer[i] ), (vector unsigned char)(1) );
//vectorize!
for ( ; i+15 < numSamples; i += 16 ) {
//load source
v0 = vecOld;
v1 = vec_ld( 15, &mixBuffer[i] );
v2 = vec_ld( 31, &mixBuffer[i] );
v3 = vec_ld( 31, &mixBuffer[i] );
vecOld = vec_ld( 47, &mixBuffer[i] );
v0 = vec_perm( v0, v1, permVec );
v1 = vec_perm( v1, v2, permVec );
v2 = vec_perm( v2, v3, permVec );
v3 = vec_perm( v3, vecOld, permVec );
//apply minimum
v4 = vec_max( v0, minVec );
v5 = vec_max( v1, minVec );
v6 = vec_max( v2, minVec );
v7 = vec_max( v3, minVec );
//apply maximum
v4 = vec_min( v4, maxVec );
v5 = vec_min( v5, maxVec );
v6 = vec_min( v6, maxVec );
v7 = vec_min( v7, maxVec );
// convert floats to ints
vi0 = vec_cts( v4, 0 );
vi1 = vec_cts( v5, 0 );
vi2 = vec_cts( v6, 0 );
vi3 = vec_cts( v7, 0 );
// pack ints into shorts
vs0 = vec_pack( vi0, vi1 );
vs1 = vec_pack( vi2, vi3 );
ALIGNED_STORE2( &samples[i], vs0, vs1 );
}
//handle cleanup
for ( ; i < numSamples ; i++ ) {
samples[i] = mixBuffer[i] <= -32768.0f ? -32768 : mixBuffer[i] >= 32767.0f ? 32767 : (short) mixBuffer[i];
}
}
#endif /* ENABLE_SOUND_ROUTINES */
#endif /* MACOS_X */