Added auto avatar muting(appearance only) based on avatar complexity (disabled by default). Added several missing debug views.

This commit is contained in:
Shyotl
2012-01-27 02:36:26 -06:00
parent c1b749e12c
commit fc65380f2a
18 changed files with 1435 additions and 152 deletions

View File

@@ -2079,6 +2079,7 @@ LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL ge
mFaceMask = 0x0;
mDetail = detail;
mSculptLevel = -2;
mSurfaceArea = 1.f; //only calculated for sculpts, defaults to 1 for all other prims
mIsMeshAssetLoaded = FALSE;
mLODScaleBias.setVec(1,1,1);
mHullPoints = NULL;
@@ -3152,6 +3153,8 @@ void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components,
{
F32 area = sculptGetSurfaceArea();
mSurfaceArea = area;
const F32 SCULPT_MAX_AREA = 384.f;
if (area < SCULPT_MIN_AREA || area > SCULPT_MAX_AREA)
@@ -4623,18 +4626,83 @@ S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& en
genBinormals(i);
}
if (!face.mOctree)
{
face.createOctree();
}
//LLVector4a* p = (LLVector4a*) face.mPositions;
if (isUnique())
{ //don't bother with an octree for flexi volumes
U32 tri_count = face.mNumIndices/3;
LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, bi_normal);
intersect.traverse(face.mOctree);
if (intersect.mHitFace)
for (U32 j = 0; j < tri_count; ++j)
{
U16 idx0 = face.mIndices[j*3+0];
U16 idx1 = face.mIndices[j*3+1];
U16 idx2 = face.mIndices[j*3+2];
const LLVector4a& v0 = face.mPositions[idx0];
const LLVector4a& v1 = face.mPositions[idx1];
const LLVector4a& v2 = face.mPositions[idx2];
F32 a,b,t;
if (LLTriangleRayIntersect(v0, v1, v2,
start, dir, a, b, t))
{
if ((t >= 0.f) && // if hit is after start
(t <= 1.f) && // and before end
(t < closest_t)) // and this hit is closer
{
closest_t = t;
hit_face = i;
if (intersection != NULL)
{
LLVector4a intersect = dir;
intersect.mul(closest_t);
intersect.add(start);
intersection->set(intersect.getF32ptr());
}
if (tex_coord != NULL)
{
LLVector2* tc = (LLVector2*) face.mTexCoords;
*tex_coord = ((1.f - a - b) * tc[idx0] +
a * tc[idx1] +
b * tc[idx2]);
}
if (normal!= NULL)
{
LLVector4* norm = (LLVector4*) face.mNormals;
*normal = ((1.f - a - b) * LLVector3(norm[idx0]) +
a * LLVector3(norm[idx1]) +
b * LLVector3(norm[idx2]));
}
if (bi_normal != NULL)
{
LLVector4* binormal = (LLVector4*) face.mBinormals;
*bi_normal = ((1.f - a - b) * LLVector3(binormal[idx0]) +
a * LLVector3(binormal[idx1]) +
b * LLVector3(binormal[idx2]));
}
}
}
}
}
else
{
hit_face = i;
if (!face.mOctree)
{
face.createOctree();
}
LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, bi_normal);
intersect.traverse(face.mOctree);
if (intersect.mHitFace)
{
hit_face = i;
}
}
}
}

View File

@@ -971,6 +971,7 @@ public:
S32 getNumFaces() const;
S32 getNumVolumeFaces() const { return mVolumeFaces.size(); }
F32 getDetail() const { return mDetail; }
F32 getSurfaceArea() const { return mSurfaceArea; }
const LLVolumeParams& getParams() const { return mParams; }
LLVolumeParams getCopyOfParams() const { return mParams; }
const LLProfile& getProfile() const { return *mProfilep; }
@@ -1073,6 +1074,7 @@ public:
BOOL mUnique;
F32 mDetail;
S32 mSculptLevel;
F32 mSurfaceArea; //unscaled surface area
BOOL mIsMeshAssetLoaded;
LLVolumeParams mParams;

View File

