mirror of
https://github.com/dhewm/dhewm3.git
synced 2024-11-30 08:01:02 +00:00
736ec20d4d
Don't include the lazy precompiled.h everywhere, only what's required for the compilation unit. platform.h needs to be included instead to provide all essential defines and types. All includes use the relative path to the neo or the game specific root. Move all idlib related includes from idlib/Lib.h to precompiled.h. precompiled.h still exists for the MFC stuff in tools/. Add some missing header guards.
11238 lines
364 KiB
C++
11238 lines
364 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
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 <http://www.gnu.org/licenses/>.
|
|
|
|
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 <math.h>
|
|
#include <float.h>
|
|
|
|
#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(__GNUC__) && defined(__ALTIVEC__)
|
|
|
|
#ifdef PPC_INTRINSICS
|
|
// for square root estimate instruction
|
|
#include <ppc_intrinsics.h>
|
|
#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 */
|