From 8df303ed8506a0c4fe8965130e1ac9df75d156b1 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 21 Jul 2025 19:30:05 +0300 Subject: #4399 Crash at load_face_from_dom_triangles Since these offsets are used for idx[i+offset] where i starts from 0, they shouldn't be below 0 to not go out of bounds. --- indra/llprimitive/lldaeloader.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'indra/llprimitive') diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index a11f9b5ca2..bfcd84a43d 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -204,12 +204,15 @@ LLModel::EModelStatus load_face_from_dom_triangles( if (idx_stride <= 0 || (pos_source && pos_offset >= idx_stride) + || (pos_source && pos_offset < 0) || (tc_source && tc_offset >= idx_stride) - || (norm_source && norm_offset >= idx_stride)) + || (tc_source && tc_offset < 0) + || (norm_source && norm_offset >= idx_stride) + || (norm_source && norm_offset < 0)) { // Looks like these offsets should fit inside idx_stride // Might be good idea to also check idx.getCount()%idx_stride != 0 - LL_WARNS() << "Invalid pos_offset " << pos_offset << ", tc_offset " << tc_offset << " or norm_offset " << norm_offset << LL_ENDL; + LL_WARNS() << "Invalid idx_stride " << idx_stride << ", pos_offset " << pos_offset << ", tc_offset " << tc_offset << " or norm_offset " << norm_offset << LL_ENDL; return LLModel::BAD_ELEMENT; } -- cgit v1.3 From d84897967e836cd2dadf8f609eb98946f500d5b1 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 22 Jul 2025 01:54:33 +0300 Subject: #4318 Warn or log when texture gets scaled down for material and model upload --- indra/llprimitive/llmodelloader.cpp | 4 +-- indra/llprimitive/llmodelloader.h | 4 +-- indra/newview/gltf/llgltfloader.cpp | 1 + indra/newview/llfloatermodelpreview.cpp | 8 ++--- indra/newview/llmaterialeditor.cpp | 36 ++++++++++++++++++++ indra/newview/llmodelpreview.cpp | 38 +++++++++++++++++----- indra/newview/llmodelpreview.h | 5 +++ .../skins/default/xui/en/floater_model_preview.xml | 1 + .../newview/skins/default/xui/en/notifications.xml | 14 ++++++++ 9 files changed, 94 insertions(+), 17 deletions(-) (limited to 'indra/llprimitive') diff --git a/indra/llprimitive/llmodelloader.cpp b/indra/llprimitive/llmodelloader.cpp index db4c4259f3..630c109d8f 100644 --- a/indra/llprimitive/llmodelloader.cpp +++ b/indra/llprimitive/llmodelloader.cpp @@ -123,7 +123,6 @@ LLModelLoader::LLModelLoader( , mLod(lod) , mTrySLM(false) , mFirstTransform(true) -, mNumOfFetchingTextures(0) , mLoadCallback(load_cb) , mJointLookupFunc(joint_lookup_func) , mTextureLoadFunc(texture_load_func) @@ -134,6 +133,7 @@ LLModelLoader::LLModelLoader( , mNoNormalize(false) , mNoOptimize(false) , mCacheOnlyHitIfRigged(false) +, mTexturesNeedScaling(false) , mMaxJointsPerMesh(maxJointsPerMesh) , mGeneratedModelLimit(modelLimit) , mDebugMode(debugMode) @@ -669,7 +669,7 @@ void LLModelLoader::loadTextures() if(!material.mDiffuseMapFilename.empty()) { - mNumOfFetchingTextures += mTextureLoadFunc(material, mOpaqueData); + mTextureLoadFunc(material, mOpaqueData); } } } diff --git a/indra/llprimitive/llmodelloader.h b/indra/llprimitive/llmodelloader.h index 06a17f006e..335d809386 100644 --- a/indra/llprimitive/llmodelloader.h +++ b/indra/llprimitive/llmodelloader.h @@ -109,6 +109,7 @@ public: bool mTrySLM; bool mCacheOnlyHitIfRigged; // ignore cached SLM if it does not contain rig info (and we want rig info) + bool mTexturesNeedScaling; model_list mModelList; // The scene is pretty much what ends up getting loaded for upload. Basically assign things to this guy if you want something uploaded. @@ -170,9 +171,6 @@ public: void stretch_extents(const LLModel* model, const LLMatrix4& mat); - S32 mNumOfFetchingTextures ; // updated in the main thread - bool areTexturesReady() { return !mNumOfFetchingTextures; } // called in the main thread. - bool verifyCount( int expected, int result ); //Determines the viability of an asset to be used as an avatar rig (w or w/o joint upload caps) diff --git a/indra/newview/gltf/llgltfloader.cpp b/indra/newview/gltf/llgltfloader.cpp index 3019a12446..9f6caf4198 100644 --- a/indra/newview/gltf/llgltfloader.cpp +++ b/indra/newview/gltf/llgltfloader.cpp @@ -611,6 +611,7 @@ LLGLTFLoader::LLGLTFImportMaterial LLGLTFLoader::processMaterial(S32 material_in LL::GLTF::Image& image = mGLTFAsset.mImages[sourceIndex]; if (image.mTexture.notNull()) { + mTexturesNeedScaling |= image.mHeight > LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT || image.mWidth > LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT; impMat.setDiffuseMap(image.mTexture->getID()); LL_INFOS("GLTF_IMPORT") << "Using existing texture ID: " << image.mTexture->getID().asString() << LL_ENDL; } diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index bd33ab2dbe..5aef7f20b4 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1340,26 +1340,26 @@ void LLFloaterModelPreview::addStringToLog(const std::string& message, const LLS { std::string str; switch (lod) -{ + { case LLModel::LOD_IMPOSTOR: str = "LOD0 "; break; case LLModel::LOD_LOW: str = "LOD1 "; break; case LLModel::LOD_MEDIUM: str = "LOD2 "; break; case LLModel::LOD_PHYSICS: str = "PHYS "; break; case LLModel::LOD_HIGH: str = "LOD3 "; break; default: break; -} + } LLStringUtil::format_map_t args_msg; LLSD::map_const_iterator iter = args.beginMap(); LLSD::map_const_iterator end = args.endMap(); for (; iter != end; ++iter) -{ + { args_msg[iter->first] = iter->second.asString(); } str += sInstance->getString(message, args_msg); sInstance->addStringToLogTab(str, flash); } - } +} // static void LLFloaterModelPreview::addStringToLog(const std::string& str, bool flash) diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 5b3ac53d51..3cab060357 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -2479,6 +2479,42 @@ void LLMaterialEditor::loadMaterial(const tinygltf::Model &model_in, const std:: pack_textures(base_color_img, normal_img, mr_img, emissive_img, occlusion_img, mBaseColorJ2C, mNormalJ2C, mMetallicRoughnessJ2C, mEmissiveJ2C); + if (open_floater) + { + bool textures_scaled = false; + if (mBaseColorFetched && mBaseColorJ2C + && (mBaseColorFetched->getWidth() != mBaseColorJ2C->getWidth() + || mBaseColorFetched->getHeight() != mBaseColorJ2C->getHeight())) + { + textures_scaled = true; + } + else if (mNormalFetched && mNormalJ2C + && (mNormalFetched->getWidth() != mNormalJ2C->getWidth() + || mNormalFetched->getHeight() != mNormalJ2C->getHeight())) + { + textures_scaled = true; + } + else if (mMetallicRoughnessFetched && mMetallicRoughnessJ2C + && (mMetallicRoughnessFetched->getWidth() != mMetallicRoughnessJ2C->getWidth() + || mMetallicRoughnessFetched->getHeight() != mMetallicRoughnessJ2C->getHeight())) + { + textures_scaled = true; + } + else if (mEmissiveFetched && mEmissiveJ2C + && (mEmissiveFetched->getWidth() != mEmissiveJ2C->getWidth() + || mEmissiveFetched->getHeight() != mEmissiveJ2C->getHeight())) + { + textures_scaled = true; + } + + if (textures_scaled) + { + LLSD args; + args["MAX_SIZE"] = LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT; + LLNotificationsUtil::add("MaterialImagesWereScaled", args); + } + } + LLUUID base_color_id; if (mBaseColorFetched.notNull()) { diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index ac697383e2..e819f4dec0 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -169,6 +169,8 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) , mLastJointUpdate(false) , mFirstSkinUpdate(true) , mHasDegenerate(false) + , mNumOfFetchingTextures(0) + , mTexturesNeedScaling(false) , mImporterDebug(LLCachedControl(gSavedSettings, "ImporterDebugVerboseLogging", false)) { mNeedsUpdate = true; @@ -559,10 +561,7 @@ void LLModelPreview::rebuildUploadData() texture->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, true, false, new LLHandle(getHandle()), &mCallbackTextureList, false); texture->forceToSaveRawImage(0, F32_MAX); texture->updateFetch(); - if (mModelLoader) - { - mModelLoader->mNumOfFetchingTextures++; - } + mNumOfFetchingTextures++; } } } @@ -997,7 +996,9 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) setRigValidForJointPositionUpload(mModelLoader->isRigValidForJointPositionUpload()); setLegacyRigFlags(mModelLoader->getLegacyRigFlags()); + mTexturesNeedScaling |= mModelLoader->mTexturesNeedScaling; mModelLoader->loadTextures(); + warnTextureScaling(); if (loaded_lod == -1) { //populate all LoDs from model loader scene @@ -2510,7 +2511,7 @@ void LLModelPreview::updateStatusMessages() LLMutexLock lock(this); if (mModelLoader) { - if (!mModelLoader->areTexturesReady() && mFMP->childGetValue("upload_textures").asBoolean()) + if (!areTexturesReady() && mFMP->childGetValue("upload_textures").asBoolean()) { // Some textures are still loading, prevent upload until they are done mModelNoErrors = false; @@ -3216,6 +3217,7 @@ U32 LLModelPreview::loadTextures(LLImportMaterial& material, LLHandlesetLoadedCallback(LLModelPreview::textureLoadedCallback, 0, true, false, new LLHandle(handle), &preview->mCallbackTextureList, false); tex->forceToSaveRawImage(0, F32_MAX); material.setDiffuseMap(tex->getID()); // record tex ID + preview->mNumOfFetchingTextures++; return 1; } @@ -4060,6 +4062,18 @@ void LLModelPreview::setPreviewLOD(S32 lod) updateStatusMessages(); } +void LLModelPreview::warnTextureScaling() +{ + if (areTexturesReady() && mTexturesNeedScaling) + { + std::ostringstream out; + out << "One or more textures in this model were scaled to be within the allowed limits."; + LL_INFOS() << out.str() << LL_ENDL; + LLSD args; + LLFloaterModelPreview::addStringToLog("ModelTextureScaling", args, true, -1); + } +} + //static void LLModelPreview::textureLoadedCallback( bool success, @@ -4080,11 +4094,19 @@ void LLModelPreview::textureLoadedCallback( LLModelPreview* preview = static_cast(handle->get()); preview->refresh(); - if (final && preview->mModelLoader) + if (final) { - if (preview->mModelLoader->mNumOfFetchingTextures > 0) + if (src_vi + && (src_vi->getOriginalWidth() > LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT + || src_vi->getOriginalHeight() > LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT)) + { + preview->mTexturesNeedScaling = true; + } + + if (preview->mNumOfFetchingTextures > 0) { - preview->mModelLoader->mNumOfFetchingTextures--; + preview->mNumOfFetchingTextures--; + preview->warnTextureScaling(); } } } diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h index 0873263587..7b3b699b33 100644 --- a/indra/newview/llmodelpreview.h +++ b/indra/newview/llmodelpreview.h @@ -204,6 +204,7 @@ public: std::vector mLodsQuery; std::vector mLodsWithParsingError; bool mHasDegenerate; + bool areTexturesReady() { return !mNumOfFetchingTextures; } protected: @@ -213,6 +214,7 @@ protected: static LLJoint* lookupJointByName(const std::string&, void* opaque); static U32 loadTextures(LLImportMaterial& material, LLHandle handle); + void warnTextureScaling(); void lookupLODModelFiles(S32 lod); private: @@ -242,6 +244,9 @@ private: /// Not read unless mWarnOfUnmatchedPhyicsMeshes is true. LLPointer mDefaultPhysicsShapeP; + S32 mNumOfFetchingTextures; + bool mTexturesNeedScaling; + typedef enum { MESH_OPTIMIZER_FULL, diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index a86b9c7da2..f11d687840 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -39,6 +39,7 @@ Analyzing... Simplifying... TBD + One or more textures in this model were scaled to be within the allowed limits. Skinning disabled due to too many joints: [JOINTS], maximum: [MAX] diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 82e77119ab..a7e892f6f2 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -7135,6 +7135,20 @@ You don't have permission to view this notecard. fail + +One or more textures in this material were scaled to be within the allowed limits. +Textures must have power of two dimensions and must not exceed [MAX_SIZE]x[MAX_SIZE] pixels. + + confirm + + + Date: Tue, 22 Jul 2025 19:14:18 +0300 Subject: #4393 Handle unknown exceptions in uploader better Output is highly technical, but better than nothing --- indra/llprimitive/llmodelloader.cpp | 3 ++- indra/newview/gltf/llgltfloader.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'indra/llprimitive') diff --git a/indra/llprimitive/llmodelloader.cpp b/indra/llprimitive/llmodelloader.cpp index 630c109d8f..0383659f62 100644 --- a/indra/llprimitive/llmodelloader.cpp +++ b/indra/llprimitive/llmodelloader.cpp @@ -33,6 +33,7 @@ #include "llmatrix4a.h" #include +#include std::list LLModelLoader::sActiveLoaderList; @@ -184,7 +185,7 @@ void LLModelLoader::run() LLSD args; args["Message"] = "UnknownException"; args["FILENAME"] = mFilename; - args["EXCEPTION"] = "Unknown exception"; + args["EXCEPTION"] = boost::current_exception_diagnostic_information(); mWarningsArray.append(args); setLoadState(ERROR_PARSING); } diff --git a/indra/newview/gltf/llgltfloader.cpp b/indra/newview/gltf/llgltfloader.cpp index 9f6caf4198..950e98c96d 100644 --- a/indra/newview/gltf/llgltfloader.cpp +++ b/indra/newview/gltf/llgltfloader.cpp @@ -59,6 +59,7 @@ #include #include +#include #include static const std::string lod_suffix[LLModel::NUM_LODS] = @@ -154,7 +155,7 @@ bool LLGLTFLoader::OpenFile(const std::string &filename) LLSD args; args["Message"] = "ParsingErrorException"; args["FILENAME"] = filename; - args["EXCEPTION"] = "Unknown exception"; + args["EXCEPTION"] = boost::current_exception_diagnostic_information(); mWarningsArray.append(args); setLoadState(ERROR_PARSING); return false; -- cgit v1.3