mirror of
https://github.com/dhewm/dhewm3.git
synced 2024-11-27 06:32:27 +00:00
8023bc5d56
Protect all SIMD implementations with the according defines and let the compiler decide if it supports the intructions. Linux will still use Simd_Generic because CPU feature runtime detection is missing.
11240 lines
364 KiB
C++
11240 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 "../precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#include "Simd_Generic.h"
|
|
#include "Simd_AltiVec.h"
|
|
#include <math.h>
|
|
#include <float.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 */
|