summaryrefslogtreecommitdiff
path: root/indra/newview/llvovolume.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llvovolume.cpp')
-rwxr-xr-x[-rw-r--r--]indra/newview/llvovolume.cpp1521
1 files changed, 1285 insertions, 236 deletions
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index a207d3e050..380d63c77b 100644..100755
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -30,12 +30,16 @@
#include "llvovolume.h"
+#include <sstream>
+
#include "llviewercontrol.h"
#include "lldir.h"
#include "llflexibleobject.h"
+#include "llfloatertools.h"
#include "llmaterialtable.h"
#include "llprimitive.h"
#include "llvolume.h"
+#include "llvolumeoctree.h"
#include "llvolumemgr.h"
#include "llvolumemessage.h"
#include "material_codes.h"
@@ -44,6 +48,7 @@
#include "object_flags.h"
#include "llagentconstants.h"
#include "lldrawable.h"
+#include "lldrawpoolavatar.h"
#include "lldrawpoolbump.h"
#include "llface.h"
#include "llspatialpartition.h"
@@ -51,18 +56,26 @@
#include "llflexibleobject.h"
#include "llsky.h"
#include "lltexturefetch.h"
+#include "llvector4a.h"
#include "llviewercamera.h"
#include "llviewertexturelist.h"
+#include "llviewerobjectlist.h"
#include "llviewerregion.h"
#include "llviewertextureanim.h"
#include "llworld.h"
#include "llselectmgr.h"
#include "pipeline.h"
#include "llsdutil.h"
+#include "llmatrix4a.h"
#include "llmediaentry.h"
#include "llmediadataclient.h"
+#include "llmeshrepository.h"
#include "llagent.h"
#include "llviewermediafocus.h"
+#include "lldatapacker.h"
+#include "llviewershadermgr.h"
+#include "llvoavatar.h"
+#include "llvocache.h"
const S32 MIN_QUIET_FRAMES_COALESCE = 30;
const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
@@ -77,11 +90,14 @@ F32 LLVOVolume::sLODFactor = 1.f;
F32 LLVOVolume::sLODSlopDistanceFactor = 0.5f; //Changing this to zero, effectively disables the LOD transition slop
F32 LLVOVolume::sDistanceFactor = 1.0f;
S32 LLVOVolume::sNumLODChanges = 0;
+S32 LLVOVolume::mRenderComplexity_last = 0;
+S32 LLVOVolume::mRenderComplexity_current = 0;
LLPointer<LLObjectMediaDataClient> LLVOVolume::sObjectMediaClient = NULL;
LLPointer<LLObjectMediaNavigateClient> LLVOVolume::sObjectMediaNavigateClient = NULL;
static LLFastTimer::DeclareTimer FTM_GEN_TRIANGLES("Generate Triangles");
static LLFastTimer::DeclareTimer FTM_GEN_VOLUME("Generate Volumes");
+static LLFastTimer::DeclareTimer FTM_VOLUME_TEXTURES("Volume Textures");
// Implementation class of LLMediaDataClientObject. See llmediadataclient.h
class LLMediaDataClientObjectImpl : public LLMediaDataClientObject
@@ -353,6 +369,7 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
//
// Unpack texture entry data
//
+
S32 result = unpackTEMessage(mesgsys, _PREHASH_ObjectData, block_num);
if (result & teDirtyBits)
{
@@ -690,18 +707,22 @@ BOOL LLVOVolume::isVisible() const
return FALSE ;
}
-void LLVOVolume::updateTextureVirtualSize()
+void LLVOVolume::updateTextureVirtualSize(bool forced)
{
+ LLFastTimer ftm(FTM_VOLUME_TEXTURES);
// Update the pixel area of all faces
- if(!isVisible())
+ if(!forced)
{
- return ;
- }
+ if(!isVisible())
+ {
+ return ;
+ }
- if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SIMPLE))
- {
- return;
+ if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SIMPLE))
+ {
+ return;
+ }
}
static LLCachedControl<bool> dont_load_textures(gSavedSettings,"TextureDisable");
@@ -725,7 +746,7 @@ void LLVOVolume::updateTextureVirtualSize()
const LLTextureEntry *te = face->getTextureEntry();
LLViewerTexture *imagep = face->getTexture();
if (!imagep || !te ||
- face->mExtents[0] == face->mExtents[1])
+ face->mExtents[0].equals3(face->mExtents[1]))
{
continue;
}
@@ -784,10 +805,12 @@ void LLVOVolume::updateTextureVirtualSize()
if (isSculpted())
{
LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
- LLUUID id = sculpt_params->getSculptTexture();
+ LLUUID id = sculpt_params->getSculptTexture();
updateSculptTexture();
+
+
if (mSculptTexture.notNull())
{
mSculptTexture->setBoostLevel(llmax((S32)mSculptTexture->getBoostLevel(),
@@ -828,6 +851,7 @@ void LLVOVolume::updateTextureVirtualSize()
mSculptTexture->getHeight(), mSculptTexture->getWidth()));
}
}
+
}
if (getLightTextureID().notNull())
@@ -843,18 +867,18 @@ void LLVOVolume::updateTextureVirtualSize()
*camera));
}
}
-
+
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
{
- setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
+ setDebugText(llformat("%.0f:%.0f", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize)));
}
else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
{
- setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
+ setDebugText(llformat("%.0f:%.0f", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize)));
}
else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA))
{
- setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
+ setDebugText(llformat("%.0f:%.0f", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize)));
}
if (mPixelArea == 0)
@@ -865,7 +889,8 @@ void LLVOVolume::updateTextureVirtualSize()
BOOL LLVOVolume::isActive() const
{
- return !mStatic || mTextureAnimp || (mVolumeImpl && mVolumeImpl->isActive());
+ return !mStatic || mTextureAnimp || (mVolumeImpl && mVolumeImpl->isActive()) ||
+ (mDrawable.notNull() && mDrawable->isActive());
}
BOOL LLVOVolume::setMaterial(const U8 material)
@@ -939,8 +964,31 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline)
return mDrawable;
}
-BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume)
+BOOL LLVOVolume::setVolume(const LLVolumeParams &params_in, const S32 detail, bool unique_volume)
{
+ LLVolumeParams volume_params = params_in;
+
+ S32 last_lod = mVolumep.notNull() ? LLVolumeLODGroup::getVolumeDetailFromScale(mVolumep->getDetail()) : -1;
+ S32 lod = mLOD;
+
+ BOOL is404 = FALSE;
+
+ if (isSculpted())
+ {
+ // if it's a mesh
+ if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
+ { //meshes might not have all LODs, get the force detail to best existing LOD
+ LLUUID mesh_id = volume_params.getSculptID();
+
+ lod = gMeshRepo.getActualMeshLOD(volume_params, lod);
+ if (lod == -1)
+ {
+ is404 = TRUE;
+ lod = 0;
+ }
+ }
+ }
+
// Check if we need to change implementations
bool is_flexible = (volume_params.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE);
if (is_flexible)
@@ -968,13 +1016,21 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail
}
}
- if ((LLPrimitive::setVolume(volume_params, mLOD, (mVolumeImpl && mVolumeImpl->isVolumeUnique()))) || mSculptChanged)
+ if (is404)
+ {
+ setIcon(LLViewerTextureManager::getFetchedTextureFromFile("icons/Inv_Mesh.png", TRUE, LLViewerTexture::BOOST_UI));
+ //render prim proxy when mesh loading attempts give up
+ volume_params.setSculptID(LLUUID::null, LL_SCULPT_TYPE_NONE);
+
+ }
+
+ if ((LLPrimitive::setVolume(volume_params, lod, (mVolumeImpl && mVolumeImpl->isVolumeUnique()))) || mSculptChanged)
{
mFaceMappingChanged = TRUE;
if (mVolumeImpl)
{
- mVolumeImpl->onSetVolume(volume_params, detail);
+ mVolumeImpl->onSetVolume(volume_params, mLOD);
}
updateSculptTexture();
@@ -982,15 +1038,33 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail
if (isSculpted())
{
updateSculptTexture();
-
- if (mSculptTexture.notNull())
+ // if it's a mesh
+ if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
{
- sculpt();
+ if (!getVolume()->isMeshAssetLoaded())
+ {
+ //load request not yet issued, request pipeline load this mesh
+ LLUUID asset_id = volume_params.getSculptID();
+ S32 available_lod = gMeshRepo.loadMesh(this, volume_params, lod, last_lod);
+ if (available_lod != lod)
+ {
+ LLPrimitive::setVolume(volume_params, available_lod);
+ }
+ }
+
+ }
+ else // otherwise is sculptie
+ {
+ if (mSculptTexture.notNull())
+ {
+ sculpt();
+ }
}
}
return TRUE;
}
+
return FALSE;
}
@@ -998,7 +1072,7 @@ void LLVOVolume::updateSculptTexture()
{
LLPointer<LLViewerFetchedTexture> old_sculpt = mSculptTexture;
- if (isSculpted())
+ if (isSculpted() && !isMesh())
{
LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
LLUUID id = sculpt_params->getSculptTexture();
@@ -1026,6 +1100,12 @@ void LLVOVolume::updateSculptTexture()
}
+void LLVOVolume::notifyMeshLoaded()
+{
+ mSculptChanged = TRUE;
+ gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
+}
+
// sculpt replaces generate() for sculpted surfaces
void LLVOVolume::sculpt()
{
@@ -1129,10 +1209,26 @@ BOOL LLVOVolume::calcLOD()
S32 cur_detail = 0;
- F32 radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length();
- F32 distance = mDrawable->mDistanceWRTCamera; //llmin(mDrawable->mDistanceWRTCamera, MAX_LOD_DISTANCE);
+ F32 radius;
+ F32 distance;
+
+ if (mDrawable->isState(LLDrawable::RIGGED))
+ {
+ LLVOAvatar* avatar = getAvatar();
+ distance = avatar->mDrawable->mDistanceWRTCamera;
+ radius = avatar->getBinRadius();
+ }
+ else
+ {
+ distance = mDrawable->mDistanceWRTCamera;
+ radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length();
+ }
+
+ //hold onto unmodified distance for debugging
+ //F32 debug_distance = distance;
+
distance *= sDistanceFactor;
-
+
F32 rampDist = LLVOVolume::sLODFactor * 2;
if (distance < rampDist)
@@ -1149,6 +1245,14 @@ BOOL LLVOVolume::calcLOD()
cur_detail = computeLODDetail(llround(distance, 0.01f),
llround(radius, 0.01f));
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LOD_INFO))
+ {
+ //setDebugText(llformat("%.2f:%.2f, %d", debug_distance, radius, cur_detail));
+
+ setDebugText(llformat("%d", mDrawable->getFace(0)->getTextureIndex()));
+ }
+
if (cur_detail != mLOD)
{
mAppAngle = llround((F32) atan2( mDrawable->getRadius(), mDrawable->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f);
@@ -1175,8 +1279,17 @@ BOOL LLVOVolume::updateLOD()
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE);
mLODChanged = TRUE;
}
+ else
+ {
+ F32 new_radius = getBinRadius();
+ F32 old_radius = mDrawable->getBinRadius();
+ if (new_radius < old_radius * 0.9f || new_radius > old_radius*1.1f)
+ {
+ gPipeline.markPartitionMove(mDrawable);
+ }
+ }
- lod_changed |= LLViewerObject::updateLOD();
+ lod_changed = lod_changed || LLViewerObject::updateLOD();
return lod_changed;
}
@@ -1212,6 +1325,11 @@ void LLVOVolume::updateFaceFlags()
for (S32 i = 0; i < getVolume()->getNumFaces(); i++)
{
LLFace *face = mDrawable->getFace(i);
+ if (!face)
+ {
+ return;
+ }
+
BOOL fullbright = getTE(i)->getFullbright();
face->clearState(LLFace::FULLBRIGHT | LLFace::HUD_RENDER | LLFace::LIGHT);
@@ -1291,14 +1409,28 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
{
BOOL res = TRUE;
- LLVector3 min,max;
+ LLVector4a min,max;
- BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION);
+ min.clear();
+ max.clear();
- for (S32 i = 0; i < getVolume()->getNumFaces(); i++)
+ BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED);
+
+// bool rigged = false;
+ LLVolume* volume = mRiggedVolume;
+ if (!volume)
+ {
+ volume = getVolume();
+ }
+
+ for (S32 i = 0; i < getVolume()->getNumVolumeFaces(); i++)
{
LLFace *face = mDrawable->getFace(i);
- res &= face->genVolumeBBoxes(*getVolume(), i,
+ if (!face)
+ {
+ continue;
+ }
+ res &= face->genVolumeBBoxes(*volume, i,
mRelativeXform, mRelativeXformInvTrans,
(mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global);
@@ -1311,17 +1443,8 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
}
else
{
- for (U32 i = 0; i < 3; i++)
- {
- if (face->mExtents[0].mV[i] < min.mV[i])
- {
- min.mV[i] = face->mExtents[0].mV[i];
- }
- if (face->mExtents[1].mV[i] > max.mV[i])
- {
- max.mV[i] = face->mExtents[1].mV[i];
- }
- }
+ min.setMin(min, face->mExtents[0]);
+ max.setMax(max, face->mExtents[1]);
}
}
}
@@ -1329,7 +1452,9 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
if (rebuild)
{
mDrawable->setSpatialExtents(min,max);
- mDrawable->setPositionGroup((min+max)*0.5f);
+ min.add(max);
+ min.mul(0.5f);
+ mDrawable->setPositionGroup(min);
}
updateRadius();
@@ -1356,7 +1481,21 @@ void LLVOVolume::updateRelativeXform()
LLDrawable* drawable = mDrawable;
- if (drawable->isActive())
+ if (drawable->isState(LLDrawable::RIGGED) && mRiggedVolume.notNull())
+ { //rigged volume (which is in agent space) is used for generating bounding boxes etc
+ //inverse of render matrix should go to partition space
+ mRelativeXform = getRenderMatrix();
+
+ F32* dst = (F32*) mRelativeXformInvTrans.mMatrix;
+ F32* src = (F32*) mRelativeXform.mMatrix;
+ dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2];
+ dst[3] = src[4]; dst[4] = src[5]; dst[5] = src[6];
+ dst[6] = src[8]; dst[7] = src[9]; dst[8] = src[10];
+
+ mRelativeXform.invert();
+ mRelativeXformInvTrans.transpose();
+ }
+ else if (drawable->isActive())
{
// setup relative transforms
LLQuaternion delta_rot;
@@ -1438,11 +1577,22 @@ void LLVOVolume::updateRelativeXform()
static LLFastTimer::DeclareTimer FTM_GEN_FLEX("Generate Flexies");
static LLFastTimer::DeclareTimer FTM_UPDATE_PRIMITIVES("Update Primitives");
+static LLFastTimer::DeclareTimer FTM_UPDATE_RIGGED_VOLUME("Update Rigged");
BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
{
LLFastTimer t(FTM_UPDATE_PRIMITIVES);
+ if (mDrawable->isState(LLDrawable::REBUILD_RIGGED))
+ {
+ {
+ LLFastTimer t(FTM_UPDATE_RIGGED_VOLUME);
+ updateRiggedVolume();
+ }
+ genBBoxes(FALSE);
+ mDrawable->clearState(LLDrawable::REBUILD_RIGGED);
+ }
+
if (mVolumeImpl != NULL)
{
BOOL res;
@@ -1510,15 +1660,31 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
compiled = TRUE;
sNumLODChanges += new_num_faces ;
+ if((S32)getNumTEs() != getVolume()->getNumFaces())
+ {
+ setNumTEs(getVolume()->getNumFaces()); //mesh loading may change number of faces.
+ }
+
drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles()
{
LLFastTimer t(FTM_GEN_TRIANGLES);
- if (new_num_faces != old_num_faces)
+ if (new_num_faces != old_num_faces || mNumFaces != (S32)getNumTEs())
{
regenFaces();
}
genBBoxes(FALSE);
+
+ if (mSculptChanged)
+ { //changes in sculpt maps can thrash an object bounding box without
+ //triggering a spatial group bounding box update -- force spatial group
+ //to update bounding boxes
+ LLSpatialGroup* group = mDrawable->getSpatialGroup();
+ if (group)
+ {
+ group->unbound();
+ }
+ }
}
}
}
@@ -1538,12 +1704,12 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
{
LLPipeline::sCompiles++;
}
-
+
mVolumeChanged = FALSE;
mLODChanged = FALSE;
mSculptChanged = FALSE;
mFaceMappingChanged = FALSE;
-
+
return LLViewerObject::updateGeometry(drawable);
}
@@ -1552,19 +1718,14 @@ void LLVOVolume::updateFaceSize(S32 idx)
LLFace* facep = mDrawable->getFace(idx);
if (idx >= getVolume()->getNumVolumeFaces())
{
- facep->setSize(0,0);
+ facep->setSize(0,0, true);
}
else
{
const LLVolumeFace& vol_face = getVolume()->getVolumeFace(idx);
- if (LLPipeline::sUseTriStrips)
- {
- facep->setSize(vol_face.mVertices.size(), vol_face.mTriStrip.size());
- }
- else
- {
- facep->setSize(vol_face.mVertices.size(), vol_face.mIndices.size());
- }
+ facep->setSize(vol_face.mNumVertices, vol_face.mNumIndices,
+ true); // <--- volume faces should be padded for 16-byte alignment
+
}
}
@@ -1819,21 +1980,25 @@ bool LLVOVolume::hasMedia() const
LLVector3 LLVOVolume::getApproximateFaceNormal(U8 face_id)
{
LLVolume* volume = getVolume();
- LLVector3 result;
+ LLVector4a result;
+ result.clear();
+
+ LLVector3 ret;
if (volume && face_id < volume->getNumVolumeFaces())
{
const LLVolumeFace& face = volume->getVolumeFace(face_id);
- for (S32 i = 0; i < (S32)face.mVertices.size(); ++i)
+ for (S32 i = 0; i < (S32)face.mNumVertices; ++i)
{
- result += face.mVertices[i].mNormal;
+ result.add(face.mNormals[i]);
}
- result = volumeDirectionToAgent(result);
- result.normVec();
+ LLVector3 ret(result.getF32ptr());
+ ret = volumeDirectionToAgent(ret);
+ ret.normVec();
}
- return result;
+ return ret;
}
void LLVOVolume::requestMediaDataUpdate(bool isNew)
@@ -2630,6 +2795,23 @@ BOOL LLVOVolume::isSculpted() const
return FALSE;
}
+BOOL LLVOVolume::isMesh() const
+{
+ if (isSculpted())
+ {
+ LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+ U8 sculpt_type = sculpt_params->getSculptType();
+
+ if ((sculpt_type & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
+ // mesh is a mesh
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
BOOL LLVOVolume::hasLightTexture() const
{
if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE))
@@ -2646,6 +2828,11 @@ BOOL LLVOVolume::isVolumeGlobal() const
{
return mVolumeImpl->isVolumeGlobal() ? TRUE : FALSE;
}
+ else if (mRiggedVolume.notNull())
+ {
+ return TRUE;
+ }
+
return FALSE;
}
@@ -2730,7 +2917,7 @@ void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_p
trans_mat.translate(getRegion()->getOriginAgent());
}
- volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, nodep->mSilhouetteSegments, view_vector, trans_mat, mRelativeXformInvTrans, nodep->getTESelectMask());
+ volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, view_vector, trans_mat, mRelativeXformInvTrans, nodep->getTESelectMask());
nodep->mSilhouetteExists = TRUE;
}
@@ -2787,24 +2974,38 @@ const LLMatrix4 LLVOVolume::getRenderMatrix() const
// total cost is returned value + 5 * size of the resulting set.
// Cannot include cost of textures, as they may be re-used in linked
// children, and cost should only be increased for unique textures -Nyx
-U32 LLVOVolume::getRenderCost(std::set<LLUUID> &textures) const
+U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const
{
- // base cost of each prim should be 10 points
- static const U32 ARC_PRIM_COST = 10;
+ // Get access to params we'll need at various points.
+ // Skip if this is object doesn't have a volume (e.g. is an avatar).
+ BOOL has_volume = (getVolume() != NULL);
+ LLVolumeParams volume_params;
+ LLPathParams path_params;
+ LLProfileParams profile_params;
+
+ U32 num_triangles = 0;
+
// per-prim costs
- static const U32 ARC_INVISI_COST = 1;
- static const U32 ARC_SHINY_COST = 1;
- static const U32 ARC_GLOW_COST = 1;
- static const U32 ARC_FLEXI_COST = 8;
- static const U32 ARC_PARTICLE_COST = 16;
- static const U32 ARC_BUMP_COST = 4;
+ static const U32 ARC_PARTICLE_COST = 1; // determined experimentally
+ static const U32 ARC_PARTICLE_MAX = 2048; // default values
+ static const U32 ARC_TEXTURE_COST = 16; // multiplier for texture resolution - performance tested
+ static const U32 ARC_LIGHT_COST = 500; // static cost for light-producing prims
+ static const U32 ARC_MEDIA_FACE_COST = 1500; // static cost per media-enabled face
- // per-face costs
- static const U32 ARC_PLANAR_COST = 1;
- static const U32 ARC_ANIM_TEX_COST = 4;
- static const U32 ARC_ALPHA_COST = 4;
- U32 shame = ARC_PRIM_COST;
+ // per-prim multipliers
+ static const F32 ARC_GLOW_MULT = 1.5f; // tested based on performance
+ static const F32 ARC_BUMP_MULT = 1.25f; // tested based on performance
+ static const F32 ARC_FLEXI_MULT = 5; // tested based on performance
+ static const F32 ARC_SHINY_MULT = 1.6f; // tested based on performance
+ static const F32 ARC_INVISI_COST = 1.2f; // tested based on performance
+ static const F32 ARC_WEIGHTED_MESH = 1.2f; // tested based on performance
+
+ static const F32 ARC_PLANAR_COST = 1.0f; // tested based on performance to have negligible impact
+ static const F32 ARC_ANIM_TEX_COST = 4.f; // tested based on performance
+ static const F32 ARC_ALPHA_COST = 4.f; // 4x max - based on performance
+
+ F32 shame = 0;
U32 invisi = 0;
U32 shiny = 0;
@@ -2813,9 +3014,72 @@ U32 LLVOVolume::getRenderCost(std::set<LLUUID> &textures) const
U32 flexi = 0;
U32 animtex = 0;
U32 particles = 0;
- U32 scale = 0;
U32 bump = 0;
U32 planar = 0;
+ U32 weighted_mesh = 0;
+ U32 produces_light = 0;
+ U32 media_faces = 0;
+
+ const LLDrawable* drawablep = mDrawable;
+ U32 num_faces = drawablep->getNumFaces();
+
+ if (has_volume)
+ {
+ volume_params = getVolume()->getParams();
+ path_params = volume_params.getPathParams();
+ profile_params = volume_params.getProfileParams();
+
+ F32 weighted_triangles = -1.0;
+ getStreamingCost(NULL, NULL, &weighted_triangles);
+
+ if (weighted_triangles > 0.0)
+ {
+ num_triangles = (U32)(weighted_triangles);
+ }
+ }
+
+ if (num_triangles == 0)
+ {
+ num_triangles = 4;
+ }
+
+ if (isSculpted())
+ {
+ if (isMesh())
+ {
+ // base cost is dependent on mesh complexity
+ // note that 3 is the highest LOD as of the time of this coding.
+ S32 size = gMeshRepo.getMeshSize(volume_params.getSculptID(),3);
+ if ( size > 0)
+ {
+ if (gMeshRepo.getSkinInfo(volume_params.getSculptID(), this))
+ {
+ // weighted attachment - 1 point for every 3 bytes
+ weighted_mesh = 1;
+ }
+
+ }
+ else
+ {
+ // something went wrong - user should know their content isn't render-free
+ return 0;
+ }
+ }
+ else
+ {
+ const LLSculptParams *sculpt_params = (LLSculptParams *) getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+ LLUUID sculpt_id = sculpt_params->getSculptTexture();
+ if (textures.find(sculpt_id) == textures.end())
+ {
+ LLViewerFetchedTexture *texture = LLViewerTextureManager::getFetchedTexture(sculpt_id);
+ if (texture)
+ {
+ S32 texture_cost = 256 + (S32)(ARC_TEXTURE_COST * (texture->getFullHeight() / 128.f + texture->getFullWidth() / 128.f));
+ textures.insert(texture_cost_t::value_type(sculpt_id, texture_cost));
+ }
+ }
+ }
+ }
if (isFlexible())
{
@@ -2826,19 +3090,12 @@ U32 LLVOVolume::getRenderCost(std::set<LLUUID> &textures) const
particles = 1;
}
- const LLVector3& sc = getScale();
- scale += (U32) sc.mV[0] + (U32) sc.mV[1] + (U32) sc.mV[2];
-
- const LLDrawable* drawablep = mDrawable;
-
- if (isSculpted())
+ if (getIsLight())
{
- const LLSculptParams *sculpt_params = (LLSculptParams *) getParameterEntry(LLNetworkData::PARAMS_SCULPT);
- LLUUID sculpt_id = sculpt_params->getSculptTexture();
- textures.insert(sculpt_id);
+ produces_light = 1;
}
- for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
+ for (S32 i = 0; i < num_faces; ++i)
{
const LLFace* face = drawablep->getFace(i);
const LLTextureEntry* te = face->getTextureEntry();
@@ -2846,74 +3103,209 @@ U32 LLVOVolume::getRenderCost(std::set<LLUUID> &textures) const
if (img)
{
- textures.insert(img->getID());
+ if (textures.find(img->getID()) == textures.end())
+ {
+ S32 texture_cost = 256 + (S32)(ARC_TEXTURE_COST * (img->getFullHeight() / 128.f + img->getFullWidth() / 128.f));
+ textures.insert(texture_cost_t::value_type(img->getID(), texture_cost));
+ }
}
if (face->getPoolType() == LLDrawPool::POOL_ALPHA)
{
- alpha++;
+ alpha = 1;
}
else if (img && img->getPrimaryFormat() == GL_ALPHA)
{
invisi = 1;
}
+ if (face->hasMedia())
+ {
+ media_faces++;
+ }
if (te)
{
if (te->getBumpmap())
{
+ // bump is a multiplier, don't add per-face
bump = 1;
}
if (te->getShiny())
{
+ // shiny is a multiplier, don't add per-face
shiny = 1;
}
if (te->getGlow() > 0.f)
{
+ // glow is a multiplier, don't add per-face
glow = 1;
}
if (face->mTextureMatrix != NULL)
{
- animtex++;
+ animtex = 1;
}
if (te->getTexGen())
{
- planar++;
+ planar = 1;
}
}
}
+ // shame currently has the "base" cost of 1 point per 15 triangles, min 2.
+ shame = num_triangles * 5.f;
+ shame = shame < 2.f ? 2.f : shame;
- shame += invisi * ARC_INVISI_COST;
- shame += shiny * ARC_SHINY_COST;
- shame += glow * ARC_GLOW_COST;
- shame += alpha * ARC_ALPHA_COST;
- shame += flexi * ARC_FLEXI_COST;
- shame += animtex * ARC_ANIM_TEX_COST;
- shame += particles * ARC_PARTICLE_COST;
- shame += bump * ARC_BUMP_COST;
- shame += planar * ARC_PLANAR_COST;
- shame += scale;
+ // multiply by per-face modifiers
+ if (planar)
+ {
+ shame *= planar * ARC_PLANAR_COST;
+ }
+
+ if (animtex)
+ {
+ shame *= animtex * ARC_ANIM_TEX_COST;
+ }
+
+ if (alpha)
+ {
+ shame *= alpha * ARC_ALPHA_COST;
+ }
+
+ if(invisi)
+ {
+ shame *= invisi * ARC_INVISI_COST;
+ }
+
+ if (glow)
+ {
+ shame *= glow * ARC_GLOW_MULT;
+ }
- LLViewerObject::const_child_list_t& child_list = getChildren();
- for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
- iter != child_list.end();
- ++iter)
+ if (bump)
{
- const LLViewerObject* child_objectp = *iter;
- const LLDrawable* child_drawablep = child_objectp->mDrawable;
- if (child_drawablep)
+ shame *= bump * ARC_BUMP_MULT;
+ }
+
+ if (shiny)
+ {
+ shame *= shiny * ARC_SHINY_MULT;
+ }
+
+
+ // multiply shame by multipliers
+ if (weighted_mesh)
+ {
+ shame *= weighted_mesh * ARC_WEIGHTED_MESH;
+ }
+
+ if (flexi)
+ {
+ shame *= flexi * ARC_FLEXI_MULT;
+ }
+
+
+ // add additional costs
+ if (particles)
+ {
+ const LLPartSysData *part_sys_data = &(mPartSourcep->mPartSysData);
+ const LLPartData *part_data = &(part_sys_data->mPartData);
+ U32 num_particles = (U32)(part_sys_data->mBurstPartCount * llceil( part_data->mMaxAge / part_sys_data->mBurstRate));
+ num_particles = num_particles > ARC_PARTICLE_MAX ? ARC_PARTICLE_MAX : num_particles;
+ F32 part_size = (llmax(part_data->mStartScale[0], part_data->mEndScale[0]) + llmax(part_data->mStartScale[1], part_data->mEndScale[1])) / 2.f;
+ shame += num_particles * part_size * ARC_PARTICLE_COST;
+ }
+
+ if (produces_light)
+ {
+ shame += ARC_LIGHT_COST;
+ }
+
+ if (media_faces)
+ {
+ shame += media_faces * ARC_MEDIA_FACE_COST;
+ }
+
+ if (shame > mRenderComplexity_current)
+ {
+ mRenderComplexity_current = (S32)shame;
+ }
+
+ return (U32)shame;
+}
+
+F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const
+{
+ F32 radius = getScale().length()*0.5f;
+
+ if (isMesh())
+ {
+ LLSD& header = gMeshRepo.getMeshHeader(getVolume()->getParams().getSculptID());
+
+ return LLMeshRepository::getStreamingCost(header, radius, bytes, visible_bytes, mLOD, unscaled_value);
+ }
+ else
+ {
+ LLVolume* volume = getVolume();
+ S32 counts[4];
+ LLVolume::getLoDTriangleCounts(volume->getParams(), counts);
+
+ LLSD header;
+ header["lowest_lod"]["size"] = counts[0] * 10;
+ header["low_lod"]["size"] = counts[1] * 10;
+ header["medium_lod"]["size"] = counts[2] * 10;
+ header["high_lod"]["size"] = counts[3] * 10;
+
+ return LLMeshRepository::getStreamingCost(header, radius, NULL, NULL, -1, unscaled_value);
+ }
+}
+
+//static
+void LLVOVolume::updateRenderComplexity()
+{
+ mRenderComplexity_last = mRenderComplexity_current;
+ mRenderComplexity_current = 0;
+}
+
+U32 LLVOVolume::getTriangleCount() const
+{
+ U32 count = 0;
+ LLVolume* volume = getVolume();
+ if (volume)
+ {
+ count = volume->getNumTriangles();
+ }
+
+ return count;
+}
+
+U32 LLVOVolume::getHighLODTriangleCount()
+{
+ U32 ret = 0;
+
+ LLVolume* volume = getVolume();
+
+ if (!isSculpted())
+ {
+ LLVolume* ref = LLPrimitive::getVolumeManager()->refVolume(volume->getParams(), 3);
+ ret = ref->getNumTriangles();
+ LLPrimitive::getVolumeManager()->unrefVolume(ref);
+ }
+ else if (isMesh())
+ {
+ LLVolume* ref = LLPrimitive::getVolumeManager()->refVolume(volume->getParams(), 3);
+ if (!ref->isMeshAssetLoaded() || ref->getNumVolumeFaces() == 0)
{
- const LLVOVolume* child_volumep = child_drawablep->getVOVolume();
- if (child_volumep)
- {
- shame += child_volumep->getRenderCost(textures);
- }
+ gMeshRepo.loadMesh(this, volume->getParams(), LLModel::LOD_HIGH);
}
+ ret = ref->getNumTriangles();
+ LLPrimitive::getVolumeManager()->unrefVolume(ref);
+ }
+ else
+ { //default sculpts have a constant number of triangles
+ ret = 31*2*31; //31 rows of 31 columns of quads for a 32x32 vertex patch
}
- return shame;
-
+ return ret;
}
//static
@@ -2953,7 +3345,7 @@ void LLVOVolume::setSelected(BOOL sel)
}
}
-void LLVOVolume::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax)
+void LLVOVolume::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
{
}
@@ -2961,7 +3353,13 @@ F32 LLVOVolume::getBinRadius()
{
F32 radius;
- const LLVector3* ext = mDrawable->getSpatialExtents();
+ F32 scale = 1.f;
+
+ S32 size_factor = llmax(gSavedSettings.getS32("OctreeStaticObjectSizeFactor"), 1);
+ S32 attachment_size_factor = llmax(gSavedSettings.getS32("OctreeAttachmentSizeFactor"), 1);
+ LLVector3 distance_factor = gSavedSettings.getVector3("OctreeDistanceFactor");
+ LLVector3 alpha_distance_factor = gSavedSettings.getVector3("OctreeAlphaDistanceFactor");
+ const LLVector4a* ext = mDrawable->getSpatialExtents();
BOOL shrink_wrap = mDrawable->isAnimating();
BOOL alpha_wrap = FALSE;
@@ -2990,34 +3388,34 @@ F32 LLVOVolume::getBinRadius()
radius = llmin(bounds.mV[1], bounds.mV[2]);
radius = llmin(radius, bounds.mV[0]);
radius *= 0.5f;
+ radius *= 1.f+mDrawable->mDistanceWRTCamera*alpha_distance_factor[1];
+ radius += mDrawable->mDistanceWRTCamera*alpha_distance_factor[0];
}
else if (shrink_wrap)
{
- radius = (ext[1]-ext[0]).length()*0.5f;
+ LLVector4a rad;
+ rad.setSub(ext[1], ext[0]);
+
+ radius = rad.getLength3().getF32()*0.5f;
}
else if (mDrawable->isStatic())
{
- /*if (mDrawable->getRadius() < 2.0f)
- {
- radius = 16.f;
- }
- else
- {
- radius = llmax(mDrawable->getRadius(), 32.f);
- }*/
-
- radius = (((S32) mDrawable->getRadius())/2+1)*8;
+ radius = llmax((S32) mDrawable->getRadius(), 1)*size_factor;
+ radius *= 1.f + mDrawable->mDistanceWRTCamera * distance_factor[1];
+ radius += mDrawable->mDistanceWRTCamera * distance_factor[0];
}
else if (mDrawable->getVObj()->isAttachment())
{
- radius = (((S32) (mDrawable->getRadius()*4)+1))*2;
+ radius = llmax((S32) mDrawable->getRadius(),1)*attachment_size_factor;
}
else
{
- radius = 8.f;
+ radius = mDrawable->getRadius();
+ radius *= 1.f + mDrawable->mDistanceWRTCamera * distance_factor[1];
+ radius += mDrawable->mDistanceWRTCamera * distance_factor[0];
}
- return llclamp(radius, 0.5f, 256.f);
+ return llclamp(radius*scale, 0.5f, 256.f);
}
const LLVector3 LLVOVolume::getPivotPositionAgent() const
@@ -3029,7 +3427,7 @@ const LLVector3 LLVOVolume::getPivotPositionAgent() const
return LLViewerObject::getPivotPositionAgent();
}
-void LLVOVolume::onShift(const LLVector3 &shift_vector)
+void LLVOVolume::onShift(const LLVector4a &shift_vector)
{
if (mVolumeImpl)
{
@@ -3106,12 +3504,38 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
BOOL ret = FALSE;
LLVolume* volume = getVolume();
+
+ bool transform = true;
+
+ if (mDrawable->isState(LLDrawable::RIGGED))
+ {
+ if (LLFloater::isVisible(gFloaterTools) && getAvatar()->isSelf())
+ {
+ updateRiggedVolume();
+ genBBoxes(FALSE);
+ volume = mRiggedVolume;
+ transform = false;
+ }
+ else
+ { //cannot pick rigged attachments on other avatars or when not in build mode
+ return FALSE;
+ }
+ }
+
if (volume)
{
LLVector3 v_start, v_end, v_dir;
- v_start = agentPositionToVolume(start);
- v_end = agentPositionToVolume(end);
+ if (transform)
+ {
+ v_start = agentPositionToVolume(start);
+ v_end = agentPositionToVolume(end);
+ }
+ else
+ {
+ v_start = start;
+ v_end = end;
+ }
LLVector3 p;
LLVector3 n;
@@ -3152,8 +3576,15 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
end_face = face+1;
}
+ bool special_cursor = specialHoverCursor();
for (S32 i = start_face; i < end_face; ++i)
{
+ if (!special_cursor && !pick_transparent && getTE(i) && getTE(i)->getColor().mV[3] == 0.f)
+ { //don't attempt to pick completely transparent faces unless
+ //pick_transparent is true
+ continue;
+ }
+
face_hit = volume->lineSegmentIntersect(v_start, v_end, i,
&p, &tc, &n, &bn);
@@ -3171,18 +3602,40 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
if (intersection != NULL)
{
- *intersection = volumePositionToAgent(p); // must map back to agent space
+ if (transform)
+ {
+ *intersection = volumePositionToAgent(p); // must map back to agent space
+ }
+ else
+ {
+ *intersection = p;
+ }
}
if (normal != NULL)
{
- *normal = volumeDirectionToAgent(n);
+ if (transform)
+ {
+ *normal = volumeDirectionToAgent(n);
+ }
+ else
+ {
+ *normal = n;
+ }
+
(*normal).normVec();
}
if (bi_normal != NULL)
{
- *bi_normal = volumeDirectionToAgent(bn);
+ if (transform)
+ {
+ *bi_normal = volumeDirectionToAgent(bn);
+ }
+ else
+ {
+ *bi_normal = bn;
+ }
(*bi_normal).normVec();
}
@@ -3200,6 +3653,201 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
return ret;
}
+bool LLVOVolume::treatAsRigged()
+{
+ return LLFloater::isVisible(gFloaterTools) &&
+ isAttachment() &&
+ getAvatar() &&
+ getAvatar()->isSelf() &&
+ mDrawable.notNull() &&
+ mDrawable->isState(LLDrawable::RIGGED);
+}
+
+LLRiggedVolume* LLVOVolume::getRiggedVolume()
+{
+ return mRiggedVolume;
+}
+
+void LLVOVolume::clearRiggedVolume()
+{
+ if (mRiggedVolume.notNull())
+ {
+ mRiggedVolume = NULL;
+ updateRelativeXform();
+ }
+}
+
+void LLVOVolume::updateRiggedVolume()
+{
+ //Update mRiggedVolume to match current animation frame of avatar.
+ //Also update position/size in octree.
+
+ if (!treatAsRigged())
+ {
+ clearRiggedVolume();
+
+ return;
+ }
+
+ LLVolume* volume = getVolume();
+
+ const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(volume->getParams().getSculptID(), this);
+
+ if (!skin)
+ {
+ clearRiggedVolume();
+ return;
+ }
+
+ LLVOAvatar* avatar = getAvatar();
+
+ if (!avatar)
+ {
+ clearRiggedVolume();
+ return;
+ }
+
+ if (!mRiggedVolume)
+ {
+ LLVolumeParams p;
+ mRiggedVolume = new LLRiggedVolume(p);
+ updateRelativeXform();
+ }
+
+ mRiggedVolume->update(skin, avatar, volume);
+
+}
+
+static LLFastTimer::DeclareTimer FTM_SKIN_RIGGED("Skin");
+static LLFastTimer::DeclareTimer FTM_RIGGED_OCTREE("Octree");
+
+void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* volume)
+{
+ bool copy = false;
+ if (volume->getNumVolumeFaces() != getNumVolumeFaces())
+ {
+ copy = true;
+ }
+
+ for (S32 i = 0; i < volume->getNumVolumeFaces() && !copy; ++i)
+ {
+ const LLVolumeFace& src_face = volume->getVolumeFace(i);
+ const LLVolumeFace& dst_face = getVolumeFace(i);
+
+ if (src_face.mNumIndices != dst_face.mNumIndices ||
+ src_face.mNumVertices != dst_face.mNumVertices)
+ {
+ copy = true;
+ }
+ }
+
+ if (copy)
+ {
+ copyVolumeFaces(volume);
+ }
+
+ //build matrix palette
+ LLMatrix4a mp[64];
+ LLMatrix4* mat = (LLMatrix4*) mp;
+
+ for (U32 j = 0; j < skin->mJointNames.size(); ++j)
+ {
+ LLJoint* joint = avatar->getJoint(skin->mJointNames[j]);
+ if (joint)
+ {
+ mat[j] = skin->mInvBindMatrix[j];
+ mat[j] *= joint->getWorldMatrix();
+ }
+ }
+
+ for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& vol_face = volume->getVolumeFace(i);
+
+ LLVolumeFace& dst_face = mVolumeFaces[i];
+
+ LLVector4a* weight = vol_face.mWeights;
+
+ LLMatrix4a bind_shape_matrix;
+ bind_shape_matrix.loadu(skin->mBindShapeMatrix);
+
+ LLVector4a* pos = dst_face.mPositions;
+
+ {
+ LLFastTimer t(FTM_SKIN_RIGGED);
+
+ for (U32 j = 0; j < dst_face.mNumVertices; ++j)
+ {
+ LLMatrix4a final_mat;
+ final_mat.clear();
+
+ S32 idx[4];
+
+ LLVector4 wght;
+
+ F32 scale = 0.f;
+ for (U32 k = 0; k < 4; k++)
+ {
+ F32 w = weight[j][k];
+
+ idx[k] = (S32) floorf(w);
+ wght[k] = w - floorf(w);
+ scale += wght[k];
+ }
+
+ wght *= 1.f/scale;
+
+ for (U32 k = 0; k < 4; k++)
+ {
+ F32 w = wght[k];
+
+ LLMatrix4a src;
+ src.setMul(mp[idx[k]], w);
+
+ final_mat.add(src);
+ }
+
+
+ LLVector4a& v = vol_face.mPositions[j];
+ LLVector4a t;
+ LLVector4a dst;
+ bind_shape_matrix.affineTransform(v, t);
+ final_mat.affineTransform(t, dst);
+ pos[j] = dst;
+ }
+
+ //update bounding box
+ LLVector4a& min = dst_face.mExtents[0];
+ LLVector4a& max = dst_face.mExtents[1];
+
+ min = pos[0];
+ max = pos[1];
+
+ for (U32 j = 1; j < dst_face.mNumVertices; ++j)
+ {
+ min.setMin(min, pos[j]);
+ max.setMax(max, pos[j]);
+ }
+
+ dst_face.mCenter->setAdd(dst_face.mExtents[0], dst_face.mExtents[1]);
+ dst_face.mCenter->mul(0.5f);
+
+ }
+
+ {
+ LLFastTimer t(FTM_RIGGED_OCTREE);
+ delete dst_face.mOctree;
+ dst_face.mOctree = NULL;
+
+ LLVector4a size;
+ size.setSub(dst_face.mExtents[1], dst_face.mExtents[0]);
+ size.splat(size.getLength3().getF32()*0.5f);
+
+ dst_face.createOctree(1.f);
+ }
+ }
+}
+
U32 LLVOVolume::getPartitionType() const
{
if (isHUDAttachment())
@@ -3234,6 +3882,26 @@ LLVolumeBridge::LLVolumeBridge(LLDrawable* drawablep)
mSlopRatio = 0.25f;
}
+bool can_batch_texture(LLFace* facep)
+{
+ if (facep->getTextureEntry()->getBumpmap())
+ { //bump maps aren't worked into texture batching yet
+ return false;
+ }
+
+ if (facep->getTexture() && facep->getTexture()->getPrimaryFormat() == GL_ALPHA)
+ { //can't batch invisiprims
+ return false;
+ }
+
+ if (facep->isState(LLFace::TEXTURE_ANIM) && facep->getVirtualSize() > MIN_TEX_ANIM_SIZE)
+ { //texture animation breaks batches
+ return false;
+ }
+
+ return true;
+}
+
void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type)
{
LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
@@ -3252,7 +3920,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
(type == LLRenderPass::PASS_INVISIBLE) ||
(type == LLRenderPass::PASS_ALPHA && facep->isState(LLFace::FULLBRIGHT));
- if (!fullbright && type != LLRenderPass::PASS_GLOW && !facep->mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL))
+ if (!fullbright && type != LLRenderPass::PASS_GLOW && !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_NORMAL))
{
llwarns << "Non fullbright face has no normals!" << llendl;
return;
@@ -3274,24 +3942,46 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
else
{
model_mat = &(drawable->getRegion()->mRenderMatrix);
+ if (model_mat->isIdentity())
+ {
+ model_mat = NULL;
+ }
}
-
U8 bump = (type == LLRenderPass::PASS_BUMP || type == LLRenderPass::PASS_POST_BUMP) ? facep->getTextureEntry()->getBumpmap() : 0;
LLViewerTexture* tex = facep->getTexture();
- U8 glow = (U8) (facep->getTextureEntry()->getGlow() * 255);
+ U8 index = facep->getTextureIndex();
+
+ bool batchable = false;
- if (facep->mVertexBuffer.isNull())
+ if (index < 255 && idx >= 0)
{
- llerrs << "WTF?" << llendl;
+ if (index < draw_vec[idx]->mTextureList.size())
+ {
+ if (draw_vec[idx]->mTextureList[index].isNull())
+ {
+ batchable = true;
+ draw_vec[idx]->mTextureList[index] = tex;
+ }
+ else if (draw_vec[idx]->mTextureList[index] == tex)
+ { //this face's texture index can be used with this batch
+ batchable = true;
+ }
+ }
+ else
+ { //texture list can be expanded to fit this texture index
+ batchable = true;
+ }
}
+
+ U8 glow = (U8) (facep->getTextureEntry()->getGlow() * 255);
if (idx >= 0 &&
- draw_vec[idx]->mVertexBuffer == facep->mVertexBuffer &&
+ draw_vec[idx]->mVertexBuffer == facep->getVertexBuffer() &&
draw_vec[idx]->mEnd == facep->getGeomIndex()-1 &&
- (LLPipeline::sTextureBindTest || draw_vec[idx]->mTexture == tex) &&
+ (LLPipeline::sTextureBindTest || draw_vec[idx]->mTexture == tex || batchable) &&
#if LL_DARWIN
draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange &&
draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange &&
@@ -3305,7 +3995,13 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
draw_vec[idx]->mCount += facep->getIndicesCount();
draw_vec[idx]->mEnd += facep->getGeomCount();
draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, facep->getVirtualSize());
- validate_draw_info(*draw_vec[idx]);
+
+ if (index >= draw_vec[idx]->mTextureList.size())
+ {
+ draw_vec[idx]->mTextureList.resize(index+1);
+ draw_vec[idx]->mTextureList[index] = tex;
+ }
+ draw_vec[idx]->validate();
update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[0]);
update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[1]);
}
@@ -3316,7 +4012,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
U32 offset = facep->getIndicesStart();
U32 count = facep->getIndicesCount();
LLPointer<LLDrawInfo> draw_info = new LLDrawInfo(start,end,count,offset, tex,
- facep->mVertexBuffer, fullbright, bump);
+ facep->getVertexBuffer(), fullbright, bump);
draw_info->mGroup = group;
draw_info->mVSize = facep->getVirtualSize();
draw_vec.push_back(draw_info);
@@ -3329,12 +4025,18 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
}
draw_info->mExtents[0] = facep->mExtents[0];
draw_info->mExtents[1] = facep->mExtents[1];
- validate_draw_info(*draw_info);
if (LLPipeline::sUseTriStrips)
{
draw_info->mDrawMode = LLRender::TRIANGLE_STRIP;
}
+
+ if (index < 255)
+ { //initialize texture list for texture batching
+ draw_info->mTextureList.resize(index+1);
+ draw_info->mTextureList[index] = tex;
+ }
+ draw_info->validate();
}
}
@@ -3346,6 +4048,32 @@ void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group)
static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume");
static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt");
+static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj)
+{
+ LLVOAvatar* avatar = vobj->getAvatar();
+
+ if (avatar)
+ {
+ LLDrawable* drawable = avatar->mDrawable;
+ if (drawable && drawable->getNumFaces() > 0)
+ {
+ LLFace* face = drawable->getFace(0);
+ if (face)
+ {
+ LLDrawPool* drawpool = face->getPool();
+ if (drawpool)
+ {
+ if (drawpool->getType() == LLDrawPool::POOL_AVATAR)
+ {
+ return (LLDrawPoolAvatar*) drawpool;
+ }
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
{
@@ -3384,8 +4112,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
std::vector<LLFace*> alpha_faces;
U32 useage = group->mSpatialPartition->mBufferUsage;
- U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcStride(group->mSpatialPartition->mVertexDataMask);
- U32 max_total = (gSavedSettings.getS32("RenderMaxNodeSize")*1024)/LLVertexBuffer::calcStride(group->mSpatialPartition->mVertexDataMask);
+ U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask);
+ U32 max_total = (gSavedSettings.getS32("RenderMaxNodeSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask);
max_vertices = llmin(max_vertices, (U32) 65535);
U32 cur_total = 0;
@@ -3406,29 +4134,211 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
LLVOVolume* vobj = drawablep->getVOVolume();
+
+ if (vobj->isMesh() &&
+ (vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded() || !gMeshRepo.meshRezEnabled()))
+ {
+ continue;
+ }
+
llassert_always(vobj);
- vobj->updateTextureVirtualSize();
+ vobj->updateTextureVirtualSize(true);
vobj->preRebuild();
drawablep->clearState(LLDrawable::HAS_ALPHA);
+ bool rigged = vobj->isAttachment() &&
+ vobj->isMesh() &&
+ gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj);
+
+ bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic();
+
+ bool is_rigged = false;
+
//for each face
for (S32 i = 0; i < drawablep->getNumFaces(); i++)
{
+ LLFace* facep = drawablep->getFace(i);
+
+ //ALWAYS null out vertex buffer on rebuild -- if the face lands in a render
+ // batch, it will recover its vertex buffer reference from the spatial group
+ facep->setVertexBuffer(NULL);
+
//sum up face verts and indices
drawablep->updateFaceSize(i);
- LLFace* facep = drawablep->getFace(i);
+
+
+
+ if (rigged)
+ {
+ if (!facep->isState(LLFace::RIGGED))
+ { //completely reset vertex buffer
+ facep->clearVertexBuffer();
+ }
+
+ facep->setState(LLFace::RIGGED);
+ is_rigged = true;
+
+ //get drawpool of avatar with rigged face
+ LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);
+
+ //Determine if we've received skininfo that contains an
+ //alternate bind matrix - if it does then apply the translational component
+ //to the joints of the avatar.
+ LLVOAvatar* pAvatarVO = vobj->getAvatar();
+ bool pelvisGotSet = false;
+
+ if ( pAvatarVO )
+ {
+ LLUUID currentId = vobj->getVolume()->getParams().getSculptID();
+ const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj );
+
+ if ( pSkinData )
+ {
+ const int bindCnt = pSkinData->mAlternateBindMatrix.size();
+ if ( bindCnt > 0 )
+ {
+ const int jointCnt = pSkinData->mJointNames.size();
+ const F32 pelvisZOffset = pSkinData->mPelvisOffset;
+ bool fullRig = (jointCnt>=20) ? true : false;
+ if ( fullRig )
+ {
+ for ( int i=0; i<jointCnt; ++i )
+ {
+ std::string lookingForJoint = pSkinData->mJointNames[i].c_str();
+ //llinfos<<"joint name "<<lookingForJoint.c_str()<<llendl;
+ LLJoint* pJoint = pAvatarVO->getJoint( lookingForJoint );
+ if ( pJoint && pJoint->getId() != currentId )
+ {
+ pJoint->setId( currentId );
+ const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation();
+ //Set the joint position
+ pJoint->storeCurrentXform( jointPos );
+ //If joint is a pelvis then handle old/new pelvis to foot values
+ if ( lookingForJoint == "mPelvis" )
+ {
+ pJoint->storeCurrentXform( jointPos );
+ if ( !pAvatarVO->hasPelvisOffset() )
+ {
+ pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset );
+ //Trigger to rebuild viewer AV
+ pelvisGotSet = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ //If we've set the pelvis to a new position we need to also rebuild some information that the
+ //viewer does at launch (e.g. body size etc.)
+ if ( pelvisGotSet )
+ {
+ pAvatarVO->postPelvisSetRecalc();
+ }
+
+ if (pool)
+ {
+ const LLTextureEntry* te = facep->getTextureEntry();
+
+ //remove face from old pool if it exists
+ LLDrawPool* old_pool = facep->getPool();
+ if (old_pool && old_pool->getType() == LLDrawPool::POOL_AVATAR)
+ {
+ ((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep);
+ }
+
+ //add face to new pool
+ LLViewerTexture* tex = facep->getTexture();
+ U32 type = gPipeline.getPoolTypeFromTE(te, tex);
+
+ if (type == LLDrawPool::POOL_ALPHA)
+ {
+ if (te->getFullbright())
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA);
+ }
+ else
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA);
+ }
+ }
+ else if (te->getShiny())
+ {
+ if (te->getFullbright())
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY);
+ }
+ else
+ {
+ if (LLPipeline::sRenderDeferred)
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
+ }
+ else
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY);
+ }
+ }
+ }
+ else
+ {
+ if (te->getFullbright())
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT);
+ }
+ else
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
+ }
+ }
+
+ if (te->getGlow())
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW);
+ }
+
+ if (LLPipeline::sRenderDeferred)
+ {
+ if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright())
+ {
+ if (te->getBumpmap())
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP);
+ }
+ else
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE);
+ }
+ }
+ }
+ }
+
+ continue;
+ }
+ else
+ {
+ if (facep->isState(LLFace::RIGGED))
+ { //face is not rigged but used to be, remove from rigged face pool
+ LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool();
+ if (pool)
+ {
+ pool->removeRiggedFace(facep);
+ }
+ facep->clearState(LLFace::RIGGED);
+ }
+ }
if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0)
{
- facep->mVertexBuffer = NULL;
- facep->mLastVertexBuffer = NULL;
+ facep->clearVertexBuffer();
continue;
}
cur_total += facep->getGeomCount();
- if (facep->hasGeometry() && facep->mPixelArea > FORCE_CULL_AREA)
+ if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA)
{
const LLTextureEntry* te = facep->getTextureEntry();
LLViewerTexture* tex = facep->getTexture();
@@ -3441,7 +4351,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
}
- BOOL force_simple = (facep->mPixelArea < FORCE_SIMPLE_RENDER_AREA);
+ BOOL force_simple = (facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA);
U32 type = gPipeline.getPoolTypeFromTE(te, tex);
if (type != LLDrawPool::POOL_ALPHA && force_simple)
{
@@ -3513,7 +4423,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
bump_faces.push_back(facep);
}
else if ((te->getShiny() && LLPipeline::sRenderBump) ||
- !te->getFullbright())
+ !(te->getFullbright() || bake_sunlight))
{ //needs normal
simple_faces.push_back(facep);
}
@@ -3527,10 +4437,18 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
else
{ //face has no renderable geometry
- facep->mVertexBuffer = NULL;
- facep->mLastVertexBuffer = NULL;
+ facep->clearVertexBuffer();
}
}
+
+ if (is_rigged)
+ {
+ drawablep->setState(LLDrawable::RIGGED);
+ }
+ else
+ {
+ drawablep->clearState(LLDrawable::RIGGED);
+ }
}
group->mBufferUsage = useage;
@@ -3541,15 +4459,24 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
U32 bump_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR;
U32 fullbright_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR;
- if (LLPipeline::sRenderDeferred)
+ bool batch_textures = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 1;
+
+ if (batch_textures)
{
bump_mask |= LLVertexBuffer::MAP_BINORMAL;
+ genDrawInfo(group, simple_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, simple_faces, FALSE, TRUE);
+ genDrawInfo(group, fullbright_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, fullbright_faces, FALSE, TRUE);
+ genDrawInfo(group, bump_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, bump_faces, FALSE, TRUE);
+ genDrawInfo(group, alpha_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, alpha_faces, TRUE, TRUE);
}
-
- genDrawInfo(group, simple_mask, simple_faces);
- genDrawInfo(group, bump_mask, bump_faces);
- genDrawInfo(group, fullbright_mask, fullbright_faces);
- genDrawInfo(group, alpha_mask, alpha_faces, TRUE);
+ else
+ {
+ genDrawInfo(group, simple_mask, simple_faces);
+ genDrawInfo(group, fullbright_mask, fullbright_faces);
+ genDrawInfo(group, bump_mask, bump_faces, FALSE, TRUE);
+ genDrawInfo(group, alpha_mask, alpha_faces, TRUE);
+ }
+
if (!LLPipeline::sDelayVBUpdate)
{
@@ -3586,53 +4513,47 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
group->mBuilt = 1.f;
+ std::set<LLVertexBuffer*> mapped_buffers;
+
for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
{
LLFastTimer t(FTM_VOLUME_GEOM_PARTIAL);
LLDrawable* drawablep = *drawable_iter;
- if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) )
- {
- continue;
- }
-
- if (drawablep->isState(LLDrawable::REBUILD_ALL))
+ if (!drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) )
{
LLVOVolume* vobj = drawablep->getVOVolume();
vobj->preRebuild();
+
LLVolume* volume = vobj->getVolume();
for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
{
LLFace* face = drawablep->getFace(i);
- if (face && face->mVertexBuffer.notNull())
+ if (face)
{
- face->getGeometryVolume(*volume, face->getTEOffset(),
- vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex());
+ LLVertexBuffer* buff = face->getVertexBuffer();
+ if (buff)
+ {
+ face->getGeometryVolume(*volume, face->getTEOffset(),
+ vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex());
+
+ if (buff->isLocked())
+ {
+ mapped_buffers.insert(buff);
+ }
+ }
}
}
-
+
drawablep->clearState(LLDrawable::REBUILD_ALL);
}
}
- //unmap all the buffers
- for (LLSpatialGroup::buffer_map_t::iterator i = group->mBufferMap.begin(); i != group->mBufferMap.end(); ++i)
+ for (std::set<LLVertexBuffer*>::iterator iter = mapped_buffers.begin(); iter != mapped_buffers.end(); ++iter)
{
- LLSpatialGroup::buffer_texture_map_t& map = i->second;
- for (LLSpatialGroup::buffer_texture_map_t::iterator j = map.begin(); j != map.end(); ++j)
- {
- LLSpatialGroup::buffer_list_t& list = j->second;
- for (LLSpatialGroup::buffer_list_t::iterator k = list.begin(); k != list.end(); ++k)
- {
- LLVertexBuffer* buffer = *k;
- if (buffer->isLocked())
- {
- buffer->setBuffer(0);
- }
- }
- }
+ (*iter)->setBuffer(0);
}
-
+
// don't forget alpha
if(group != NULL &&
!group->mVertexBuffer.isNull() &&
@@ -3651,9 +4572,10 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
{
LLFace* face = drawablep->getFace(i);
- if (face && face->mVertexBuffer.notNull() && face->mVertexBuffer->isLocked())
+ LLVertexBuffer* buff = face->getVertexBuffer();
+ if (face && buff && buff->isLocked())
{
- face->mVertexBuffer->setBuffer(0) ;
+ buff->setBuffer(0) ;
}
}
}
@@ -3662,22 +4584,46 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
group->clearState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO);
}
- if (group && group->isState(LLSpatialGroup::NEW_DRAWINFO))
+ llassert(!group || !group->isState(LLSpatialGroup::NEW_DRAWINFO));
+}
+
+struct CompareBatchBreakerModified
+{
+ bool operator()(const LLFace* const& lhs, const LLFace* const& rhs)
{
- llerrs << "WTF?" << llendl;
+ const LLTextureEntry* lte = lhs->getTextureEntry();
+ const LLTextureEntry* rte = rhs->getTextureEntry();
+
+ if (lte->getBumpmap() != rte->getBumpmap())
+ {
+ return lte->getBumpmap() < rte->getBumpmap();
+ }
+ else if (lte->getFullbright() != rte->getFullbright())
+ {
+ return lte->getFullbright() < rte->getFullbright();
+ }
+ else if (lte->getGlow() != rte->getGlow())
+ {
+ return lte->getGlow() < rte->getGlow();
+ }
+ else
+ {
+ return lhs->getTexture() < rhs->getTexture();
+ }
+
}
-}
+};
-void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort)
+void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort, BOOL batch_textures)
{
//calculate maximum number of vertices to store in a single buffer
- U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcStride(group->mSpatialPartition->mVertexDataMask);
+ U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask);
max_vertices = llmin(max_vertices, (U32) 65535);
if (!distance_sort)
{
//sort faces by things that break batches
- std::sort(faces.begin(), faces.end(), LLFace::CompareBatchBreaker());
+ std::sort(faces.begin(), faces.end(), CompareBatchBreakerModified());
}
else
{
@@ -3685,6 +4631,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
std::sort(faces.begin(), faces.end(), LLFace::CompareDistanceGreater());
}
+ bool hud_group = group->isHUDGroup() ;
std::vector<LLFace*>::iterator face_iter = faces.begin();
LLSpatialGroup::buffer_map_t buffer_map;
@@ -3697,6 +4644,21 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
buffer_index = -1;
}
+ S32 texture_index_channels = gGLManager.mNumTextureImageUnits-1; //always reserve one for shiny for now just for simplicity
+
+ if (gGLManager.mGLVersion < 3.1f)
+ {
+ texture_index_channels = 1;
+ }
+
+ if (LLPipeline::sRenderDeferred && distance_sort)
+ {
+ texture_index_channels = gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels;
+ }
+
+ texture_index_channels = llmin(texture_index_channels, (S32) gSavedSettings.getU32("RenderMaxTextureIndex"));
+
+
while (face_iter != faces.end())
{
//pull off next face
@@ -3718,31 +4680,110 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
buffer_index = 0;
}
+ bool bake_sunlight = LLPipeline::sBakeSunlight && facep->getDrawable()->isStatic();
+
U32 index_count = facep->getIndicesCount();
U32 geom_count = facep->getGeomCount();
- //sum up vertices needed for this texture
+ //sum up vertices needed for this render batch
std::vector<LLFace*>::iterator i = face_iter;
++i;
- while (i != faces.end() &&
- (LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex)))
+ std::vector<LLViewerTexture*> texture_list;
+
+ if (batch_textures)
{
- facep = *i;
-
- if (geom_count + facep->getGeomCount() > max_vertices)
- { //cut vertex buffers on geom count too big
- break;
+ U8 cur_tex = 0;
+ facep->setTextureIndex(cur_tex);
+ texture_list.push_back(tex);
+
+ //if (can_batch_texture(facep))
+ {
+ while (i != faces.end())
+ {
+ facep = *i;
+ if (facep->getTexture() != tex)
+ {
+ if (distance_sort)
+ { //textures might be out of order, see if texture exists in current batch
+ bool found = false;
+ for (U32 tex_idx = 0; tex_idx < texture_list.size(); ++tex_idx)
+ {
+ if (facep->getTexture() == texture_list[tex_idx])
+ {
+ cur_tex = tex_idx;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ cur_tex = texture_list.size();
+ }
+ }
+ else
+ {
+ cur_tex++;
+ }
+
+ if (!can_batch_texture(facep))
+ { //face is bump mapped or has an animated texture matrix -- can't
+ //batch more than 1 texture at a time
+ break;
+ }
+
+ if (cur_tex >= texture_index_channels)
+ { //cut batches when index channels are depleted
+ break;
+ }
+
+ tex = facep->getTexture();
+
+ texture_list.push_back(tex);
+ }
+
+ if (geom_count + facep->getGeomCount() > max_vertices)
+ { //cut batches on geom count too big
+ break;
+ }
+
+ ++i;
+ index_count += facep->getIndicesCount();
+ geom_count += facep->getGeomCount();
+
+ facep->setTextureIndex(cur_tex);
+ }
}
- ++i;
- index_count += facep->getIndicesCount();
- geom_count += facep->getGeomCount();
+ tex = texture_list[0];
+ }
+ else
+ {
+ while (i != faces.end() &&
+ (LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex)))
+ {
+ facep = *i;
+
+
+ //face has no texture index
+ facep->mDrawInfo = NULL;
+ facep->setTextureIndex(255);
+
+ if (geom_count + facep->getGeomCount() > max_vertices)
+ { //cut batches on geom count too big
+ break;
+ }
+
+ ++i;
+ index_count += facep->getIndicesCount();
+ geom_count += facep->getGeomCount();
+ }
}
//create/delete/resize vertex buffer if needed
LLVertexBuffer* buffer = NULL;
- LLSpatialGroup::buffer_texture_map_t::iterator found_iter = group->mBufferMap[mask].find(tex);
+ LLSpatialGroup::buffer_texture_map_t::iterator found_iter = group->mBufferMap[mask].find(*face_iter);
if (found_iter != group->mBufferMap[mask].end())
{
@@ -3759,10 +4800,11 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
buffer->allocateBuffer(geom_count, index_count, TRUE);
}
else
- {
- if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != group->mBufferUsage)
+ { //resize pre-existing buffer
+ if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != group->mBufferUsage ||
+ buffer->getTypeMask() != mask)
{
- buffer = createVertexBuffer(group->mSpatialPartition->mVertexDataMask,
+ buffer = createVertexBuffer(mask,
group->mBufferUsage);
buffer->allocateBuffer(geom_count, index_count, TRUE);
}
@@ -3772,7 +4814,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
}
}
- buffer_map[mask][tex].push_back(buffer);
+ buffer_map[mask][*face_iter].push_back(buffer);
//add face geometry
@@ -3780,34 +4822,41 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
U16 index_offset = 0;
while (face_iter < i)
- {
+ { //update face indices for new buffer
facep = *face_iter;
- facep->mIndicesIndex = indices_index;
- facep->mGeomIndex = index_offset;
- facep->mVertexBuffer = buffer;
+ facep->setIndicesIndex(indices_index);
+ facep->setGeomIndex(index_offset);
+ facep->setVertexBuffer(buffer);
+
+ if (batch_textures && facep->getTextureIndex() == 255)
{
+ llerrs << "Invalid texture index." << llendl;
+ }
+
+ {
+ //for debugging, set last time face was updated vs moved
facep->updateRebuildFlags();
+
if (!LLPipeline::sDelayVBUpdate)
- {
+ { //copy face geometry into vertex buffer
LLDrawable* drawablep = facep->getDrawable();
LLVOVolume* vobj = drawablep->getVOVolume();
LLVolume* volume = vobj->getVolume();
U32 te_idx = facep->getTEOffset();
- if (facep->getGeometryVolume(*volume, te_idx,
- vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset))
- {
- buffer->markDirty(facep->getGeomIndex(), facep->getGeomCount(),
- facep->getIndicesStart(), facep->getIndicesCount());
- }
+ facep->getGeometryVolume(*volume, te_idx,
+ vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset);
}
}
index_offset += facep->getGeomCount();
- indices_index += facep->mIndicesCount;
+ indices_index += facep->getIndicesCount();
+
+
+ //append face to appropriate render batch
- BOOL force_simple = facep->mPixelArea < FORCE_SIMPLE_RENDER_AREA;
+ BOOL force_simple = facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA;
BOOL fullbright = facep->isState(LLFace::FULLBRIGHT);
if ((mask & LLVertexBuffer::MAP_NORMAL) == 0)
{ //paranoia check to make sure GL doesn't try to read non-existant normals
@@ -3815,6 +4864,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
}
const LLTextureEntry* te = facep->getTextureEntry();
+ tex = facep->getTexture();
BOOL is_alpha = (facep->getPoolType() == LLDrawPool::POOL_ALPHA) ? TRUE : FALSE;
@@ -3823,7 +4873,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
// can we safely treat this as an alpha mask?
if (facep->canRenderAsMask())
{
- if (te->getFullbright())
+ if (te->getFullbright() || LLPipeline::sNoAlpha)
{
registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK);
}
@@ -3852,7 +4902,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
registerFace(group, facep, LLRenderPass::PASS_INVISI_SHINY);
registerFace(group, facep, LLRenderPass::PASS_INVISIBLE);
}
- else if (LLPipeline::sRenderDeferred)
+ else if (LLPipeline::sRenderDeferred && !hud_group)
{ //deferred rendering
if (te->getFullbright())
{ //register in post deferred fullbright shiny pass
@@ -3887,10 +4937,10 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
{ //invisiprim
registerFace(group, facep, LLRenderPass::PASS_INVISIBLE);
}
- else if (fullbright)
+ else if (fullbright || bake_sunlight)
{ //fullbright
registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT);
- if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && te->getBumpmap())
+ if (LLPipeline::sRenderDeferred && !hud_group && LLPipeline::sRenderBump && te->getBumpmap())
{ //if this is the deferred render and a bump map is present, register in post deferred bump
registerFace(group, facep, LLRenderPass::PASS_POST_BUMP);
}
@@ -3916,7 +4966,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
}
//not sure why this is here, and looks like it might cause bump mapped objects to get rendered redundantly -- davep 5/11/2010
- if (!is_alpha && !LLPipeline::sRenderDeferred)
+ if (!is_alpha && (hud_group || !LLPipeline::sRenderDeferred))
{
llassert((mask & LLVertexBuffer::MAP_NORMAL) || fullbright);
facep->setPoolType((fullbright) ? LLDrawPool::POOL_FULLBRIGHT : LLDrawPool::POOL_SIMPLE);
@@ -3974,18 +5024,17 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun
//sum up face verts and indices
drawablep->updateFaceSize(i);
LLFace* facep = drawablep->getFace(i);
- if (facep->hasGeometry() && facep->mPixelArea > FORCE_CULL_AREA)
+ if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA)
{
vertex_count += facep->getGeomCount();
index_count += facep->getIndicesCount();
-
+ llassert(facep->getIndicesCount() < 65536);
//remember face (for sorting)
mFaceList.push_back(facep);
}
else
{
- facep->mVertexBuffer = NULL;
- facep->mLastVertexBuffer = NULL;
+ facep->clearVertexBuffer();
}
}
}
@@ -4001,7 +5050,7 @@ LLHUDPartition::LLHUDPartition()
mLODPeriod = 1;
}
-void LLHUDPartition::shift(const LLVector3 &offset)
+void LLHUDPartition::shift(const LLVector4a &offset)
{
//HUD objects don't shift with region crossing. That would be silly.
}