diff options
Diffstat (limited to 'indra/llmath/llvolume.cpp')
| -rw-r--r-- | indra/llmath/llvolume.cpp | 228 |
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()) |