@@ -371,6 +371,7 @@ set(viewer_SOURCE_FILES
llparcelselection.cpp
llpatchvertexarray.cpp
llphysicsmotion.cpp
llphysicsshapebuilderutil.cpp
llpolymesh.cpp
llpolymorph.cpp
llprefschat.cpp
@@ -850,6 +851,7 @@ set(viewer_HEADER_FILES
llparcelselection.h
llpatchvertexarray.h
llphysicsmotion.h
llphysicsshapebuilderutil.h
llpolymesh.h
llpolymorph.h
llprefschat.h

View File

@@ -8746,6 +8746,66 @@
<key>Value</key>
<real>0.0</real>
</map>
<key>ObjectCostHighThreshold</key>
<map>
<key>Comment</key>
<string>Threshold at which object cost is considered high (displayed in red).</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>50.0</real>
</map>
<key>ObjectCostLowColor</key>
<map>
<key>Comment</key>
<string>Color for object with a low object cost.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Color4</string>
<key>Value</key>
<array>
<real>0.0</real>
<real>0.5</real>
<real>1.0</real>
<real>0.5</real>
</array>
</map>
<key>ObjectCostMidColor</key>
<map>
<key>Comment</key>
<string>Color for object with a medium object cost.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Color4</string>
<key>Value</key>
<array>
<real>1.0</real>
<real>0.75</real>
<real>0.0</real>
<real>0.65</real>
</array>
</map>
<key>ObjectCostHighColor</key>
<map>
<key>Comment</key>
<string>Color for object a high object cost.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Color4</string>
<key>Value</key>
<array>
<real>1.0</real>
<real>0.0</real>
<real>0.0</real>
<real>0.75</real>
</array>
</map>
<key>ParcelMediaAutoPlayEnable</key>
<map>
<key>Comment</key>
@@ -9583,6 +9643,88 @@
<key>Value</key>
<integer>1</integer>
</map>
<key>RenderAvatarComplexityLimit</key>
<map>
<key>Comment</key>
<string>Max visual complexity of avatars in a scene</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>RenderComplexityColorMin</key>
<map>
<key>Comment</key>
<string>Max visual complexity of avatars in a scene</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Color4</string>
<key>Value</key>
<array>
<real>0.0</real>
<real>0.0</real>
<real>1.0</real>
<real>0.5</real>
</array>
</map>
<key>RenderComplexityColorMid</key>
<map>
<key>Comment</key>
<string>Max visual complexity of avatars in a scene</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Color4</string>
<key>Value</key>
<array>
<real>0.0</real>
<real>1.0</real>
<real>0.0</real>
<real>0.5</real>
</array>
</map>
<key>RenderComplexityColorMax</key>
<map>
<key>Comment</key>
<string>Max visual complexity of avatars in a scene</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Color4</string>
<key>Value</key>
<array>
<real>1.0</real>
<real>0.0</real>
<real>0.0</real>
<real>0.5</real>
</array>
</map>
<key>RenderComplexityThreshold</key>
<map>
<key>Comment</key>
<string>Only color objects higher than render threshold</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>RenderComplexityStaticMax</key>
<map>
<key>Comment</key>
<string>Sets a static max value for scaling of RenderComplexity
display (-1 for dynamic scaling)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>RenderAvatarLODFactor</key>
<map>
<key>Comment</key>
@@ -9847,6 +9989,17 @@
<key>Value</key>
<integer>0</integer>
</map>
<key>RenderDebugNormalScale</key>
<map>
<key>Comment</key>
<string>Scale of normals in debug display.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>0.03</real>
</map>
<key>RenderDebugPipeline</key>
<map>
<key>Comment</key>
@@ -11139,6 +11292,28 @@
<key>Value</key>
<integer>1</integer>
</map>
<key>RenderAutoMuteByteLimit</key>
<map>
<key>Comment</key>
<string>Maximum bytes of attachments before an avatar is automatically visually muted (0 for no limit).</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>RenderAutoMuteSurfaceAreaLimit</key>
<map>
<key>Comment</key>
<string>Maximum surface area of attachments before an avatar is automatically visually muted (0 for no limit).</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>RenderUseShaderLOD</key>
<map>
<key>Comment</key>

View File

@@ -1081,6 +1081,7 @@ BOOL LLDrawable::isVisible() const
LLSpatialBridge::LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 data_mask)
: LLSpatialPartition(data_mask, render_by_group, GL_STREAM_DRAW_ARB)
{
mBridge = this;
mDrawable = root;
root->setSpatialBridge(this);
@@ -1109,6 +1110,15 @@ LLSpatialBridge::~LLSpatialBridge()
{
group->mSpatialPartition->remove(this, group);
}
//delete octree here so listeners will still be able to access bridge specific state
destroyTree();
}
void LLSpatialBridge::destroyTree()
{
delete mOctree;
mOctree = NULL;
}
void LLSpatialBridge::updateSpatialExtents()

View File

@@ -34,6 +34,7 @@
#define LL_LLDRAWPOOLALPHA_H
#include "lldrawpool.h"
#include "llrender.h"
#include "llframetimer.h"
class LLFace;
@@ -72,6 +73,7 @@ public:
virtual void render(S32 pass = 0);
/*virtual*/ void prerender();
void renderGroupAlpha(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE);
void renderAlpha(U32 mask);
void renderAlphaHighlight(U32 mask);

View File

@@ -1037,51 +1037,48 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText
llassert( (bump_code == BE_BRIGHTNESS) || (bump_code == BE_DARKNESS) );
LLViewerTexture* bump = NULL;
const F32 BRIGHTNESS_DARKNESS_PIXEL_AREA_THRESHOLD = 1000;
if( src_image->getMaxVirtualSize() > BRIGHTNESS_DARKNESS_PIXEL_AREA_THRESHOLD )
bump_image_map_t* entries_list = NULL;
void (*callback_func)( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) = NULL;
switch( bump_code )
{
bump_image_map_t* entries_list = NULL;
void (*callback_func)( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) = NULL;
case BE_BRIGHTNESS:
entries_list = &mBrightnessEntries;
callback_func = LLBumpImageList::onSourceBrightnessLoaded;
break;
case BE_DARKNESS:
entries_list = &mDarknessEntries;
callback_func = LLBumpImageList::onSourceDarknessLoaded;
break;
default:
llassert(0);
return NULL;
}
switch( bump_code )
bump_image_map_t::iterator iter = entries_list->find(src_image->getID());
if (iter != entries_list->end() && iter->second.notNull())
{
bump = iter->second;
}
else
{
LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,1);
raw->clear(0x77, 0x77, 0xFF, 0xFF);
(*entries_list)[src_image->getID()] = LLViewerTextureManager::getLocalTexture( raw.get(), TRUE);
bump = (*entries_list)[src_image->getID()]; // In case callback was called immediately and replaced the image
}
if (!src_image->hasCallbacks())
{ //if image has no callbacks but resolutions don't match, trigger raw image loaded callback again
if (src_image->getWidth() != bump->getWidth() ||
src_image->getHeight() != bump->getHeight())// ||
//(LLPipeline::sRenderDeferred && bump->getComponents() != 4))
{
case BE_BRIGHTNESS:
entries_list = &mBrightnessEntries;
callback_func = LLBumpImageList::onSourceBrightnessLoaded;
break;
case BE_DARKNESS:
entries_list = &mDarknessEntries;
callback_func = LLBumpImageList::onSourceDarknessLoaded;
break;
default:
llassert(0);
return NULL;
}
bump_image_map_t::iterator iter = entries_list->find(src_image->getID());
if (iter != entries_list->end() && iter->second.notNull())
{
bump = iter->second;
}
else
{
LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,1);
raw->clear(0x77, 0x77, 0xFF, 0xFF);
(*entries_list)[src_image->getID()] = LLViewerTextureManager::getLocalTexture( raw.get(), TRUE);
bump = (*entries_list)[src_image->getID()]; // In case callback was called immediately and replaced the image
}
if (!src_image->hasCallbacks())
{ //if image has no callbacks but resolutions don't match, trigger raw image loaded callback again
if (src_image->getWidth() != bump->getWidth() ||
src_image->getHeight() != bump->getHeight())// ||
//(LLPipeline::sRenderDeferred && bump->getComponents() != 4))
{
src_image->setBoostLevel(LLViewerTexture::BOOST_BUMP) ;
src_image->setLoadedCallback( callback_func, 0, TRUE, FALSE, new LLUUID(src_image->getID()), NULL );
src_image->forceToSaveRawImage(0) ;
}
src_image->setBoostLevel(LLViewerTexture::BOOST_BUMP) ;
src_image->setLoadedCallback( callback_func, 0, TRUE, FALSE, new LLUUID(src_image->getID()), NULL );
src_image->forceToSaveRawImage(0) ;
}
}
@@ -1593,7 +1590,7 @@ void LLDrawPoolInvisible::endDeferredPass( S32 pass )
void LLDrawPoolInvisible::renderDeferred( S32 pass )
{ //render invisiprims; this doesn't work becaue it also blocks all the post-deferred stuff
#if 0
#if 0
LLFastTimer t(FTM_RENDER_INVISIBLE);
U32 invisi_mask = LLVertexBuffer::MAP_VERTEX;

View File

@@ -89,6 +89,9 @@ const S32 MAX_MESH_VERSION = 999;
U32 LLMeshRepository::sBytesReceived = 0;
U32 LLMeshRepository::sHTTPRequestCount = 0;
U32 LLMeshRepository::sHTTPRetryCount = 0;
U32 LLMeshRepository::sLODProcessing = 0;
U32 LLMeshRepository::sLODPending = 0;
U32 LLMeshRepository::sCacheBytesRead = 0;
U32 LLMeshRepository::sCacheBytesWritten = 0;
U32 LLMeshRepository::sPeakKbps = 0;
@@ -206,6 +209,12 @@ public:
LLMeshHeaderResponder(const LLVolumeParams& mesh_params)
: mMeshParams(mesh_params)
{
LLMeshRepoThread::sActiveHeaderRequests++;
}
~LLMeshHeaderResponder()
{
LLMeshRepoThread::sActiveHeaderRequests--;
}
virtual void completedRaw(U32 status, const std::string& reason,
@@ -225,6 +234,12 @@ public:
LLMeshLODResponder(const LLVolumeParams& mesh_params, S32 lod, U32 offset, U32 requested_bytes)
: mMeshParams(mesh_params), mLOD(lod), mOffset(offset), mRequestedBytes(requested_bytes)
{
LLMeshRepoThread::sActiveLODRequests++;
}
~LLMeshLODResponder()
{
LLMeshRepoThread::sActiveLODRequests--;
}
virtual void completedRaw(U32 status, const std::string& reason,
@@ -503,6 +518,7 @@ void LLMeshRepoThread::run()
mMutex->lock();
LODRequest req = mLODReqQ.front();
mLODReqQ.pop();
LLMeshRepository::sLODProcessing--;
mMutex->unlock();
if (fetchMeshLOD(req.mMeshParams, req.mLOD))
{
@@ -611,6 +627,7 @@ void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
{
LLMutexLock lock(mMutex);
mLODReqQ.push(req);
LLMeshRepository::sLODProcessing++;
}
}
else
@@ -713,7 +730,6 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
std::string http_url = constructUrl(mesh_id);
if (!http_url.empty())
{
++sActiveLODRequests;
LLMeshRepository::sHTTPRequestCount++;
mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size,
new LLMeshSkinInfoResponder(mesh_id, offset, size));
@@ -786,7 +802,6 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
std::string http_url = constructUrl(mesh_id);
if (!http_url.empty())
{
++sActiveLODRequests;
LLMeshRepository::sHTTPRequestCount++;
mCurlRequest->getByteRange(http_url, headers, offset, size,
new LLMeshDecompositionResponder(mesh_id, offset, size));
@@ -859,7 +874,6 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
std::string http_url = constructUrl(mesh_id);
if (!http_url.empty())
{
++sActiveLODRequests;
LLMeshRepository::sHTTPRequestCount++;
mCurlRequest->getByteRange(http_url, headers, offset, size,
new LLMeshPhysicsShapeResponder(mesh_id, offset, size));
@@ -910,7 +924,6 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params)
std::string http_url = constructUrl(mesh_params.getSculptID());
if (!http_url.empty())
{
++sActiveHeaderRequests;
retval = true;
//grab first 4KB if we're going to bother with a fetch. Cache will prevent future fetches if a full mesh fits
//within the first 4KB
@@ -976,7 +989,6 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
std::string http_url = constructUrl(mesh_id);
if (!http_url.empty())
{
++sActiveLODRequests;
retval = true;
LLMeshRepository::sHTTPRequestCount++;
mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size,
@@ -1052,6 +1064,7 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat
{
LODRequest req(mesh_params, iter->second[i]);
mLODReqQ.push(req);
LLMeshRepository::sLODProcessing++;
}
}
mPendingLOD.erase(iter);
@@ -1725,7 +1738,6 @@ void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason,
const LLIOPipe::buffer_ptr_t& buffer)
{
LLMeshRepoThread::sActiveLODRequests--;
S32 data_size = buffer->countAfter(channels.in(), NULL);
if (status < 200 || status > 400)
@@ -1942,7 +1954,6 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason,
const LLChannelDescriptors& channels,
const LLIOPipe::buffer_ptr_t& buffer)
{
LLMeshRepoThread::sActiveHeaderRequests--;
if (status < 200 || status > 400)
{
//llwarns
@@ -2385,6 +2396,7 @@ void LLMeshRepository::notifyLoadedMeshes()
LLMeshRepoThread::LODRequest& request = mPendingRequests.front();
mThread->loadMeshLOD(request.mMeshParams, request.mLOD);
mPendingRequests.erase(mPendingRequests.begin());
LLMeshRepository::sLODPending--;
push_count--;
}
}

View File

@@ -464,15 +464,14 @@ private:
class LLMeshRepository
{
private:
S32 mMeshUploadTimeOut ; //maximum time in seconds to execute an uploading request.
public:
//metrics
static U32 sBytesReceived;
static U32 sHTTPRequestCount;
static U32 sHTTPRetryCount;
static U32 sLODPending;
static U32 sLODProcessing;
static U32 sCacheBytesRead;
static U32 sCacheBytesWritten;
static U32 sPeakKbps;

View File

@@ -1078,6 +1078,8 @@ void LLSpatialGroup::clearOcclusionState(eOcclusionState state, S32 mode)
LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
mState(0),
mGeometryBytes(0),
mSurfaceArea(0.f),
mBuilt(0.f),
mOctreeNode(node),
mSpatialPartition(part),
@@ -1086,9 +1088,7 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
mDistance(0.f),
mDepth(0.f),
mLastUpdateDistance(-1.f),
mLastUpdateTime(gFrameTimeSeconds),
mViewAngle(0.f),
mLastUpdateViewAngle(-1.f)
mLastUpdateTime(gFrameTimeSeconds)
{
sNodeCount++;
LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
@@ -1302,6 +1302,17 @@ void LLSpatialGroup::handleDestruction(const TreeNode* node)
}
}
//clean up avatar attachment stats
LLSpatialBridge* bridge = mSpatialPartition->asBridge();
if (bridge)
{
if (bridge->mAvatar.notNull())
{
bridge->mAvatar->mAttachmentGeometryBytes -= mGeometryBytes;
bridge->mAvatar->mAttachmentSurfaceArea -= mSurfaceArea;
}
}
clearDrawMap();
mVertexBuffer = NULL;
mBufferMap.clear();
@@ -1659,7 +1670,7 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)
//==============================================
LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 buffer_usage)
: mRenderByGroup(render_by_group)
: mRenderByGroup(render_by_group), mBridge(NULL)
{
LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
mOcclusionEnabled = TRUE;
@@ -2718,6 +2729,115 @@ void renderUpdateType(LLDrawable* drawablep)
}
}
void renderComplexityDisplay(LLDrawable* drawablep)
{
LLViewerObject* vobj = drawablep->getVObj();
if (!vobj)
{
return;
}
LLVOVolume *voVol = dynamic_cast<LLVOVolume*>(vobj);
if (!voVol)
{
return;
}
if (!voVol->isRoot())
{
return;
}
LLVOVolume::texture_cost_t textures;
F32 cost = (F32) voVol->getRenderCost(textures);
// add any child volumes
LLViewerObject::const_child_list_t children = voVol->getChildren();
for (LLViewerObject::const_child_list_t::const_iterator iter = children.begin(); iter != children.end(); ++iter)
{
const LLViewerObject *child = *iter;
const LLVOVolume *child_volume = dynamic_cast<const LLVOVolume*>(child);
if (child_volume)
{
cost += child_volume->getRenderCost(textures);
}
}
// add texture cost
for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter)
{
// add the cost of each individual texture in the linkset
cost += iter->second;
}
F32 cost_max = (F32) LLVOVolume::getRenderComplexityMax();
// allow user to set a static color scale
if (gSavedSettings.getS32("RenderComplexityStaticMax") > 0)
{
cost_max = gSavedSettings.getS32("RenderComplexityStaticMax");
}
F32 cost_ratio = cost / cost_max;
// cap cost ratio at 1.0f in case cost_max is at a low threshold
cost_ratio = cost_ratio > 1.0f ? 1.0f : cost_ratio;
LLGLEnable blend(GL_BLEND);
LLColor4 color;
const LLColor4 color_min = gSavedSettings.getColor4("RenderComplexityColorMin");
const LLColor4 color_mid = gSavedSettings.getColor4("RenderComplexityColorMid");
const LLColor4 color_max = gSavedSettings.getColor4("RenderComplexityColorMax");
if (cost_ratio < 0.5f)
{
color = color_min * (1 - cost_ratio * 2) + color_mid * (cost_ratio * 2);
}
else
{
color = color_mid * (1 - (cost_ratio - 0.5) * 2) + color_max * ((cost_ratio - 0.5) * 2);
}
LLSD color_val = color.getValue();
// don't highlight objects below the threshold
if (cost > gSavedSettings.getS32("RenderComplexityThreshold"))
{
glColor4f(color[0],color[1],color[2],0.5f);
S32 num_faces = drawablep->getNumFaces();
if (num_faces)
{
for (S32 i = 0; i < num_faces; ++i)
{
pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
}
}
LLViewerObject::const_child_list_t children = voVol->getChildren();
for (LLViewerObject::const_child_list_t::const_iterator iter = children.begin(); iter != children.end(); ++iter)
{
const LLViewerObject *child = *iter;
if (child)
{
num_faces = child->getNumFaces();
if (num_faces)
{
for (S32 i = 0; i < num_faces; ++i)
{
pushVerts(child->mDrawable->getFace(i), LLVertexBuffer::MAP_VERTEX);
}
}
}
}
}
voVol->setDebugText(llformat("%4.0f", cost));
}
void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
{
@@ -2811,7 +2931,490 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
{
drawBoxOutline(pos,size);
}
}
void renderNormals(LLDrawable* drawablep)
{
LLVertexBuffer::unbind();
LLVOVolume* vol = drawablep->getVOVolume();
if (vol)
{
LLVolume* volume = vol->getVolume();
gGL.pushMatrix();
gGL.multMatrix((F32*) vol->getRelativeXform().mMatrix);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
LLVector4a scale(gSavedSettings.getF32("RenderDebugNormalScale"));
for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
{
const LLVolumeFace& face = volume->getVolumeFace(i);
for (S32 j = 0; j < face.mNumVertices; ++j)
{
gGL.begin(LLRender::LINES);
LLVector4a n,p;
n.setMul(face.mNormals[j], scale);
p.setAdd(face.mPositions[j], n);
gGL.diffuseColor4f(1,1,1,1);
gGL.vertex3fv(face.mPositions[j].getF32ptr());
gGL.vertex3fv(p.getF32ptr());
if (face.mBinormals)
{
n.setMul(face.mBinormals[j], scale);
p.setAdd(face.mPositions[j], n);
gGL.diffuseColor4f(0,1,1,1);
gGL.vertex3fv(face.mPositions[j].getF32ptr());
gGL.vertex3fv(p.getF32ptr());
}
gGL.end();
}
}
gGL.popMatrix();
}
}
S32 get_physics_detail(const LLVolumeParams& volume_params, const LLVector3& scale)
{
const S32 DEFAULT_DETAIL = 1;
const F32 LARGE_THRESHOLD = 5.f;
const F32 MEGA_THRESHOLD = 25.f;
S32 detail = DEFAULT_DETAIL;
F32 avg_scale = (scale[0]+scale[1]+scale[2])/3.f;
if (avg_scale > LARGE_THRESHOLD)
{
detail += 1;
if (avg_scale > MEGA_THRESHOLD)
{
detail += 1;
}
}
return detail;
}
void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLColor4& line_color)
{
LLUUID mesh_id = volume->getVolume()->getParams().getSculptID();
LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id);
const LLVector3 center(0,0,0);
const LLVector3 size(0.25f,0.25f,0.25f);
if (decomp)
{
if (!decomp->mBaseHullMesh.empty())
{
gGL.diffuseColor4fv(color.mV);
LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions, decomp->mBaseHullMesh.mNormals);
}
else
{
gMeshRepo.buildPhysicsMesh(*decomp);
gGL.diffuseColor4f(0,1,1,1);
drawBoxOutline(center, size);
}
}
else
{
gGL.diffuseColor3f(1,0,1);
drawBoxOutline(center, size);
}
}
void render_hull(LLModel::PhysicsMesh& mesh, const LLColor4& color, const LLColor4& line_color)
{
gGL.diffuseColor4fv(color.mV);
LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
LLGLEnable offset(GL_POLYGON_OFFSET_LINE);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glPolygonOffset(3.f, 3.f);
glLineWidth(3.f);
gGL.diffuseColor4fv(line_color.mV);
LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
glLineWidth(1.f);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
{
U8 physics_type = volume->getPhysicsShapeType();
if (physics_type == LLViewerObject::PHYSICS_SHAPE_NONE || volume->isFlexible())
{
return;
}
//not allowed to return at this point without rendering *something*
F32 threshold = gSavedSettings.getF32("ObjectCostHighThreshold");
F32 cost = volume->getObjectCost();
LLColor4 low = gSavedSettings.getColor4("ObjectCostLowColor");
LLColor4 mid = gSavedSettings.getColor4("ObjectCostMidColor");
LLColor4 high = gSavedSettings.getColor4("ObjectCostHighColor");
F32 normalizedCost = 1.f - exp( -(cost / threshold) );
LLColor4 color;
if ( normalizedCost <= 0.5f )
{
color = lerp( low, mid, 2.f * normalizedCost );
}
else
{
color = lerp( mid, high, 2.f * ( normalizedCost - 0.5f ) );
}
LLColor4 line_color = color*0.5f;
U32 data_mask = LLVertexBuffer::MAP_VERTEX;
LLVolumeParams volume_params = volume->getVolume()->getParams();
LLPhysicsVolumeParams physics_params(volume_params,
physics_type == LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification physics_spec;
LLPhysicsShapeBuilderUtil::determinePhysicsShape(physics_params, volume->getScale(), physics_spec);
U32 type = physics_spec.getType();
LLVector3 center(0,0,0);
LLVector3 size(0.25f,0.25f,0.25f);
gGL.pushMatrix();
gGL.multMatrix((F32*) volume->getRelativeXform().mMatrix);
if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_MESH)
{
//Skip. no
LLUUID mesh_id = volume->getVolume()->getParams().getSculptID();
LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id);
if (decomp)
{ //render a physics based mesh
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
if (!decomp->mHull.empty())
{ //decomposition exists, use that
if (decomp->mMesh.empty())
{
gMeshRepo.buildPhysicsMesh(*decomp);
}
for (U32 i = 0; i < decomp->mMesh.size(); ++i)
{
render_hull(decomp->mMesh[i], color, line_color);
}
}
else if (!decomp->mPhysicsShapeMesh.empty())
{
//decomp has physics mesh, render that mesh
gGL.diffuseColor4fv(color.mV);
LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
gGL.diffuseColor4fv(line_color.mV);
LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
else
{ //no mesh or decomposition, render base hull
renderMeshBaseHull(volume, data_mask, color, line_color);
if (decomp->mPhysicsShapeMesh.empty())
{
//attempt to fetch physics shape mesh if available
gMeshRepo.fetchPhysicsShape(mesh_id);
}
}
}
else
{
gGL.diffuseColor3f(1,1,0);
drawBoxOutline(center, size);
}
}
else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_CONVEX ||
type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_CONVEX)
{
if (volume->isMesh())
{
renderMeshBaseHull(volume, data_mask, color, line_color);
}
/*else
{
LLVolumeParams volume_params = volume->getVolume()->getParams();
S32 detail = get_physics_detail(volume_params, volume->getScale());
LLVolume* phys_volume = LLPrimitive::getVolumeManager()->refVolume(volume_params, detail);
if (!phys_volume->mHullPoints)
{ //build convex hull
std::vector<LLVector3> pos;
std::vector<U16> index;
S32 index_offset = 0;
for (S32 i = 0; i < phys_volume->getNumVolumeFaces(); ++i)
{
const LLVolumeFace& face = phys_volume->getVolumeFace(i);
if (index_offset + face.mNumVertices > 65535)
{
continue;
}
for (S32 j = 0; j < face.mNumVertices; ++j)
{
pos.push_back(LLVector3(face.mPositions[j].getF32ptr()));
}
for (S32 j = 0; j < face.mNumIndices; ++j)
{
index.push_back(face.mIndices[j]+index_offset);
}
index_offset += face.mNumVertices;
}
if (!pos.empty() && !index.empty())
{
LLCDMeshData mesh;
mesh.mIndexBase = &index[0];
mesh.mVertexBase = pos[0].mV;
mesh.mNumVertices = pos.size();
mesh.mVertexStrideBytes = 12;
mesh.mIndexStrideBytes = 6;
mesh.mIndexType = LLCDMeshData::INT_16;
mesh.mNumTriangles = index.size()/3;
LLCDMeshData res;
LLConvexDecomposition::getInstance()->generateSingleHullMeshFromMesh( &mesh, &res );
//copy res into phys_volume
phys_volume->mHullPoints = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*res.mNumVertices);
phys_volume->mNumHullPoints = res.mNumVertices;
S32 idx_size = (res.mNumTriangles*3*2+0xF) & ~0xF;
phys_volume->mHullIndices = (U16*) ll_aligned_malloc_16(idx_size);
phys_volume->mNumHullIndices = res.mNumTriangles*3;
const F32* v = res.mVertexBase;
for (S32 i = 0; i < res.mNumVertices; ++i)
{
F32* p = (F32*) ((U8*)v+i*res.mVertexStrideBytes);
phys_volume->mHullPoints[i].load3(p);
}
if (res.mIndexType == LLCDMeshData::INT_16)
{
for (S32 i = 0; i < res.mNumTriangles; ++i)
{
U16* idx = (U16*) (((U8*)res.mIndexBase)+i*res.mIndexStrideBytes);
phys_volume->mHullIndices[i*3+0] = idx[0];
phys_volume->mHullIndices[i*3+1] = idx[1];
phys_volume->mHullIndices[i*3+2] = idx[2];
}
}
else
{
for (S32 i = 0; i < res.mNumTriangles; ++i)
{
U32* idx = (U32*) (((U8*)res.mIndexBase)+i*res.mIndexStrideBytes);
phys_volume->mHullIndices[i*3+0] = (U16) idx[0];
phys_volume->mHullIndices[i*3+1] = (U16) idx[1];
phys_volume->mHullIndices[i*3+2] = (U16) idx[2];
}
}
}
}
if (phys_volume->mHullPoints)
{
//render hull
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
gGL.diffuseColor4fv(line_color.mV);
LLVertexBuffer::unbind();
llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0);
LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
gGL.diffuseColor4fv(color.mV);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
}
else
{
gGL.diffuseColor4f(1,0,1,1);
drawBoxOutline(center, size);
}
LLPrimitive::sVolumeManager->unrefVolume(phys_volume);
}*/
}
else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::BOX)
{
LLVector3 center = physics_spec.getCenter();
LLVector3 scale = physics_spec.getScale();
LLVector3 vscale = volume->getScale()*2.f;
scale.set(scale[0]/vscale[0], scale[1]/vscale[1], scale[2]/vscale[2]);
gGL.diffuseColor4fv(color.mV);
drawBox(center, scale);
}
else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::SPHERE)
{
/*LLVolumeParams volume_params;
volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE );
volume_params.setBeginAndEndS( 0.f, 1.f );
volume_params.setBeginAndEndT( 0.f, 1.f );
volume_params.setRatio ( 1, 1 );
volume_params.setShear ( 0, 0 );
LLVolume* sphere = LLPrimitive::sVolumeManager->refVolume(volume_params, 3);
gGL.diffuseColor4fv(color.mV);
pushVerts(sphere);
LLPrimitive::sVolumeManager->unrefVolume(sphere);*/
}
else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::CYLINDER)
{
LLVolumeParams volume_params;
volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE );
volume_params.setBeginAndEndS( 0.f, 1.f );
volume_params.setBeginAndEndT( 0.f, 1.f );
volume_params.setRatio ( 1, 1 );
volume_params.setShear ( 0, 0 );
LLVolume* cylinder = LLPrimitive::getVolumeManager()->refVolume(volume_params, 3);
gGL.diffuseColor4fv(color.mV);
pushVerts(cylinder);
LLPrimitive::getVolumeManager()->unrefVolume(cylinder);
}
else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_MESH)
{
LLVolumeParams volume_params = volume->getVolume()->getParams();
S32 detail = get_physics_detail(volume_params, volume->getScale());
LLVolume* phys_volume = LLPrimitive::getVolumeManager()->refVolume(volume_params, detail);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
gGL.diffuseColor4fv(line_color.mV);
pushVerts(phys_volume);
gGL.diffuseColor4fv(color.mV);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
pushVerts(phys_volume);
LLPrimitive::getVolumeManager()->unrefVolume(phys_volume);
}
else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_CONVEX)
{
LLVolumeParams volume_params = volume->getVolume()->getParams();
S32 detail = get_physics_detail(volume_params, volume->getScale());
LLVolume* phys_volume = LLPrimitive::getVolumeManager()->refVolume(volume_params, detail);
if (phys_volume->mHullPoints && phys_volume->mHullIndices)
{
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0);
LLVertexBuffer::unbind();
glVertexPointer(3, GL_FLOAT, 16, phys_volume->mHullPoints);
gGL.diffuseColor4fv(line_color.mV);
gGL.syncMatrices();
glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices);
gGL.diffuseColor4fv(color.mV);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices);
}
else
{
gGL.diffuseColor3f(1,0,1);
drawBoxOutline(center, size);
gMeshRepo.buildHull(volume_params, detail);
}
LLPrimitive::getVolumeManager()->unrefVolume(phys_volume);
}
else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::SCULPT)
{
//TODO: implement sculpted prim physics display
}
else
{
llerrs << "Unhandled type" << llendl;
}
gGL.popMatrix();
}
void renderPhysicsShapes(LLSpatialGroup* group)
{
for (LLSpatialGroup::OctreeNode::const_element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
{
LLDrawable* drawable = *i;
LLVOVolume* volume = drawable->getVOVolume();
if (volume && !volume->isAttachment() && volume->getPhysicsShapeType() != LLViewerObject::PHYSICS_SHAPE_NONE )
{
if (!group->mSpatialPartition->isBridge())
{
gGL.pushMatrix();
LLVector3 trans = drawable->getRegion()->getOriginAgent();
gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]);
renderPhysicsShape(drawable, volume);
gGL.popMatrix();
}
else
{
renderPhysicsShape(drawable, volume);
}
}
else
{
LLViewerObject* object = drawable->getVObj();
if (object && object->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH)
{
//push face vertices for terrain
for (S32 i = 0; i < drawable->getNumFaces(); ++i)
{
LLFace* face = drawable->getFace(i);
LLVertexBuffer* buff = face->getVertexBuffer();
if (buff)
{
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
gGL.diffuseColor3f(0.2f, 0.5f, 0.3f);
buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0);
gGL.diffuseColor3f(0.2f, 1.f, 0.3f);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0);
}
}
}
}
}
}
void renderTexturePriority(LLDrawable* drawable)
@@ -2908,6 +3511,43 @@ void renderBatchSize(LLDrawInfo* params)
pushVerts(params, LLVertexBuffer::MAP_VERTEX);
}
void renderShadowFrusta(LLDrawInfo* params)
{
LLGLEnable blend(GL_BLEND);
gGL.setSceneBlendType(LLRender::BT_ADD);
LLVector4a center;
center.setAdd(params->mExtents[1], params->mExtents[0]);
center.mul(0.5f);
LLVector4a size;
size.setSub(params->mExtents[1],params->mExtents[0]);
size.mul(0.5f);
if (gPipeline.mShadowCamera[4].AABBInFrustum(center, size))
{
gGL.diffuseColor3f(1,0,0);
pushVerts(params, LLVertexBuffer::MAP_VERTEX);
}
if (gPipeline.mShadowCamera[5].AABBInFrustum(center, size))
{
gGL.diffuseColor3f(0,1,0);
pushVerts(params, LLVertexBuffer::MAP_VERTEX);
}
if (gPipeline.mShadowCamera[6].AABBInFrustum(center, size))
{
gGL.diffuseColor3f(0,0,1);
pushVerts(params, LLVertexBuffer::MAP_VERTEX);
}
if (gPipeline.mShadowCamera[7].AABBInFrustum(center, size))
{
gGL.diffuseColor3f(1,0,1);
pushVerts(params, LLVertexBuffer::MAP_VERTEX);
}
gGL.setSceneBlendType(LLRender::BT_ALPHA);
}
void renderLights(LLDrawable* drawablep)
{
if (!drawablep->isLight())
@@ -3248,11 +3888,16 @@ public:
for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
{
LLDrawable* drawable = *i;
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES))
{
renderBoundingBox(drawable);
}
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_NORMALS))
{
renderNormals(drawable);
}
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BUILD_QUEUE))
{
@@ -3293,6 +3938,10 @@ public:
{
renderUpdateType(drawable);
}
if(gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY))
{
renderComplexityDisplay(drawable);
}
LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(drawable->getVObj().get());
@@ -3344,11 +3993,50 @@ public:
{
renderBatchSize(draw_info);
}
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
{
renderShadowFrusta(draw_info);
}
}
}
}
};
class LLOctreeRenderPhysicsShapes : public LLOctreeTraveler<LLDrawable>
{
public:
LLCamera* mCamera;
LLOctreeRenderPhysicsShapes(LLCamera* camera): mCamera(camera) {}
virtual void traverse(const LLSpatialGroup::OctreeNode* node)
{
LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))
{
node->accept(this);
stop_glerror();
for (U32 i = 0; i < node->getChildCount(); i++)
{
traverse(node->getChild(i));
stop_glerror();
}
group->rebuildGeom();
group->rebuildMesh();
renderPhysicsShapes(group);
}
}
virtual void visit(const LLSpatialGroup::OctreeNode* branch)
{
}
};
class LLOctreePushBBoxVerts : public LLOctreeTraveler<LLDrawable>
{
public:
@@ -3467,6 +4155,25 @@ public:
};
void LLSpatialPartition::renderPhysicsShapes()
{
LLSpatialBridge* bridge = asBridge();
LLCamera* camera = LLViewerCamera::getInstance();
if (bridge)
{
camera = NULL;
}
gGL.flush();
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
glLineWidth(3.f);
LLOctreeRenderPhysicsShapes render_physics(camera);
render_physics.traverse(mOctree);
gGL.flush();
glLineWidth(1.f);
}
void LLSpatialPartition::renderDebug()
{
if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE |
@@ -3475,13 +4182,16 @@ void LLSpatialPartition::renderDebug()
LLPipeline::RENDER_DEBUG_BATCH_SIZE |
LLPipeline::RENDER_DEBUG_UPDATE_TYPE |
LLPipeline::RENDER_DEBUG_BBOXES |
LLPipeline::RENDER_DEBUG_NORMALS |
LLPipeline::RENDER_DEBUG_POINTS |
LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY |
LLPipeline::RENDER_DEBUG_TEXTURE_ANIM |
LLPipeline::RENDER_DEBUG_RAYCAST |
LLPipeline::RENDER_DEBUG_AVATAR_VOLUME |
LLPipeline::RENDER_DEBUG_AGENT_TARGET |
LLPipeline::RENDER_DEBUG_BUILD_QUEUE))
//LLPipeline::RENDER_DEBUG_BUILD_QUEUE |
LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA |
LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY))
{
return;
}

