summaryrefslogtreecommitdiff
path: root/indra/llmath/llvolume.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llmath/llvolume.cpp')
-rw-r--r--indra/llmath/llvolume.cpp228
1 files changed, 208 insertions, 20 deletions
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 0cf5ecd3d0..e2407860b3 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -52,6 +52,7 @@
#include "llmeshoptimizer.h"
#include "lltimer.h"
#include "llvolumeoctree.h"
+#include "workqueue.h"
#include "mikktspace/mikktspace.hh"
@@ -912,7 +913,7 @@ bool LLProfile::generate(const LLProfileParams& params, bool path_open,F32 detai
case LL_PCODE_HOLE_CIRCLE:
case LL_PCODE_HOLE_SAME:
default:
- addHole(params, true, circle_detail, 0, hollow, 1.f);
+ addHole(params, false, circle_detail, 0, hollow, 1.f);
break;
}
}
@@ -2292,30 +2293,149 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
+ // Sanity-check before even trying to decompress
+ constexpr S32 MAX_MESH_COMPRESSED_SIZE = 128 * 1024 * 1024; // 128 MB
+ const LLUUID& mesh_id = getParams().getSculptID();
+
+ if (size <= 0 || size > MAX_MESH_COMPRESSED_SIZE)
+ {
+ LL_WARNS("MeshStreaming") << "Rejecting implausible compressed mesh size " << size
+ << " for mesh id " << mesh_id << LL_ENDL;
+ return false;
+ }
+
//input stream is now pointing at a zlib compressed block of LLSD
//decompress block
- LLSD mdl;
- U32 uzip_result = LLUZipHelper::unzip_llsd(mdl, is, size);
- if (uzip_result != LLUZipHelper::ZR_OK)
+ try
{
- LL_DEBUGS("MeshStreaming") << "Failed to unzip LLSD blob for LoD with code " << uzip_result << " , will probably fetch from sim again." << LL_ENDL;
+ LLSD mdl;
+ U32 uzip_result = LLUZipHelper::unzip_llsd(mdl, is, size);
+ if (uzip_result != LLUZipHelper::ZR_OK)
+ {
+ LL_DEBUGS("MeshStreaming") << "Failed to unzip LLSD blob for LoD with code " << uzip_result << " , will probably fetch from sim again." << LL_ENDL;
+ return false;
+ }
+ return unpackVolumeFacesInternal(mdl);
+ }
+ catch (const std::bad_alloc&)
+ {
+ constexpr S32 SMALL_MESH_THRESHOLD = 4000;
+ if (size < SMALL_MESH_THRESHOLD)
+ {
+ // showOutOfMemory and LL_ERRS must run on the main thread.
+ // Post to mainloop WorkQueue, mirroring LLThread::tryRun().
+ LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop");
+ bool done = false;
+ if (main_queue)
+ {
+ const LLUUID mesh_id_copy = mesh_id; // capture by value for the lambda
+ done = main_queue->post([mesh_id_copy, size]()
+ {
+ LLError::LLUserWarningMsg::showOutOfMemory();
+ LL_ERRS("MeshStreaming") << "Out of memory unpacking mesh id " << mesh_id_copy
+ << " of compressed size " << size << LL_ENDL;
+ });
+ }
+ if (!done)
+ {
+ // No main queue available (e.g. during shutdown)
+ LL_WARNS("MeshStreaming") << "Out of memory unpacking mesh id " << mesh_id
+ << " of compressed size " << size << " (main queue unavailable)" << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_WARNS("MeshStreaming") << "Out of memory unpacking mesh id " << mesh_id
+ << " of compressed size " << size << LL_ENDL;
+ }
+ return false;
+ }
+ catch (const std::exception& e)
+ {
+ LL_WARNS("MeshStreaming") << "Exception unpacking mesh id " << mesh_id
+ << " of compressed size " << size << ": " << e.what() << LL_ENDL;
+ return false;
+ }
+ catch (...)
+ {
+ LL_WARNS("MeshStreaming") << "Unknown exception unpacking mesh id " << mesh_id
+ << " of compressed size " << size << LL_ENDL;
return false;
}
- return unpackVolumeFacesInternal(mdl);
}
bool LLVolume::unpackVolumeFaces(U8* in_data, S32 size)
{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
+ constexpr S32 MAX_MESH_COMPRESSED_SIZE = 128 * 1024 * 1024; // 128 MB
+ const LLUUID& mesh_id = getParams().getSculptID();
+
+ if (!in_data || size <= 0 || size > MAX_MESH_COMPRESSED_SIZE)
+ {
+ LL_WARNS("MeshStreaming") << "Rejecting implausible compressed mesh size " << size
+ << " for mesh id " << mesh_id << LL_ENDL;
+ return false;
+ }
+
//input data is now pointing at a zlib compressed block of LLSD
//decompress block
- LLSD mdl;
- U32 uzip_result = LLUZipHelper::unzip_llsd(mdl, in_data, size);
- if (uzip_result != LLUZipHelper::ZR_OK)
+ try
+ {
+ LLSD mdl;
+ U32 uzip_result = LLUZipHelper::unzip_llsd(mdl, in_data, size);
+ if (uzip_result != LLUZipHelper::ZR_OK)
+ {
+ LL_DEBUGS("MeshStreaming") << "Failed to unzip LLSD blob for LoD, mesh id " << mesh_id
+ << ", code " << uzip_result << " , will probably fetch from sim again." << LL_ENDL;
+ return false;
+ }
+ return unpackVolumeFacesInternal(mdl);
+ }
+ catch (const std::bad_alloc&)
+ {
+ constexpr S32 SMALL_MESH_THRESHOLD = 4000;
+ if (size < SMALL_MESH_THRESHOLD)
+ {
+ // showOutOfMemory and LL_ERRS must run on the main thread.
+ // Post to mainloop WorkQueue, mirroring LLThread::tryRun().
+ LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop");
+ bool done = false;
+ if (main_queue)
+ {
+ const LLUUID mesh_id_copy = mesh_id; // capture by value for the lambda
+ done = main_queue->post([mesh_id_copy, size]()
+ {
+ LLError::LLUserWarningMsg::showOutOfMemory();
+ LL_ERRS("MeshStreaming") << "Out of memory unpacking mesh id " << mesh_id_copy
+ << " of compressed size " << size << LL_ENDL;
+ });
+ }
+ if (!done)
+ {
+ // No main queue available (e.g. during shutdown)
+ LL_WARNS("MeshStreaming") << "Out of memory unpacking mesh id " << mesh_id
+ << " of compressed size " << size << " (main queue unavailable)" << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_WARNS("MeshStreaming") << "Out of memory unpacking mesh id " << mesh_id
+ << " of compressed size " << size << LL_ENDL;
+ }
+ return false;
+ }
+ catch (const std::exception& e)
{
- LL_DEBUGS("MeshStreaming") << "Failed to unzip LLSD blob for LoD with code " << uzip_result << " , will probably fetch from sim again." << LL_ENDL;
+ LL_WARNS("MeshStreaming") << "Exception unpacking mesh id " << mesh_id
+ << " of compressed size " << size << ": " << e.what() << LL_ENDL;
+ return false;
+ }
+ catch (...)
+ {
+ LL_WARNS("MeshStreaming") << "Unknown exception unpacking mesh id " << mesh_id
+ << " of compressed size " << size << LL_ENDL;
return false;
}
- return unpackVolumeFacesInternal(mdl);
}
bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl)
@@ -2348,7 +2468,9 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl)
const LLSD::Binary& pos = mdl[i]["Position"].asBinary();
const LLSD::Binary& norm = mdl[i]["Normal"].asBinary();
+#if 0 // keep this code for now in case we decide to add support for on-the-wire tangents
const LLSD::Binary& tangent = mdl[i]["Tangent"].asBinary();
+#endif
const LLSD::Binary& tc = mdl[i]["TexCoord0"].asBinary();
const LLSD::Binary& idx = mdl[i]["TriangleList"].asBinary();
@@ -2383,11 +2505,31 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl)
//copy out vertices
U32 num_verts = static_cast<U32>(pos.size())/(3*2);
+ if (num_verts == 0)
+ {
+ LL_WARNS() << "Zero vertices for face index: " << i << LL_ENDL;
+ face.resizeIndices(3);
+ face.resizeVertices(1);
+ face.mPositions->clear();
+ face.mNormals->clear();
+ face.mTexCoords->setZero();
+ memset(face.mIndices, 0, sizeof(U16) * 3);
+ continue;
+ }
+
+ if (num_verts > 65535) // U16 indices
+ {
+ LL_WARNS() << "Invalid vertex count " << num_verts << " exceeds maximum for face index: " << i << LL_ENDL;
+ mVolumeFaces.clear();
+ return false;
+ }
+
face.resizeVertices(num_verts);
if (num_verts > 0 && !face.mPositions)
{
LL_WARNS() << "Failed to allocate " << num_verts << " vertices for face index: " << i << " Total: " << face_count << LL_ENDL;
+ face.resizeVertices(0);
face.resizeIndices(0);
continue;
}
@@ -4943,9 +5085,17 @@ LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
mOctree(NULL),
mOctreeTriangles(NULL)
{
- mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
- mCenter = mExtents+2;
- *this = src;
+ try
+ {
+ mExtents = (LLVector4a*)ll_aligned_malloc_16(sizeof(LLVector4a) * 3);
+ mCenter = mExtents + 2;
+ *this = src;
+ }
+ catch (std::bad_alloc&)
+ {
+ LLError::LLUserWarningMsg::showOutOfMemory();
+ LL_ERRS("LLVolume") << "Bad memory allocation in LLVolumeFace" << LL_ENDL;
+ }
}
LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
@@ -5163,7 +5313,7 @@ void LLVolumeFace::remap()
// Documentation for meshopt_generateVertexRemapMulti claims that remap should use vertice count
// but all examples use indice count. There are out of bounds crashes when using vertice count.
// To be on the safe side use bigger of the two.
- std::vector<unsigned int> remap(llmax(mNumIndices, mNumVertices));
+ std::vector<unsigned int> remap(llmax(mNumIndices, mNumVertices), 0);
S32 remap_vertices_count = static_cast<S32>(LLMeshOptimizer::generateRemapMultiU16(&remap[0],
mIndices,
mNumIndices,
@@ -5669,7 +5819,40 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
mOptimized = true;
if (gen_tangents && mNormals && mTexCoords)
- { // generate mikkt space tangents before cache optimizing since the index buffer may change
+ {
+ if (!mPositions || !mIndices || mNumVertices <= 0 || mNumIndices <= 0)
+ {
+ LL_WARNS_ONCE("LLVolume") << "Invalid volume face data for tangent generation: "
+ << "mPositions=" << (void*)mPositions
+ << ", mIndices=" << (void*)mIndices
+ << ", mNumVertices=" << mNumVertices
+ << ", mNumIndices=" << mNumIndices << LL_ENDL;
+ return false;
+ }
+
+ if (mNumIndices % 3 != 0)
+ {
+ LL_WARNS_ONCE("LLVolume") << "Non-triangulated mesh, mNumIndices=" << mNumIndices << LL_ENDL;
+ return false;
+ }
+
+ for (S32 i = 0; i < mNumIndices; ++i)
+ {
+ if (mIndices[i] >= mNumVertices)
+ {
+ LL_WARNS_ONCE("LLVolume") << "Out of bounds index detected: mIndices[" << i << "]="
+ << mIndices[i] << " >= mNumVertices=" << mNumVertices << LL_ENDL;
+ return false;
+ }
+ }
+
+ if (mNormalizedScale.mV[0] == 0.0f || mNormalizedScale.mV[1] == 0.0f || mNormalizedScale.mV[2] == 0.0f)
+ {
+ LL_WARNS_ONCE("LLVolume") << "Invalid normalized scale: " << mNormalizedScale << LL_ENDL;
+ return false;
+ }
+
+ // generate mikkt space tangents before cache optimizing since the index buffer may change
// a bit of a hack to do this here, but this function gets called exactly once for the lifetime of a mesh
// and is executed on a background thread
MikktData data(this);
@@ -5681,7 +5864,12 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
- LL_ERRS("LLCoros") << "Bad memory allocation in MikktData::genTangSpace" << LL_ENDL;
+ LL_ERRS("LLVolume") << "Bad memory allocation in MikktData::genTangSpace" << LL_ENDL;
+ }
+ catch (...)
+ {
+ LL_WARNS_ONCE("LLVolume") << "Mikktspace::genTangSpace() failed" << LL_ENDL;
+ return false;
}
@@ -5703,7 +5891,7 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
- LL_ERRS("LLCoros") << "Failed to allocate memory for remap: " << (S32)data.p.size() << LL_ENDL;
+ LL_ERRS("LLVOLUME") << "Failed to allocate memory for remap: " << (S32)data.p.size() << LL_ENDL;
}
U32 stream_count = data.w.empty() ? 4 : 5;
@@ -5720,7 +5908,7 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
- LL_ERRS("LLCoros") << "Failed to allocate memory for VertexRemap: " << (S32)data.p.size() << LL_ENDL;
+ LL_ERRS("LLVolume") << "Failed to allocate memory for VertexRemap: " << (S32)data.p.size() << LL_ENDL;
}
}
@@ -5732,7 +5920,7 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
if (mNumVertices == 0)
{
LLError::LLUserWarningMsg::showOutOfMemory();
- LL_ERRS("LLCoros") << "Failed to allocate memory for resizeVertices(" << vert_count << ")" << LL_ENDL;
+ LL_ERRS("LLVolume") << "Failed to allocate memory for resizeVertices(" << vert_count << ")" << LL_ENDL;
}
if (!data.w.empty())