Meshy update. Mostly related to cost calculations... mostly.

This commit is contained in:
Shyotl
2011-08-28 04:05:36 -05:00
parent c66065b688
commit 59d50f3062
11 changed files with 622 additions and 199 deletions

View File

@@ -7233,7 +7233,40 @@
<string>F32</string>
<key>Value</key>
<real>0.25</real>
</map>
</map>
<key>Jpeg2000AdvancedCompression</key>
<map>
<key>Comment</key>
<string>Use advanced Jpeg2000 compression options (precincts, blocks, ordering, markers)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>Jpeg2000PrecinctsSize</key>
<map>
<key>Comment</key>
<string>Size of image precincts. Assumed square and same for all levels. Must be power of 2.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>256</integer>
</map>
<key>Jpeg2000BlocksSize</key>
<map>
<key>Comment</key>
<string>Size of encoding blocks. Assumed square and same for all levels. Must be power of 2. Max 64, Min 4.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>64</integer>
</map>
<key>KeepAspectForSnapshot</key>
<map>
<key>Comment</key>
@@ -11207,28 +11240,51 @@
<key>Value</key>
<real>1.0</real>
</map>
<key>MeshStreamingCostScaler</key>
<key>MeshTriangleBudget</key>
<map>
<key>Comment</key>
<string>DEBUG</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>2.0</real>
</map>
<key>MeshThreadCount</key>
<map>
<key>Comment</key>
<string>Number of threads to use for loading meshes.</string>
<string>Target visible triangle budget to use when estimating streaming cost.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>8</integer>
<real>250000</real>
</map>
<key>MeshMetaDataDiscount</key>
<map>
<key>Comment</key>
<string>Number of bytes to deduct for metadata when determining streaming cost.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>384</real>
</map>
<key>MeshMinimumByteSize</key>
<map>
<key>Comment</key>
<string>Minimum number of bytes per LoD block when determining streaming cost.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>16</real>
</map>
<key>MeshBytesPerTriangle</key>
<map>
<key>Comment</key>
<string>Approximation of bytes per triangle to use for determining mesh streaming cost.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>16</real>
</map>
<key>MeshMaxConcurrentRequests</key>
<map>
<key>Comment</key>

View File