View File

@@ -376,6 +376,9 @@ public:
bridge_list_t mBridgeList;
buffer_map_t mBufferMap; //used by volume buffers to store unique buffers per texture
U32 mGeometryBytes; //used by volumes to track how many bytes of geometry data are in this node
F32 mSurfaceArea; //used by volumes to track estimated surface area of geometry in this node
F32 mBuilt;
OctreeNode* mOctreeNode;
LLSpatialPartition* mSpatialPartition;
@@ -455,9 +458,10 @@ public:
BOOL isVisible(const LLVector3& v);
bool isHUDPartition() ;
virtual LLSpatialBridge* asBridge() { return NULL; }
virtual BOOL isBridge() { return asBridge() != NULL; }
LLSpatialBridge* asBridge() { return mBridge; }
BOOL isBridge() { return asBridge() != NULL; }
void renderPhysicsShapes();
void renderDebug();
void renderIntersectingBBoxes(LLCamera* camera);
void restoreGL();
@@ -467,6 +471,9 @@ public:
public:
LLSpatialGroup::OctreeNode* mOctree;
LLSpatialBridge* mBridge; // NULL for non-LLSpatialBridge instances, otherwise, mBridge == this
// use a pointer instead of making "isBridge" and "asBridge" virtual so it's safe
// to call asBridge() from the destructor
BOOL mOcclusionEnabled; // if TRUE, occlusion culling is performed
BOOL mInfiniteFarClip; // if TRUE, frustum culling ignores far clip plane
U32 mBufferUsage;
@@ -491,8 +498,9 @@ public:
LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 data_mask);
virtual BOOL isSpatialBridge() const { return TRUE; }
void destroyTree();
virtual BOOL isSpatialBridge() const { return TRUE; }
virtual void updateSpatialExtents();
virtual void updateBinRadius();
virtual void setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results = NULL, BOOL for_select = FALSE);
@@ -503,11 +511,11 @@ public:
virtual void shiftPos(const LLVector4a& vec);
virtual void cleanupReferences();
virtual LLSpatialPartition* asPartition() { return this; }
virtual LLSpatialBridge* asBridge() { return this; }
virtual LLCamera transformCamera(LLCamera& camera);
LLDrawable* mDrawable;
LLPointer<LLVOAvatar> mAvatar;
};
class LLCullResult

