diff options
Diffstat (limited to 'indra/newview/llmeshrepository.cpp')
-rw-r--r-- | indra/newview/llmeshrepository.cpp | 194 |
1 files changed, 116 insertions, 78 deletions
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 6e0722bcf9..be11c53efa 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -78,6 +78,14 @@ LLMeshRepository gMeshRepo; const U32 MAX_MESH_REQUESTS_PER_SECOND = 100; +// Maximum mesh version to support. Three least significant digits are reserved for the minor version, +// with major version changes indicating a format change that is not backwards compatible and should not +// be parsed by viewers that don't specifically support that version. For example, if the integer "1" is +// present, the version is 0.001. A viewer that can parse version 0.001 can also parse versions up to 0.999, +// but not 1.0 (integer 1000). +// See wiki at https://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format +const S32 MAX_MESH_VERSION = 999; + U32 LLMeshRepository::sBytesReceived = 0; U32 LLMeshRepository::sHTTPRequestCount = 0; U32 LLMeshRepository::sHTTPRetryCount = 0; @@ -843,12 +851,13 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) if (header_size > 0) { + S32 version = mMeshHeader[mesh_id]["version"].asInteger(); S32 offset = header_size + mMeshHeader[mesh_id]["skin"]["offset"].asInteger(); S32 size = mMeshHeader[mesh_id]["skin"]["size"].asInteger(); mHeaderMutex->unlock(); - if (offset >= 0 && size > 0) + if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) { //check VFS for mesh skin info LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH); @@ -915,12 +924,13 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) if (header_size > 0) { + S32 version = mMeshHeader[mesh_id]["version"].asInteger(); S32 offset = header_size + mMeshHeader[mesh_id]["physics_convex"]["offset"].asInteger(); S32 size = mMeshHeader[mesh_id]["physics_convex"]["size"].asInteger(); mHeaderMutex->unlock(); - if (offset >= 0 && size > 0) + if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) { //check VFS for mesh skin info LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH); @@ -987,12 +997,13 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) if (header_size > 0) { + S32 version = mMeshHeader[mesh_id]["version"].asInteger(); S32 offset = header_size + mMeshHeader[mesh_id]["physics_mesh"]["offset"].asInteger(); S32 size = mMeshHeader[mesh_id]["physics_mesh"]["size"].asInteger(); mHeaderMutex->unlock(); - if (offset >= 0 && size > 0) + if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) { //check VFS for mesh physics shape info LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH); @@ -1103,10 +1114,12 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod) if (header_size > 0) { + S32 version = mMeshHeader[mesh_id]["version"].asInteger(); S32 offset = header_size + mMeshHeader[mesh_id][header_lod[lod]]["offset"].asInteger(); S32 size = mMeshHeader[mesh_id][header_lod[lod]]["size"].asInteger(); mHeaderMutex->unlock(); - if (offset >= 0 && size > 0) + + if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) { //check VFS for mesh asset @@ -1383,6 +1396,8 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, mWholeModelFeeCapability = gAgent.getRegion()->getCapability("NewFileAgentInventory"); mOrigin += gAgent.getAtAxis() * scale.magVec(); + + mMeshUploadTimeOut = gSavedSettings.getS32("MeshUploadTimeOut") ; } LLMeshUploadThread::~LLMeshUploadThread() @@ -1573,6 +1588,11 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) for (S32 face_num = 0; face_num < data.mBaseModel->getNumVolumeFaces(); face_num++) { + if(face_num >= instance.mMaterial.size()) + { + break ; + } + LLImportMaterial& material = instance.mMaterial[face_num]; LLSD face_entry = LLSD::emptyMap(); LLViewerFetchedTexture *texture = material.mDiffuseMap.get(); @@ -1686,7 +1706,7 @@ void LLMeshUploadThread::doWholeModelUpload() mPendingUploads++; LLCurlRequest::headers_t headers; mCurlRequest->post(mWholeModelFeeCapability, headers, model_data, - new LLWholeModelFeeResponder(this,model_data)); + new LLWholeModelFeeResponder(this,model_data), mMeshUploadTimeOut); do { @@ -1705,7 +1725,7 @@ void LLMeshUploadThread::doWholeModelUpload() LLSD body = full_model_data["asset_resources"]; dump_llsd_to_file(body,make_dump_name("whole_model_body_",dump_num)); mCurlRequest->post(mWholeModelUploadURL, headers, body, - new LLWholeModelUploadResponder(this, model_data)); + new LLWholeModelUploadResponder(this, model_data), mMeshUploadTimeOut); do { mCurlRequest->process(); @@ -1799,7 +1819,9 @@ S32 LLMeshRepository::getActualMeshLOD(LLSD& header, S32 lod) { lod = llclamp(lod, 0, 3); - if (header.has("404")) + S32 version = header["version"]; + + if (header.has("404") || version > MAX_MESH_VERSION) { return -1; } @@ -2135,54 +2157,59 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason, LLUUID mesh_id = mMeshParams.getSculptID(); LLSD header = gMeshRepo.mThread->mMeshHeader[mesh_id]; - std::stringstream str; + S32 version = header["version"].asInteger(); + + if (version <= MAX_MESH_VERSION) + { + std::stringstream str; - S32 lod_bytes = 0; + S32 lod_bytes = 0; - for (U32 i = 0; i < LLModel::LOD_PHYSICS; ++i) - { //figure out how many bytes we'll need to reserve in the file - std::string lod_name = header_lod[i]; - lod_bytes = llmax(lod_bytes, header[lod_name]["offset"].asInteger()+header[lod_name]["size"].asInteger()); - } + for (U32 i = 0; i < LLModel::LOD_PHYSICS; ++i) + { //figure out how many bytes we'll need to reserve in the file + std::string lod_name = header_lod[i]; + lod_bytes = llmax(lod_bytes, header[lod_name]["offset"].asInteger()+header[lod_name]["size"].asInteger()); + } - //just in case skin info or decomposition is at the end of the file (which it shouldn't be) - lod_bytes = llmax(lod_bytes, header["skin"]["offset"].asInteger() + header["skin"]["size"].asInteger()); - lod_bytes = llmax(lod_bytes, header["physics_convex"]["offset"].asInteger() + header["physics_convex"]["size"].asInteger()); + //just in case skin info or decomposition is at the end of the file (which it shouldn't be) + lod_bytes = llmax(lod_bytes, header["skin"]["offset"].asInteger() + header["skin"]["size"].asInteger()); + lod_bytes = llmax(lod_bytes, header["physics_convex"]["offset"].asInteger() + header["physics_convex"]["size"].asInteger()); - S32 header_bytes = (S32) gMeshRepo.mThread->mMeshHeaderSize[mesh_id]; - S32 bytes = lod_bytes + header_bytes; + S32 header_bytes = (S32) gMeshRepo.mThread->mMeshHeaderSize[mesh_id]; + S32 bytes = lod_bytes + header_bytes; - //it's possible for the remote asset to have more data than is needed for the local cache - //only allocate as much space in the VFS as is needed for the local cache - data_size = llmin(data_size, bytes); + //it's possible for the remote asset to have more data than is needed for the local cache + //only allocate as much space in the VFS as is needed for the local cache + data_size = llmin(data_size, bytes); - LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH, LLVFile::WRITE); - if (file.getMaxSize() >= bytes || file.setMaxSize(bytes)) - { - LLMeshRepository::sCacheBytesWritten += data_size; + LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH, LLVFile::WRITE); + if (file.getMaxSize() >= bytes || file.setMaxSize(bytes)) + { + LLMeshRepository::sCacheBytesWritten += data_size; - file.write((const U8*) data, data_size); + file.write((const U8*) data, data_size); - //zero out the rest of the file - U8 block[4096]; - memset(block, 0, 4096); + //zero out the rest of the file + U8 block[4096]; + memset(block, 0, 4096); - while (bytes-file.tell() > 4096) - { - file.write(block, 4096); - } + while (bytes-file.tell() > 4096) + { + file.write(block, 4096); + } - S32 remaining = bytes-file.tell(); + S32 remaining = bytes-file.tell(); - if (remaining < 0 || remaining > 4096) - { - llerrs << "Bad padding of mesh asset cache entry." << llendl; - } + if (remaining < 0 || remaining > 4096) + { + llerrs << "Bad padding of mesh asset cache entry." << llendl; + } - if (remaining > 0) - { - file.write(block, remaining); + if (remaining > 0) + { + file.write(block, remaining); + } } } } @@ -2874,7 +2901,7 @@ void LLMeshUploadThread::doUploadModel(LLMeshUploadData& data) LLCurlRequest::headers_t headers; mPendingUploads++; - mCurlRequest->post(data.mRSVP, headers, data.mAssetData, new LLMeshUploadResponder(data, this)); + mCurlRequest->post(data.mRSVP, headers, data.mAssetData, new LLMeshUploadResponder(data, this), mMeshUploadTimeOut); } } @@ -2906,7 +2933,7 @@ void LLMeshUploadThread::doUploadTexture(LLTextureUploadData& data) LLCurlRequest::headers_t headers; mPendingUploads++; - mCurlRequest->post(data.mRSVP, headers, data.mAssetData, new LLTextureUploadResponder(data, this)); + mCurlRequest->post(data.mRSVP, headers, data.mAssetData, new LLTextureUploadResponder(data, this), mMeshUploadTimeOut); } } @@ -3158,55 +3185,66 @@ void LLMeshRepository::uploadError(LLSD& args) //static F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod) { - F32 dlowest = llmin(radius/0.03f, 256.f); - F32 dlow = llmin(radius/0.06f, 256.f); - F32 dmid = llmin(radius/0.24f, 256.f); - - F32 bytes_lowest = header["lowest_lod"]["size"].asReal()/1024.f; - F32 bytes_low = header["low_lod"]["size"].asReal()/1024.f; - F32 bytes_mid = header["medium_lod"]["size"].asReal()/1024.f; - F32 bytes_high = header["high_lod"]["size"].asReal()/1024.f; + F32 max_distance = 512.f; - if (bytes) - { - *bytes = 0; - *bytes += header["lowest_lod"]["size"].asInteger(); - *bytes += header["low_lod"]["size"].asInteger(); - *bytes += header["medium_lod"]["size"].asInteger(); - *bytes += header["high_lod"]["size"].asInteger(); - } + F32 dlowest = llmin(radius/0.03f, max_distance); + 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" + F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle"); - if (bytes_visible) - { - lod = LLMeshRepository::getActualMeshLOD(header, lod); - if (lod >= 0 && lod <= 3) - { - *bytes_visible = header[header_lod[lod]]["size"].asInteger(); - } - } + S32 bytes_lowest = header["lowest_lod"]["size"].asInteger(); + S32 bytes_low = header["low_lod"]["size"].asInteger(); + S32 bytes_mid = header["medium_lod"]["size"].asInteger(); + S32 bytes_high = header["high_lod"]["size"].asInteger(); - if (bytes_high == 0.f) + if (bytes_high == 0) { return 0.f; } - if (bytes_mid == 0.f) + if (bytes_mid == 0) { bytes_mid = bytes_high; } - if (bytes_low == 0.f) + if (bytes_low == 0) { bytes_low = bytes_mid; } - if (bytes_lowest == 0.f) + if (bytes_lowest == 0) { bytes_lowest = bytes_low; } - F32 max_area = 65536.f; + F32 triangles_lowest = llmax((F32) bytes_lowest-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; + F32 triangles_low = llmax((F32) bytes_low-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; + F32 triangles_mid = llmax((F32) bytes_mid-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; + F32 triangles_high = llmax((F32) bytes_high-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; + + if (bytes) + { + *bytes = 0; + *bytes += header["lowest_lod"]["size"].asInteger(); + *bytes += header["low_lod"]["size"].asInteger(); + *bytes += header["medium_lod"]["size"].asInteger(); + *bytes += header["high_lod"]["size"].asInteger(); + } + + if (bytes_visible) + { + lod = LLMeshRepository::getActualMeshLOD(header, lod); + if (lod >= 0 && lod <= 3) + { + *bytes_visible = header[header_lod[lod]]["size"].asInteger(); + } + } + + F32 max_area = 102932.f; //area of circle that encompasses region F32 min_area = 1.f; F32 high_area = llmin(F_PI*dmid*dmid, max_area); @@ -3229,12 +3267,12 @@ F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32 low_area /= total_area; lowest_area /= total_area; - F32 weighted_avg = bytes_high*high_area + - bytes_mid*mid_area + - bytes_low*low_area + - bytes_lowest*lowest_area; + F32 weighted_avg = triangles_high*high_area + + triangles_mid*mid_area + + triangles_low*low_area + + triangles_lowest*lowest_area; - return weighted_avg * gSavedSettings.getF32("MeshStreamingCostScaler"); + return weighted_avg/gSavedSettings.getU32("MeshTriangleBudget")*15000.f; } |