@@ -171,7 +171,7 @@ void LLDrawPoolTree::endDeferredPass(S32 pass)
void LLDrawPoolTree::beginShadowPass(S32 pass)
{
LLFastTimer t(LLFastTimer::FTM_SHADOW_TREE);
gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
static const LLCachedControl<F32> render_deferred_offset("RenderDeferredTreeShadowOffset",1.f);
static const LLCachedControl<F32> render_deferred_bias("RenderDeferredTreeShadowBias",1.f);
glPolygonOffset(render_deferred_offset,render_deferred_bias);
@@ -187,12 +187,10 @@ void LLDrawPoolTree::renderShadow(S32 pass)
void LLDrawPoolTree::endShadowPass(S32 pass)
{
LLFastTimer t(LLFastTimer::FTM_SHADOW_TREE);
gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
static const LLCachedControl<F32> render_deferred_offset("RenderDeferredTreeShadowOffset",1.f);
static const LLCachedControl<F32> render_deferred_bias("RenderDeferredTreeShadowBias",1.f);
glPolygonOffset(render_deferred_offset,render_deferred_bias);
//gDeferredShadowProgram.unbind();
static const LLCachedControl<F32> render_deferred_offset("RenderDeferredSpotShadowOffset",1.f);
static const LLCachedControl<F32> render_deferred_bias("RenderDeferredSpotShadowBias",1.f);
glPolygonOffset(render_deferred_offset,render_deferred_bias);
}
void LLDrawPoolTree::renderTree(BOOL selecting)

View File

@@ -1717,6 +1717,7 @@ void LLMeshRepository::cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header)
if (data.mModel[i].notNull())
{
LLPointer<LLVolume> volume = new LLVolume(volume_params, LLVolumeLODGroup::getVolumeScaleFromDetail(i));
volume->copyVolumeFaces(data.mModel[i]);
volume->setMeshAssetLoaded(TRUE);
}
}
@@ -2552,7 +2553,7 @@ S32 LLMeshRepository::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lo
return mThread->getActualMeshLOD(mesh_params, lod);
}
const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, LLVOVolume* requesting_obj)
const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const LLVOVolume* requesting_obj)
{
if (mesh_id.notNull())
{
@@ -2813,7 +2814,7 @@ void LLMeshRepository::uploadError(LLSD& args)
}
//static
F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod)
F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value)
{
F32 max_distance = 512.f;
@@ -2821,10 +2822,15 @@ F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32
F32 dlow = llmin(radius/0.06f, max_distance);
F32 dmid = llmin(radius/0.24f, max_distance);
F32 METADATA_DISCOUNT = (F32) gSavedSettings.getU32("MeshMetaDataDiscount"); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead
F32 MINIMUM_SIZE = (F32) gSavedSettings.getU32("MeshMinimumByteSize"); //make sure nothing is "free"
static const LLCachedControl<U32> mesh_meta_data_discount("MeshMetaDataDiscount");
static const LLCachedControl<U32> mesh_minimum_byte_size("MeshMinimumByteSize");
static const LLCachedControl<U32> mesh_bytes_per_triangle("MeshBytesPerTriangle");
static const LLCachedControl<U32> mesh_triangle_budget("MeshTriangleBudget");
F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle");
F32 METADATA_DISCOUNT = (F32) mesh_meta_data_discount.get(); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead
F32 MINIMUM_SIZE = (F32) mesh_minimum_byte_size.get(); //make sure nothing is "free"
F32 bytes_per_triangle = (F32) mesh_bytes_per_triangle.get();
S32 bytes_lowest = header["lowest_lod"]["size"].asInteger();
S32 bytes_low = header["low_lod"]["size"].asInteger();
@@ -2902,7 +2908,12 @@ F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32
triangles_low*low_area +
triangles_lowest*lowest_area;
return weighted_avg/gSavedSettings.getU32("MeshTriangleBudget")*15000.f;
if (unscaled_value)
{
*unscaled_value = weighted_avg;
}
return weighted_avg/mesh_triangle_budget*15000.f;
}
@@ -3204,32 +3215,33 @@ void LLPhysicsDecomp::doDecompositionSingleHull()
llwarns << "Could not execute decomposition stage when attempting to create single hull." << llendl;
make_box(mCurRequest);
}
mMutex->lock();
mCurRequest->mHull.clear();
mCurRequest->mHull.resize(1);
mCurRequest->mHullMesh.clear();
mMutex->unlock();
std::vector<LLVector3> p;
LLCDHull hull;
// if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code
decomp->getSingleHull(&hull);
const F32* v = hull.mVertexBase;
for (S32 j = 0; j < hull.mNumVertices; ++j)
else
{
LLVector3 vert(v[0], v[1], v[2]);
p.push_back(vert);
v = (F32*) (((U8*) v) + hull.mVertexStrideBytes);
}
mMutex->lock();
mCurRequest->mHull.clear();
mCurRequest->mHull.resize(1);
mCurRequest->mHullMesh.clear();
mMutex->unlock();
std::vector<LLVector3> p;
LLCDHull hull;
// if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code
decomp->getSingleHull(&hull);
const F32* v = hull.mVertexBase;
for (S32 j = 0; j < hull.mNumVertices; ++j)
{
LLVector3 vert(v[0], v[1], v[2]);
p.push_back(vert);
v = (F32*) (((U8*) v) + hull.mVertexStrideBytes);
}
mMutex->lock();
mCurRequest->mHull[0] = p;
mMutex->unlock();
mMutex->lock();
mCurRequest->mHull[0] = p;
mMutex->unlock();
}
#else
setMeshData(mesh, false);