View File

@@ -764,6 +764,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo
{
LLAppViewer::instance()->pingMainloopTimeout("Display:Imagery");
gPipeline.generateWaterReflection(*LLViewerCamera::getInstance());
gPipeline.renderPhysicsDisplay();
}
LLGLState::checkStates();

View File

@@ -1489,6 +1489,21 @@ void init_debug_rendering_menu(LLMenuGL* menu)
sub_menu->append(new LLMenuItemCheckGL("Update Types", &LLPipeline::toggleRenderDebug, NULL,
&LLPipeline::toggleRenderDebugControl,
(void*)LLPipeline::RENDER_DEBUG_UPDATE_TYPE));
sub_menu->append(new LLMenuItemCheckGL("Physics Shapes", &LLPipeline::toggleRenderDebug, NULL,
&LLPipeline::toggleRenderDebugControl,
(void*)LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES));
sub_menu->append(new LLMenuItemCheckGL("Normals", &LLPipeline::toggleRenderDebug, NULL,
&LLPipeline::toggleRenderDebugControl,
(void*)LLPipeline::RENDER_DEBUG_NORMALS));
sub_menu->append(new LLMenuItemCheckGL("LOD Info", &LLPipeline::toggleRenderDebug, NULL,
&LLPipeline::toggleRenderDebugControl,
(void*)LLPipeline::RENDER_DEBUG_LOD_INFO));
sub_menu->append(new LLMenuItemCheckGL("Wind Vectors", &LLPipeline::toggleRenderDebug, NULL,
&LLPipeline::toggleRenderDebugControl,
(void*)LLPipeline::RENDER_DEBUG_WIND_VECTORS));
sub_menu->append(new LLMenuItemCheckGL("Complexity", &LLPipeline::toggleRenderDebug, NULL,
&LLPipeline::toggleRenderDebugControl,
(void*)LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY)); ;
sub_menu = new LLMenuGL("Render Tests");
@@ -1632,6 +1647,10 @@ void init_debug_avatar_menu(LLMenuGL* menu)
&LLPipeline::toggleRenderDebug, NULL,
&LLPipeline::toggleRenderDebugControl,
(void*)LLPipeline::RENDER_DEBUG_AGENT_TARGET));
menu->append(new LLMenuItemCheckGL("Attachment Bytes",
&LLPipeline::toggleRenderDebug, NULL,
&LLPipeline::toggleRenderDebugControl,
(void*)LLPipeline::RENDER_DEBUG_ATTACHMENT_BYTES));
menu->append(new LLMenuItemToggleGL( "Debug Rotation", &LLVOAvatar::sDebugAvatarRotation));
menu->append(new LLMenuItemCallGL("Dump Attachments", handle_dump_attachments));
menu->append(new LLMenuItemCallGL("Rebake Textures", handle_rebake_textures, NULL, NULL, 'R', MASK_ALT | MASK_CONTROL ));

