Neon optimization


x1212

Member
Joined
Apr 1, 2013
Messages
134
And vectorize, noting that NEON has support for scalar * vector multiplication and instructions for interleaving variables:

I was trying to speed up godot's 3d-physics by vectorizing some functions used by collision-tests.

So I when I found a loop, where results of one iteration didn't depend on results of any other iteration I decided to do 4 iterations at once using float32x4_t.

however I get an error when I try to compile:

error: invalid operands of types 'float32x4_t {aka __vector(4) __builtin_neon_sf}' and 'real_t {aka float}' to binary 'operator*'

from my understanding that means that it does not like multiplication of vectors with scalars ...

Does anyone have any idea what I might be doing wrong?

Are those scalar*vector operations only available for float32x2_t? (edit: changing them from float32x4_t to float32x2_t did nothing)

Or am I missing some compiler-switch or include?
 
Last edited by a moderator:

ptitSeb

Serial Porter
Joined
Aug 15, 2012
Messages
8,979
Age
48
Location
France, near Lyon
And vectorize, noting that NEON has support for scalar * vector multiplication and instructions for interleaving variables:

I was trying to speed up godot's 3d-physics by vectorizing some functions used by collision-tests.

So I when I found a loop, where results of one iteration didn't depend on results of any other iteration I decided to do 4 iterations at once using float32x4_t.

however I get an error when I try to compile:

error: invalid operands of types 'float32x4_t {aka __vector(4) __builtin_neon_sf}' and 'real_t {aka float}' to binary 'operator*'

from my understanding that means that it does not like multiplication of vectors with scalars ...

Does anyone have any idea what I might be doing wrong?

Are those scalar*vector operations only available for float32x2_t? (edit: changing them from float32x4_t to float32x2_t did nothing)

Or am I missing some compiler-switch or include?
Which version of GCC do you used?

Can you put a sample of your code?
 

x1212

Member
Joined
Apr 1, 2013
Messages
134
g++ --version gives me "g++ (Sourcery CodeBench Lite 2011.09-70) 4.6.1"
 

also here the function I'm trying to optimize: (big wall of code ... will try to clean that up asap)
 

#ifdef NEON
#include <arm_neon.h>
#endif

...

void ConvexPolygonShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {


int vertex_count=mesh.vertices.size();
if (vertex_count==0)
return;

const Vector3 *vrts=&mesh.vertices[0];
#ifndef NEON
for (int i=0;i<vertex_count;i++) {

float d=p_normal.dot( p_transform.xform( vrts ) );

if (i==0 || d > r_max)
r_max=d;
if (i==0 || d < r_min)
r_min=d;
}
#else
int i;
for (i=0;i<vertex_count-4;i+=4) { // as long as 4 calculations at a time are possible
/*_FORCE_INLINE_ Vector3 Transform::xform(const Vector3& p_vector) const {

return Vector3(
basis[0].dot(p_vector)+origin.x,
basis[1].dot(p_vector)+origin.y,
basis[2].dot(p_vector)+origin.z
);

}*/
//float d1, d2, d3, d4;

Matrix3 m = p_transform.get_basis();
Vector3 o = p_transform.get_origin();

//float f1_1, f1_2, f1_3, f1_4, f2_1, f2_2, f2_3, f2_4, f3_1, f3_2, f3_3, f3_4;
float32x4_t f1, f2, f3;
float32x4_t d;
float32x4_t vrts_x = {vrts.x, vrts[i+1].x, vrts[i+2].x, vrts[i+3].x};
float32x4_t vrts_y = {vrts.y, vrts[i+1].y, vrts[i+2].y, vrts[i+3].y};
float32x4_t vrts_z = {vrts.z, vrts[i+1].z, vrts[i+2].z, vrts[i+3].z};

/*f1_1 = m[0][0]*vrts[0];
f1_2 = m[0][0]*vrts[i+1][0];
f1_3 = m[0][0]*vrts[i+2][0];
f1_4 = m[0][0]*vrts[i+3][0];*/
f1 = vrts_x * m[0][0];

/*f2_1 = m[1][0]*vrts[0];
f2_2 = m[1][0]*vrts[i+1][0];
f2_3 = m[1][0]*vrts[i+2][0];
f2_4 = m[1][0]*vrts[i+3][0];*/
f2 = m[1][0] * vrts_x;

/*f3_1 = m[2][0]*vrts[0];
f3_2 = m[2][0]*vrts[i+1][0];
f3_3 = m[2][0]*vrts[i+2][0];
f3_4 = m[2][0]*vrts[i+3][0];*/
f3 = m[2][0] * vrts_x;

/*f1_1 += m[0][1]*vrts[1];
f1_2 += m[0][1]*vrts[i+1][1];
f1_3 += m[0][1]*vrts[i+2][1];
f1_4 += m[0][1]*vrts[i+3][1];*/
f1 += m[0][1] * vrts_y;

/*f2_1 += m[1][1]*vrts[1];
f2_2 += m[1][1]*vrts[i+1][1];
f2_3 += m[1][1]*vrts[i+2][1];
f2_4 += m[1][1]*vrts[i+3][1];*/
f2 += m[1][1] * vrts_y;

/*f3_1 += m[2][1]*vrts[1];
f3_2 += m[2][1]*vrts[i+1][1];
f3_3 += m[2][1]*vrts[i+2][1];
f3_4 += m[2][1]*vrts[i+3][1];*/
f3 += m[2][1] * vrts_y;


/*f1_1 += m[0][2]*vrts[2];
f1_2 += m[0][2]*vrts[i+1][2];
f1_3 += m[0][2]*vrts[i+2][2];
f1_4 += m[0][2]*vrts[i+3][2];*/
f1 += m[0][2] * vrts_z;

/*f2_1 += m[1][2]*vrts[2];
f2_2 += m[1][2]*vrts[i+1][2];
f2_3 += m[1][2]*vrts[i+2][2];
f2_4 += m[1][2]*vrts[i+3][2];*/
f2 += m[1][2] * vrts_z;

/*f3_1 += m[2][2]*vrts[2];
f3_2 += m[2][2]*vrts[i+1][2];
f3_3 += m[2][2]*vrts[i+2][2];
f3_4 += m[2][2]*vrts[i+3][2];*/
f3 += m[2][2] * vrts_z;

/*f1_1 += o[0];
f1_2 += o[0];
f1_3 += o[0];
f1_4 += o[0];*/
f1 += o[0];

/*f2_1 += o[1];
f2_2 += o[1];
f2_3 += o[1];
f2_4 += o[1];*/
f2 += o[1];

/*f3_1 += o[2];
f3_2 += o[2];
f3_3 += o[2];
f3_4 += o[2];*/
f3 += o[2];

/*d1 = f1_1*p_normal[0];
d2 = f1_2*p_normal[0];
d3 = f1_3*p_normal[0];
d4 = f1_4*p_normal[0];*/
d = f1 * p_normal[0];

/*d1 += f2_1*p_normal[1];
d2 += f2_2*p_normal[1];
d3 += f2_3*p_normal[1];
d4 += f2_4*p_normal[1];*/
d = f2 * p_normal[1];

/*d1 += f3_1*p_normal[2];
d2 += f3_2*p_normal[2];
d3 += f3_3*p_normal[2];
d4 += f3_4*p_normal[2];*/
d = f3 * p_normal[2];

if (i==0 || d[0] > r_max)
r_max=d[0];
if (i==0 || d[0] < r_min)
r_min=d[0];

if (i==0 || d[1] > r_max)
r_max=d[1];
if (i==0 || d[1] < r_min)
r_min=d[1];

if (i==0 || d[2] > r_max)
r_max=d[2];
if (i==0 || d[2] < r_min)
r_min=d[2];

if (i==0 || d[3] > r_max)
r_max=d[3];
if (i==0 || d[3] < r_min)
r_min=d[3];
}
for (i=i;i<vertex_count;i++) { // rest
/*_FORCE_INLINE_ Vector3 Transform::xform(const Vector3& p_vector) const {

return Vector3(
basis[0].dot(p_vector)+origin.x,
basis[1].dot(p_vector)+origin.y,
basis[2].dot(p_vector)+origin.z
);

}*/

float d;

Matrix3 m = p_transform.get_basis();
Vector3 o = p_transform.get_origin();

float f1, f2, f3;

f1 = m[0][0]*vrts[0];
f2 = m[1][0]*vrts[0];
f3 = m[2][0]*vrts[0];

f1 += m[0][1]*vrts[1];
f2 += m[1][1]*vrts[1];
f3 += m[2][1]*vrts[1];

f1 += m[0][2]*vrts[2];
f2 += m[1][2]*vrts[2];
f3 += m[2][2]*vrts[2];

f1 += o[0];
f2 += o[1];
f3 += o[2];

d = f1*p_normal[0];
d += f2*p_normal[1];
d += f3*p_normal[2];

if (i==0 || d > r_max)
r_max=d;
if (i==0 || d < r_min)
r_min=d;
}
#endif
}





edit: here also the compiler-switches that I can see in the shell:

-march=armv7-a -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard  -DNEON -O2 -ffast-math -fomit-frame-pointer

edit2: shortened version of the code:

Code:
#ifdef NEON
    #include <arm_neon.h>
#endif

...

void ConvexPolygonShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
	...
    #ifndef NEON
	for (int i=0;i<vertex_count;i++) {

		...
	}
    #else
    int i;
    for (i=0;i<vertex_count-4;i+=4) { // as long as 4 calculations at a time are possible
            
            Matrix3 m = p_transform.get_basis();
            Vector3 o = p_transform.get_origin();
            
            float32x4_t f1, f2, f3;
            float32x4_t d;
            float32x4_t vrts_x = {vrts[i].x, vrts[i+1].x, vrts[i+2].x, vrts[i+3].x};
            float32x4_t vrts_y = {vrts[i].y, vrts[i+1].y, vrts[i+2].y, vrts[i+3].y};
            float32x4_t vrts_z = {vrts[i].z, vrts[i+1].z, vrts[i+2].z, vrts[i+3].z};

            f1 = vrts_x * m[0][0];
            f2 = m[1][0] * vrts_x;
            f3 = m[2][0] * vrts_x;

            f1 += m[0][1] * vrts_y;
            f2 += m[1][1] * vrts_y;
            f3 += m[2][1] * vrts_y;

            f1 += m[0][2] * vrts_z;
            f2 += m[1][2] * vrts_z;
            f3 += m[2][2] * vrts_z;
            f1 += o[0];
            f2 += o[1];
            f3 += o[2];
            

            d = f1 * p_normal[0];
            d = f2 * p_normal[1];
            d = f3 * p_normal[2];
            
            ...
    }  
    for (i=i;i<vertex_count;i++) { 
           ...
    }    
    #endif
}
 
Last edited by a moderator:

ptitSeb

Serial Porter
Joined
Aug 15, 2012
Messages
8,979
Age
48
Location
France, near Lyon
g++ --version gives me "g++ (Sourcery CodeBench Lite 2011.09-70) 4.6.1"


also here the function I'm trying to optimize: (big wall of code ... will try to clean that up asap)

#ifdef NEON
#include <arm_neon.h>
#endif

...

void ConvexPolygonShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {


int vertex_count=mesh.vertices.size();
if (vertex_count==0)
return;

const Vector3 *vrts=&mesh.vertices[0];
#ifndef NEON
for (int i=0;i<vertex_count;i++) {

float d=p_normal.dot( p_transform.xform( vrts ) );

if (i==0 || d > r_max)
r_max=d;
if (i==0 || d < r_min)
r_min=d;
}
#else
int i;
for (i=0;i<vertex_count-4;i+=4) { // as long as 4 calculations at a time are possible
/*_FORCE_INLINE_ Vector3 Transform::xform(const Vector3& p_vector) const {

return Vector3(
basis[0].dot(p_vector)+origin.x,
basis[1].dot(p_vector)+origin.y,
basis[2].dot(p_vector)+origin.z
);

}*/
//float d1, d2, d3, d4;

Matrix3 m = p_transform.get_basis();
Vector3 o = p_transform.get_origin();

//float f1_1, f1_2, f1_3, f1_4, f2_1, f2_2, f2_3, f2_4, f3_1, f3_2, f3_3, f3_4;
float32x4_t f1, f2, f3;
float32x4_t d;
float32x4_t vrts_x = {vrts.x, vrts[i+1].x, vrts[i+2].x, vrts[i+3].x};
float32x4_t vrts_y = {vrts.y, vrts[i+1].y, vrts[i+2].y, vrts[i+3].y};
float32x4_t vrts_z = {vrts.z, vrts[i+1].z, vrts[i+2].z, vrts[i+3].z};

/*f1_1 = m[0][0]*vrts[0];
f1_2 = m[0][0]*vrts[i+1][0];
f1_3 = m[0][0]*vrts[i+2][0];
f1_4 = m[0][0]*vrts[i+3][0];*/
f1 = vrts_x * m[0][0];

/*f2_1 = m[1][0]*vrts[0];
f2_2 = m[1][0]*vrts[i+1][0];
f2_3 = m[1][0]*vrts[i+2][0];
f2_4 = m[1][0]*vrts[i+3][0];*/
f2 = m[1][0] * vrts_x;

/*f3_1 = m[2][0]*vrts[0];
f3_2 = m[2][0]*vrts[i+1][0];
f3_3 = m[2][0]*vrts[i+2][0];
f3_4 = m[2][0]*vrts[i+3][0];*/
f3 = m[2][0] * vrts_x;

/*f1_1 += m[0][1]*vrts[1];
f1_2 += m[0][1]*vrts[i+1][1];
f1_3 += m[0][1]*vrts[i+2][1];
f1_4 += m[0][1]*vrts[i+3][1];*/
f1 += m[0][1] * vrts_y;

/*f2_1 += m[1][1]*vrts[1];
f2_2 += m[1][1]*vrts[i+1][1];
f2_3 += m[1][1]*vrts[i+2][1];
f2_4 += m[1][1]*vrts[i+3][1];*/
f2 += m[1][1] * vrts_y;

/*f3_1 += m[2][1]*vrts[1];
f3_2 += m[2][1]*vrts[i+1][1];
f3_3 += m[2][1]*vrts[i+2][1];
f3_4 += m[2][1]*vrts[i+3][1];*/
f3 += m[2][1] * vrts_y;


/*f1_1 += m[0][2]*vrts[2];
f1_2 += m[0][2]*vrts[i+1][2];
f1_3 += m[0][2]*vrts[i+2][2];
f1_4 += m[0][2]*vrts[i+3][2];*/
f1 += m[0][2] * vrts_z;

/*f2_1 += m[1][2]*vrts[2];
f2_2 += m[1][2]*vrts[i+1][2];
f2_3 += m[1][2]*vrts[i+2][2];
f2_4 += m[1][2]*vrts[i+3][2];*/
f2 += m[1][2] * vrts_z;

/*f3_1 += m[2][2]*vrts[2];
f3_2 += m[2][2]*vrts[i+1][2];
f3_3 += m[2][2]*vrts[i+2][2];
f3_4 += m[2][2]*vrts[i+3][2];*/
f3 += m[2][2] * vrts_z;

/*f1_1 += o[0];
f1_2 += o[0];
f1_3 += o[0];
f1_4 += o[0];*/
f1 += o[0];

/*f2_1 += o[1];
f2_2 += o[1];
f2_3 += o[1];
f2_4 += o[1];*/
f2 += o[1];

/*f3_1 += o[2];
f3_2 += o[2];
f3_3 += o[2];
f3_4 += o[2];*/
f3 += o[2];

/*d1 = f1_1*p_normal[0];
d2 = f1_2*p_normal[0];
d3 = f1_3*p_normal[0];
d4 = f1_4*p_normal[0];*/
d = f1 * p_normal[0];

/*d1 += f2_1*p_normal[1];
d2 += f2_2*p_normal[1];
d3 += f2_3*p_normal[1];
d4 += f2_4*p_normal[1];*/
d = f2 * p_normal[1];

/*d1 += f3_1*p_normal[2];
d2 += f3_2*p_normal[2];
d3 += f3_3*p_normal[2];
d4 += f3_4*p_normal[2];*/
d = f3 * p_normal[2];

if (i==0 || d[0] > r_max)
r_max=d[0];
if (i==0 || d[0] < r_min)
r_min=d[0];

if (i==0 || d[1] > r_max)
r_max=d[1];
if (i==0 || d[1] < r_min)
r_min=d[1];

if (i==0 || d[2] > r_max)
r_max=d[2];
if (i==0 || d[2] < r_min)
r_min=d[2];

if (i==0 || d[3] > r_max)
r_max=d[3];
if (i==0 || d[3] < r_min)
r_min=d[3];
}
for (i=i;i<vertex_count;i++) { // rest
/*_FORCE_INLINE_ Vector3 Transform::xform(const Vector3& p_vector) const {

return Vector3(
basis[0].dot(p_vector)+origin.x,
basis[1].dot(p_vector)+origin.y,
basis[2].dot(p_vector)+origin.z
);

}*/

float d;

Matrix3 m = p_transform.get_basis();
Vector3 o = p_transform.get_origin();

float f1, f2, f3;

f1 = m[0][0]*vrts[0];
f2 = m[1][0]*vrts[0];
f3 = m[2][0]*vrts[0];

f1 += m[0][1]*vrts[1];
f2 += m[1][1]*vrts[1];
f3 += m[2][1]*vrts[1];

f1 += m[0][2]*vrts[2];
f2 += m[1][2]*vrts[2];
f3 += m[2][2]*vrts[2];

f1 += o[0];
f2 += o[1];
f3 += o[2];

d = f1*p_normal[0];
d += f2*p_normal[1];
d += f3*p_normal[2];

if (i==0 || d > r_max)
r_max=d;
if (i==0 || d < r_min)
r_min=d;
}
#endif
}






edit: here also the compiler-switches that I can see in the shell:

-march=armv7-a -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard  -DNEON -O2 -ffast-math -fomit-frame-pointer

for Pandora, -mfloat-abi is softfp.

Instead of trying to use scalar*float32x4_t, maybe try to use vmulq_n_f32(dest, source, scalar) ?
 

x1212

Member
Joined
Apr 1, 2013
Messages
134
Ah ok, I switched to hardfp after I got the first errors with those optimizations because of something I read on the wiki:

Therefore i recommend the following flags:


-O3 -mcpu=cortex-a8 -mfpu=neon -ftree-vectorize -mfloat-abi=(softfp|hard) -ffast-math -fsingle-precision-constant
where -mfloat-abi=hard for the CSL 2009q1 release and softfp for all the others.
Now I switched back to softfp the errors are still present, but changing


f1 = vrts_x * m[0][0];

to:


f1 = vmulq_n_f32(vrts_x, m[0][0]);

made the error dissapear for at least that line.

Thanks, I will change all those lines now to use these functions and see if that works (or if I broke everything).
 