View File

@@ -474,7 +474,7 @@ public:
static U32 sCacheBytesWritten;
static U32 sPeakKbps;
static F32 getStreamingCost(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1);
static F32 getStreamingCost(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL);
LLMeshRepository();
@@ -493,7 +493,7 @@ public:
S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
static S32 getActualMeshLOD(LLSD& header, S32 lod);
const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id, LLVOVolume* requesting_obj);
const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id, const LLVOVolume* requesting_obj);
LLModel::Decomposition* getDecomposition(const LLUUID& mesh_id);
void fetchPhysicsShape(const LLUUID& mesh_id);
bool hasPhysicsShape(const LLUUID& mesh_id);

View File

@@ -6536,31 +6536,77 @@ U32 LLObjectSelection::getSelectedObjectTriangleCount()
return count;
}
/*S32 LLObjectSelection::getSelectedObjectRenderCost()
S32 LLObjectSelection::getSelectedObjectRenderCost()
{
S32 cost = 0;
LLVOVolume::texture_cost_t textures;
typedef std::set<LLUUID> uuid_list_t;
uuid_list_t computed_objects;
typedef std::list<LLPointer<LLViewerObject> > child_list_t;
typedef const child_list_t const_child_list_t;
// add render cost of complete linksets first, to get accurate texture counts
for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter)
{
LLSelectNode* node = *iter;
LLVOVolume* object = (LLVOVolume*)node->getObject();
if (object)
if (object && object->isRootEdit())
{
cost += object->getRenderCost(textures);
}
cost += object->getRenderCost(textures);
computed_objects.insert(object->getID());
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;
const_child_list_t children = object->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);
computed_objects.insert(child->getID());
}
}
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;
}
textures.clear();
}
textures.clear();
}
// add any partial linkset objects, texture cost may be slightly misleading
for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter)
{
LLSelectNode* node = *iter;
LLVOVolume* object = (LLVOVolume*)node->getObject();
if (object && computed_objects.find(object->getID()) == computed_objects.end() )
{
cost += object->getRenderCost(textures);
computed_objects.insert(object->getID());
}
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;
}
textures.clear();
}
return cost;
}*/
}
#endif //MESH_ENABLED

View File

@@ -3167,12 +3167,12 @@ F32 LLViewerObject::getLinksetPhysicsCost()
return mLinksetPhysicsCost;
}
F32 LLViewerObject::getStreamingCost(S32* bytes, S32* visible_bytes)
F32 LLViewerObject::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const
{
return 0.f;
}
U32 LLViewerObject::getTriangleCount()
U32 LLViewerObject::getTriangleCount() const
{
return 0;
}

View File

@@ -328,8 +328,8 @@ public:
virtual void setScale(const LLVector3 &scale, BOOL damped = FALSE);
#if MESH_ENABLED
virtual F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL);
virtual U32 getTriangleCount();
virtual F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL, F32* unscaled_value = NULL) const;
virtual U32 getTriangleCount() const;
virtual U32 getHighLODTriangleCount();
void setObjectCost(F32 cost);

View File