View File

@@ -689,6 +689,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
LLViewerObject(id, pcode, regionp),
mIsDummy(FALSE),
mSpecialRenderMode(0),
mAttachmentGeometryBytes(0),
mAttachmentSurfaceArea(0.f),
mTurning(FALSE),
mPelvisToFoot(0.f),
mLastSkeletonSerialNum( 0 ),
@@ -1370,6 +1372,7 @@ void LLVOAvatar::initInstance(void)
mesh->setName(mesh_name);
mesh->setMeshID(mesh_index);
mesh->setPickName(mesh_dict->mPickName);
mesh->setIsTransparent(FALSE);
switch((int)mesh_index)
{
case MESH_ID_HAIR:
@@ -4044,6 +4047,16 @@ void LLVOAvatar::slamPosition()
mRoot.updateWorldMatrixChildren();
}
bool LLVOAvatar::isVisuallyMuted()
{
static LLCachedControl<U32> max_attachment_bytes(gSavedSettings, "RenderAutoMuteByteLimit");
static LLCachedControl<F32> max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit");
return LLMuteList::getInstance()->isMuted(getID()) ||
(mAttachmentGeometryBytes > max_attachment_bytes && max_attachment_bytes > 0) ||
(mAttachmentSurfaceArea > max_attachment_area && max_attachment_area > 0.f);
}
//------------------------------------------------------------------------
// updateCharacter()
// called on both your avatar and other avatars
@@ -4119,8 +4132,9 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
size.setSub(ext[1],ext[0]);
F32 mag = size.getLength3().getF32()*0.5f;
F32 impostor_area = 256.f*512.f*(8.125f - LLVOAvatar::sLODFactor*8.f);
if (LLMuteList::getInstance()->isMuted(getID()))
if (isVisuallyMuted())
{ // muted avatars update at 16 hz
mUpdatePeriod = 16;
}
@@ -5234,6 +5248,7 @@ void LLVOAvatar::updateTextures()
}
}
}
}
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
@@ -10426,19 +10441,41 @@ void LLVOAvatar::getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& d
void LLVOAvatar::idleUpdateRenderCost()
{
static const U32 ARC_BODY_PART_COST = 200;
static const U32 ARC_LIMIT = 20000;
static std::set<LLUUID> all_textures;
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_ATTACHMENT_BYTES))
{ //set debug text to attachment geometry bytes here so render cost will override
setDebugText(llformat("%.1f KB, %.2f m^2", mAttachmentGeometryBytes/1024.f, mAttachmentSurfaceArea));
}
if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME))
{
return;
}
U32 shame = 1;
U32 cost = 0;
LLVOVolume::texture_cost_t textures;
std::set<LLUUID> textures;
for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
{
const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index);
ETextureIndex tex_index = baked_dict->mTextureIndex;
if ((tex_index != TEX_SKIRT_BAKED) || (isWearingWearableType(LLWearableType::WT_SKIRT)))
{
if (isTextureVisible(tex_index))
{
cost +=ARC_BODY_PART_COST;
}
}
}
attachment_map_t::const_iterator iter;
for (iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end();
++iter)
for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end();
++iter)
{
LLViewerJointAttachment* attachment = iter->second;
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
@@ -10448,52 +10485,89 @@ void LLVOAvatar::idleUpdateRenderCost()
const LLViewerObject* attached_object = (*attachment_iter);
if (attached_object && !attached_object->isHUDAttachment())
{
textures.clear();
const LLDrawable* drawable = attached_object->mDrawable;
if (drawable)
{
shame += 10;
LLVOVolume* volume = drawable->getVOVolume();
const LLVOVolume* volume = drawable->getVOVolume();
if (volume)
{
shame += calc_shame(volume, textures);
cost += volume->getRenderCost(textures);
const_child_list_t children = volume->getChildren();
for (const_child_list_t::const_iterator child_iter = children.begin();
child_iter != children.end();
++child_iter)
{
LLViewerObject* child_obj = *child_iter;
LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj );
if (child)
{
cost += child->getRenderCost(textures);
}
}
for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter)
{
// add the cost of each individual texture in the linkset
cost += iter->second;
}
}
}
}
}
}
if(sDoProperArc)
}
// Diagnostic output to identify all avatar-related textures.
// Does not affect rendering cost calculation.
// Could be wrapped in a debug option if output becomes problematic.
if (isSelf())
{
std::set<LLUUID>::const_iterator tex_iter;
for(tex_iter = textures.begin();tex_iter != textures.end();++tex_iter)
// print any attachment textures we didn't already know about.
for (LLVOVolume::texture_cost_t::iterator it = textures.begin(); it != textures.end(); ++it)
{
LLViewerTexture* img = LLViewerTextureManager::getFetchedTexture(*tex_iter);
if(img)
LLUUID image_id = it->first;
if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR)
continue;
if (all_textures.find(image_id) == all_textures.end())
{
shame += (img->getHeight() * img->getWidth()) >> 4;
// attachment texture not previously seen.
llinfos << "attachment_texture: " << image_id.asString() << llendl;
all_textures.insert(image_id);
}
}
// print any avatar textures we didn't already know about
for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin();
iter != LLVOAvatarDictionary::getInstance()->getTextures().end();
++iter)
{
const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second;
// TODO: MULTI-WEARABLE: handle multiple textures for self
const LLViewerTexture* te_image = getTEImage(iter->first);//getImage(iter->first,0);
if (!te_image)
continue;
LLUUID image_id = te_image->getID();
if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR)
continue;
if (all_textures.find(image_id) == all_textures.end())
{
llinfos << "local_texture: " << texture_dict->mName << ": " << image_id << llendl;
all_textures.insert(image_id);
}
}
}
shame += textures.size() * 5;
setDebugText(llformat("%d", shame));
F32 green = 1.f-llclamp(((F32) shame-1024.f)/1024.f, 0.f, 1.f);
F32 red = llmin((F32) shame/1024.f, 1.f);
if(sDoProperArc)
{
green = 1.f-llclamp(((F32)shame-1000000.f)/1000000.f, 0.f, 1.f);
red = llmin((F32)shame/1000000.f, 1.f);
}
else
{
green = 1.f-llclamp(((F32)shame-1024.f)/1024.f, 0.f, 1.f);
red = llmin((F32)shame/1024.f, 1.f);
}
setDebugText(llformat("%d", cost));
mVisualComplexity = cost;
F32 green = 1.f-llclamp(((F32) cost-(F32)ARC_LIMIT)/(F32)ARC_LIMIT, 0.f, 1.f);
F32 red = llmin((F32) cost/(F32)ARC_LIMIT, 1.f);
mText->setColor(LLColor4(red,green,0,1));
}
// static
BOOL LLVOAvatar::isIndexLocalTexture(ETextureIndex index)
{

View File

@@ -287,6 +287,7 @@ private:
BOOL mPreviousFullyLoaded;
BOOL mFullyLoadedInitialized;
S32 mFullyLoadedFrameCounter;
S32 mVisualComplexity;
LLFrameTimer mFullyLoadedTimer;
LLFrameTimer mRuthTimer;
@@ -379,6 +380,8 @@ public:
// Graphical stuff for objects - maybe broken out into render class later?
U32 renderFootShadows();
U32 renderImpostor(LLColor4U color = LLColor4U(255,255,255,255), S32 diffuse_channel = 0);
bool isVisuallyMuted();
U32 renderRigid();
U32 renderSkinned(EAvatarRenderPass pass);
F32 getLastSkinTime() { return mLastSkinTime; }
@@ -390,6 +393,9 @@ public:
static void restoreGL();
BOOL mIsDummy; // for special views
S32 mSpecialRenderMode; // special lighting
U32 mAttachmentGeometryBytes; //number of bytes in attached geometry
F32 mAttachmentSurfaceArea; //estimated surface area of attachments
private:
bool shouldAlphaMask();

View File

@@ -1032,6 +1032,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);
@@ -3346,6 +3354,32 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB);
LLVOAvatar* pAvatarVO = NULL;
LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
if (bridge)
{
if (bridge->mAvatar.isNull())
{
LLViewerObject* vobj = bridge->mDrawable->getVObj();
if (vobj)
{
bridge->mAvatar = vobj->getAvatar();
}
}
pAvatarVO = bridge->mAvatar;
}
if (pAvatarVO)
{
pAvatarVO->mAttachmentGeometryBytes -= group->mGeometryBytes;
pAvatarVO->mAttachmentSurfaceArea -= group->mSurfaceArea;
}
group->mGeometryBytes = 0;
group->mSurfaceArea = 0;
group->clearDrawMap();
mFaceList.clear();
@@ -3384,12 +3418,24 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
LLVOVolume* vobj = drawablep->getVOVolume();
if (!vobj)
{
continue;
}
if (vobj->isMesh() &&
(vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded() || !gMeshRepo.meshRezEnabled()))
{
continue;
}
LLVolume* volume = vobj->getVolume();
if (volume)
{
const LLVector3& scale = vobj->getScale();
group->mSurfaceArea += volume->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]);
}
llassert_always(vobj);
vobj->updateTextureVirtualSize(true);
vobj->preRebuild();
@@ -3434,7 +3480,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
//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 )
@@ -3504,13 +3549,16 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
if (type == LLDrawPool::POOL_ALPHA)
{
if (te->getFullbright())
if (te->getColor().mV[3] > 0.f)
{
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA);
}
else
{
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA);
if (te->getFullbright())
{
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA);
}
else
{
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA);
}
}
}
else if (te->getShiny())
@@ -3643,8 +3691,11 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
else
{
drawablep->setState(LLDrawable::HAS_ALPHA);
alpha_faces.push_back(facep);
if (te->getColor().mV[3] > 0.f)
{
drawablep->setState(LLDrawable::HAS_ALPHA);
alpha_faces.push_back(facep);
}
}
}
else
@@ -3761,6 +3812,12 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
mFaceList.clear();
if (pAvatarVO)
{
pAvatarVO->mAttachmentGeometryBytes += group->mGeometryBytes;
pAvatarVO->mAttachmentSurfaceArea += group->mSurfaceArea;
}
}
static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM("Volume Geometry");
@@ -4102,6 +4159,9 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
}
}
group->mGeometryBytes += buffer->getSize() + buffer->getIndicesSize();
buffer_map[mask][*face_iter].push_back(buffer);
//add face geometry