Last edited by a moderator:

x1212

Member
Joined
Apr 1, 2013
Messages
134
Thanks, got it to work.
I didn't expect any wonders since that was just a single function used by the collisiondetection.
However it did:
 
 

https://www.youtube.com/embed/B71zu28GK24?feature=oembed
 
Looks like profiling on PC with gprof was a good idea :D
 
 
In case anyone is interested, here the final code: (I left that commented out code in there because it might help to understand what is going on)


Code:
void ConvexPolygonShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {


	int vertex_count=mesh.vertices.size();
	if (vertex_count==0)
		return;

	const Vector3 *vrts=&mesh.vertices[0];
    #ifndef NEON
	for (int i=0;i<vertex_count;i++) {

		float d=p_normal.dot( p_transform.xform( vrts[i] ) );

		if (i==0 || d > r_max)
			r_max=d;
		if (i==0 || d < r_min)
			r_min=d;
	}
    #else
    int i;
    Matrix3 m = p_transform.get_basis();
    Vector3 o = p_transform.get_origin();
    float32x4_t vo[4] = {{o[0],o[0],o[0],o[0]} , {o[1],o[1],o[1],o[1]} , {o[2],o[2],o[2],o[2]} , {o[3],o[3],o[3],o[3]}};
    for (i=0;i<vertex_count-4;i+=4) { // as long as 4 calculations at a time are possible
            /*_FORCE_INLINE_ Vector3 Transform::xform(const Vector3& p_vector) const {

            return Vector3(
                basis[0].dot(p_vector)+origin.x,
                basis[1].dot(p_vector)+origin.y,
                basis[2].dot(p_vector)+origin.z
            );
            
            }*/
            //print_line("yay");
            //float d1, d2, d3, d4;
            
            
            
            //float f1_1, f1_2, f1_3, f1_4, f2_1, f2_2, f2_3, f2_4, f3_1, f3_2, f3_3, f3_4;
            float32x4_t f1, f2, f3;
            float32x4_t d;
            float32x4_t vrts_x = {vrts[i].x, vrts[i+1].x, vrts[i+2].x, vrts[i+3].x};
            float32x4_t vrts_y = {vrts[i].y, vrts[i+1].y, vrts[i+2].y, vrts[i+3].y};
            float32x4_t vrts_z = {vrts[i].z, vrts[i+1].z, vrts[i+2].z, vrts[i+3].z};
            
            /*f1_1 = m[0][0]*vrts[i][0];
            f1_2 = m[0][0]*vrts[i+1][0];
            f1_3 = m[0][0]*vrts[i+2][0];
            f1_4 = m[0][0]*vrts[i+3][0];*/
            
            //f1 = vrts_x * m[0][0];
            f1 = vmulq_n_f32(vrts_x, m[0][0]);
            
            /*f2_1 = m[1][0]*vrts[i][0];
            f2_2 = m[1][0]*vrts[i+1][0];
            f2_3 = m[1][0]*vrts[i+2][0];
            f2_4 = m[1][0]*vrts[i+3][0];*/
            
            //f2 = m[1][0] * vrts_x;
            f2 = vmulq_n_f32(vrts_x, m[1][0]);
            
            /*f3_1 = m[2][0]*vrts[i][0];
            f3_2 = m[2][0]*vrts[i+1][0];
            f3_3 = m[2][0]*vrts[i+2][0];
            f3_4 = m[2][0]*vrts[i+3][0];*/
            
            //f3 = m[2][0] * vrts_x;
            f3 = vmulq_n_f32(vrts_x, m[2][0]);
            
            /*f1_1 += m[0][1]*vrts[i][1];
            f1_2 += m[0][1]*vrts[i+1][1];
            f1_3 += m[0][1]*vrts[i+2][1];
            f1_4 += m[0][1]*vrts[i+3][1];*/
            
            //f1 += m[0][1] * vrts_y;
            f1 += vmulq_n_f32(vrts_y, m[0][1]);
            
            /*f2_1 += m[1][1]*vrts[i][1];
            f2_2 += m[1][1]*vrts[i+1][1];
            f2_3 += m[1][1]*vrts[i+2][1];
            f2_4 += m[1][1]*vrts[i+3][1];*/
            
            //f2 += m[1][1] * vrts_y;
            f2 += vmulq_n_f32(vrts_y, m[1][1]);
            
            /*f3_1 += m[2][1]*vrts[i][1];
            f3_2 += m[2][1]*vrts[i+1][1];
            f3_3 += m[2][1]*vrts[i+2][1];
            f3_4 += m[2][1]*vrts[i+3][1];*/
            
            //f3 += m[2][1] * vrts_y;
            f3 += vmulq_n_f32(vrts_y, m[2][1]);
            
            
            /*f1_1 += m[0][2]*vrts[i][2];
            f1_2 += m[0][2]*vrts[i+1][2];
            f1_3 += m[0][2]*vrts[i+2][2];
            f1_4 += m[0][2]*vrts[i+3][2];*/
            
            //f1 += m[0][2] * vrts_z;
            f1 += vmulq_n_f32(vrts_z, m[0][2]);
            
            /*f2_1 += m[1][2]*vrts[i][2];
            f2_2 += m[1][2]*vrts[i+1][2];
            f2_3 += m[1][2]*vrts[i+2][2];
            f2_4 += m[1][2]*vrts[i+3][2];*/
            
            //f2 += m[1][2] * vrts_z;
            f2 += vmulq_n_f32(vrts_z, m[1][2]);
            
            /*f3_1 += m[2][2]*vrts[i][2];
            f3_2 += m[2][2]*vrts[i+1][2];
            f3_3 += m[2][2]*vrts[i+2][2];
            f3_4 += m[2][2]*vrts[i+3][2];*/
            
            //f3 += m[2][2] * vrts_z;
            f3 += vmulq_n_f32(vrts_z, m[2][2]);
            
            /*f1_1 += o[0];
            f1_2 += o[0];
            f1_3 += o[0];
            f1_4 += o[0];*/
            f1 += vo[0];
            
            /*f2_1 += o[1];
            f2_2 += o[1];
            f2_3 += o[1];
            f2_4 += o[1];*/
            f2 += vo[1];
            
            /*f3_1 += o[2];
            f3_2 += o[2];
            f3_3 += o[2];
            f3_4 += o[2];*/
            f3 += vo[2];
            
            /*d1 = f1_1*p_normal[0];
            d2 = f1_2*p_normal[0];
            d3 = f1_3*p_normal[0];
            d4 = f1_4*p_normal[0];*/
            d = vmulq_n_f32(f1 , p_normal[0]);
            
            /*d1 += f2_1*p_normal[1];
            d2 += f2_2*p_normal[1];
            d3 += f2_3*p_normal[1];
            d4 += f2_4*p_normal[1];*/
            d += vmulq_n_f32(f2 , p_normal[1]);
            
            /*d1 += f3_1*p_normal[2];
            d2 += f3_2*p_normal[2];
            d3 += f3_3*p_normal[2];
            d4 += f3_4*p_normal[2];*/
            d += vmulq_n_f32(f3 , p_normal[2]);
            
            float *fd = (float *)&d;
            if (i==0 || fd[0] > r_max)
                r_max=fd[0];
            if (i==0 || fd[0] < r_min)
                r_min=fd[0];
                
            if (i==0 || fd[1] > r_max)
                r_max=fd[1];
            if (i==0 || fd[1] < r_min)
                r_min=fd[1];
                
            if (i==0 || fd[2] > r_max)
                r_max=fd[2];
            if (i==0 || fd[2] < r_min)
                r_min=fd[2];
                
            if (i==0 || fd[3] > r_max)
                r_max=fd[3];
            if (i==0 || fd[3] < r_min)
                r_min=fd[3];
    }  
    for (i=i;i<vertex_count;i++) { // rest
            /*_FORCE_INLINE_ Vector3 Transform::xform(const Vector3& p_vector) const {

            return Vector3(
                basis[0].dot(p_vector)+origin.x,
                basis[1].dot(p_vector)+origin.y,
                basis[2].dot(p_vector)+origin.z
            );
            
            }*/
            
            float d;
            
            Matrix3 m = p_transform.get_basis();
            Vector3 o = p_transform.get_origin();
            
            float f1, f2, f3;
            
            f1 = m[0][0]*vrts[i][0];
            f2 = m[1][0]*vrts[i][0];
            f3 = m[2][0]*vrts[i][0];
            
            f1 += m[0][1]*vrts[i][1];
            f2 += m[1][1]*vrts[i][1];
            f3 += m[2][1]*vrts[i][1];
            
            f1 += m[0][2]*vrts[i][2];
            f2 += m[1][2]*vrts[i][2];
            f3 += m[2][2]*vrts[i][2];
            
            f1 += o[0];
            f2 += o[1];
            f3 += o[2];
            
            d = f1*p_normal[0];
            d += f2*p_normal[1];
            d += f3*p_normal[2];
            
            if (i==0 || d > r_max)
                r_max=d;
            if (i==0 || d < r_min)
                r_min=d;
    }    
    #endif
}
 

