From 57153cf0f1fffe669b9d8871c33f9c4aaba67a2f Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Thu, 23 Dec 2010 01:48:44 -0800 Subject: SH-655 - Project mesh viewer crashes on exit. A copy constructor was implemented which did a memcpy, which included the vtable pointer which was to another object of another class (same child though). This resulted in the wrong destructor being called. The reason for the memcpy was for alignment purposes. The solution was to move to LLVector4a, which is intrinsicly aligned. Also, did some performance optimizations based on the LLVector4a optimizations. The solution was to re-implement the --- indra/llmath/llcamera.cpp | 171 ++++++++++++++++------------------------------ indra/llmath/llcamera.h | 11 +-- indra/llmath/llplane.h | 44 ++++++++++-- indra/llmath/llvector4a.h | 2 +- 4 files changed, 102 insertions(+), 126 deletions(-) (limited to 'indra/llmath') diff --git a/indra/llmath/llcamera.cpp b/indra/llmath/llcamera.cpp index a442a0edb8..a30a50ab2e 100644 --- a/indra/llmath/llcamera.cpp +++ b/indra/llmath/llcamera.cpp @@ -42,7 +42,6 @@ LLCamera::LLCamera() : mPlaneCount(6), mFrustumCornerDist(0.f) { - alignPlanes(); calculateFrustumPlanes(); } @@ -53,7 +52,6 @@ LLCamera::LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_p mPlaneCount(6), mFrustumCornerDist(0.f) { - alignPlanes(); mAspect = llclamp(aspect_ratio, MIN_ASPECT_RATIO, MAX_ASPECT_RATIO); mNearPlane = llclamp(near_plane, MIN_NEAR_PLANE, MAX_NEAR_PLANE); if(far_plane < 0) far_plane = DEFAULT_FAR_PLANE; @@ -67,19 +65,6 @@ LLCamera::~LLCamera() } -const LLCamera& LLCamera::operator=(const LLCamera& rhs) -{ - memcpy(this, &rhs, sizeof(LLCamera)); - alignPlanes(); - LLVector4a::memcpyNonAliased16((F32*) mAgentPlanes, (F32*) rhs.mAgentPlanes, 4*7*sizeof(F32)); - return *this; -} - -void LLCamera::alignPlanes() -{ - mAgentPlanes = (LLPlane*) LL_NEXT_ALIGNED_ADDRESS(mAgentPlaneBuffer); -} - // ---------------- LLCamera::getFoo() member functions ---------------- F32 LLCamera::getMinView() const @@ -104,7 +89,7 @@ void LLCamera::setUserClipPlane(LLPlane plane) { mPlaneCount = 7; mAgentPlanes[6] = plane; - mPlaneMask[6] = calcPlaneMask(plane); + mPlaneMask[6] = plane.calcPlaneMask(); } void LLCamera::disableUserClipPlane() @@ -190,38 +175,33 @@ S32 LLCamera::AABBInFrustum(const LLVector4a ¢er, const LLVector4a& radius) }; U8 mask = 0; - S32 result = 2; - + bool result = false; + LLVector4a rscale, maxp, minp; + LLSimdScalar d; for (U32 i = 0; i < mPlaneCount; i++) { mask = mPlaneMask[i]; - if (mask == 0xff) - { - continue; - } - - const LLPlane& p = mAgentPlanes[i]; - const LLVector4a& n = reinterpret_cast(p); - float d = p.mV[3]; - LLVector4a rscale; - rscale.setMul(radius, scaler[mask]); - - LLVector4a minp, maxp; - minp.setSub(center, rscale); - maxp.setAdd(center, rscale); - - if (n.dot3(minp) > -d) + if (mask != 0xff) { - return 0; - } - - if (n.dot3(maxp) > -d) - { - result = 1; + const LLPlane& p(mAgentPlanes[i]); + p.getAt<3>(d); + rscale.setMul(radius, scaler[mask]); + minp.setSub(center, rscale); + d = -d; + if (p.dot3(minp).getF32() > d) + { + return 0; + } + + if(!result) + { + maxp.setAdd(center, rscale); + result = (p.dot3(maxp).getF32() > d); + } } } - return result; + return result?1:2; } @@ -239,43 +219,33 @@ S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& }; U8 mask = 0; - S32 result = 2; - + bool result = false; + LLVector4a rscale, maxp, minp; + LLSimdScalar d; for (U32 i = 0; i < mPlaneCount; i++) { - if (i == 5) - { - continue; - } - mask = mPlaneMask[i]; - if (mask == 0xff) - { - continue; - } - - const LLPlane& p = mAgentPlanes[i]; - const LLVector4a& n = reinterpret_cast(p); - float d = p.mV[3]; - LLVector4a rscale; - rscale.setMul(radius, scaler[mask]); - - LLVector4a minp, maxp; - minp.setSub(center, rscale); - maxp.setAdd(center, rscale); - - if (n.dot3(minp) > -d) - { - return 0; - } - - if (n.dot3(maxp) > -d) + if ((i != 5) && (mask != 0xff)) { - result = 1; + const LLPlane& p(mAgentPlanes[i]); + p.getAt<3>(d); + rscale.setMul(radius, scaler[mask]); + minp.setSub(center, rscale); + d = -d; + if (p.dot3(minp).getF32() > d) + { + return 0; + } + + if(!result) + { + maxp.setAdd(center, rscale); + result = (p.dot3(maxp).getF32() > d); + } } } - return result; + return result?1:2; } int LLCamera::sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius) @@ -396,28 +366,22 @@ int LLCamera::sphereInFrustumOld(const LLVector3 &sphere_center, const F32 radiu int LLCamera::sphereInFrustum(const LLVector3 &sphere_center, const F32 radius) const { // Returns 1 if sphere is in frustum, 0 if not. - int res = 2; + bool res = false; for (int i = 0; i < 6; i++) { - if (mPlaneMask[i] == 0xff) - { - continue; - } - - float d = mAgentPlanes[i].dist(sphere_center); - - if (d > radius) + if (mPlaneMask[i] != 0xff) { - return 0; - } + float d = mAgentPlanes[i].dist(sphere_center); - if (d > -radius) - { - res = 1; + if (d > radius) + { + return 0; + } + res |= (d > -radius); } } - return res; + return res?1:2; } @@ -569,25 +533,6 @@ LLPlane planeFromPoints(LLVector3 p1, LLVector3 p2, LLVector3 p3) return LLPlane(p1, n); } -U8 LLCamera::calcPlaneMask(const LLPlane& plane) -{ - U8 mask = 0; - - if (plane.mV[0] >= 0) - { - mask |= 1; - } - if (plane.mV[1] >= 0) - { - mask |= 2; - } - if (plane.mV[2] >= 0) - { - mask |= 4; - } - - return mask; -} void LLCamera::ignoreAgentFrustumPlane(S32 idx) { @@ -597,13 +542,12 @@ void LLCamera::ignoreAgentFrustumPlane(S32 idx) } mPlaneMask[idx] = 0xff; - mAgentPlanes[idx].clearVec(); + mAgentPlanes[idx].clear(); } void LLCamera::calcAgentFrustumPlanes(LLVector3* frust) { - alignPlanes(); - + for (int i = 0; i < 8; i++) { mAgentFrustum[i] = frust[i]; @@ -636,7 +580,7 @@ void LLCamera::calcAgentFrustumPlanes(LLVector3* frust) //cache plane octant facing mask for use in AABBInFrustum for (U32 i = 0; i < mPlaneCount; i++) { - mPlaneMask[i] = calcPlaneMask(mAgentPlanes[i]); + mPlaneMask[i] = mAgentPlanes[i].calcPlaneMask(); } } @@ -689,9 +633,10 @@ void LLCamera::calculateWorldFrustumPlanes() F32 d; LLVector3 center = mOrigin - mXAxis*mNearPlane; mWorldPlanePos = center; + LLVector3 pnorm; for (int p=0; p<4; p++) { - LLVector3 pnorm = LLVector3(mLocalPlanes[p]); + mLocalPlanes[p].getVector3(pnorm); LLVector3 norm = rotateToAbsolute(pnorm); norm.normVec(); d = -(center * norm); @@ -701,13 +646,15 @@ void LLCamera::calculateWorldFrustumPlanes() LLVector3 zaxis(0, 0, 1.0f); F32 yaw = getYaw(); { - LLVector3 tnorm = LLVector3(mLocalPlanes[PLANE_LEFT]); + LLVector3 tnorm; + mLocalPlanes[PLANE_LEFT].getVector3(tnorm); tnorm.rotVec(yaw, zaxis); d = -(mOrigin * tnorm); mHorizPlanes[HORIZ_PLANE_LEFT] = LLPlane(tnorm, d); } { - LLVector3 tnorm = LLVector3(mLocalPlanes[PLANE_RIGHT]); + LLVector3 tnorm; + mLocalPlanes[PLANE_RIGHT].getVector3(tnorm); tnorm.rotVec(yaw, zaxis); d = -(mOrigin * tnorm); mHorizPlanes[HORIZ_PLANE_RIGHT] = LLPlane(tnorm, d); diff --git a/indra/llmath/llcamera.h b/indra/llmath/llcamera.h index e15bd7ad43..a346322e0e 100644 --- a/indra/llmath/llcamera.h +++ b/indra/llmath/llcamera.h @@ -79,8 +79,6 @@ public: { *this = rhs; } - - const LLCamera& operator=(const LLCamera& rhs); enum { PLANE_LEFT = 0, @@ -119,6 +117,9 @@ public: }; private: + LLPlane mAgentPlanes[7]; //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP + U8 mPlaneMask[8]; // 8 for alignment + F32 mView; // angle between top and bottom frustum planes in radians. F32 mAspect; // width/height S32 mViewHeightInPixels; // for ViewHeightInPixels() only @@ -132,10 +133,6 @@ private: LLPlane mWorldPlanes[PLANE_NUM]; LLPlane mHorizPlanes[HORIZ_PLANE_NUM]; - LLPlane* mAgentPlanes; //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP - U8 mAgentPlaneBuffer[sizeof(LLPlane)*8]; - U8 mPlaneMask[7]; - U32 mPlaneCount; //defaults to 6, if setUserClipPlane is called, uses user supplied clip plane in LLVector3 mWorldPlanePos; // Position of World Planes (may be offset from camera) @@ -149,11 +146,9 @@ public: LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_pixels, F32 near_plane, F32 far_plane); virtual ~LLCamera(); - void alignPlanes(); void setUserClipPlane(LLPlane plane); void disableUserClipPlane(); - U8 calcPlaneMask(const LLPlane& plane); virtual void setView(F32 vertical_fov_rads); void setViewHeightInPixels(S32 height); void setAspect(F32 new_aspect); diff --git a/indra/llmath/llplane.h b/indra/llmath/llplane.h index 443f3f46b9..a611894721 100644 --- a/indra/llmath/llplane.h +++ b/indra/llmath/llplane.h @@ -36,19 +36,23 @@ // The plane normal = [A, B, C] // The closest approach = D / sqrt(A*A + B*B + C*C) -class LLPlane : public LLVector4 +class LLPlane { public: + + // Constructors LLPlane() {}; // no default constructor LLPlane(const LLVector3 &p0, F32 d) { setVec(p0, d); } LLPlane(const LLVector3 &p0, const LLVector3 &n) { setVec(p0, n); } - void setVec(const LLVector3 &p0, F32 d) { LLVector4::setVec(p0[0], p0[1], p0[2], d); } - void setVec(const LLVector3 &p0, const LLVector3 &n) + inline void setVec(const LLVector3 &p0, F32 d) { mV.set(p0[0], p0[1], p0[2], d); } + + // Set + inline void setVec(const LLVector3 &p0, const LLVector3 &n) { F32 d = -(p0 * n); setVec(n, d); } - void setVec(const LLVector3 &p0, const LLVector3 &p1, const LLVector3 &p2) + inline void setVec(const LLVector3 &p0, const LLVector3 &p1, const LLVector3 &p2) { LLVector3 u, v, w; u = p1 - p0; @@ -58,8 +62,38 @@ public: F32 d = -(w * p0); setVec(w, d); } - LLPlane& operator=(const LLVector4& v2) { LLVector4::setVec(v2[0],v2[1],v2[2],v2[3]); return *this;} + + inline LLPlane& operator=(const LLVector4& v2) { mV.set(v2[0],v2[1],v2[2],v2[3]); return *this;} + + inline LLPlane& operator=(const LLVector4a& v2) { mV.set(v2[0],v2[1],v2[2],v2[3]); return *this;} + + inline void set(const LLPlane& p2) { mV = p2.mV; } + + // F32 dist(const LLVector3 &v2) const { return mV[0]*v2[0] + mV[1]*v2[1] + mV[2]*v2[2] + mV[3]; } + + inline LLSimdScalar dot3(const LLVector4a& b) const { return mV.dot3(b); } + + // Read-only access a single float in this vector. Do not use in proximity to any function call that manipulates + // the data at the whole vector level or you will incur a substantial penalty. Consider using the splat functions instead + inline F32 operator[](const S32 idx) const { return mV[idx]; } + + // preferable when index is known at compile time + template LL_FORCE_INLINE void getAt(LLSimdScalar& v) const { v = mV.getScalarAt(); } + + // reset the vector to 0, 0, 0, 1 + inline void clear() { mV.set(0, 0, 0, 1); } + + inline void getVector3(LLVector3& vec) const { vec.set(mV[0], mV[1], mV[2]); } + + // Retrieve the mask indicating which of the x, y, or z axis are greater or equal to zero. + inline U8 calcPlaneMask() + { + return mV.greaterEqual(LLVector4a::getZero()).getGatheredBits() & LLVector4Logical::MASK_XYZ; + } + +private: + LLVector4a mV; }; diff --git a/indra/llmath/llvector4a.h b/indra/llmath/llvector4a.h index 79022eade3..596082509d 100644 --- a/indra/llmath/llvector4a.h +++ b/indra/llmath/llvector4a.h @@ -67,7 +67,7 @@ public: extern const LLVector4a LL_V4A_ZERO; return LL_V4A_ZERO; } - + // Return a vector of all epsilon, where epsilon is a small float suitable for approximate equality checks static inline const LLVector4a& getEpsilon() { -- cgit v1.2.3