View File

@@ -364,6 +364,7 @@ LLPipeline::LLPipeline() :
mOldRenderDebugMask(0),
mGroupQ1Locked(false),
mGroupQ2Locked(false),
mResetVertexBuffers(false),
mLastRebuildPool(NULL),
mAlphaPool(NULL),
mSkyPool(NULL),
@@ -591,6 +592,17 @@ void LLPipeline::resizeScreenTexture()
}
}
void LLPipeline::allocatePhysicsBuffer()
{
GLuint resX = gViewerWindow->getWorldViewWidthRaw();
GLuint resY = gViewerWindow->getWorldViewHeightRaw();
if (mPhysicsDisplay.getWidth() != resX || mPhysicsDisplay.getHeight() != resY)
{
mPhysicsDisplay.allocate(resX, resY, GL_RGBA, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
}
}
void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY)
{
refreshCachedSettings();
@@ -839,6 +851,7 @@ void LLPipeline::releaseScreenBuffers()
{
mScreen.release();
mFXAABuffer.release();
mPhysicsDisplay.release();
mDeferredScreen.release();
mDeferredDepth.release();
mDeferredLight.release();
@@ -3993,6 +4006,69 @@ void LLPipeline::addTrianglesDrawn(S32 index_count, U32 render_type)
}
}
void LLPipeline::renderPhysicsDisplay()
{
if (!hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES))
{
return;
}
allocatePhysicsBuffer();
gGL.flush();
mPhysicsDisplay.bindTarget();
glClearColor(0,0,0,1);
gGL.setColorMask(true, true);
mPhysicsDisplay.clear();
glClearColor(0,0,0,0);
gGL.setColorMask(true, false);
if (LLGLSLShader::sNoFixedFunction)
{
gDebugProgram.bind();
}
for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
{
LLViewerRegion* region = *iter;
for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
{
LLSpatialPartition* part = region->getSpatialPartition(i);
if (part)
{
if (hasRenderType(part->mDrawableType))
{
part->renderPhysicsShapes();
}
}
}
}
for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
{
LLSpatialBridge* bridge = *i;
if (!bridge->isDead() && hasRenderType(bridge->mDrawableType))
{
gGL.pushMatrix();
gGL.multMatrix((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
bridge->renderPhysicsShapes();
gGL.popMatrix();
}
}
gGL.flush();
if (LLGLSLShader::sNoFixedFunction)
{
gDebugProgram.unbind();
}
mPhysicsDisplay.flush();
}
void LLPipeline::renderDebug()
{
LLMemType mt(LLMemType::MTYPE_PIPELINE);
@@ -4956,7 +5032,8 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
light_state->setConstantAttenuation(0.f);
if (sRenderDeferred)
{
light_state->setLinearAttenuation(light_radius*1.5f);
F32 size = light_radius*1.5f;
light_state->setLinearAttenuation(size*size);
light_state->setQuadraticAttenuation(light->getLightFalloff()*0.5f+1.f);
}
else
@@ -6034,16 +6111,16 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
U32 res_mod = RenderResolutionDivisor;//.get();
//U32 res_mod = RenderResolutionDivisor;//.get();
LLVector2 tc1(0,0);
LLVector2 tc2((F32) mScreen.getWidth()*2,
(F32) mScreen.getHeight()*2);
if (res_mod > 1)
/*if (res_mod > 1)
{
tc2 /= (F32) res_mod;
}
}*/
LLFastTimer ftm(FTM_RENDER_BLOOM);
gGL.color4f(1,1,1,1);
@@ -6560,7 +6637,13 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b
mFXAABuffer.bindTexture(0, channel);
gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
}
gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom;
gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth();
gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight();
glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
F32 scale_x = (F32) width/mFXAABuffer.getWidth();
F32 scale_y = (F32) height/mFXAABuffer.getHeight();
shader->uniform2f(LLShaderMgr::FXAA_TC_SCALE, scale_x, scale_y);
@@ -6580,10 +6663,10 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b
}
else
{
if (res_mod > 1)
/*if (res_mod > 1)
{
tc2 /= (F32) res_mod;
}
}*/
U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1;
LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(mask, 0);
@@ -6649,6 +6732,45 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b
}
gGL.setSceneBlendType(LLRender::BT_ALPHA);
if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES))
{
if (LLGLSLShader::sNoFixedFunction)
{
gSplatTextureRectProgram.bind();
}
gGL.setColorMask(true, false);
LLVector2 tc1(0,0);
LLVector2 tc2((F32) gViewerWindow->getWorldViewWidthRaw()*2,
(F32) gViewerWindow->getWorldViewHeightRaw()*2);
LLGLEnable blend(GL_BLEND);
gGL.color4f(1,1,1,0.75f);
gGL.getTexUnit(0)->bind(&mPhysicsDisplay);
gGL.begin(LLRender::TRIANGLES);
gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
gGL.vertex2f(-1,-1);
gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
gGL.vertex2f(-1,3);
gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
gGL.vertex2f(3,-1);
gGL.end();
gGL.flush();
if (LLGLSLShader::sNoFixedFunction)
{
gSplatTextureRectProgram.unbind();
}
}
if (LLRenderTarget::sUseFBO)
{ //copy depth buffer from mScreen to framebuffer
LLRenderTarget::copyContentsToFramebuffer(mScreen, 0, 0, mScreen.getWidth(), mScreen.getHeight(),
@@ -9094,7 +9216,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
assertInitialized();
BOOL muted = LLMuteList::getInstance()->isMuted(avatar->getID());
bool muted = avatar->isVisuallyMuted();
pushRenderTypeMask();

View File

@@ -33,14 +33,14 @@
#ifndef LL_PIPELINE_H
#define LL_PIPELINE_H
#include "llcamera.h"
#include "llerror.h"
#include "lldarrayptr.h"
#include "lldqueueptr.h"
#include "llstat.h"
#include "lldrawpool.h"
#include "llspatialpartition.h"
#include "m4math.h"
#include "llmemory.h"
#include "llpointer.h"
#include "lldrawpool.h"
#include "llgl.h"
#include "lldrawable.h"
@@ -48,6 +48,10 @@
#include <stack>
#include <stack>
#include <stack>
class LLViewerTexture;
class LLEdge;
class LLFace;
@@ -118,7 +122,8 @@ public:
void allocateScreenBuffer(U32 resX, U32 resY);
bool allocateScreenBuffer(U32 resX, U32 resY, U32 samples);
void allocatePhysicsBuffer();
void resetVertexBuffers(LLDrawable* drawable);
void generateImpostor(LLVOAvatar* avatar);
void bindScreenToTexture();
@@ -260,6 +265,7 @@ public:
void renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& camera, LLCullResult& result, BOOL use_shader = TRUE, BOOL use_occlusion = TRUE);
void renderHighlights();
void renderDebug();
void renderPhysicsDisplay();
void rebuildPools(); // Rebuild pools
@@ -424,30 +430,35 @@ public:
enum LLRenderDebugMask
{
RENDER_DEBUG_COMPOSITION = 0x0000001,
RENDER_DEBUG_VERIFY = 0x0000002,
RENDER_DEBUG_BBOXES = 0x0000004,
RENDER_DEBUG_OCTREE = 0x0000008,
RENDER_DEBUG_WIND_VECTORS = 0x0000010,
RENDER_DEBUG_OCCLUSION = 0x0000020,
RENDER_DEBUG_POINTS = 0x0000040,
RENDER_DEBUG_TEXTURE_PRIORITY = 0x0000080,
RENDER_DEBUG_TEXTURE_AREA = 0x0000100,
RENDER_DEBUG_FACE_AREA = 0x0000200,
RENDER_DEBUG_PARTICLES = 0x0000400,
RENDER_DEBUG_GLOW = 0x0000800,
RENDER_DEBUG_TEXTURE_ANIM = 0x0001000,
RENDER_DEBUG_LIGHTS = 0x0002000,
RENDER_DEBUG_BATCH_SIZE = 0x0004000,
RENDER_DEBUG_ALPHA_BINS = 0x0008000,
RENDER_DEBUG_RAYCAST = 0x0010000,
RENDER_DEBUG_SHAME = 0x0020000,
RENDER_DEBUG_SHADOW_FRUSTA = 0x0040000,
RENDER_DEBUG_SCULPTED = 0x0080000,
RENDER_DEBUG_AVATAR_VOLUME = 0x0100000,
RENDER_DEBUG_BUILD_QUEUE = 0x0200000,
RENDER_DEBUG_AGENT_TARGET = 0x0400000,
RENDER_DEBUG_UPDATE_TYPE = 0x0800000,
RENDER_DEBUG_COMPOSITION = 0x00000001,
RENDER_DEBUG_VERIFY = 0x00000002,
RENDER_DEBUG_BBOXES = 0x00000004,
RENDER_DEBUG_OCTREE = 0x00000008,
RENDER_DEBUG_WIND_VECTORS = 0x00000010,
RENDER_DEBUG_OCCLUSION = 0x00000020,
RENDER_DEBUG_POINTS = 0x00000040,
RENDER_DEBUG_TEXTURE_PRIORITY = 0x00000080,
RENDER_DEBUG_TEXTURE_AREA = 0x00000100,
RENDER_DEBUG_FACE_AREA = 0x00000200,
RENDER_DEBUG_PARTICLES = 0x00000400,
RENDER_DEBUG_GLOW = 0x00000800,
RENDER_DEBUG_TEXTURE_ANIM = 0x00001000,
RENDER_DEBUG_LIGHTS = 0x00002000,
RENDER_DEBUG_BATCH_SIZE = 0x00004000,
RENDER_DEBUG_ALPHA_BINS = 0x00008000,
RENDER_DEBUG_RAYCAST = 0x00010000,
RENDER_DEBUG_SHAME = 0x00020000,
RENDER_DEBUG_SHADOW_FRUSTA = 0x00040000,
RENDER_DEBUG_SCULPTED = 0x00080000,
RENDER_DEBUG_AVATAR_VOLUME = 0x00100000,
RENDER_DEBUG_BUILD_QUEUE = 0x00200000,
RENDER_DEBUG_AGENT_TARGET = 0x00400000,
RENDER_DEBUG_UPDATE_TYPE = 0x00800000,
RENDER_DEBUG_PHYSICS_SHAPES = 0x01000000,
RENDER_DEBUG_NORMALS = 0x02000000,
RENDER_DEBUG_LOD_INFO = 0x04000000,
RENDER_DEBUG_RENDER_COMPLEXITY = 0x08000000,
RENDER_DEBUG_ATTACHMENT_BYTES = 0x10000000,
};
public:
@@ -470,6 +481,10 @@ public:
S32 mNumVisibleNodes;
S32 mVerticesRelit;
S32 mDebugTextureUploadCost;
S32 mDebugSculptUploadCost;
S32 mDebugMeshUploadCost;
S32 mLightingChanges;
S32 mGeometryChanges;
@@ -516,6 +531,7 @@ public:
LLRenderTarget mDeferredDepth;
LLRenderTarget mDeferredLight;
LLMultisampleBuffer mSampleBuffer;
LLRenderTarget mPhysicsDisplay;
//utility buffer for rendering post effects, gets abused by renderDeferredLighting
LLPointer<LLVertexBuffer> mDeferredVB;