ptitSeb

Serial Porter
Joined
Aug 15, 2012
Messages
8,979
Age
48
Location
France, near Lyon
Thanks, got it to work.


I didn't expect any wonders since that was just a single function used by the collisiondetection.


However it did:


Looks like profiling on PC with gprof was a good idea :D


In case anyone is interested, here the final code: (I left that commented out code in there because it might help to understand what is going on)

void ConvexPolygonShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {


int vertex_count=mesh.vertices.size();
if (vertex_count==0)
return;

const Vector3 *vrts=&mesh.vertices[0];
#ifndef NEON
for (int i=0;i<vertex_count;i++) {

float d=p_normal.dot( p_transform.xform( vrts ) );

if (i==0 || d > r_max)
r_max=d;
if (i==0 || d < r_min)
r_min=d;
}
#else
int i;
Matrix3 m = p_transform.get_basis();
Vector3 o = p_transform.get_origin();
float32x4_t vo[4] = {{o[0],o[0],o[0],o[0]} , {o[1],o[1],o[1],o[1]} , {o[2],o[2],o[2],o[2]} , {o[3],o[3],o[3],o[3]}};
for (i=0;i<vertex_count-4;i+=4) { // as long as 4 calculations at a time are possible
/*_FORCE_INLINE_ Vector3 Transform::xform(const Vector3& p_vector) const {

return Vector3(
basis[0].dot(p_vector)+origin.x,
basis[1].dot(p_vector)+origin.y,
basis[2].dot(p_vector)+origin.z
);

}*/
//print_line("yay");
//float d1, d2, d3, d4;



//float f1_1, f1_2, f1_3, f1_4, f2_1, f2_2, f2_3, f2_4, f3_1, f3_2, f3_3, f3_4;
float32x4_t f1, f2, f3;
float32x4_t d;
float32x4_t vrts_x = {vrts.x, vrts[i+1].x, vrts[i+2].x, vrts[i+3].x};
float32x4_t vrts_y = {vrts.y, vrts[i+1].y, vrts[i+2].y, vrts[i+3].y};
float32x4_t vrts_z = {vrts.z, vrts[i+1].z, vrts[i+2].z, vrts[i+3].z};

/*f1_1 = m[0][0]*vrts[0];
f1_2 = m[0][0]*vrts[i+1][0];
f1_3 = m[0][0]*vrts[i+2][0];
f1_4 = m[0][0]*vrts[i+3][0];*/

//f1 = vrts_x * m[0][0];
f1 = vmulq_n_f32(vrts_x, m[0][0]);

/*f2_1 = m[1][0]*vrts[0];
f2_2 = m[1][0]*vrts[i+1][0];
f2_3 = m[1][0]*vrts[i+2][0];
f2_4 = m[1][0]*vrts[i+3][0];*/

//f2 = m[1][0] * vrts_x;
f2 = vmulq_n_f32(vrts_x, m[1][0]);

/*f3_1 = m[2][0]*vrts[0];
f3_2 = m[2][0]*vrts[i+1][0];
f3_3 = m[2][0]*vrts[i+2][0];
f3_4 = m[2][0]*vrts[i+3][0];*/

//f3 = m[2][0] * vrts_x;
f3 = vmulq_n_f32(vrts_x, m[2][0]);

/*f1_1 += m[0][1]*vrts[1];
f1_2 += m[0][1]*vrts[i+1][1];
f1_3 += m[0][1]*vrts[i+2][1];
f1_4 += m[0][1]*vrts[i+3][1];*/

//f1 += m[0][1] * vrts_y;
f1 += vmulq_n_f32(vrts_y, m[0][1]);

/*f2_1 += m[1][1]*vrts[1];
f2_2 += m[1][1]*vrts[i+1][1];
f2_3 += m[1][1]*vrts[i+2][1];
f2_4 += m[1][1]*vrts[i+3][1];*/

//f2 += m[1][1] * vrts_y;
f2 += vmulq_n_f32(vrts_y, m[1][1]);

/*f3_1 += m[2][1]*vrts[1];
f3_2 += m[2][1]*vrts[i+1][1];
f3_3 += m[2][1]*vrts[i+2][1];
f3_4 += m[2][1]*vrts[i+3][1];*/

//f3 += m[2][1] * vrts_y;
f3 += vmulq_n_f32(vrts_y, m[2][1]);


/*f1_1 += m[0][2]*vrts[2];
f1_2 += m[0][2]*vrts[i+1][2];
f1_3 += m[0][2]*vrts[i+2][2];
f1_4 += m[0][2]*vrts[i+3][2];*/

//f1 += m[0][2] * vrts_z;
f1 += vmulq_n_f32(vrts_z, m[0][2]);

/*f2_1 += m[1][2]*vrts[2];
f2_2 += m[1][2]*vrts[i+1][2];
f2_3 += m[1][2]*vrts[i+2][2];
f2_4 += m[1][2]*vrts[i+3][2];*/

//f2 += m[1][2] * vrts_z;
f2 += vmulq_n_f32(vrts_z, m[1][2]);

/*f3_1 += m[2][2]*vrts[2];
f3_2 += m[2][2]*vrts[i+1][2];
f3_3 += m[2][2]*vrts[i+2][2];
f3_4 += m[2][2]*vrts[i+3][2];*/

//f3 += m[2][2] * vrts_z;
f3 += vmulq_n_f32(vrts_z, m[2][2]);

/*f1_1 += o[0];
f1_2 += o[0];
f1_3 += o[0];
f1_4 += o[0];*/
f1 += vo[0];

/*f2_1 += o[1];
f2_2 += o[1];
f2_3 += o[1];
f2_4 += o[1];*/
f2 += vo[1];

/*f3_1 += o[2];
f3_2 += o[2];
f3_3 += o[2];
f3_4 += o[2];*/
f3 += vo[2];

/*d1 = f1_1*p_normal[0];
d2 = f1_2*p_normal[0];
d3 = f1_3*p_normal[0];
d4 = f1_4*p_normal[0];*/
d = vmulq_n_f32(f1 , p_normal[0]);

/*d1 += f2_1*p_normal[1];
d2 += f2_2*p_normal[1];
d3 += f2_3*p_normal[1];
d4 += f2_4*p_normal[1];*/
d += vmulq_n_f32(f2 , p_normal[1]);

/*d1 += f3_1*p_normal[2];
d2 += f3_2*p_normal[2];
d3 += f3_3*p_normal[2];
d4 += f3_4*p_normal[2];*/
d += vmulq_n_f32(f3 , p_normal[2]);

float *fd = (float *)&d;
if (i==0 || fd[0] > r_max)
r_max=fd[0];
if (i==0 || fd[0] < r_min)
r_min=fd[0];

if (i==0 || fd[1] > r_max)
r_max=fd[1];
if (i==0 || fd[1] < r_min)
r_min=fd[1];

if (i==0 || fd[2] > r_max)
r_max=fd[2];
if (i==0 || fd[2] < r_min)
r_min=fd[2];

if (i==0 || fd[3] > r_max)
r_max=fd[3];
if (i==0 || fd[3] < r_min)
r_min=fd[3];
}
for (i=i;i<vertex_count;i++) { // rest
/*_FORCE_INLINE_ Vector3 Transform::xform(const Vector3& p_vector) const {

return Vector3(
basis[0].dot(p_vector)+origin.x,
basis[1].dot(p_vector)+origin.y,
basis[2].dot(p_vector)+origin.z
);

}*/

float d;

Matrix3 m = p_transform.get_basis();
Vector3 o = p_transform.get_origin();

float f1, f2, f3;

f1 = m[0][0]*vrts[0];
f2 = m[1][0]*vrts[0];
f3 = m[2][0]*vrts[0];

f1 += m[0][1]*vrts[1];
f2 += m[1][1]*vrts[1];
f3 += m[2][1]*vrts[1];

f1 += m[0][2]*vrts[2];
f2 += m[1][2]*vrts[2];
f3 += m[2][2]*vrts[2];

f1 += o[0];
f2 += o[1];
f3 += o[2];

d = f1*p_normal[0];
d += f2*p_normal[1];
d += f3*p_normal[2];

if (i==0 || d > r_max)
r_max=d;
if (i==0 || d < r_min)
r_min=d;
}
#endif
}




Nice improvement.

You still have a few issue in your GLES2 port. It looks like some type in some geometry transform to me, like the "z" that is in fact "y" coordinates (so review your code, I think you have a [2] instead of [3], i.e. 2 times [2] somewhere in the geometry transformation).
 

x1212

Member
Joined
Apr 1, 2013
Messages
134
You still have a few issue in your GLES2 port. It looks like some type in some geometry transform to me, like the "z" that is in fact "y" coordinates (so review your code, I think you have a [2] instead of [3], i.e. 2 times [2] somewhere in the geometry transformation).
I was able to fix that with the last build, however I don't understand why ... I got pretty desperate and started changing highp variables within the vertexshader to mediump. Before doing so depending on the cameras and the objects z-axis-rotation one of the axis got a scaling by a value between 1 and 0 (0 at 90 and 270 degrees and 1 at 0 and 180 degrees). This only happened when there was a light (and in case of a pointlight it had to be of at least a certain size ...) within the scene ... this was a nightmare (and since I don't really under stand what the cause was it still is somehow)...
 

Hooka

That Guy!
Joined
Jul 19, 2003
Messages
1,746
Age
38
Location
Canada
Website
Visit site
Just figured I'd throw this down somewhere, and this seems like kinda the right place... the math-neon code, if you have issues with it returning weirdness from cos (or any of the functions), just make sure you modify the code to use the PROPER functions:

Make sure cosf_neon_hfp(float) returns


sinf_neon(xx)
not


sinf_neon_hfp(xx)
Otherwise problems will ensue, I'm sure other functions have small quirks like this, but figured seeing as it's one that I ran into I'd bring it to people's attention ;)

P.S. Feels like I'm digging around in a Cemetery looking @ these and the GP32x boards again...
 
Top