@@ -966,99 +966,54 @@ void LLViewerTextureList::decodeAllImages(F32 max_time)
BOOL LLViewerTextureList::createUploadFile(const std::string& filename,
const std::string& out_filename,
const U8 codec)
{
// First, load the image.
{
// Load the image
LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
if (image.isNull())
{
image->setLastError("Couldn't open the image to be uploaded.");
return FALSE;
}
if (!image->load(filename))
{
image->setLastError("Couldn't load the image to be uploaded.");
return FALSE;
}
// Decompress or expand it in a raw image structure
LLPointer<LLImageRaw> raw_image = new LLImageRaw;
switch (codec)
if (!image->decode(raw_image, 0.0f))
{
case IMG_CODEC_BMP:
{
LLPointer<LLImageBMP> bmp_image = new LLImageBMP;
if (!bmp_image->load(filename))
{
return FALSE;
}
if (!bmp_image->decode(raw_image, 0.0f))
{
return FALSE;
}
}
break;
case IMG_CODEC_TGA:
{
LLPointer<LLImageTGA> tga_image = new LLImageTGA;
if (!tga_image->load(filename))
{
return FALSE;
}
if (!tga_image->decode(raw_image))
{
return FALSE;
}
if( (tga_image->getComponents() != 3) &&
(tga_image->getComponents() != 4) )
{
tga_image->setLastError( "Image files with less than 3 or more than 4 components are not supported." );
return FALSE;
}
}
break;
case IMG_CODEC_JPEG:
{
LLPointer<LLImageJPEG> jpeg_image = new LLImageJPEG;
if (!jpeg_image->load(filename))
{
return FALSE;
}
if (!jpeg_image->decode(raw_image, 0.0f))
{
return FALSE;
}
}
break;
case IMG_CODEC_PNG:
{
LLPointer<LLImagePNG> png_image = new LLImagePNG;
if (!png_image->load(filename))
{
return FALSE;
}
if (!png_image->decode(raw_image, 0.0f))
{
return FALSE;
}
}
break;
default:
return FALSE;
}
LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image);
if( !compressedImage->save(out_filename) )
{
llinfos << "Couldn't create output file " << out_filename << llendl;
image->setLastError("Couldn't decode the image to be uploaded.");
return FALSE;
}
// test to see if the encode and save worked.
// Check the image constraints
if ((image->getComponents() != 3) && (image->getComponents() != 4))
{
image->setLastError("Image files with less than 3 or more than 4 components are not supported.");
return FALSE;
}
// Convert to j2c (JPEG2000) and save the file locally
LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image);
if (compressedImage.isNull())
{
image->setLastError("Couldn't convert the image to jpeg2000.");
llinfos << "Couldn't convert to j2c, file : " << filename << llendl;
return FALSE;
}
if (!compressedImage->save(out_filename))
{
image->setLastError("Couldn't create the jpeg2000 image for upload.");
llinfos << "Couldn't create output file : " << out_filename << llendl;
return FALSE;
}
// Test to see if the encode and save worked
LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C;
if( !integrity_test->loadAndValidate( out_filename ) )
if (!integrity_test->loadAndValidate( out_filename ))
{
llinfos << "Image: " << out_filename << " is corrupt." << llendl;
image->setLastError("The created jpeg2000 image is corrupt.");
llinfos << "Image file : " << out_filename << " is corrupt" << llendl;
return FALSE;
}
return TRUE;
}
@@ -1073,7 +1028,25 @@ LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImage
(raw_image->getWidth() * raw_image->getHeight() <= LL_IMAGE_REZ_LOSSLESS_CUTOFF * LL_IMAGE_REZ_LOSSLESS_CUTOFF))
compressedImage->setReversible(TRUE);
compressedImage->encode(raw_image, 0.0f);
/* if (gSavedSettings.getBOOL("Jpeg2000AdvancedCompression"))
{
// This test option will create jpeg2000 images with precincts for each level, RPCL ordering
// and PLT markers. The block size is also optionally modifiable.
// Note: the images hence created are compatible with older versions of the viewer.
// Read the blocks and precincts size settings
S32 block_size = gSavedSettings.getS32("Jpeg2000BlocksSize");
S32 precinct_size = gSavedSettings.getS32("Jpeg2000PrecinctsSize");
llinfos << "Advanced JPEG2000 Compression: precinct = " << precinct_size << ", block = " << block_size << llendl;
compressedImage->initEncode(*raw_image, block_size, precinct_size, 0);
}*/
if (!compressedImage->encode(raw_image, 0.0f))
{
llinfos << "convertToUploadFile : encode returns with error!!" << llendl;
// Clear up the pointer so we don't leak that one
compressedImage = NULL;
}
return compressedImage;
}

View File

@@ -311,7 +311,8 @@ public:
U32 ypos = 64;
const U32 y_inc = 20;
if (gSavedSettings.getBOOL("DebugShowTime"))
static const LLCachedControl<bool> debug_show_time("DebugShowTime");
if (debug_show_time)
{
const U32 y_inc2 = 15;
for (std::map<S32,LLFrameTimer>::reverse_iterator iter = gDebugTimers.rbegin();
@@ -336,7 +337,8 @@ public:
}
#if LL_WINDOWS
if (gSavedSettings.getBOOL("DebugShowMemory"))
static const LLCachedControl<bool> debug_show_memory("DebugShowMemory");
if (debug_show_memory)
{
addText(xpos, ypos, llformat("Memory: %d (KB)", LLMemory::getWorkingSetSize() / 1024));
ypos += y_inc;
@@ -426,7 +428,8 @@ public:
ypos += y_inc;
}*/
if (gSavedSettings.getBOOL("DebugShowRenderInfo"))
static const LLCachedControl<bool> debug_show_render_info("DebugShowRenderInfo");
if (debug_show_render_info)
{
if (gPipeline.getUseVertexShaders() == 0)
{
@@ -456,6 +459,59 @@ public:
addText(xpos, ypos, llformat("%.2f MB Video Memory Free", free_memory/1024.f));
ypos += y_inc;
}
#if MESH_ENABLED
//show streaming cost/triangle count of known prims in current region OR selection
//Note: This is SUPER slow
{
F32 cost = 0.f;
S32 count = 0;
S32 object_count = 0;
S32 total_bytes = 0;
S32 visible_bytes = 0;
const char* label = "Region";
if (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 0)
{ //region
LLViewerRegion* region = gAgent.getRegion();
if (region)
{
for (U32 i = 0; i < (U32)gObjectList.getNumObjects(); ++i)
{
LLViewerObject* object = gObjectList.getObject(i);
if (object &&
object->getRegion() == region &&
object->getVolume())
{
object_count++;
S32 bytes = 0;
S32 visible = 0;
cost += object->getStreamingCost(&bytes, &visible);
count += object->getTriangleCount();
total_bytes += bytes;
visible_bytes += visible;
}
}
}
}
else
{
label = "Selection";
cost = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectStreamingCost(&total_bytes, &visible_bytes);
count = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectTriangleCount();
object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
}
addText(xpos,ypos, llformat("%s streaming cost: %.1f", label, cost));
ypos += y_inc;
addText(xpos, ypos, llformat(" %.3f KTris, %.1f/%.1f KB, %d objects",
count/1000.f, visible_bytes/1024.f, total_bytes/1024.f, object_count));
ypos += y_inc;
}
#endif //MESH_ENABLED
addText(xpos, ypos, llformat("%d MB Vertex Data", LLVertexBuffer::sAllocatedBytes/(1024*1024)));
ypos += y_inc;
@@ -520,7 +576,7 @@ public:
ypos += y_inc;
#if MESH_ENABLED
if (gSavedSettings.getBOOL("MeshEnabled"))
if (gMeshRepo.meshRezEnabled())
{
addText(xpos, ypos, llformat("%.3f MB Mesh Data Received", LLMeshRepository::sBytesReceived/(1024.f*1024.f)));
@@ -541,7 +597,8 @@ public:
LLVertexBuffer::sSetCount = LLImageGL::sUniqueCount =
gPipeline.mNumVisibleNodes = LLPipeline::sVisibleLightCount = 0;
}
if (gSavedSettings.getBOOL("DebugShowRenderMatrices"))
static const LLCachedControl<bool> debug_show_render_matrices("DebugShowRenderMatrices");
if (debug_show_render_matrices)
{
addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[12], gGLProjection[13], gGLProjection[14], gGLProjection[15]));
ypos += y_inc;
@@ -574,7 +631,8 @@ public:
addText(xpos, ypos, "View Matrix");
ypos += y_inc;
}
if (gSavedSettings.getBOOL("DebugShowColor"))
static const LLCachedControl<bool> debug_show_color("DebugShowColor");
if (debug_show_color)
{
U8 color[4];
LLCoordGL coord = gViewerWindow->getCurrentMouse();

View File

@@ -93,6 +93,8 @@ 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;
LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
: LLViewerObject(id, pcode, regionp),
@@ -489,18 +491,24 @@ BOOL LLVOVolume::isVisible() const
return FALSE ;
}
void LLVOVolume::updateTextureVirtualSize()
void LLVOVolume::updateTextureVirtualSize(bool forced)
{
// Update the pixel area of all faces
if(!isVisible() || mDrawable.isNull())
{
if(mDrawable.isNull())
return;
}
if(!forced)
{
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");
@@ -559,12 +567,12 @@ void LLVOVolume::updateTextureVirtualSize()
// Animating textures also rez badly in Snowglobe because the
// actual displayed area is only a fraction (corresponding to one
// frame) of the animating texture. Let's fix that here:
if (mTextureAnimp && mTextureAnimp->mScaleS > 0.0f && mTextureAnimp->mScaleT > 0.0f)
/* if (mTextureAnimp && mTextureAnimp->mScaleS > 0.0f && mTextureAnimp->mScaleT > 0.0f)
{
// Adjust to take into account the actual frame size which is only a
// portion of the animating texture
vsize = vsize / mTextureAnimp->mScaleS / mTextureAnimp->mScaleT;
}
}*/
if ((vsize < MIN_TEX_ANIM_SIZE && old_size > MIN_TEX_ANIM_SIZE) ||
(vsize > MIN_TEX_ANIM_SIZE && old_size < MIN_TEX_ANIM_SIZE))
@@ -578,13 +586,17 @@ void LLVOVolume::updateTextureVirtualSize()
if (vsize < min_vsize) min_vsize = vsize;
if (vsize > max_vsize) max_vsize = vsize;
}
// else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
// {
// F32 pri = imagep->getDecodePriority();
// pri = llmax(pri, 0.0f);
// if (pri < min_vsize) min_vsize = pri;
// if (pri > max_vsize) max_vsize = pri;
// }
else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
{
LLViewerFetchedTexture* img = LLViewerTextureManager::staticCastToFetchedTexture(imagep) ;
if(img)
{
F32 pri = img->getDecodePriority();
pri = llmax(pri, 0.0f);
if (pri < min_vsize) min_vsize = pri;
if (pri > max_vsize) max_vsize = pri;
}
}
else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA))
{
F32 pri = mPixelArea;
@@ -657,10 +669,10 @@ void LLVOVolume::updateTextureVirtualSize()
{
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", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize)));
// }
else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
{
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", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize)));
@@ -995,19 +1007,11 @@ BOOL LLVOVolume::calcLOD()
F32 distance;
#if MESH_ENABLED
if (mDrawable->isState(LLDrawable::RIGGED))
if (mDrawable->isState(LLDrawable::RIGGED) && getAvatar())
{
LLVOAvatar* avatar = getAvatar();
if(avatar)
{
distance = avatar->mDrawable->mDistanceWRTCamera;
radius = avatar->getBinRadius();
}
else
{
distance = mDrawable->mDistanceWRTCamera;
radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length();
}
distance = avatar->mDrawable->mDistanceWRTCamera;
radius = avatar->getBinRadius();
}
else
#endif //MESH_ENABLED
@@ -2211,8 +2215,270 @@ const LLMatrix4 LLVOVolume::getRenderMatrix() const
return mDrawable->getWorldMatrix();
}
// Returns a base cost and adds textures to passed in set.
// 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(texture_cost_t &textures) const
{
// 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_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-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;
U32 glow = 0;
U32 alpha = 0;
U32 flexi = 0;
U32 animtex = 0;
U32 particles = 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())
{
flexi = 1;
}
if (isParticleSource())
{
particles = 1;
}
if (getIsLight())
{
produces_light = 1;
}
for (U32 i = 0; i < num_faces; ++i)
{
const LLFace* face = drawablep->getFace(i);
const LLTextureEntry* te = face->getTextureEntry();
const LLViewerTexture* img = face->getTexture();
if (img)
{
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 = 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 = 1;
}
if (te->getTexGen())
{
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;
// 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;
}
if (bump)
{
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;
}
#if MESH_ENABLED
F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes)
F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const
{
F32 radius = getScale().length()*0.5f;
@@ -2220,7 +2486,7 @@ F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes)
{
LLSD& header = gMeshRepo.getMeshHeader(getVolume()->getParams().getSculptID());
return LLMeshRepository::getStreamingCost(header, radius, bytes, visible_bytes, mLOD);
return LLMeshRepository::getStreamingCost(header, radius, bytes, visible_bytes, mLOD, unscaled_value);
}
else
{
@@ -2234,12 +2500,18 @@ F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes)
header["medium_lod"]["size"] = counts[2] * 10;
header["high_lod"]["size"] = counts[3] * 10;
return LLMeshRepository::getStreamingCost(header, radius);
return LLMeshRepository::getStreamingCost(header, radius, NULL, NULL, -1, unscaled_value);
}
}
#endif //MESH_ENABLED
//static
void LLVOVolume::updateRenderComplexity()
{
mRenderComplexity_last = mRenderComplexity_current;
mRenderComplexity_current = 0;
}
U32 LLVOVolume::getTriangleCount()
U32 LLVOVolume::getTriangleCount() const
{
U32 count = 0;
LLVolume* volume = getVolume();
@@ -3137,7 +3409,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
#endif //MESH_ENABLED
llassert_always(vobj);
vobj->updateTextureVirtualSize();
vobj->updateTextureVirtualSize(true);
vobj->preRebuild();
drawablep->clearState(LLDrawable::HAS_ALPHA);

View File

@@ -90,6 +90,7 @@ public:
// Class which embodies all Volume objects (with pcode LL_PCODE_VOLUME)
class LLVOVolume : public LLViewerObject
{
LOG_CLASS(LLVOVolume);
protected:
virtual ~LLVOVolume();
@@ -131,11 +132,12 @@ public:
const LLMatrix4& getRelativeXform() const { return mRelativeXform; }
const LLMatrix3& getRelativeXformInvTrans() const { return mRelativeXformInvTrans; }
/*virtual*/ const LLMatrix4 getRenderMatrix() const;
typedef std::map<LLUUID, S32> texture_cost_t;
U32 getRenderCost(texture_cost_t &textures) const;
#if MESH_ENABLED
/*virtual*/ F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL);
/*virtual*/ F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL, F32* unscaled_value = NULL) const;
#endif //MESH_ENABLED
/*virtual*/ U32 getTriangleCount();
/*virtual*/ U32 getTriangleCount() const;
/*virtual*/ U32 getHighLODTriangleCount();
/*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
S32 face = -1, // which face to check, -1 = ALL_SIDES
@@ -210,7 +212,7 @@ public:
/*virtual*/ BOOL updateLOD();
void updateRadius();
/*virtual*/ void updateTextures();
void updateTextureVirtualSize();
void updateTextureVirtualSize(bool forced = false);
void updateFaceFlags();
void regenFaces();
@@ -291,7 +293,13 @@ protected:
LLFace* addFace(S32 face_index);
void updateTEData();
// stats tracking for render complexity
static S32 mRenderComplexity_last;
static S32 mRenderComplexity_current;
public:
static S32 getRenderComplexityMax() {return mRenderComplexity_last;}
static void updateRenderComplexity();
LLViewerTextureAnim *mTextureAnimp;
U8 mTexAnimMode;
private: